[Libguestfs] [nbdkit PATCH 5/5] file: Support punching holes for write zero

Eric Blake
2017-01-20T20:16:22Z

On Linux, use fallocate() to punch holes as a more efficient way
of writing zeroes.  If hole punching is not allowed, or if we
can't use fallocate (whether because this is not Linux, or because
the file system on Linux doesn't support it), gracefully fall
back to the write method.  If wdelayms is set and a fallback occurs,
we end up sleeping at least twice as long; oh well.

Signed-off-by: Eric Blake <eblake@redhat.com>
---
 plugins/file/file.c | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/plugins/file/file.c b/plugins/file/file.c
index 1368e4e..bd7a9c1 100644
--- a/plugins/file/file.c
+++ b/plugins/file/file.c
@@ -41,6 +41,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <time.h>
+#include <errno.h>

 #include <nbdkit-plugin.h>

@@ -248,6 +249,36 @@ file_pwrite (void *handle, const void *buf, uint32_t count,
uint64_t offset)
   return 0;
 }

+/* Write data to the file. */
+static int
+file_zero (void *handle, uint32_t count, uint64_t offset, int may_trim)
+{
+  struct handle *h = handle;
+
+  if (wdelayms > 0) {
+    const struct timespec ts = {
+      .tv_sec = wdelayms / 1000,
+      .tv_nsec = (wdelayms * 1000000) % 1000000000
+    };
+    nanosleep (&ts, NULL);
+  }
+
+#ifdef FALLOC_FL_PUNCH_HOLE
+  if (may_trim) {
+    int r = fallocate (h->fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+		       offset, count);
+    if (r == -1 && errno != EOPNOTSUPP) {
+      nbdkit_error ("pwrite: %m");
+    }
+    return r;
+  }
+#endif
+
+  /* Trigger a fall back to writing */
+  errno = EOPNOTSUPP;
+  return -1;
+}
+
 /* Flush the file to disk. */
 static int
 file_flush (void *handle)
@@ -275,6 +306,7 @@ static struct nbdkit_plugin plugin = {
   .get_size          = file_get_size,
   .pread             = file_pread,
   .pwrite            = file_pwrite,
+  .zero              = file_zero,
   .flush             = file_flush,
 };

--
2.9.3