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 5bf6f23..179c5eb 100644
--- a/daemon/stream.c
+++ b/daemon/stream.c
@@ -54,6 +54,7 @@ struct daemonClientStream {
bool tx;
bool seekable;
+ size_t dataLen; /* How much data is there remaining until we see a hole */
daemonClientStreamPtr next;
};
@@ -792,7 +793,7 @@ daemonStreamHandleRead(virNetServerClientPtr client,
if (!(msg = virNetMessageNew(false)))
goto cleanup;
- if (stream->seekable) {
+ if (stream->seekable && !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. */
@@ -836,10 +837,13 @@ daemonStreamHandleRead(virNetServerClientPtr client,
}
}
- if (offset < bufferLen)
- bufferLen = offset;
+ stream->dataLen = offset;
}
+ if (stream->seekable &&
+ 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
@@ -854,6 +858,8 @@ daemonStreamHandleRead(virNetServerClientPtr client,
goto cleanup;
msg = NULL;
} else {
+ stream->dataLen -= rv;
+
stream->tx = false;
if (rv == 0)
stream->recvEOF = true;
--
2.8.1