While our plugin code always advertises WRITE_ZEROES on writable
connections (because we can emulate .zero by calling .pwrite),
it is conceivable that a filter may want to explicitly avoid
advertising particular bits. More to the point, an upcoming
patch will add a 'nozero' filter that hides WRITE_ZEROES support,
at least for the purposes of timing comparisons between server
emulation and the client having to send zeroes over the wire.
This change alters filter API; but given that we've already bumped
the API in a previous patch, we can group all of the API changes
within the same release without having to bump the #define value
in this patch.
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
docs/nbdkit-filter.pod | 20 +++++++++++++++++++-
include/nbdkit-filter.h | 3 +++
src/filters.c | 16 ++++++++++++++--
filters/log/log.c | 7 ++++---
4 files changed, 40 insertions(+), 6 deletions(-)
diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod
index 32d50cb..3af97b0 100644
--- a/docs/nbdkit-filter.pod
+++ b/docs/nbdkit-filter.pod
@@ -353,7 +353,8 @@ calls.
int (*can_trim) (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle);
-These intercept the corresponding plugin methods.
+These intercept the corresponding plugin methods, and control feature
+bits advertised to the client.
If there is an error, the callback should call C<nbdkit_error> with an
error message and return C<-1>. If these functions are called more
@@ -361,6 +362,23 @@ than once for the same connection, they should return the same
value;
similarly, the filter may cache the results of each counterpart in
C<next_ops> for a given connection rather than repeating calls.
+=head2 C<.can_zero>
+
+ int (*can_zero) (struct nbdkit_next_ops *next_ops, void *nxdata,
+ void *handle);
+
+This controls whether write zero support will be advertised to the
+client. This function has no counterpart in plugins, because nbdkit
+can always emulate zero by using pwrite; but a filter may want to
+force different handling than the nbdkit implementation. If this
+callback is omitted, the default returned for the plugin layer is
+true.
+
+If there is an error, the callback should call C<nbdkit_error> with an
+error message and return C<-1>. Like the other initial queries
+documented above, caching the return value of this function is
+allowed.
+
=head2 C<.pread>
int (*pread) (struct nbdkit_next_ops *next_ops, void *nxdata,
diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h
index 95be130..533713b 100644
--- a/include/nbdkit-filter.h
+++ b/include/nbdkit-filter.h
@@ -57,6 +57,7 @@ struct nbdkit_next_ops {
int (*can_flush) (void *nxdata);
int (*is_rotational) (void *nxdata);
int (*can_trim) (void *nxdata);
+ int (*can_zero) (void *nxdata);
int (*pread) (void *nxdata, void *buf, uint32_t count, uint64_t offset,
uint32_t flags, int *err);
@@ -115,6 +116,8 @@ struct nbdkit_filter {
void *handle);
int (*can_trim) (struct nbdkit_next_ops *next_ops, void *nxdata,
void *handle);
+ int (*can_zero) (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,
diff --git a/src/filters.c b/src/filters.c
index 0cf7594..491c676 100644
--- a/src/filters.c
+++ b/src/filters.c
@@ -287,6 +287,13 @@ next_can_trim (void *nxdata)
return b_conn->b->can_trim (b_conn->b, b_conn->conn);
}
+static int
+next_can_zero (void *nxdata)
+{
+ struct b_conn *b_conn = nxdata;
+ return b_conn->b->can_zero (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)
@@ -334,6 +341,7 @@ static struct nbdkit_next_ops next_ops = {
.can_flush = next_can_flush,
.is_rotational = next_is_rotational,
.can_trim = next_can_trim,
+ .can_zero = next_can_zero,
.pread = next_pread,
.pwrite = next_pwrite,
.flush = next_flush,
@@ -450,11 +458,15 @@ static int
filter_can_zero (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 ("can_zero");
- /* TODO expose this to filters */
- return f->backend.next->can_zero (f->backend.next, conn);
+ if (f->filter.can_zero)
+ return f->filter.can_zero (&next_ops, &nxdata, handle);
+ else
+ return f->backend.next->can_zero (f->backend.next, conn);
}
static int
diff --git a/filters/log/log.c b/filters/log/log.c
index 58fd4f8..2dd61c0 100644
--- a/filters/log/log.c
+++ b/filters/log/log.c
@@ -235,13 +235,14 @@ log_prepare (struct nbdkit_next_ops *next_ops, void *nxdata, void
*handle)
int f = next_ops->can_flush (nxdata);
int r = next_ops->is_rotational (nxdata);
int t = next_ops->can_trim (nxdata);
+ int z = next_ops->can_zero (nxdata);
- if (size < 0 || w < 0 || f < 0 || r < 0 || t < 0)
+ if (size < 0 || w < 0 || f < 0 || r < 0 || t < 0 || z < 0)
return -1;
- /* TODO expose can_zero, can_fua to filters */
+ /* TODO expose can_fua to filters */
output (h, "Connect", 0, "size=0x%" PRIx64 " write=%d flush=%d
"
- "rotational=%d trim=%d" /* zero=? fua=? */, size, w, f, r, t);
+ "rotational=%d trim=%d zero=%d" /* fua=? */, size, w, f, r, t, z);
return 0;
}
--
2.14.3