Make it possible for plugins to provide an alternative behavior for NBD_CMD_CACHE rather than just discarding the buffer of .pread.
Signed-off-by: Eric Blake <[email protected]> --- docs/nbdkit-plugin.pod | 52 +++++++++++++++++++++++++++++++++++++++++ include/nbdkit-plugin.h | 2 ++ server/plugins.c | 17 +++++++++----- 3 files changed, 65 insertions(+), 6 deletions(-) diff --git a/docs/nbdkit-plugin.pod b/docs/nbdkit-plugin.pod index 318be4c..0657151 100644 --- a/docs/nbdkit-plugin.pod +++ b/docs/nbdkit-plugin.pod @@ -620,6 +620,31 @@ with an error message and return C<-1>. This callback is not required. If omitted, then we return false. +=head2 C<.can_cache> + + int can_cache (void *handle); + +This is called during the option negotiation phase to find out if the +plugin supports a cache operation. The nature of the caching is +unspecified (including whether there are limits on how much can be +cached at once, and whether writes to a cached region have +write-through or write-back semantics), but the command exists to let +clients issue a hint to the server that they will be accessing that +region of the export. + +If there is an error, C<.can_cache> should call C<nbdkit_error> with +an error message and return C<-1>. Since the NBD protocol has +reserved the right to add future flags to mandate specific caching +capabilities, this function should only return C<1> on success (in the +future, other positive results may be treated as a bitmask of +supported flags). + +This callback is not required. If omitted, then we return true iff a +C<.cache> callback has been defined. Note that nbdkit always +advertises caching capabilities to the client regardless of this +callback; if this callback returns false, nbdkit handles a client +cache request by calling C<.pread> and ignoring the resulting data. + =head2 C<.pread> int pread (void *handle, void *buf, uint32_t count, uint64_t offset, @@ -814,6 +839,33 @@ C<nbdkit_extent_add> returns C<0> on success or C<-1> on failure. On failure C<nbdkit_error> and/or C<nbdkit_set_error> has already been called. C<errno> will be set to a suitable value. +=head2 C<.cache> + + int cache (void *handle, uint32_t count, uint64_t offset, uint32_t flags); + +During the data serving phase, this callback is used to give the +plugin a hint that the client intends to make further accesses to the +given region of the export. The nature of caching is not specified +further by the NBD specification (for example, a server may place +limits on how much may be cached at once, and there is no way to +control if writes to a cached area have write-through or write-back +semantics). In fact, the cache command can always fail and still be +compliant, and success might not guarantee a performance gain. If +this callback is omitted, nbdkit defaults to providing cache semantics +obtained by calling C<.pread> over the same region and ignoring the +results. + +This function will not be called if C<.can_cache> returned false. The +parameter C<flags> exists in case of future NBD protocol extensions; +at this time, it will be 0 on input. A plugin must fail this function +if C<flags> includes an unrecognized flag, as that may indicate a +requirement that the plugin comply must with a specific caching +semantic. + +If there is an error, C<.cache> should call C<nbdkit_error> with an +error message, and C<nbdkit_set_error> to record an appropriate error +(unless C<errno> is sufficient), then return C<-1>. + =head1 THREADS Each nbdkit plugin must declare its thread safety model by defining diff --git a/include/nbdkit-plugin.h b/include/nbdkit-plugin.h index 54b4ce2..e9b1808 100644 --- a/include/nbdkit-plugin.h +++ b/include/nbdkit-plugin.h @@ -128,6 +128,8 @@ struct nbdkit_plugin { int (*can_extents) (void *handle); int (*extents) (void *handle, uint32_t count, uint64_t offset, uint32_t flags, struct nbdkit_extents *extents); + int (*can_cache) (void *handle); + int (*cache) (void *handle, uint32_t count, uint64_t offset, uint32_t flags); }; extern void nbdkit_set_error (int err); diff --git a/server/plugins.c b/server/plugins.c index cabf543..947fe79 100644 --- a/server/plugins.c +++ b/server/plugins.c @@ -201,6 +201,8 @@ plugin_dump_fields (struct backend *b) HAS (can_multi_conn); HAS (can_extents); HAS (extents); + HAS (can_cache); + HAS (cache); #undef HAS /* Custom fields. */ @@ -451,12 +453,16 @@ plugin_can_multi_conn (struct backend *b, struct connection *conn) static int plugin_can_cache (struct backend *b, struct connection *conn) { + struct backend_plugin *p = container_of (b, struct backend_plugin, backend); + assert (connection_get_handle (conn, 0)); debug ("can_cache"); - /* FIXME: return default based on plugin->cache */ - return 0; + if (p->plugin.can_cache) + return p->plugin.can_cache (connection_get_handle (conn, 0)); + else + return p->plugin.cache != NULL; } /* Plugins and filters can call this to set the true errno, in cases @@ -710,16 +716,15 @@ plugin_cache (struct backend *b, struct connection *conn, int *err) { struct backend_plugin *p = container_of (b, struct backend_plugin, backend); - int r = -1; + int r; assert (connection_get_handle (conn, 0)); assert (!flags); + assert (p->plugin.cache); debug ("cache count=%" PRIu32 " offset=%" PRIu64, count, offset); - /* FIXME: assert plugin->cache and call it */ - assert (false); - + r = p->plugin.cache (connection_get_handle (conn, 0), count, offset, flags); if (r == -1) *err = get_error (p); return r; -- 2.20.1 _______________________________________________ Libguestfs mailing list [email protected] https://www.redhat.com/mailman/listinfo/libguestfs
