Make it possible for filters to adjust the behavior for
NBD_CMD_CACHE. To avoid any 'git bisect' breakage, this patch leaves
.can_cache as NBDKIT_CACHE_NONE if a filter does not provide an
override, rather than passthrough to the plugin; it will be flipped
later after all necessary filters have been patched first.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
docs/nbdkit-filter.pod | 42 ++++++++++++++++++++++++++++++++++-------
include/nbdkit-filter.h | 8 ++++++++
server/filters.c | 37 ++++++++++++++++++++++++++++++++----
3 files changed, 76 insertions(+), 11 deletions(-)
diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod
index 6aeaa7b..857f241 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.
@@ -385,12 +389,14 @@ the plugin's own C<.can_zero> callback returned false,
because nbdkit
implements a fallback to C<.pwrite> at the plugin layer.
Remember that most of the feature check functions return merely a
-boolean success value, while C<.can_fua> has three success values.
-The difference between values may affect choices made in the filter:
-when splitting a write request that requested FUA from the client, if
-C<next_ops-E<gt>can_fua> returns C<NBDKIT_FUA_NATIVE>, then the filter
-should pass the FUA flag on to each sub-request; while if it is known
-that FUA is emulated by a flush because of a return of
+boolean success value, while C<.can_fua> and C<.can_cache> have three
+success values.
+
+The difference between C<.can_fua> values may affect choices made in
+the filter: when splitting a write request that requested FUA from the
+client, if C<next_ops-E<gt>can_fua> returns C<NBDKIT_FUA_NATIVE>, then
+the filter should pass the FUA flag on to each sub-request; while if
+it is known that FUA is emulated by a flush because of a return of
C<NBDKIT_FUA_EMULATE>, it is more efficient to only flush once after
all sub-requests have completed (often by passing C<NBDKIT_FLAG_FUA>
on to only the final sub-request, or by dropping the flag and ending
@@ -597,6 +603,28 @@ 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
+C<NBDKIT_CACHE_NONE> or C<NBDKIT_CACHE_EMULATE>; in turn, the filter
+should not call C<next_ops-E<gt>cache> unless
+C<next_ops-E<gt>can_cache> returned C<NBDKIT_CACHE_NATIVE>.
+
+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 +736,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 e456fbf..430d515 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,18 @@ 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);
+ if (f->filter.can_cache)
+ return f->filter.can_cache (&next_ops, &nxdata, handle);
/* FIXME: Default to f->backend.next->can_cache, once all filters
have been audited */
- return NBDKIT_CACHE_NONE;
+ else
+ return NBDKIT_CACHE_NONE;
+ return f->backend.next->can_cache (f->backend.next, conn);
}
static int
@@ -720,15 +744,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