]> git.ipfire.org Git - thirdparty/libvirt.git/commitdiff
virshStreamSkip: Emulate skip for block devices
authorMichal Privoznik <mprivozn@redhat.com>
Thu, 2 Jul 2020 13:49:33 +0000 (15:49 +0200)
committerMichal Privoznik <mprivozn@redhat.com>
Mon, 24 Aug 2020 11:32:53 +0000 (13:32 +0200)
This callback is called when the server sends us STREAM_HOLE
meaning there is no real data, only zeroes. For regular files
we would just seek() beyond EOF and ftruncate() to create the
hole. But for block devices this won't work. Not only we can't
seek() beyond EOF, and ftruncate() will fail, this approach won't
fill the device with zeroes. We have to do it manually.

Partially resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1852528

Signed-off-by: Michal Privoznik <mprivozn@redhat.com>
Reviewed-by: Peter Krempa <pkrempa@redhat.com>
tools/virsh-util.c

index 89f15efd0862ec1b91676f02ab5b71cbd2d2fd93..884261eb49dc776a43e52a282dcf06d642d7ceae 100644 (file)
@@ -189,11 +189,33 @@ virshStreamSkip(virStreamPtr st G_GNUC_UNUSED,
     virshStreamCallbackDataPtr cbData = opaque;
     off_t cur;
 
-    if ((cur = lseek(cbData->fd, offset, SEEK_CUR)) == (off_t) -1)
-        return -1;
+    if (cbData->isBlock) {
+        g_autofree char * buf = NULL;
+        const size_t buflen = 1 * 1024 * 1024; /* 1MiB */
 
-    if (ftruncate(cbData->fd, cur) < 0)
-        return -1;
+        /* While for files it's enough to lseek() and ftruncate() to create
+         * a hole which would emulate zeroes on read(), for block devices
+         * we have to write zeroes to read() zeroes. And we have to write
+         * @got bytes of zeroes. Do that in smaller chunks though.*/
+
+        buf = g_new0(char, buflen);
+
+        while (offset) {
+            size_t count = MIN(offset, buflen);
+            ssize_t r;
+
+            if ((r = safewrite(cbData->fd, buf, count)) < 0)
+                return -1;
+
+            offset -= r;
+        }
+    } else {
+        if ((cur = lseek(cbData->fd, offset, SEEK_CUR)) == (off_t) -1)
+            return -1;
+
+        if (ftruncate(cbData->fd, cur) < 0)
+            return -1;
+    }
 
     return 0;
 }