Make qemu_peek_buffer loop until it gets it's data

Make qemu_peek_buffer repeatedly call fill_buffer until it gets
all the data it requires, or until there is an error.

  At the moment, qemu_peek_buffer will try one qemu_fill_buffer if there
  isn't enough data waiting, however the kernel is entitled to return
  just a few bytes, and still leave qemu_peek_buffer with less bytes
  than it needed.  I've seen this fail in a dev world, and I think it
  could theoretically fail in the peeking of the subsection headers in
  the current world.

Comment qemu_peek_byte to point out it's not guaranteed to work for
  non-continuous peeks

Signed-off-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Reviewed-by: ChenLiang <chenliang0016@icloud.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>
This commit is contained in:
Dr. David Alan Gilbert 2014-04-08 15:29:37 +01:00 committed by Juan Quintela
parent ca99993adc
commit 548f52ea06
2 changed files with 54 additions and 4 deletions

View File

@ -123,6 +123,11 @@ void qemu_put_be32(QEMUFile *f, unsigned int v);
void qemu_put_be64(QEMUFile *f, uint64_t v); void qemu_put_be64(QEMUFile *f, uint64_t v);
int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset); int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset);
int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size);
/*
* 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
* previously peeked +n-1.
*/
int qemu_peek_byte(QEMUFile *f, int offset); int qemu_peek_byte(QEMUFile *f, int offset);
int qemu_get_byte(QEMUFile *f); int qemu_get_byte(QEMUFile *f);
void qemu_file_skip(QEMUFile *f, int size); void qemu_file_skip(QEMUFile *f, int size);

View File

@ -530,7 +530,15 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
return RAM_SAVE_CONTROL_NOT_SUPP; return RAM_SAVE_CONTROL_NOT_SUPP;
} }
static void qemu_fill_buffer(QEMUFile *f) /*
* Attempt to fill the buffer from the underlying file
* Returns the number of bytes read, or negative value for an error.
*
* Note that it can return a partially full buffer even in a not error/not EOF
* case if the underlying file descriptor gives a short read, and that can
* happen even on a blocking fd.
*/
static ssize_t qemu_fill_buffer(QEMUFile *f)
{ {
int len; int len;
int pending; int pending;
@ -554,6 +562,8 @@ static void qemu_fill_buffer(QEMUFile *f)
} else if (len != -EAGAIN) { } else if (len != -EAGAIN) {
qemu_file_set_error(f, len); qemu_file_set_error(f, len);
} }
return len;
} }
int qemu_get_fd(QEMUFile *f) int qemu_get_fd(QEMUFile *f)
@ -685,17 +695,39 @@ void qemu_file_skip(QEMUFile *f, int size)
} }
} }
/*
* Read 'size' bytes from file (at 'offset') into buf without moving the
* pointer.
*
* 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)
*/
int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
{ {
int pending; int pending;
int index; int index;
assert(!qemu_file_is_writable(f)); assert(!qemu_file_is_writable(f));
assert(offset < IO_BUF_SIZE);
assert(size <= IO_BUF_SIZE - offset);
/* The 1st byte to read from */
index = f->buf_index + offset; index = f->buf_index + offset;
/* The number of available bytes starting at index */
pending = f->buf_size - index; pending = f->buf_size - index;
if (pending < size) {
qemu_fill_buffer(f); /*
* qemu_fill_buffer might return just a few bytes, even when there isn't
* an error, so loop collecting them until we get enough.
*/
while (pending < size) {
int received = qemu_fill_buffer(f);
if (received <= 0) {
break;
}
index = f->buf_index + offset; index = f->buf_index + offset;
pending = f->buf_size - index; pending = f->buf_size - index;
} }
@ -711,6 +743,14 @@ int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset)
return size; return size;
} }
/*
* Read 'size' bytes of data from the file into buf.
* 'size' can be larger than the internal buffer.
*
* 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)
*/
int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
{ {
int pending = size; int pending = size;
@ -719,7 +759,7 @@ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
while (pending > 0) { while (pending > 0) {
int res; int res;
res = qemu_peek_buffer(f, buf, pending, 0); res = qemu_peek_buffer(f, buf, MIN(pending, IO_BUF_SIZE), 0);
if (res == 0) { if (res == 0) {
return done; return done;
} }
@ -731,11 +771,16 @@ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
return done; return done;
} }
/*
* Peeks a single byte from the buffer; this isn't guaranteed to work if
* offset leaves a gap after the previous read/peeked data.
*/
int qemu_peek_byte(QEMUFile *f, int offset) int qemu_peek_byte(QEMUFile *f, int offset)
{ {
int index = f->buf_index + offset; int index = f->buf_index + offset;
assert(!qemu_file_is_writable(f)); assert(!qemu_file_is_writable(f));
assert(offset < IO_BUF_SIZE);
if (index >= f->buf_size) { if (index >= f->buf_size) {
qemu_fill_buffer(f); qemu_fill_buffer(f);