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 <ebl...@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 _______________________________________________ Libguestfs mailing list Libguestfs@redhat.com https://www.redhat.com/mailman/listinfo/libguestfs