While virStreamInData() should be a small and quick function, in
our implementation it seeks multiple times. Moreover, it is
called even if we know that we are in data. Well, quite. If we
track its return values and do some basic math with them, we can
end up calling virStreamInData right at the boundaries of a data
section or a hole and nowhere else.
Signed-off-by: Michal Privoznik <mprivozn(a)redhat.com>
---
daemon/stream.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/daemon/stream.c b/daemon/stream.c
index a8ad8f7..22d7cf7 100644
--- a/daemon/stream.c
+++ b/daemon/stream.c
@@ -54,6 +54,7 @@ struct daemonClientStream {
bool tx;
bool skippable;
+ size_t dataLen; /* How much data is there remaining until we see a hole */
daemonClientStreamPtr next;
};
@@ -823,7 +824,7 @@ daemonStreamHandleRead(virNetServerClientPtr client,
if (!(msg = virNetMessageNew(false)))
goto cleanup;
- if (stream->skippable) {
+ if (stream->skippable && !stream->dataLen) {
/* Handle skip. We want to send some data to the client. But we might
* be in a hole. Seek to next data. But if we are in data already, just
* carry on. */
@@ -867,10 +868,13 @@ daemonStreamHandleRead(virNetServerClientPtr client,
}
}
- if (length < bufferLen)
- bufferLen = length;
+ stream->dataLen = length;
}
+ if (stream->skippable &&
+ bufferLen > stream->dataLen)
+ bufferLen = stream->dataLen;
+
rv = virStreamRecv(stream->st, buffer, bufferLen);
if (rv == -2) {
/* Should never get this, since we're only called when we know
@@ -885,6 +889,8 @@ daemonStreamHandleRead(virNetServerClientPtr client,
goto cleanup;
msg = NULL;
} else {
+ stream->dataLen -= rv;
+
stream->tx = false;
if (rv == 0)
stream->recvEOF = true;
--
2.8.4