machine: add default_ram_size to machine class
[qemu/ar7.git] / migration / qemu-file-buf.c
blob16a51a1e172601935c8ad5ce32b60d053340feff
1 /*
2 * QEMU System Emulator
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 * Copyright (c) 2014 IBM Corp.
7 * Authors:
8 * Stefan Berger <stefanb@linux.vnet.ibm.com>
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 * THE SOFTWARE.
28 #include "qemu-common.h"
29 #include "qemu/iov.h"
30 #include "qemu/sockets.h"
31 #include "block/coroutine.h"
32 #include "migration/migration.h"
33 #include "migration/qemu-file.h"
34 #include "migration/qemu-file-internal.h"
35 #include "trace.h"
37 #define QSB_CHUNK_SIZE (1 << 10)
38 #define QSB_MAX_CHUNK_SIZE (16 * QSB_CHUNK_SIZE)
40 /**
41 * Create a QEMUSizedBuffer
42 * This type of buffer uses scatter-gather lists internally and
43 * can grow to any size. Any data array in the scatter-gather list
44 * can hold different amount of bytes.
46 * @buffer: Optional buffer to copy into the QSB
47 * @len: size of initial buffer; if @buffer is given, buffer must
48 * hold at least len bytes
50 * Returns a pointer to a QEMUSizedBuffer or NULL on allocation failure
52 QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len)
54 QEMUSizedBuffer *qsb;
55 size_t alloc_len, num_chunks, i, to_copy;
56 size_t chunk_size = (len > QSB_MAX_CHUNK_SIZE)
57 ? QSB_MAX_CHUNK_SIZE
58 : QSB_CHUNK_SIZE;
60 num_chunks = DIV_ROUND_UP(len ? len : QSB_CHUNK_SIZE, chunk_size);
61 alloc_len = num_chunks * chunk_size;
63 qsb = g_try_new0(QEMUSizedBuffer, 1);
64 if (!qsb) {
65 return NULL;
68 qsb->iov = g_try_new0(struct iovec, num_chunks);
69 if (!qsb->iov) {
70 g_free(qsb);
71 return NULL;
74 qsb->n_iov = num_chunks;
76 for (i = 0; i < num_chunks; i++) {
77 qsb->iov[i].iov_base = g_try_malloc0(chunk_size);
78 if (!qsb->iov[i].iov_base) {
79 /* qsb_free is safe since g_free can cope with NULL */
80 qsb_free(qsb);
81 return NULL;
84 qsb->iov[i].iov_len = chunk_size;
85 if (buffer) {
86 to_copy = (len - qsb->used) > chunk_size
87 ? chunk_size : (len - qsb->used);
88 memcpy(qsb->iov[i].iov_base, &buffer[qsb->used], to_copy);
89 qsb->used += to_copy;
93 qsb->size = alloc_len;
95 return qsb;
98 /**
99 * Free the QEMUSizedBuffer
101 * @qsb: The QEMUSizedBuffer to free
103 void qsb_free(QEMUSizedBuffer *qsb)
105 size_t i;
107 if (!qsb) {
108 return;
111 for (i = 0; i < qsb->n_iov; i++) {
112 g_free(qsb->iov[i].iov_base);
114 g_free(qsb->iov);
115 g_free(qsb);
119 * Get the number of used bytes in the QEMUSizedBuffer
121 * @qsb: A QEMUSizedBuffer
123 * Returns the number of bytes currently used in this buffer
125 size_t qsb_get_length(const QEMUSizedBuffer *qsb)
127 return qsb->used;
131 * Set the length of the buffer; the primary usage of this
132 * function is to truncate the number of used bytes in the buffer.
133 * The size will not be extended beyond the current number of
134 * allocated bytes in the QEMUSizedBuffer.
136 * @qsb: A QEMUSizedBuffer
137 * @new_len: The new length of bytes in the buffer
139 * Returns the number of bytes the buffer was truncated or extended
140 * to.
142 size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t new_len)
144 if (new_len <= qsb->size) {
145 qsb->used = new_len;
146 } else {
147 qsb->used = qsb->size;
149 return qsb->used;
153 * Get the iovec that holds the data for a given position @pos.
155 * @qsb: A QEMUSizedBuffer
156 * @pos: The index of a byte in the buffer
157 * @d_off: Pointer to an offset that this function will indicate
158 * at what position within the returned iovec the byte
159 * is to be found
161 * Returns the index of the iovec that holds the byte at the given
162 * index @pos in the byte stream; a negative number if the iovec
163 * for the given position @pos does not exist.
165 static ssize_t qsb_get_iovec(const QEMUSizedBuffer *qsb,
166 off_t pos, off_t *d_off)
168 ssize_t i;
169 off_t curr = 0;
171 if (pos > qsb->used) {
172 return -1;
175 for (i = 0; i < qsb->n_iov; i++) {
176 if (curr + qsb->iov[i].iov_len > pos) {
177 *d_off = pos - curr;
178 return i;
180 curr += qsb->iov[i].iov_len;
182 return -1;
186 * Convert the QEMUSizedBuffer into a flat buffer.
188 * Note: If at all possible, try to avoid this function since it
189 * may unnecessarily copy memory around.
191 * @qsb: pointer to QEMUSizedBuffer
192 * @start: offset to start at
193 * @count: number of bytes to copy
194 * @buf: a pointer to a buffer to write into (at least @count bytes)
196 * Returns the number of bytes copied into the output buffer
198 ssize_t qsb_get_buffer(const QEMUSizedBuffer *qsb, off_t start,
199 size_t count, uint8_t *buffer)
201 const struct iovec *iov;
202 size_t to_copy, all_copy;
203 ssize_t index;
204 off_t s_off;
205 off_t d_off = 0;
206 char *s;
208 if (start > qsb->used) {
209 return 0;
212 all_copy = qsb->used - start;
213 if (all_copy > count) {
214 all_copy = count;
215 } else {
216 count = all_copy;
219 index = qsb_get_iovec(qsb, start, &s_off);
220 if (index < 0) {
221 return 0;
224 while (all_copy > 0) {
225 iov = &qsb->iov[index];
227 s = iov->iov_base;
229 to_copy = iov->iov_len - s_off;
230 if (to_copy > all_copy) {
231 to_copy = all_copy;
233 memcpy(&buffer[d_off], &s[s_off], to_copy);
235 d_off += to_copy;
236 all_copy -= to_copy;
238 s_off = 0;
239 index++;
242 return count;
246 * Grow the QEMUSizedBuffer to the given size and allocate
247 * memory for it.
249 * @qsb: A QEMUSizedBuffer
250 * @new_size: The new size of the buffer
252 * Return:
253 * a negative error code in case of memory allocation failure
254 * or
255 * the new size of the buffer. The returned size may be greater or equal
256 * to @new_size.
258 static ssize_t qsb_grow(QEMUSizedBuffer *qsb, size_t new_size)
260 size_t needed_chunks, i;
262 if (qsb->size < new_size) {
263 struct iovec *new_iov;
264 size_t size_diff = new_size - qsb->size;
265 size_t chunk_size = (size_diff > QSB_MAX_CHUNK_SIZE)
266 ? QSB_MAX_CHUNK_SIZE : QSB_CHUNK_SIZE;
268 needed_chunks = DIV_ROUND_UP(size_diff, chunk_size);
270 new_iov = g_try_new(struct iovec, qsb->n_iov + needed_chunks);
271 if (new_iov == NULL) {
272 return -ENOMEM;
275 /* Allocate new chunks as needed into new_iov */
276 for (i = qsb->n_iov; i < qsb->n_iov + needed_chunks; i++) {
277 new_iov[i].iov_base = g_try_malloc0(chunk_size);
278 new_iov[i].iov_len = chunk_size;
279 if (!new_iov[i].iov_base) {
280 size_t j;
282 /* Free previously allocated new chunks */
283 for (j = qsb->n_iov; j < i; j++) {
284 g_free(new_iov[j].iov_base);
286 g_free(new_iov);
288 return -ENOMEM;
293 * Now we can't get any allocation errors, copy over to new iov
294 * and switch.
296 for (i = 0; i < qsb->n_iov; i++) {
297 new_iov[i] = qsb->iov[i];
300 qsb->n_iov += needed_chunks;
301 g_free(qsb->iov);
302 qsb->iov = new_iov;
303 qsb->size += (needed_chunks * chunk_size);
306 return qsb->size;
310 * Write into the QEMUSizedBuffer at a given position and a given
311 * number of bytes. This function will automatically grow the
312 * QEMUSizedBuffer.
314 * @qsb: A QEMUSizedBuffer
315 * @source: A byte array to copy data from
316 * @pos: The position within the @qsb to write data to
317 * @size: The number of bytes to copy into the @qsb
319 * Returns @size or a negative error code in case of memory allocation failure,
320 * or with an invalid 'pos'
322 ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *source,
323 off_t pos, size_t count)
325 ssize_t rc = qsb_grow(qsb, pos + count);
326 size_t to_copy;
327 size_t all_copy = count;
328 const struct iovec *iov;
329 ssize_t index;
330 char *dest;
331 off_t d_off, s_off = 0;
333 if (rc < 0) {
334 return rc;
337 if (pos + count > qsb->used) {
338 qsb->used = pos + count;
341 index = qsb_get_iovec(qsb, pos, &d_off);
342 if (index < 0) {
343 return -EINVAL;
346 while (all_copy > 0) {
347 iov = &qsb->iov[index];
349 dest = iov->iov_base;
351 to_copy = iov->iov_len - d_off;
352 if (to_copy > all_copy) {
353 to_copy = all_copy;
356 memcpy(&dest[d_off], &source[s_off], to_copy);
358 s_off += to_copy;
359 all_copy -= to_copy;
361 d_off = 0;
362 index++;
365 return count;
368 typedef struct QEMUBuffer {
369 QEMUSizedBuffer *qsb;
370 QEMUFile *file;
371 bool qsb_allocated;
372 } QEMUBuffer;
374 static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
376 QEMUBuffer *s = opaque;
377 ssize_t len = qsb_get_length(s->qsb) - pos;
379 if (len <= 0) {
380 return 0;
383 if (len > size) {
384 len = size;
386 return qsb_get_buffer(s->qsb, pos, len, buf);
389 static int buf_put_buffer(void *opaque, const uint8_t *buf,
390 int64_t pos, int size)
392 QEMUBuffer *s = opaque;
394 return qsb_write_at(s->qsb, buf, pos, size);
397 static int buf_close(void *opaque)
399 QEMUBuffer *s = opaque;
401 if (s->qsb_allocated) {
402 qsb_free(s->qsb);
405 g_free(s);
407 return 0;
410 const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f)
412 QEMUBuffer *p;
414 qemu_fflush(f);
416 p = f->opaque;
418 return p->qsb;
421 static const QEMUFileOps buf_read_ops = {
422 .get_buffer = buf_get_buffer,
423 .close = buf_close,
426 static const QEMUFileOps buf_write_ops = {
427 .put_buffer = buf_put_buffer,
428 .close = buf_close,
431 QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
433 QEMUBuffer *s;
435 if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') ||
436 mode[1] != '\0') {
437 error_report("qemu_bufopen: Argument validity check failed");
438 return NULL;
441 s = g_malloc0(sizeof(QEMUBuffer));
442 s->qsb = input;
444 if (s->qsb == NULL) {
445 s->qsb = qsb_create(NULL, 0);
446 s->qsb_allocated = true;
448 if (!s->qsb) {
449 g_free(s);
450 error_report("qemu_bufopen: qsb_create failed");
451 return NULL;
455 if (mode[0] == 'r') {
456 s->file = qemu_fopen_ops(s, &buf_read_ops);
457 } else {
458 s->file = qemu_fopen_ops(s, &buf_write_ops);
460 return s->file;