qemu/migration/qemu-file-buf.c
<<
>>
Prefs
   1/*
   2 * QEMU System Emulator
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 * Copyright (c) 2014 IBM Corp.
   6 *
   7 * Authors:
   8 *  Stefan Berger <stefanb@linux.vnet.ibm.com>
   9 *
  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:
  16 *
  17 * The above copyright notice and this permission notice shall be included in
  18 * all copies or substantial portions of the Software.
  19 *
  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.
  27 */
  28#include "qemu/osdep.h"
  29#include "qemu-common.h"
  30#include "qemu/error-report.h"
  31#include "qemu/iov.h"
  32#include "qemu/sockets.h"
  33#include "qemu/coroutine.h"
  34#include "migration/migration.h"
  35#include "migration/qemu-file.h"
  36#include "migration/qemu-file-internal.h"
  37#include "trace.h"
  38
  39#define QSB_CHUNK_SIZE      (1 << 10)
  40#define QSB_MAX_CHUNK_SIZE  (16 * QSB_CHUNK_SIZE)
  41
  42/**
  43 * Create a QEMUSizedBuffer
  44 * This type of buffer uses scatter-gather lists internally and
  45 * can grow to any size. Any data array in the scatter-gather list
  46 * can hold different amount of bytes.
  47 *
  48 * @buffer: Optional buffer to copy into the QSB
  49 * @len: size of initial buffer; if @buffer is given, buffer must
  50 *       hold at least len bytes
  51 *
  52 * Returns a pointer to a QEMUSizedBuffer or NULL on allocation failure
  53 */
  54QEMUSizedBuffer *qsb_create(const uint8_t *buffer, size_t len)
  55{
  56    QEMUSizedBuffer *qsb;
  57    size_t alloc_len, num_chunks, i, to_copy;
  58    size_t chunk_size = (len > QSB_MAX_CHUNK_SIZE)
  59                        ? QSB_MAX_CHUNK_SIZE
  60                        : QSB_CHUNK_SIZE;
  61
  62    num_chunks = DIV_ROUND_UP(len ? len : QSB_CHUNK_SIZE, chunk_size);
  63    alloc_len = num_chunks * chunk_size;
  64
  65    qsb = g_try_new0(QEMUSizedBuffer, 1);
  66    if (!qsb) {
  67        return NULL;
  68    }
  69
  70    qsb->iov = g_try_new0(struct iovec, num_chunks);
  71    if (!qsb->iov) {
  72        g_free(qsb);
  73        return NULL;
  74    }
  75
  76    qsb->n_iov = num_chunks;
  77
  78    for (i = 0; i < num_chunks; i++) {
  79        qsb->iov[i].iov_base = g_try_malloc0(chunk_size);
  80        if (!qsb->iov[i].iov_base) {
  81            /* qsb_free is safe since g_free can cope with NULL */
  82            qsb_free(qsb);
  83            return NULL;
  84        }
  85
  86        qsb->iov[i].iov_len = chunk_size;
  87        if (buffer) {
  88            to_copy = (len - qsb->used) > chunk_size
  89                      ? chunk_size : (len - qsb->used);
  90            memcpy(qsb->iov[i].iov_base, &buffer[qsb->used], to_copy);
  91            qsb->used += to_copy;
  92        }
  93    }
  94
  95    qsb->size = alloc_len;
  96
  97    return qsb;
  98}
  99
 100/**
 101 * Free the QEMUSizedBuffer
 102 *
 103 * @qsb: The QEMUSizedBuffer to free
 104 */
 105void qsb_free(QEMUSizedBuffer *qsb)
 106{
 107    size_t i;
 108
 109    if (!qsb) {
 110        return;
 111    }
 112
 113    for (i = 0; i < qsb->n_iov; i++) {
 114        g_free(qsb->iov[i].iov_base);
 115    }
 116    g_free(qsb->iov);
 117    g_free(qsb);
 118}
 119
 120/**
 121 * Get the number of used bytes in the QEMUSizedBuffer
 122 *
 123 * @qsb: A QEMUSizedBuffer
 124 *
 125 * Returns the number of bytes currently used in this buffer
 126 */
 127size_t qsb_get_length(const QEMUSizedBuffer *qsb)
 128{
 129    return qsb->used;
 130}
 131
 132/**
 133 * Set the length of the buffer; the primary usage of this
 134 * function is to truncate the number of used bytes in the buffer.
 135 * The size will not be extended beyond the current number of
 136 * allocated bytes in the QEMUSizedBuffer.
 137 *
 138 * @qsb: A QEMUSizedBuffer
 139 * @new_len: The new length of bytes in the buffer
 140 *
 141 * Returns the number of bytes the buffer was truncated or extended
 142 * to.
 143 */
 144size_t qsb_set_length(QEMUSizedBuffer *qsb, size_t new_len)
 145{
 146    if (new_len <= qsb->size) {
 147        qsb->used = new_len;
 148    } else {
 149        qsb->used = qsb->size;
 150    }
 151    return qsb->used;
 152}
 153
 154/**
 155 * Get the iovec that holds the data for a given position @pos.
 156 *
 157 * @qsb: A QEMUSizedBuffer
 158 * @pos: The index of a byte in the buffer
 159 * @d_off: Pointer to an offset that this function will indicate
 160 *         at what position within the returned iovec the byte
 161 *         is to be found
 162 *
 163 * Returns the index of the iovec that holds the byte at the given
 164 * index @pos in the byte stream; a negative number if the iovec
 165 * for the given position @pos does not exist.
 166 */
 167static ssize_t qsb_get_iovec(const QEMUSizedBuffer *qsb,
 168                             off_t pos, off_t *d_off)
 169{
 170    ssize_t i;
 171    off_t curr = 0;
 172
 173    if (pos > qsb->used) {
 174        return -1;
 175    }
 176
 177    for (i = 0; i < qsb->n_iov; i++) {
 178        if (curr + qsb->iov[i].iov_len > pos) {
 179            *d_off = pos - curr;
 180            return i;
 181        }
 182        curr += qsb->iov[i].iov_len;
 183    }
 184    return -1;
 185}
 186
 187/*
 188 * Convert the QEMUSizedBuffer into a flat buffer.
 189 *
 190 * Note: If at all possible, try to avoid this function since it
 191 *       may unnecessarily copy memory around.
 192 *
 193 * @qsb: pointer to QEMUSizedBuffer
 194 * @start: offset to start at
 195 * @count: number of bytes to copy
 196 * @buf: a pointer to a buffer to write into (at least @count bytes)
 197 *
 198 * Returns the number of bytes copied into the output buffer
 199 */
 200ssize_t qsb_get_buffer(const QEMUSizedBuffer *qsb, off_t start,
 201                       size_t count, uint8_t *buffer)
 202{
 203    const struct iovec *iov;
 204    size_t to_copy, all_copy;
 205    ssize_t index;
 206    off_t s_off;
 207    off_t d_off = 0;
 208    char *s;
 209
 210    if (start > qsb->used) {
 211        return 0;
 212    }
 213
 214    all_copy = qsb->used - start;
 215    if (all_copy > count) {
 216        all_copy = count;
 217    } else {
 218        count = all_copy;
 219    }
 220
 221    index = qsb_get_iovec(qsb, start, &s_off);
 222    if (index < 0) {
 223        return 0;
 224    }
 225
 226    while (all_copy > 0) {
 227        iov = &qsb->iov[index];
 228
 229        s = iov->iov_base;
 230
 231        to_copy = iov->iov_len - s_off;
 232        if (to_copy > all_copy) {
 233            to_copy = all_copy;
 234        }
 235        memcpy(&buffer[d_off], &s[s_off], to_copy);
 236
 237        d_off += to_copy;
 238        all_copy -= to_copy;
 239
 240        s_off = 0;
 241        index++;
 242    }
 243
 244    return count;
 245}
 246
 247/**
 248 * Grow the QEMUSizedBuffer to the given size and allocate
 249 * memory for it.
 250 *
 251 * @qsb: A QEMUSizedBuffer
 252 * @new_size: The new size of the buffer
 253 *
 254 * Return:
 255 *    a negative error code in case of memory allocation failure
 256 * or
 257 *    the new size of the buffer. The returned size may be greater or equal
 258 *    to @new_size.
 259 */
 260static ssize_t qsb_grow(QEMUSizedBuffer *qsb, size_t new_size)
 261{
 262    size_t needed_chunks, i;
 263
 264    if (qsb->size < new_size) {
 265        struct iovec *new_iov;
 266        size_t size_diff = new_size - qsb->size;
 267        size_t chunk_size = (size_diff > QSB_MAX_CHUNK_SIZE)
 268                             ? QSB_MAX_CHUNK_SIZE : QSB_CHUNK_SIZE;
 269
 270        needed_chunks = DIV_ROUND_UP(size_diff, chunk_size);
 271
 272        new_iov = g_try_new(struct iovec, qsb->n_iov + needed_chunks);
 273        if (new_iov == NULL) {
 274            return -ENOMEM;
 275        }
 276
 277        /* Allocate new chunks as needed into new_iov */
 278        for (i = qsb->n_iov; i < qsb->n_iov + needed_chunks; i++) {
 279            new_iov[i].iov_base = g_try_malloc0(chunk_size);
 280            new_iov[i].iov_len = chunk_size;
 281            if (!new_iov[i].iov_base) {
 282                size_t j;
 283
 284                /* Free previously allocated new chunks */
 285                for (j = qsb->n_iov; j < i; j++) {
 286                    g_free(new_iov[j].iov_base);
 287                }
 288                g_free(new_iov);
 289
 290                return -ENOMEM;
 291            }
 292        }
 293
 294        /*
 295         * Now we can't get any allocation errors, copy over to new iov
 296         * and switch.
 297         */
 298        for (i = 0; i < qsb->n_iov; i++) {
 299            new_iov[i] = qsb->iov[i];
 300        }
 301
 302        qsb->n_iov += needed_chunks;
 303        g_free(qsb->iov);
 304        qsb->iov = new_iov;
 305        qsb->size += (needed_chunks * chunk_size);
 306    }
 307
 308    return qsb->size;
 309}
 310
 311/**
 312 * Write into the QEMUSizedBuffer at a given position and a given
 313 * number of bytes. This function will automatically grow the
 314 * QEMUSizedBuffer.
 315 *
 316 * @qsb: A QEMUSizedBuffer
 317 * @source: A byte array to copy data from
 318 * @pos: The position within the @qsb to write data to
 319 * @size: The number of bytes to copy into the @qsb
 320 *
 321 * Returns @size or a negative error code in case of memory allocation failure,
 322 *           or with an invalid 'pos'
 323 */
 324ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *source,
 325                     off_t pos, size_t count)
 326{
 327    ssize_t rc = qsb_grow(qsb, pos + count);
 328    size_t to_copy;
 329    size_t all_copy = count;
 330    const struct iovec *iov;
 331    ssize_t index;
 332    char *dest;
 333    off_t d_off, s_off = 0;
 334
 335    if (rc < 0) {
 336        return rc;
 337    }
 338
 339    if (pos + count > qsb->used) {
 340        qsb->used = pos + count;
 341    }
 342
 343    index = qsb_get_iovec(qsb, pos, &d_off);
 344    if (index < 0) {
 345        return -EINVAL;
 346    }
 347
 348    while (all_copy > 0) {
 349        iov = &qsb->iov[index];
 350
 351        dest = iov->iov_base;
 352
 353        to_copy = iov->iov_len - d_off;
 354        if (to_copy > all_copy) {
 355            to_copy = all_copy;
 356        }
 357
 358        memcpy(&dest[d_off], &source[s_off], to_copy);
 359
 360        s_off += to_copy;
 361        all_copy -= to_copy;
 362
 363        d_off = 0;
 364        index++;
 365    }
 366
 367    return count;
 368}
 369
 370typedef struct QEMUBuffer {
 371    QEMUSizedBuffer *qsb;
 372    QEMUFile *file;
 373    bool qsb_allocated;
 374} QEMUBuffer;
 375
 376static ssize_t buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
 377                              size_t size)
 378{
 379    QEMUBuffer *s = opaque;
 380    ssize_t len = qsb_get_length(s->qsb) - pos;
 381
 382    if (len <= 0) {
 383        return 0;
 384    }
 385
 386    if (len > size) {
 387        len = size;
 388    }
 389    return qsb_get_buffer(s->qsb, pos, len, buf);
 390}
 391
 392static ssize_t buf_put_buffer(void *opaque, const uint8_t *buf,
 393                              int64_t pos, size_t size)
 394{
 395    QEMUBuffer *s = opaque;
 396
 397    return qsb_write_at(s->qsb, buf, pos, size);
 398}
 399
 400static int buf_close(void *opaque)
 401{
 402    QEMUBuffer *s = opaque;
 403
 404    if (s->qsb_allocated) {
 405        qsb_free(s->qsb);
 406    }
 407
 408    g_free(s);
 409
 410    return 0;
 411}
 412
 413const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f)
 414{
 415    QEMUBuffer *p;
 416
 417    qemu_fflush(f);
 418
 419    p = f->opaque;
 420
 421    return p->qsb;
 422}
 423
 424static const QEMUFileOps buf_read_ops = {
 425    .get_buffer = buf_get_buffer,
 426    .close =      buf_close,
 427};
 428
 429static const QEMUFileOps buf_write_ops = {
 430    .put_buffer = buf_put_buffer,
 431    .close =      buf_close,
 432};
 433
 434QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
 435{
 436    QEMUBuffer *s;
 437
 438    if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') ||
 439        mode[1] != '\0') {
 440        error_report("qemu_bufopen: Argument validity check failed");
 441        return NULL;
 442    }
 443
 444    s = g_new0(QEMUBuffer, 1);
 445    s->qsb = input;
 446
 447    if (s->qsb == NULL) {
 448        s->qsb = qsb_create(NULL, 0);
 449        s->qsb_allocated = true;
 450    }
 451    if (!s->qsb) {
 452        g_free(s);
 453        error_report("qemu_bufopen: qsb_create failed");
 454        return NULL;
 455    }
 456
 457
 458    if (mode[0] == 'r') {
 459        s->file = qemu_fopen_ops(s, &buf_read_ops);
 460    } else {
 461        s->file = qemu_fopen_ops(s, &buf_write_ops);
 462    }
 463    return s->file;
 464}
 465