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(a)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