qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v5 1/2] QEMUSizedBuffer based QEMUFile


From: Dr. David Alan Gilbert
Subject: Re: [Qemu-devel] [PATCH v5 1/2] QEMUSizedBuffer based QEMUFile
Date: Wed, 8 Oct 2014 10:08:31 +0100
User-agent: Mutt/1.5.23 (2014-03-12)

* zhanghailiang (address@hidden) wrote:

> >+static ssize_t qsb_grow(QEMUSizedBuffer *qsb, size_t new_size)
> >+{
> >+    size_t needed_chunks, i;
> >+
> >+    if (qsb->size < new_size) {
> >+        struct iovec *new_iov;
> >+        size_t size_diff = new_size - qsb->size;
> >+        size_t chunk_size = (size_diff > QSB_MAX_CHUNK_SIZE)
> >+                             ? QSB_MAX_CHUNK_SIZE : QSB_CHUNK_SIZE;
> >+
> >+        needed_chunks = DIV_ROUND_UP(size_diff, chunk_size);
> >+
> >+        new_iov = g_try_malloc_n(qsb->n_iov + needed_chunks,
> >+                                 sizeof(struct iovec));
> 
> It seems that *g_try_malloc_n* was supported since glib2-2.24 version,
> But it don't check this when do *configure* before compile...;)

        new_iov = g_try_new(struct iovec, qsb->n_iov + needed_chunks);

seems to work for me; let me know if you hit any others.

Dave



> 
> >+        if (new_iov == NULL) {
> >+            return -ENOMEM;
> >+        }
> >+
> >+        /* Allocate new chunks as needed into new_iov */
> >+        for (i = qsb->n_iov; i < qsb->n_iov + needed_chunks; i++) {
> >+            new_iov[i].iov_base = g_try_malloc0(chunk_size);
> >+            new_iov[i].iov_len = chunk_size;
> >+            if (!new_iov[i].iov_base) {
> >+                size_t j;
> >+
> >+                /* Free previously allocated new chunks */
> >+                for (j = qsb->n_iov; j < i; j++) {
> >+                    g_free(new_iov[j].iov_base);
> >+                }
> >+                g_free(new_iov);
> >+
> >+                return -ENOMEM;
> >+            }
> >+        }
> >+
> >+        /*
> >+         * Now we can't get any allocation errors, copy over to new iov
> >+         * and switch.
> >+         */
> >+        for (i = 0; i < qsb->n_iov; i++) {
> >+            new_iov[i] = qsb->iov[i];
> >+        }
> >+
> >+        qsb->n_iov += needed_chunks;
> >+        g_free(qsb->iov);
> >+        qsb->iov = new_iov;
> >+        qsb->size += (needed_chunks * chunk_size);
> >+    }
> >+
> >+    return qsb->size;
> >+}
> >+
> >+/**
> >+ * Write into the QEMUSizedBuffer at a given position and a given
> >+ * number of bytes. This function will automatically grow the
> >+ * QEMUSizedBuffer.
> >+ *
> >+ * @qsb: A QEMUSizedBuffer
> >+ * @source: A byte array to copy data from
> >+ * @pos: The position within the @qsb to write data to
> >+ * @size: The number of bytes to copy into the @qsb
> >+ *
> >+ * Returns @size or a negative error code in case of memory allocation 
> >failure,
> >+ *           or with an invalid 'pos'
> >+ */
> >+ssize_t qsb_write_at(QEMUSizedBuffer *qsb, const uint8_t *source,
> >+                     off_t pos, size_t count)
> >+{
> >+    ssize_t rc = qsb_grow(qsb, pos + count);
> >+    size_t to_copy;
> >+    size_t all_copy = count;
> >+    const struct iovec *iov;
> >+    ssize_t index;
> >+    char *dest;
> >+    off_t d_off, s_off = 0;
> >+
> >+    if (rc < 0) {
> >+        return rc;
> >+    }
> >+
> >+    if (pos + count > qsb->used) {
> >+        qsb->used = pos + count;
> >+    }
> >+
> >+    index = qsb_get_iovec(qsb, pos, &d_off);
> >+    if (index < 0) {
> >+        return -EINVAL;
> >+    }
> >+
> >+    while (all_copy > 0) {
> >+        iov = &qsb->iov[index];
> >+
> >+        dest = iov->iov_base;
> >+
> >+        to_copy = iov->iov_len - d_off;
> >+        if (to_copy > all_copy) {
> >+            to_copy = all_copy;
> >+        }
> >+
> >+        memcpy(&dest[d_off], &source[s_off], to_copy);
> >+
> >+        s_off += to_copy;
> >+        all_copy -= to_copy;
> >+
> >+        d_off = 0;
> >+        index++;
> >+    }
> >+
> >+    return count;
> >+}
> >+
> >+/**
> >+ * Create a deep copy of the given QEMUSizedBuffer.
> >+ *
> >+ * @qsb: A QEMUSizedBuffer
> >+ *
> >+ * Returns a clone of @qsb or NULL on allocation failure
> >+ */
> >+QEMUSizedBuffer *qsb_clone(const QEMUSizedBuffer *qsb)
> >+{
> >+    QEMUSizedBuffer *out = qsb_create(NULL, qsb_get_length(qsb));
> >+    size_t i;
> >+    ssize_t res;
> >+    off_t pos = 0;
> >+
> >+    if (!out) {
> >+        return NULL;
> >+    }
> >+
> >+    for (i = 0; i < qsb->n_iov; i++) {
> >+        res =  qsb_write_at(out, qsb->iov[i].iov_base,
> >+                            pos, qsb->iov[i].iov_len);
> >+        if (res < 0) {
> >+            qsb_free(out);
> >+            return NULL;
> >+        }
> >+        pos += res;
> >+    }
> >+
> >+    return out;
> >+}
> >+
> >+typedef struct QEMUBuffer {
> >+    QEMUSizedBuffer *qsb;
> >+    QEMUFile *file;
> >+} QEMUBuffer;
> >+
> >+static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size)
> >+{
> >+    QEMUBuffer *s = opaque;
> >+    ssize_t len = qsb_get_length(s->qsb) - pos;
> >+
> >+    if (len <= 0) {
> >+        return 0;
> >+    }
> >+
> >+    if (len > size) {
> >+        len = size;
> >+    }
> >+    return qsb_get_buffer(s->qsb, pos, len, buf);
> >+}
> >+
> >+static int buf_put_buffer(void *opaque, const uint8_t *buf,
> >+                          int64_t pos, int size)
> >+{
> >+    QEMUBuffer *s = opaque;
> >+
> >+    return qsb_write_at(s->qsb, buf, pos, size);
> >+}
> >+
> >+static int buf_close(void *opaque)
> >+{
> >+    QEMUBuffer *s = opaque;
> >+
> >+    qsb_free(s->qsb);
> >+
> >+    g_free(s);
> >+
> >+    return 0;
> >+}
> >+
> >+const QEMUSizedBuffer *qemu_buf_get(QEMUFile *f)
> >+{
> >+    QEMUBuffer *p;
> >+
> >+    qemu_fflush(f);
> >+
> >+    p = f->opaque;
> >+
> >+    return p->qsb;
> >+}
> >+
> >+static const QEMUFileOps buf_read_ops = {
> >+    .get_buffer = buf_get_buffer,
> >+    .close =      buf_close,
> >+};
> >+
> >+static const QEMUFileOps buf_write_ops = {
> >+    .put_buffer = buf_put_buffer,
> >+    .close =      buf_close,
> >+};
> >+
> >+QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input)
> >+{
> >+    QEMUBuffer *s;
> >+
> >+    if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') ||
> >+        mode[1] != '\0') {
> >+        error_report("qemu_bufopen: Argument validity check failed");
> >+        return NULL;
> >+    }
> >+
> >+    s = g_malloc0(sizeof(QEMUBuffer));
> >+    if (mode[0] == 'r') {
> >+        s->qsb = input;
> >+    }
> >+
> >+    if (s->qsb == NULL) {
> >+        s->qsb = qsb_create(NULL, 0);
> >+    }
> >+    if (!s->qsb) {
> >+        g_free(s);
> >+        error_report("qemu_bufopen: qsb_create failed");
> >+        return NULL;
> >+    }
> >+
> >+
> >+    if (mode[0] == 'r') {
> >+        s->file = qemu_fopen_ops(s, &buf_read_ops);
> >+    } else {
> >+        s->file = qemu_fopen_ops(s, &buf_write_ops);
> >+    }
> >+    return s->file;
> >+}
> >
> 
> 
--
Dr. David Alan Gilbert / address@hidden / Manchester, UK



reply via email to

[Prev in Thread] Current Thread [Next in Thread]