]> Git Repo - qemu.git/blame - migration/qemu-file-buf.c
target-arm: Add arm_boot_info secure_boot control
[qemu.git] / migration / qemu-file-buf.c
CommitLineData
977184db
DDAG
1/*
2 * QEMU System Emulator
3 *
4 * Copyright (c) 2003-2008 Fabrice Bellard
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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.
23 */
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"
32
33#define QSB_CHUNK_SIZE (1 << 10)
34#define QSB_MAX_CHUNK_SIZE (16 * QSB_CHUNK_SIZE)
35
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.
41 *
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
45 *
46 * Returns a pointer to a QEMUSizedBuffer or NULL on allocation failure
47 */
48QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len)
49{
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;
55
56 num_chunks = DIV_ROUND_UP(len ? len : QSB_CHUNK_SIZE, chunk_size);
57 alloc_len = num_chunks * chunk_size;
58
59 qsb = g_try_new0(QEMUSizedBuffer, 1);
60 if (!qsb) {
61 return NULL;
62 }
63
64 qsb->iov = g_try_new0(struct iovec, num_chunks);
65 if (!qsb->iov) {
66 g_free(qsb);
67 return NULL;
68 }
69
70 qsb->n_iov = num_chunks;
71
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;
78 }
79
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;
86 }
87 }
88
89 qsb->size = alloc_len;
90
91 return qsb;
92}
93
94/**
95 * Free the QEMUSizedBuffer
96 *
97 * @qsb: The QEMUSizedBuffer to free
98 */
99void qsb_free(QEMUSizedBuffer *qsb)
100{
101 size_t i;
102
103 if (!qsb) {
104 return;
105 }
106
107 for (i = 0; i < qsb->n_iov; i++) {
108 g_free(qsb->iov[i].iov_base);
109 }
110 g_free(qsb->iov);
111 g_free(qsb);
112}
113
114/**
115 * Get the number of used bytes in the QEMUSizedBuffer
116 *
117 * @qsb: A QEMUSizedBuffer
118 *
119 * Returns the number of bytes currently used in this buffer
120 */
121size_t qsb_get_length(const QEMUSizedBuffer *qsb)
122{
123 return qsb->used;
124}
125
126/**
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.
131 *
132 * @qsb: A QEMUSizedBuffer
133 * @new_len: The new length of bytes in the buffer
134 *
135 * Returns the number of bytes the buffer was truncated or extended
136 * to.
137 */
138size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t new_len)
139{
140 if (new_len <= qsb->size) {
141 qsb->used = new_len;
142 } else {
143 qsb->used = qsb->size;
144 }
145 return qsb->used;
146}
147
148/**
149 * Get the iovec that holds the data for a given position @pos.
150 *
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
156 *
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.
160 */
161static ssize_t qsb_get_iovec(const QEMUSizedBuffer *qsb,
162 off_t pos, off_t *d_off)
163{
164 ssize_t i;
165 off_t curr = 0;
166
167 if (pos > qsb->used) {
168 return -1;
169 }
170
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;
175 }
176 curr += qsb->iov[i].iov_len;
177 }
178 return -1;
179}
180
181/*
182 * Convert the QEMUSizedBuffer into a flat buffer.
183 *
184 * Note: If at all possible, try to avoid this function since it
185 * may unnecessarily copy memory around.
186 *
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)
191 *
192 * Returns the number of bytes copied into the output buffer
193 */
194ssize_t qsb_get_buffer(const QEMUSizedBuffer *qsb, off_t start,
195 size_t count, uint8_t *buffer)
196{
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;
203
204 if (start > qsb->used) {
205 return 0;
206 }
207
208 all_copy = qsb->used - start;
209 if (all_copy > count) {
210 all_copy = count;
211 } else {
212 count = all_copy;
213 }
214
215 index = qsb_get_iovec(qsb, start, &s_off);
216 if (index < 0) {
217 return 0;
218 }
219
220 while (all_copy > 0) {
221 iov = &qsb->iov[index];
222
223 s = iov->iov_base;
224
225 to_copy = iov->iov_len - s_off;
226 if (to_copy > all_copy) {
227 to_copy = all_copy;
228 }
229 memcpy(&buffer[d_off], &s[s_off], to_copy);
230
231 d_off += to_copy;
232 all_copy -= to_copy;
233
234 s_off = 0;
235 index++;
236 }
237
238 return count;
239}
240
241/**
242 * Grow the QEMUSizedBuffer to the given size and allocate
243 * memory for it.
244 *
245 * @qsb: A QEMUSizedBuffer
246 * @new_size: The new size of the buffer
247 *
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.
253 */
254static ssize_t qsb_grow(QEMUSizedBuffer *qsb, size_t new_size)
255{
256 size_t needed_chunks, i;
257
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;
263
264 needed_chunks = DIV_ROUND_UP(size_diff, chunk_size);
265
266 new_iov = g_try_new(struct iovec, qsb->n_iov + needed_chunks);
267 if (new_iov == NULL) {
268 return -ENOMEM;
269 }
270
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;
277
278 /* Free previously allocated new chunks */
279 for (j = qsb->n_iov; j < i; j++) {
280 g_free(new_iov[j].iov_base);
281 }
282 g_free(new_iov);
283
284 return -ENOMEM;
285 }
286 }
287
288 /*
289 * Now we can't get any allocation errors, copy over to new iov
290 * and switch.
291 */
292 for (i = 0; i < qsb->n_iov; i++) {
293 new_iov[i] = qsb->iov[i];
294 }
295
296 qsb->n_iov += needed_chunks;
297 g_free(qsb->iov);
298 qsb->iov = new_iov;
299 qsb->size += (needed_chunks * chunk_size);
300 }
301
302 return qsb->size;
303}
304
305/**
306 * Write into the QEMUSizedBuffer at a given position and a given
307 * number of bytes. This function will automatically grow the
308 * QEMUSizedBuffer.
309 *
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
314 *
315 * Returns @size or a negative error code in case of memory allocation failure,
316 * or with an invalid 'pos'
317 */
318ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *source,
319 off_t pos, size_t count)
320{
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;
328
329 if (rc < 0) {
330 return rc;
331 }
332
333 if (pos + count > qsb->used) {
334 qsb->used = pos + count;
335 }
336
337 index = qsb_get_iovec(qsb, pos, &d_off);
338 if (index < 0) {
339 return -EINVAL;
340 }
341
342 while (all_copy > 0) {
343 iov = &qsb->iov[index];
344
345 dest = iov->iov_base;
346
347 to_copy = iov->iov_len - d_off;
348 if (to_copy > all_copy) {
349 to_copy = all_copy;
350 }
351
352 memcpy(&dest[d_off], &source[s_off], to_copy);
353
354 s_off += to_copy;
355 all_copy -= to_copy;
356
357 d_off = 0;
358 index++;
359 }
360
361 return count;
362}
363
364/**
365 * Create a deep copy of the given QEMUSizedBuffer.
366 *
367 * @qsb: A QEMUSizedBuffer
368 *
369 * Returns a clone of @qsb or NULL on allocation failure
370 */
371QEMUSizedBuffer *qsb_clone(const QEMUSizedBuffer *qsb)
372{
373 QEMUSizedBuffer *out = qsb_create(NULL, qsb_get_length(qsb));
374 size_t i;
375 ssize_t res;
376 off_t pos = 0;
377
378 if (!out) {
379 return NULL;
380 }
381
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;
388 }
389 pos += res;
390 }
391
392 return out;
393}
394
395typedef struct QEMUBuffer {
396 QEMUSizedBuffer *qsb;
397 QEMUFile *file;
398} QEMUBuffer;
399
400static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
401{
402 QEMUBuffer *s = opaque;
403 ssize_t len = qsb_get_length(s->qsb) - pos;
404
405 if (len <= 0) {
406 return 0;
407 }
408
409 if (len > size) {
410 len = size;
411 }
412 return qsb_get_buffer(s->qsb, pos, len, buf);
413}
414
415static int buf_put_buffer(void *opaque, const uint8_t *buf,
416 int64_t pos, int size)
417{
418 QEMUBuffer *s = opaque;
419
420 return qsb_write_at(s->qsb, buf, pos, size);
421}
422
423static int buf_close(void *opaque)
424{
425 QEMUBuffer *s = opaque;
426
427 qsb_free(s->qsb);
428
429 g_free(s);
430
431 return 0;
432}
433
434const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f)
435{
436 QEMUBuffer *p;
437
438 qemu_fflush(f);
439
440 p = f->opaque;
441
442 return p->qsb;
443}
444
445static const QEMUFileOps buf_read_ops = {
446 .get_buffer = buf_get_buffer,
447 .close = buf_close,
448};
449
450static const QEMUFileOps buf_write_ops = {
451 .put_buffer = buf_put_buffer,
452 .close = buf_close,
453};
454
455QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
456{
457 QEMUBuffer *s;
458
459 if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') ||
460 mode[1] != '\0') {
461 error_report("qemu_bufopen: Argument validity check failed");
462 return NULL;
463 }
464
465 s = g_malloc0(sizeof(QEMUBuffer));
466 if (mode[0] == 'r') {
467 s->qsb = input;
468 }
469
470 if (s->qsb == NULL) {
471 s->qsb = qsb_create(NULL, 0);
472 }
473 if (!s->qsb) {
474 g_free(s);
475 error_report("qemu_bufopen: qsb_create failed");
476 return NULL;
477 }
478
479
480 if (mode[0] == 'r') {
481 s->file = qemu_fopen_ops(s, &buf_read_ops);
482 } else {
483 s->file = qemu_fopen_ops(s, &buf_write_ops);
484 }
485 return s->file;
486}
This page took 0.076617 seconds and 4 git commands to generate.