[libvirt] [PATCH RFC 2/8] Introduce virStream{Recv,Send}Offset

Michal Privoznik mprivozn at redhat.com
Fri Jan 29 13:26:53 UTC 2016


When dealing with sparse files we need to be able to jump over
holes as there's no added value in reading/writing them. For
that, we need new set of send and receive APIs that will have
@offset argument. Sending data to a stream would be easy - just
say from which offset we are sending data. Reading is a bit
tricky - we need read function which can detect holes and thus
when requested to read from one it will set @offset to new value
that contains data.

Signed-off-by: Michal Privoznik <mprivozn at redhat.com>
---
 include/libvirt/libvirt-stream.h |   8 +++
 src/driver-stream.h              |  13 +++++
 src/libvirt-stream.c             | 113 +++++++++++++++++++++++++++++++++++++++
 src/libvirt_public.syms          |   6 +++
 4 files changed, 140 insertions(+)

diff --git a/include/libvirt/libvirt-stream.h b/include/libvirt/libvirt-stream.h
index 831640d..5a2bde3 100644
--- a/include/libvirt/libvirt-stream.h
+++ b/include/libvirt/libvirt-stream.h
@@ -40,11 +40,19 @@ int virStreamRef(virStreamPtr st);
 int virStreamSend(virStreamPtr st,
                   const char *data,
                   size_t nbytes);
+int virStreamSendOffset(virStreamPtr stream,
+                        unsigned long long offset,
+                        const char *data,
+                        size_t nbytes);
 
 int virStreamRecv(virStreamPtr st,
                   char *data,
                   size_t nbytes);
 
+int virStreamRecvOffset(virStreamPtr stream,
+                        unsigned long long *offset,
+                        char *data,
+                        size_t nbytes);
 
 /**
  * virStreamSourceFunc:
diff --git a/src/driver-stream.h b/src/driver-stream.h
index 85b4e3b..5419b85 100644
--- a/src/driver-stream.h
+++ b/src/driver-stream.h
@@ -31,9 +31,20 @@ typedef int
                     size_t nbytes);
 
 typedef int
+(*virDrvStreamSendOffset)(virStreamPtr st,
+                          unsigned long long offset,
+                          const char *data,
+                          size_t nbytes);
+
+typedef int
 (*virDrvStreamRecv)(virStreamPtr st,
                     char *data,
                     size_t nbytes);
+typedef int
+(*virDrvStreamRecvOffset)(virStreamPtr st,
+                          unsigned long long *offset,
+                          char *data,
+                          size_t nbytes);
 
 typedef int
 (*virDrvStreamEventAddCallback)(virStreamPtr stream,
@@ -60,7 +71,9 @@ typedef virStreamDriver *virStreamDriverPtr;
 
 struct _virStreamDriver {
     virDrvStreamSend streamSend;
+    virDrvStreamSendOffset streamSendOffset;
     virDrvStreamRecv streamRecv;
+    virDrvStreamRecvOffset streamRecvOffset;
     virDrvStreamEventAddCallback streamEventAddCallback;
     virDrvStreamEventUpdateCallback streamEventUpdateCallback;
     virDrvStreamEventRemoveCallback streamEventRemoveCallback;
diff --git a/src/libvirt-stream.c b/src/libvirt-stream.c
index c16f586..1df188c 100644
--- a/src/libvirt-stream.c
+++ b/src/libvirt-stream.c
@@ -192,6 +192,58 @@ virStreamSend(virStreamPtr stream,
 
 
 /**
+ * virStreamSendOffset:
+ * @stream: pointer to the stream object
+ * @offset: <something>
+ * @data: buffer to write to stream
+ * @nbytes: size of @data buffer
+ *
+ * Sends some data down the pipe.
+ *
+ * Returns the number of bytes written, which may be less
+ * than requested.
+ *
+ * Returns -1 upon error, at which time the stream will
+ * be marked as aborted, and the caller should now release
+ * the stream with virStreamFree.
+ *
+ * Returns -2 if the outgoing transmit buffers are full &
+ * the stream is marked as non-blocking.
+ */
+int
+virStreamSendOffset(virStreamPtr stream,
+                    unsigned long long offset,
+                    const char *data,
+                    size_t nbytes)
+{
+    VIR_DEBUG("stream=%p, offset=%llu, data=%p, nbytes=%zu",
+              stream, offset, data, nbytes);
+
+    virResetLastError();
+
+    virCheckStreamReturn(stream, -1);
+    virCheckNonNullArgGoto(data, error);
+
+    if (stream->driver &&
+        stream->driver->streamSendOffset) {
+        int ret;
+        ret = (stream->driver->streamSendOffset)(stream, offset, data, nbytes);
+        if (ret == -2)
+            return -2;
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(stream->conn);
+    return -1;
+}
+
+
+/**
  * virStreamRecv:
  * @stream: pointer to the stream object
  * @data: buffer to read into from stream
@@ -285,6 +337,67 @@ virStreamRecv(virStreamPtr stream,
 
 
 /**
+ * virStreamRecvOffset:
+ * @stream: pointer to the stream object
+ * @offset: <something>
+ * @data: buffer to write to stream
+ * @nbytes: size of @data buffer
+ *
+ * Recieve some data from stream. On return set offset to next location.
+ *
+ * Returns the number of bytes read, which may be less
+ * than requested.
+ *
+ * Returns 0 when either the end of the stream is reached, or
+ * there are no data to be sent at current @offset. In case of
+ * the former, the stream should be finished by calling
+ * virStreamFinish(). However, in case of the latter, @offset
+ * should be set to new position where interesting data is.
+ * Failing to do so will result in assumption that there is no
+ * data left.
+ *
+ * Returns -1 upon error, at which time the stream will
+ * be marked as aborted, and the caller should now release
+ * the stream with virStreamFree.
+ *
+ * Returns -2 if there is no data pending to be read & the
+ * stream is marked as non-blocking.
+ */
+int
+virStreamRecvOffset(virStreamPtr stream,
+                    unsigned long long *offset,
+                    char *data,
+                    size_t nbytes)
+{
+    VIR_DEBUG("stream=%p, offset=%p, data=%p, nbytes=%zu",
+              stream, offset, data, nbytes);
+
+    virResetLastError();
+
+    virCheckStreamReturn(stream, -1);
+    virCheckNonNullArgGoto(offset, error);
+    virCheckNonNullArgGoto(data, error);
+
+    if (stream->driver &&
+        stream->driver->streamRecvOffset) {
+        int ret;
+        ret = (stream->driver->streamRecvOffset)(stream, offset, data, nbytes);
+        if (ret == -2)
+            return -2;
+        if (ret < 0)
+            goto error;
+        return ret;
+    }
+
+    virReportUnsupportedError();
+
+ error:
+    virDispatchError(stream->conn);
+    return -1;
+}
+
+
+/**
  * virStreamSendAll:
  * @stream: pointer to the stream object
  * @handler: source callback for reading data from application
diff --git a/src/libvirt_public.syms b/src/libvirt_public.syms
index dd94191..4229df9 100644
--- a/src/libvirt_public.syms
+++ b/src/libvirt_public.syms
@@ -725,4 +725,10 @@ LIBVIRT_1.2.19 {
         virDomainRename;
 } LIBVIRT_1.2.17;
 
+LIBVIRT_1.3.1 {
+    global:
+        virStreamRecvOffset;
+        virStreamSendOffset;
+} LIBVIRT_1.2.19;
+
 # .... define new API here using predicted next version number ....
-- 
2.4.10




More information about the libvir-list mailing list