Make qemu_peek_buffer loop until it gets it's data
PATCH 1/1 Make qemu_peek_buffer loop until it gets it's data
From: "Dr. David Alan Gilbert" <[email protected]>
Make qemu_peek_buffer repatedly 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.
Ditto for qemu_peek_byte (which can only be affected due to it's offset).
Simplify qemu_get_buffer since it can now rely on qemu_peek_buffer to loop.
Use size_t rather than int for size parameters, (and result for those functions that never return -errno).
Fail vmstate_subsection_load if idstr couldn't be peek'd
--- include/migration/qemu-file.h | 6 ++-- qemu-file.c | 64 +++++++++++++++++++++++++++---------------- vmstate.c | 2 +- 3 files changed, 44 insertions(+), 28 deletions(-)
include/migration/qemu-file.h +3 -3
@@ -121,11 +121,11 @@ static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v)void qemu_put_be16 (QEMUFile *f,unsigned int v);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); +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);int qemu_peek_byte (QEMUFile *f,int offset);int qemu_get_byte (QEMUFile *f); -void qemu_file_skip (QEMUFile *f,int size); +void qemu_file_skip (QEMUFile *f,size_t size);void qemu_update_position (QEMUFile *f,size_t size);static inline unsigned int qemu_get_ubyte (QEMUFile *f)
qemu-file.c +40 -24
113 lines not on this page · raw message
vmstate.c +1 -1
@@ -170,7 +170,7 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, } size =qemu_peek_buffer (f, (uint8_t *)idstr, len,2 );if (size != len) { -return 0 ; +return -EIO ; } idstr[size] =0 ;
Signature · 1 line
1.8.5.3
Quoted 12 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Make
qemu_peek_bufferrepatedly callfill_bufferuntil it gets all the data it requires, or until there is an error.At the moment,
qemu_peek_bufferwill try oneqemu_fill_bufferif there isn't enough data waiting, however the kernel is entitled to return just a few bytes, and still leaveqemu_peek_bufferwith 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.
Quoted 5 lines
Ditto for
qemu_peek_byte(which can only be affected due to it's offset).Simplify
qemu_get_buffersince it can now rely onqemu_peek_bufferto loop.
I think this one is wrong, will explain there.
Quoted 2 lines
Use
size_trather than int for size parameters, (and result for those functions that never return -errno).
Nice.
Quoted 14 lines
qemu-file.c +3
-8-int qemu_get_buffer (QEMUFile *f,uint8_t *buf,int size) +size_t qemu_get_buffer (QEMUFile *f,uint8_t *buf,size_t size) { -int pending = size; -int done =0 ; +size_t res; -while (pending >0 ) { -int res; + res =qemu_peek_buffer (f, buf, size,0 ); - res =qemu_peek_buffer (f, buf, pending,0 ); -if (res ==0 ) { -return done;
qemu-file.c int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) · line 743
Quoted 10 lines
qemu-file.c +3
-7- } -qemu_file_skip (f, res); - buf += res; - pending -= res; - done += res; - } -return done; +qemu_file_skip (f, res); + +return res;
I think this is "theoretical" (a.k.a. no user of this functionality). As this was coded, we could receive buffers bigger than IOBUF_SIZE, with your change, we can't. Just maintating the loop should fix this, right?
qemu-file.c int qemu_peek_byte(QEMUFile *f, int offset) · line 755
Quoted 4 lines
qemu-file.c +4
-0+while (index >= f->buf_size) { +int received =qemu_fill_buffer (f); + +if (received <=0 ) {
here, I don't know really what to do. We just need one character, so the 1st call to qemu_fill_buffer() gives it to us, or we are already on problems. i.e. no need of the while() loop.
On the other hand, having exactly the same code looks so nice.
At some point I was thinking about making qemu_peek_byte() to use qemu_peek_buffer(), but I think that we used qemu_peek_byte() more to justify the overhead. I am talking from memory here.
vmstate.c static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, · line 175
Quoted 12 lines
vmstate.c +1
-1@@ -170,7 +170,7 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, } size =qemu_peek_buffer (f, (uint8_t *)idstr, len,2 );if (size != len) { -return 0 ; +return -EIO ; } idstr[size] =0 ;
This was coded this way on purpose. If we don't have a valid buffer after the subsection identifier, just let the code continue to see if it wasn't a subsection at all. This colud be removed one tested that we don't allow subsections in the middle of a section, only in places where a section can appear.
In general, very nice patch, and fixes the problem.
Later, Juan.
Quoted 47 lines · * Juan Quintela ([email protected]) wrote:
Quoted 12 lines · Dr. David Alan Gilbert (git)
From: "Dr. David Alan Gilbert" <[email protected]>
Make
qemu_peek_bufferrepatedly callfill_bufferuntil it gets all the data it requires, or until there is an error.At the moment,
qemu_peek_bufferwill try oneqemu_fill_bufferif there isn't enough data waiting, however the kernel is entitled to return just a few bytes, and still leaveqemu_peek_bufferwith 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.Quoted 5 lines
Ditto for
qemu_peek_byte(which can only be affected due to it's offset).Simplify
qemu_get_buffersince it can now rely onqemu_peek_bufferto loop.I think this one is wrong, will explain there.
Quoted 2 lines
Use
size_trather than int for size parameters, (and result for those functions that never return -errno).Nice.
Quoted 20 lines
qemu-file.c +3
-14-int qemu_get_buffer (QEMUFile *f,uint8_t *buf,int size) +size_t qemu_get_buffer (QEMUFile *f,uint8_t *buf,size_t size) { -int pending = size; -int done =0 ; +size_t res; -while (pending >0 ) { -int res; + res =qemu_peek_buffer (f, buf, size,0 ); - res =qemu_peek_buffer (f, buf, pending,0 ); -if (res ==0 ) { -return done; - } -qemu_file_skip (f, res); - buf += res; - pending -= res; - done += res; - }
Quoted 8 lines
qemu-file.c int qemu_peek_buffer(QEMUFile *f, uint8_t *buf, int size, size_t offset) · line 743
Quoted 4 lines
qemu-file.c +3
-1-return done; +qemu_file_skip (f, res); + +return res;I think this is "theoretical" (a.k.a. no user of this functionality). As this was coded, we could receive buffers bigger than
IOBUF_SIZE, with your change, we can't. Just maintating the loop should fix this, right?
Ah, actually that is a good point (I've got a feeling one of my other worlds relies on that); yes, I'll put the loop back and fix it all to be size_t.
Quoted 8 lines
qemu-file.c int qemu_peek_byte(QEMUFile *f, int offset) · line 755
Quoted 4 lines
qemu-file.c +4
-0+while (index >= f->buf_size) { +int received =qemu_fill_buffer (f); + +if (received <=0 ) {here, I don't know really what to do. We just need one character, so the 1st call to
qemu_fill_buffer()gives it to us, or we are already on problems. i.e. no need of thewhile()loop.
The problem is that peek_byte takes an offset, so while qemu_fill_buffer will get us a byte, we actually need it to get us all the bytes upto the offset, and that's not guaranteed from one call.
Quoted 26 lines
On the other hand, having exactly the same code looks so nice.
At some point I was thinking about making
qemu_peek_byte()to useqemu_peek_buffer(), but I think that we usedqemu_peek_byte()more to justify the overhead. I am talking from memory here.vmstate.c static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, · line 175
Quoted 12 lines
vmstate.c +1
-1@@ -170,7 +170,7 @@ static int vmstate_subsection_load(QEMUFile *f, const VMStateDescription *vmsd, } size =qemu_peek_buffer (f, (uint8_t *)idstr, len,2 );if (size != len) { -return 0 ; +return -EIO ; } idstr[size] =0 ;This was coded this way on purpose. If we don't have a valid buffer after the subsection identifier, just let the code continue to see if it wasn't a subsection at all. This colud be removed one tested that we don't allow subsections in the middle of a section, only in places where a section can appear.
Quoted 1 line
In general, very nice patch, and fixes the problem.
Thanks, I'll rework and get a V2 up later.
Dave
Quoted 2 lines
Later, Juan.
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Quoted 5 lines · Dr. David Alan Gilbert
Quoted 5 lines
Quoted 4 lines
qemu-file.c +4
-0+while (index >= f->buf_size) { +int received =qemu_fill_buffer (f); + +if (received <=0 ) {
Quoted 7 lines
Quoted 3 lines
here, I don't know really what to do. We just need one character, so the 1st call to
qemu_fill_buffer()gives it to us, or we are already on problems. i.e. no need of thewhile()loop.The problem is that
peek_bytetakes an offset, so whileqemu_fill_bufferwill get us a byte, we actually need it to get us all the bytes upto the offset, and that's not guaranteed from one call.
that is not a problem.
We never got a "hole" on the things that we ask for. We ask for the "next byte", or the "next bytes", so in qemu_peek_byte() we are guaranteed (with current users) that we would only have to read a single byte.
I.e. qemu_peek_{buffer,byte}(....,offset, size) means that we have "already" peek until offset, and now we want size more bytes.
Later, Juan.
Quoted 16 lines · * Juan Quintela ([email protected]) wrote:
Quoted 5 lines · Dr. David Alan Gilbert
Quoted 5 lines
Quoted 4 lines
qemu-file.c +4
-0+while (index >= f->buf_size) { +int received =qemu_fill_buffer (f); + +if (received <=0 ) {Quoted 7 lines
Quoted 3 lines
here, I don't know really what to do. We just need one character, so the 1st call to
qemu_fill_buffer()gives it to us, or we are already on problems. i.e. no need of thewhile()loop.The problem is that
peek_bytetakes an offset, so whileqemu_fill_bufferwill get us a byte, we actually need it to get us all the bytes upto the offset, and that's not guaranteed from one call.that is not a problem.
Quoted 7 lines
We never got a "hole" on the things that we ask for. We ask for the "next byte", or the "next bytes", so in
qemu_peek_byte()we are guaranteed (with current users) that we would only have to read a single byte.I.e. qemu_peek_{buffer,byte}(....,offset, size) means that we have "already" peek until offset, and now we want size more bytes.
Hmm ok, that is convenient but is neither documented or enforced; I'll rework my patch and at least document it, and possibly enforce it.
Dave
--
Dr. David Alan Gilbert / [email protected] / Manchester, UK
Quoted 22 lines · Dr. David Alan Gilbert
Quoted 21 lines · * Juan Quintela ([email protected]) wrote:
Quoted 5 lines · Dr. David Alan Gilbert
Quoted 5 lines
Quoted 4 lines
qemu-file.c +4
-0+while (index >= f->buf_size) { +int received =qemu_fill_buffer (f); + +if (received <=0 ) {Quoted 7 lines
Quoted 3 lines
here, I don't know really what to do. We just need one character, so the 1st call to
qemu_fill_buffer()gives it to us, or we are already on problems. i.e. no need of thewhile()loop.The problem is that
peek_bytetakes an offset, so whileqemu_fill_bufferwill get us a byte, we actually need it to get us all the bytes upto the offset, and that's not guaranteed from one call.that is not a problem.
We never got a "hole" on the things that we ask for. We ask for the "next byte", or the "next bytes", so in
qemu_peek_byte()we are guaranteed (with current users) that we would only have to read a single byte.
Quoted 5 lines
Quoted 2 lines
I.e. qemu_peek_{buffer,byte}(....,offset, size) means that we have "already" peek until offset, and now we want size more bytes.
Hmm ok, that is convenient but is neither documented or enforced; I'll rework my patch and at least document it, and possibly enforce it.
thanks very much to take the time to understand it and document it O;-)
Later, Juan.