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