gt64xxx: remove isa_mem_base usage
[qemu/ar7.git] / migration / qemu-file-buf.c
blobe97e0bd655e81556c83f4974615d8c708418b4ac
1 /*
2 * QEMU System Emulator
4 * Copyright (c) 2003-2008 Fabrice Bellard
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
24 #include "qemu-common.h"
25 #include "qemu/iov.h"
26 #include "qemu/sockets.h"
27 #include "block/coroutine.h"
28 #include "migration/migration.h"
29 #include "migration/qemu-file.h"
30 #include "migration/qemu-file-internal.h"
31 #include "trace.h"
33 #define QSB_CHUNK_SIZE (1 << 10)
34 #define QSB_MAX_CHUNK_SIZE (16 * QSB_CHUNK_SIZE)
36 /**
37 * Create a QEMUSizedBuffer
38 * This type of buffer uses scatter-gather lists internally and
39 * can grow to any size. Any data array in the scatter-gather list
40 * can hold different amount of bytes.
42 * @buffer: Optional buffer to copy into the QSB
43 * @len: size of initial buffer; if @buffer is given, buffer must
44 * hold at least len bytes
46 * Returns a pointer to a QEMUSizedBuffer or NULL on allocation failure
48 QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len)
50 QEMUSizedBuffer *qsb;
51 size_t alloc_len, num_chunks, i, to_copy;
52 size_t chunk_size = (len > QSB_MAX_CHUNK_SIZE)
53 ? QSB_MAX_CHUNK_SIZE
54 : QSB_CHUNK_SIZE;
56 num_chunks = DIV_ROUND_UP(len ? len : QSB_CHUNK_SIZE, chunk_size);
57 alloc_len = num_chunks * chunk_size;
59 qsb = g_try_new0(QEMUSizedBuffer, 1);
60 if (!qsb) {
61 return NULL;
64 qsb->iov = g_try_new0(struct iovec, num_chunks);
65 if (!qsb->iov) {
66 g_free(qsb);
67 return NULL;
70 qsb->n_iov = num_chunks;
72 for (i = 0; i < num_chunks; i++) {
73 qsb->iov[i].iov_base = g_try_malloc0(chunk_size);
74 if (!qsb->iov[i].iov_base) {
75 /* qsb_free is safe since g_free can cope with NULL */
76 qsb_free(qsb);
77 return NULL;
80 qsb->iov[i].iov_len = chunk_size;
81 if (buffer) {
82 to_copy = (len - qsb->used) > chunk_size
83 ? chunk_size : (len - qsb->used);
84 memcpy(qsb->iov[i].iov_base, &buffer[qsb->used], to_copy);
85 qsb->used += to_copy;
89 qsb->size = alloc_len;
91 return qsb;
94 /**
95 * Free the QEMUSizedBuffer
97 * @qsb: The QEMUSizedBuffer to free
99 void qsb_free(QEMUSizedBuffer *qsb)
101 size_t i;
103 if (!qsb) {
104 return;
107 for (i = 0; i < qsb->n_iov; i++) {
108 g_free(qsb->iov[i].iov_base);
110 g_free(qsb->iov);
111 g_free(qsb);
115 * Get the number of used bytes in the QEMUSizedBuffer
117 * @qsb: A QEMUSizedBuffer
119 * Returns the number of bytes currently used in this buffer
121 size_t qsb_get_length(const QEMUSizedBuffer *qsb)
123 return qsb->used;
127 * Set the length of the buffer; the primary usage of this
128 * function is to truncate the number of used bytes in the buffer.
129 * The size will not be extended beyond the current number of
130 * allocated bytes in the QEMUSizedBuffer.
132 * @qsb: A QEMUSizedBuffer
133 * @new_len: The new length of bytes in the buffer
135 * Returns the number of bytes the buffer was truncated or extended
136 * to.
138 size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t new_len)
140 if (new_len <= qsb->size) {
141 qsb->used = new_len;
142 } else {
143 qsb->used = qsb->size;
145 return qsb->used;
149 * Get the iovec that holds the data for a given position @pos.
151 * @qsb: A QEMUSizedBuffer
152 * @pos: The index of a byte in the buffer
153 * @d_off: Pointer to an offset that this function will indicate
154 * at what position within the returned iovec the byte
155 * is to be found
157 * Returns the index of the iovec that holds the byte at the given
158 * index @pos in the byte stream; a negative number if the iovec
159 * for the given position @pos does not exist.
161 static ssize_t qsb_get_iovec(const QEMUSizedBuffer *qsb,
162 off_t pos, off_t *d_off)
164 ssize_t i;
165 off_t curr = 0;
167 if (pos > qsb->used) {
168 return -1;
171 for (i = 0; i < qsb->n_iov; i++) {
172 if (curr + qsb->iov[i].iov_len > pos) {
173 *d_off = pos - curr;
174 return i;
176 curr += qsb->iov[i].iov_len;
178 return -1;
182 * Convert the QEMUSizedBuffer into a flat buffer.
184 * Note: If at all possible, try to avoid this function since it
185 * may unnecessarily copy memory around.
187 * @qsb: pointer to QEMUSizedBuffer
188 * @start: offset to start at
189 * @count: number of bytes to copy
190 * @buf: a pointer to a buffer to write into (at least @count bytes)
192 * Returns the number of bytes copied into the output buffer
194 ssize_t qsb_get_buffer(const QEMUSizedBuffer *qsb, off_t start,
195 size_t count, uint8_t *buffer)
197 const struct iovec *iov;
198 size_t to_copy, all_copy;
199 ssize_t index;
200 off_t s_off;
201 off_t d_off = 0;
202 char *s;
204 if (start > qsb->used) {
205 return 0;
208 all_copy = qsb->used - start;
209 if (all_copy > count) {
210 all_copy = count;
211 } else {
212 count = all_copy;
215 index = qsb_get_iovec(qsb, start, &s_off);
216 if (index < 0) {
217 return 0;
220 while (all_copy > 0) {
221 iov = &qsb->iov[index];
223 s = iov->iov_base;
225 to_copy = iov->iov_len - s_off;
226 if (to_copy > all_copy) {
227 to_copy = all_copy;
229 memcpy(&buffer[d_off], &s[s_off], to_copy);
231 d_off += to_copy;
232 all_copy -= to_copy;
234 s_off = 0;
235 index++;
238 return count;
242 * Grow the QEMUSizedBuffer to the given size and allocate
243 * memory for it.
245 * @qsb: A QEMUSizedBuffer
246 * @new_size: The new size of the buffer
248 * Return:
249 * a negative error code in case of memory allocation failure
250 * or
251 * the new size of the buffer. The returned size may be greater or equal
252 * to @new_size.
254 static ssize_t qsb_grow(QEMUSizedBuffer *qsb, size_t new_size)
256 size_t needed_chunks, i;
258 if (qsb->size < new_size) {
259 struct iovec *new_iov;
260 size_t size_diff = new_size - qsb->size;
261 size_t chunk_size = (size_diff > QSB_MAX_CHUNK_SIZE)
262 ? QSB_MAX_CHUNK_SIZE : QSB_CHUNK_SIZE;
264 needed_chunks = DIV_ROUND_UP(size_diff, chunk_size);
266 new_iov = g_try_new(struct iovec, qsb->n_iov + needed_chunks);
267 if (new_iov == NULL) {
268 return -ENOMEM;
271 /* Allocate new chunks as needed into new_iov */
272 for (i = qsb->n_iov; i < qsb->n_iov + needed_chunks; i++) {
273 new_iov[i].iov_base = g_try_malloc0(chunk_size);
274 new_iov[i].iov_len = chunk_size;
275 if (!new_iov[i].iov_base) {
276 size_t j;
278 /* Free previously allocated new chunks */
279 for (j = qsb->n_iov; j < i; j++) {
280 g_free(new_iov[j].iov_base);
282 g_free(new_iov);
284 return -ENOMEM;
289 * Now we can't get any allocation errors, copy over to new iov
290 * and switch.
292 for (i = 0; i < qsb->n_iov; i++) {
293 new_iov[i] = qsb->iov[i];
296 qsb->n_iov += needed_chunks;
297 g_free(qsb->iov);
298 qsb->iov = new_iov;
299 qsb->size += (needed_chunks * chunk_size);
302 return qsb->size;
306 * Write into the QEMUSizedBuffer at a given position and a given
307 * number of bytes. This function will automatically grow the
308 * QEMUSizedBuffer.
310 * @qsb: A QEMUSizedBuffer
311 * @source: A byte array to copy data from
312 * @pos: The position within the @qsb to write data to
313 * @size: The number of bytes to copy into the @qsb
315 * Returns @size or a negative error code in case of memory allocation failure,
316 * or with an invalid 'pos'
318 ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *source,
319 off_t pos, size_t count)
321 ssize_t rc = qsb_grow(qsb, pos + count);
322 size_t to_copy;
323 size_t all_copy = count;
324 const struct iovec *iov;
325 ssize_t index;
326 char *dest;
327 off_t d_off, s_off = 0;
329 if (rc < 0) {
330 return rc;
333 if (pos + count > qsb->used) {
334 qsb->used = pos + count;
337 index = qsb_get_iovec(qsb, pos, &d_off);
338 if (index < 0) {
339 return -EINVAL;
342 while (all_copy > 0) {
343 iov = &qsb->iov[index];
345 dest = iov->iov_base;
347 to_copy = iov->iov_len - d_off;
348 if (to_copy > all_copy) {
349 to_copy = all_copy;
352 memcpy(&dest[d_off], &source[s_off], to_copy);
354 s_off += to_copy;
355 all_copy -= to_copy;
357 d_off = 0;
358 index++;
361 return count;
365 * Create a deep copy of the given QEMUSizedBuffer.
367 * @qsb: A QEMUSizedBuffer
369 * Returns a clone of @qsb or NULL on allocation failure
371 QEMUSizedBuffer *qsb_clone(const QEMUSizedBuffer *qsb)
373 QEMUSizedBuffer *out = qsb_create(NULL, qsb_get_length(qsb));
374 size_t i;
375 ssize_t res;
376 off_t pos = 0;
378 if (!out) {
379 return NULL;
382 for (i = 0; i < qsb->n_iov; i++) {
383 res = qsb_write_at(out, qsb->iov[i].iov_base,
384 pos, qsb->iov[i].iov_len);
385 if (res < 0) {
386 qsb_free(out);
387 return NULL;
389 pos += res;
392 return out;
395 typedef struct QEMUBuffer {
396 QEMUSizedBuffer *qsb;
397 QEMUFile *file;
398 bool qsb_allocated;
399 } QEMUBuffer;
401 static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
403 QEMUBuffer *s = opaque;
404 ssize_t len = qsb_get_length(s->qsb) - pos;
406 if (len <= 0) {
407 return 0;
410 if (len > size) {
411 len = size;
413 return qsb_get_buffer(s->qsb, pos, len, buf);
416 static int buf_put_buffer(void *opaque, const uint8_t *buf,
417 int64_t pos, int size)
419 QEMUBuffer *s = opaque;
421 return qsb_write_at(s->qsb, buf, pos, size);
424 static int buf_close(void *opaque)
426 QEMUBuffer *s = opaque;
428 if (s->qsb_allocated) {
429 qsb_free(s->qsb);
432 g_free(s);
434 return 0;
437 const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f)
439 QEMUBuffer *p;
441 qemu_fflush(f);
443 p = f->opaque;
445 return p->qsb;
448 static const QEMUFileOps buf_read_ops = {
449 .get_buffer = buf_get_buffer,
450 .close = buf_close,
453 static const QEMUFileOps buf_write_ops = {
454 .put_buffer = buf_put_buffer,
455 .close = buf_close,
458 QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
460 QEMUBuffer *s;
462 if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') ||
463 mode[1] != '\0') {
464 error_report("qemu_bufopen: Argument validity check failed");
465 return NULL;
468 s = g_malloc0(sizeof(QEMUBuffer));
469 s->qsb = input;
471 if (s->qsb == NULL) {
472 s->qsb = qsb_create(NULL, 0);
473 s->qsb_allocated = true;
475 if (!s->qsb) {
476 g_free(s);
477 error_report("qemu_bufopen: qsb_create failed");
478 return NULL;
482 if (mode[0] == 'r') {
483 s->file = qemu_fopen_ops(s, &buf_read_ops);
484 } else {
485 s->file = qemu_fopen_ops(s, &buf_write_ops);
487 return s->file;