Add qemu_get_buffer_in_place to avoid copies some of the time

qemu_get_buffer always copies the data it reads to a users buffer,
however in many cases the file buffer inside qemu_file could be given
back to the caller, avoiding the copy.  This isn't always possible
depending on the size and alignment of the data.

Thus 'qemu_get_buffer_in_place' either copies the data to a supplied
buffer or updates a pointer to the internal buffer if convenient.

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
This commit is contained in:
Dr. David Alan Gilbert 2015-11-05 18:10:35 +00:00 committed by Juan Quintela
parent 42e2aa5637
commit 9504fb510c
2 changed files with 39 additions and 0 deletions

View File

@ -163,9 +163,11 @@ void qemu_put_be32(QEMUFile *f, unsigned int v);
void qemu_put_be64(QEMUFile *f, uint64_t v);
size_t qemu_peek_buffer(QEMUFile *f, uint8_t **buf, size_t size, size_t offset);
size_t qemu_get_buffer(QEMUFile *f, uint8_t *buf, size_t size);
size_t qemu_get_buffer_in_place(QEMUFile *f, uint8_t **buf, size_t size);
ssize_t qemu_put_compression_data(QEMUFile *f, const uint8_t *p, size_t size,
int level);
int qemu_put_qemu_file(QEMUFile *f_des, QEMUFile *f_src);
/*
* Note that you can only peek continuous bytes from where the current pointer
* is; you aren't guaranteed to be able to peak to +n bytes unless you've

View File

@ -433,6 +433,43 @@ size_t qemu_get_buffer(QEMUFile *f, uint8_t *buf, size_t size)
return done;
}
/*
* Read 'size' bytes of data from the file.
* 'size' can be larger than the internal buffer.
*
* The data:
* may be held on an internal buffer (in which case *buf is updated
* to point to it) that is valid until the next qemu_file operation.
* OR
* will be copied to the *buf that was passed in.
*
* The code tries to avoid the copy if possible.
*
* It will return size bytes unless there was an error, in which case it will
* return as many as it managed to read (assuming blocking fd's which
* all current QEMUFile are)
*
* Note: Since **buf may get changed, the caller should take care to
* keep a pointer to the original buffer if it needs to deallocate it.
*/
size_t qemu_get_buffer_in_place(QEMUFile *f, uint8_t **buf, size_t size)
{
if (size < IO_BUF_SIZE) {
size_t res;
uint8_t *src;
res = qemu_peek_buffer(f, &src, size, 0);
if (res == size) {
qemu_file_skip(f, res);
*buf = src;
return res;
}
}
return qemu_get_buffer(f, *buf, size);
}
/*
* Peeks a single byte from the buffer; this isn't guaranteed to work if
* offset leaves a gap after the previous read/peeked data.