[Libguestfs] [nbdkit PATCH v2 03/24] file, split: Implement .cache with posix_fadvise

Eric Blake eblake at redhat.com
Thu May 16 03:57:53 UTC 2019


Since NBD_CMD_CACHE is already advisory, let's use an advisory kernel
interface to implement it ;)

Even when posix_fadvise() is not present, it is likely that nbdkit's
fallback to .pread will actually have a similar benefit in populating
the filesystem cache, since we aren't using O_DIRECT to avoid that
cache, so always define .can_cache with one of the two positive
results.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 configure.ac          |  3 ++-
 plugins/file/file.c   | 37 ++++++++++++++++++++++++++++++
 plugins/split/split.c | 52 ++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 90 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index 58031f3..06124c5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -195,7 +195,8 @@ dnl Check for functions in libc, all optional.
 AC_CHECK_FUNCS([\
 	fdatasync \
 	get_current_dir_name \
-	mkostemp])
+	mkostemp \
+	posix_fadvise])

 dnl Check whether printf("%m") works
 AC_CACHE_CHECK([whether the printf family supports %m],
diff --git a/plugins/file/file.c b/plugins/file/file.c
index f0ac23b..4d4bcba 100644
--- a/plugins/file/file.c
+++ b/plugins/file/file.c
@@ -294,6 +294,20 @@ file_can_fua (void *handle)
   return NBDKIT_FUA_NATIVE;
 }

+static int
+file_can_cache (void *handle)
+{
+  /* Prefer posix_fadvise(), but letting nbdkit call .pread on our
+   * behalf also tends to work well for the local file system
+   * cache.
+   */
+#if HAVE_POSIX_FADVISE
+  return NBDKIT_FUA_NATIVE;
+#else
+  return NBDKIT_FUA_EMULATE;
+#endif
+}
+
 /* Flush the file to disk. */
 static int
 file_flush (void *handle, uint32_t flags)
@@ -608,6 +622,25 @@ file_extents (void *handle, uint32_t count, uint64_t offset,
 }
 #endif /* SEEK_HOLE */

+#if HAVE_POSIX_FADVISE
+/* Caching. */
+static int
+file_cache (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
+{
+  struct handle *h = handle;
+  int r;
+
+  /* Cache is advisory, we don't care if this fails */
+  r = posix_fadvise (h->fd, offset, count, POSIX_FADV_WILLNEED);
+  if (r) {
+    errno = r;
+    nbdkit_error ("posix_fadvise: %m");
+    return -1;
+  }
+  return 0;
+}
+#endif /* HAVE_POSIX_FADVISE */
+
 static struct nbdkit_plugin plugin = {
   .name              = "file",
   .longname          = "nbdkit file plugin",
@@ -624,6 +657,7 @@ static struct nbdkit_plugin plugin = {
   .can_multi_conn    = file_can_multi_conn,
   .can_trim          = file_can_trim,
   .can_fua           = file_can_fua,
+  .can_cache         = file_can_cache,
   .pread             = file_pread,
   .pwrite            = file_pwrite,
   .flush             = file_flush,
@@ -632,6 +666,9 @@ static struct nbdkit_plugin plugin = {
 #ifdef SEEK_HOLE
   .can_extents       = file_can_extents,
   .extents           = file_extents,
+#endif
+#if HAVE_POSIX_FADVISE
+  .cache             = file_cache,
 #endif
   .errno_is_preserved = 1,
 };
diff --git a/plugins/split/split.c b/plugins/split/split.c
index cf2b2c7..1b8e69a 100644
--- a/plugins/split/split.c
+++ b/plugins/split/split.c
@@ -1,5 +1,5 @@
 /* nbdkit
- * Copyright (C) 2017-2018 Red Hat Inc.
+ * Copyright (C) 2017-2019 Red Hat Inc.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -195,6 +195,20 @@ split_get_size (void *handle)
   return (int64_t) h->size;
 }

+static int
+split_can_cache (void *handle)
+{
+  /* Prefer posix_fadvise(), but letting nbdkit call .pread on our
+   * behalf also tends to work well for the local file system
+   * cache.
+   */
+#if HAVE_POSIX_FADVISE
+  return NBDKIT_FUA_NATIVE;
+#else
+  return NBDKIT_FUA_EMULATE;
+#endif
+}
+
 /* Helper function to map the offset to the correct file. */
 static int
 compare_offset (const void *offsetp, const void *filep)
@@ -277,6 +291,38 @@ split_pwrite (void *handle, const void *buf, uint32_t count, uint64_t offset)
   return 0;
 }

+#if HAVE_POSIX_FADVISE
+/* Caching. */
+static int
+split_cache (void *handle, uint32_t count, uint64_t offset, uint32_t flags)
+{
+  struct handle *h = handle;
+
+  /* Cache is advisory, we don't care if this fails */
+  while (count > 0) {
+    struct file *file = get_file (h, offset);
+    uint64_t foffs = offset - file->offset;
+    uint64_t max;
+    int r;
+
+    max = file->size - foffs;
+    if (max > count)
+      max = count;
+
+    r = posix_fadvise (file->fd, offset, max, POSIX_FADV_WILLNEED);
+    if (r) {
+      errno = r;
+      nbdkit_error ("posix_fadvise: %m");
+      return -1;
+    }
+    count -= r;
+    offset += r;
+  }
+
+  return 0;
+}
+#endif /* HAVE_POSIX_FADVISE */
+
 static struct nbdkit_plugin plugin = {
   .name              = "split",
   .version           = PACKAGE_VERSION,
@@ -287,8 +333,12 @@ static struct nbdkit_plugin plugin = {
   .open              = split_open,
   .close             = split_close,
   .get_size          = split_get_size,
+  .can_cache         = split_can_cache,
   .pread             = split_pread,
   .pwrite            = split_pwrite,
+#if HAVE_POSIX_FADVISE
+  .cache             = split_cache,
+#endif
   /* In this plugin, errno is preserved properly along error return
    * paths from failed system calls.
    */
-- 
2.20.1




More information about the Libguestfs mailing list