* zhanghailiang (zhang.zhanghaili...@huawei.com) 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 / dgilb...@redhat.com / Manchester, UK