[Libguestfs] [nbdkit PATCH 7/9] filters: Add .cache callback

Eric Blake eblake at redhat.com
Fri May 10 03:03:40 UTC 2019


Make it possible for filters to adjust the behavior for
NBD_CMD_CACHE. To avoid any 'git bisect' breakage, this patch defaults
.can_cache to false until all necessary filters have been patched
first.

Signed-off-by: Eric Blake <eblake at redhat.com>
---
 docs/nbdkit-filter.pod  | 27 ++++++++++++++++++++++++++-
 include/nbdkit-filter.h |  8 ++++++++
 server/filters.c        | 39 +++++++++++++++++++++++++++++++++------
 3 files changed, 67 insertions(+), 7 deletions(-)

diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod
index 6aeaa7b..787333a 100644
--- a/docs/nbdkit-filter.pod
+++ b/docs/nbdkit-filter.pod
@@ -356,6 +356,8 @@ calls.

 =head2 C<.can_multi_conn>

+=head2 C<.can_cache>
+
  int (*can_write) (struct nbdkit_next_ops *next_ops, void *nxdata,
                    void *handle);
  int (*can_flush) (struct nbdkit_next_ops *next_ops, void *nxdata,
@@ -373,6 +375,8 @@ calls.
                  void *handle);
  int (*can_multi_conn) (struct nbdkit_next_ops *next_ops, void *nxdata,
                         void *handle);
+ int (*can_cache) (struct nbdkit_next_ops *next_ops, void *nxdata,
+                   void *handle);

 These intercept the corresponding plugin methods, and control feature
 bits advertised to the client.
@@ -597,6 +601,27 @@ Returns the number of extents in the list.

 Returns a copy of the C<i>'th extent.

+=head2 C<.cache>
+
+ int (*cache) (struct nbdkit_next_ops *next_ops, void *nxdata,
+               void *handle, uint32_t count, uint64_t offset,
+               uint32_t flags, int *err);
+
+This intercepts the plugin C<.cache> method and can be used to modify
+cache requests.
+
+This function will not be called if C<.can_cache> returned false; in
+turn, the filter should not call C<next_ops-E<gt>cache> if
+C<next_ops-E<gt>can_cache> did not return true.
+
+The parameter C<flags> exists in case of future NBD protocol
+extensions; at this time, it will be 0 on input, and the filter should
+not pass any flags to C<next_ops-E<gt>cache>.
+
+If there is an error, C<.cache> should call C<nbdkit_error> with an
+error message B<and> return -1 with C<err> set to the positive errno
+value to return to the client.
+
 =head1 ERROR HANDLING

 If there is an error in the filter itself, the filter should call
@@ -708,4 +733,4 @@ Richard W.M. Jones

 =head1 COPYRIGHT

-Copyright (C) 2013-2018 Red Hat Inc.
+Copyright (C) 2013-2019 Red Hat Inc.
diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h
index 9b6cd6e..5893dd8 100644
--- a/include/nbdkit-filter.h
+++ b/include/nbdkit-filter.h
@@ -74,6 +74,7 @@ struct nbdkit_next_ops {
   int (*can_extents) (void *nxdata);
   int (*can_fua) (void *nxdata);
   int (*can_multi_conn) (void *nxdata);
+  int (*can_cache) (void *nxdata);

   int (*pread) (void *nxdata, void *buf, uint32_t count, uint64_t offset,
                 uint32_t flags, int *err);
@@ -87,6 +88,8 @@ struct nbdkit_next_ops {
                int *err);
   int (*extents) (void *nxdata, uint32_t count, uint64_t offset, uint32_t flags,
                   struct nbdkit_extents *extents, int *err);
+  int (*cache) (void *nxdata, uint32_t count, uint64_t offset, uint32_t flags,
+                int *err);
 };

 struct nbdkit_filter {
@@ -142,6 +145,8 @@ struct nbdkit_filter {
                   void *handle);
   int (*can_multi_conn) (struct nbdkit_next_ops *next_ops, void *nxdata,
                          void *handle);
+  int (*can_cache) (struct nbdkit_next_ops *next_ops, void *nxdata,
+                    void *handle);

   int (*pread) (struct nbdkit_next_ops *next_ops, void *nxdata,
                 void *handle, void *buf, uint32_t count, uint64_t offset,
@@ -161,6 +166,9 @@ struct nbdkit_filter {
   int (*extents) (struct nbdkit_next_ops *next_ops, void *nxdata,
                   void *handle, uint32_t count, uint64_t offset, uint32_t flags,
                   struct nbdkit_extents *extents, int *err);
+  int (*cache) (struct nbdkit_next_ops *next_ops, void *nxdata,
+                void *handle, uint32_t count, uint64_t offset, uint32_t flags,
+                int *err);
 };

 #define NBDKIT_REGISTER_FILTER(filter)                                  \
diff --git a/server/filters.c b/server/filters.c
index c619fd6..a48f67e 100644
--- a/server/filters.c
+++ b/server/filters.c
@@ -329,6 +329,13 @@ next_can_multi_conn (void *nxdata)
   return b_conn->b->can_multi_conn (b_conn->b, b_conn->conn);
 }

+static int
+next_can_cache (void *nxdata)
+{
+  struct b_conn *b_conn = nxdata;
+  return b_conn->b->can_cache (b_conn->b, b_conn->conn);
+}
+
 static int
 next_pread (void *nxdata, void *buf, uint32_t count, uint64_t offset,
             uint32_t flags, int *err)
@@ -379,6 +386,15 @@ next_extents (void *nxdata, uint32_t count, uint64_t offset, uint32_t flags,
                              extents, err);
 }

+static int
+next_cache (void *nxdata, uint32_t count, uint64_t offset,
+            uint32_t flags, int *err)
+{
+  struct b_conn *b_conn = nxdata;
+  return b_conn->b->cache (b_conn->b, b_conn->conn, count, offset, flags,
+                           err);
+}
+
 static struct nbdkit_next_ops next_ops = {
   .get_size = next_get_size,
   .can_write = next_can_write,
@@ -389,12 +405,14 @@ static struct nbdkit_next_ops next_ops = {
   .can_extents = next_can_extents,
   .can_fua = next_can_fua,
   .can_multi_conn = next_can_multi_conn,
+  .can_cache = next_can_cache,
   .pread = next_pread,
   .pwrite = next_pwrite,
   .flush = next_flush,
   .trim = next_trim,
   .zero = next_zero,
   .extents = next_extents,
+  .cache = next_cache,
 };

 static int
@@ -577,12 +595,16 @@ static int
 filter_can_cache (struct backend *b, struct connection *conn)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
+  void *handle = connection_get_handle (conn, f->backend.i);
+  struct b_conn nxdata = { .b = f->backend.next, .conn = conn };

   debug ("%s: can_cache", f->name);

-  /* FIXME: Default to f->backend.next->can_cache, once all filters
-     have been audited */
-  return 0;
+  if (f->filter.can_cache)
+    return f->filter.can_cache (&next_ops, &nxdata, handle);
+  else
+    return 0; /* FIXME - allow passthrough once all filters are audited */
+  return f->backend.next->can_cache (f->backend.next, conn);
 }

 static int
@@ -720,15 +742,20 @@ filter_cache (struct backend *b, struct connection *conn,
               uint32_t flags, int *err)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
+  void *handle = connection_get_handle (conn, f->backend.i);
+  struct b_conn nxdata = { .b = f->backend.next, .conn = conn };

   assert (flags == 0);

   debug ("%s: cache count=%" PRIu32 " offset=%" PRIu64 " flags=0x%" PRIx32,
          f->name, count, offset, flags);

-  /* FIXME: Allow filter to rewrite request */
-  return f->backend.next->cache (f->backend.next, conn,
-                                 count, offset, flags, err);
+  if (f->filter.cache)
+    return f->filter.cache (&next_ops, &nxdata, handle,
+                            count, offset, flags, err);
+  else
+    return f->backend.next->cache (f->backend.next, conn,
+                                   count, offset, flags, err);
 }

 static struct backend filter_functions = {
-- 
2.20.1




More information about the Libguestfs mailing list