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:
parent
ca99993adc
commit
548f52ea06
@ -123,6 +123,11 @@ void qemu_put_be32(QEMUFile *f, unsigned int 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_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_get_byte(QEMUFile *f);
|
||||
void qemu_file_skip(QEMUFile *f, int size);
|
||||
|
53
qemu-file.c
53
qemu-file.c
@ -530,7 +530,15 @@ size_t ram_control_save_page(QEMUFile *f, ram_addr_t block_offset,
|
||||
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 pending;
|
||||
@ -554,6 +562,8 @@ static void qemu_fill_buffer(QEMUFile *f)
|
||||
} else if (len != -EAGAIN) {
|
||||
qemu_file_set_error(f, len);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
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 pending;
|
||||
int index;
|
||||
|
||||
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;
|
||||
/* The number of available bytes starting at 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;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 pending = size;
|
||||
@ -719,7 +759,7 @@ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
|
||||
while (pending > 0) {
|
||||
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) {
|
||||
return done;
|
||||
}
|
||||
@ -731,11 +771,16 @@ int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size)
|
||||
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 index = f->buf_index + offset;
|
||||
|
||||
assert(!qemu_file_is_writable(f));
|
||||
assert(offset < IO_BUF_SIZE);
|
||||
|
||||
if (index >= f->buf_size) {
|
||||
qemu_fill_buffer(f);
|
||||
|
Loading…
Reference in New Issue
Block a user