The previous patch argued that globally affecting .can_write based on
'-r' (the global 'readonly') prevents the ability for a filter to call
next_open(nxdata, true) to purposefully write to the plugin, even
while advertising .can_write=0 to the client. But it also
demonstrated that when a filter passes false to next_open, we were
still making needless probes into the plugin, for something the filter
won't be using.
This patch improves things to prime the .can_write cache according to
.open. The same script from the previous patch now fails a lot faster
under -r (since nozero is not a filter that changes readonly=false to
true, the plugin now fails .can_zero quickly):
$ /bin/time -f %e ./nbdkit -U - -r --filter=nozero sh script zeromode=notrim \
--run 'qemu-nbd --list -k $unixsocket >/dev/null'
nbdkit: sh[1]: error: zeromode 'notrim' requires plugin zero support
qemu-nbd: Failed to read initial magic: Unexpected end-of-file before all bytes were read
Command exited with non-zero status 1
0.06
Signed-off-by: Eric Blake <eblake(a)redhat.com>
---
server/internal.h | 3 +++
server/backend.c | 20 +++++++++++++++-----
server/connections.c | 2 +-
server/filters.c | 6 ++----
server/plugins.c | 2 --
5 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/server/internal.h b/server/internal.h
index a55d6406..fb197b9e 100644
--- a/server/internal.h
+++ b/server/internal.h
@@ -325,6 +325,9 @@ extern void backend_load (struct backend *b, const char *name,
extern void backend_unload (struct backend *b, void (*unload) (void))
__attribute__((__nonnull__ (1)));
+extern int backend_open (struct backend *b, struct connection *conn,
+ int readonly)
+ __attribute__((__nonnull__ (1, 2)));
extern void backend_set_handle (struct backend *b, struct connection *conn,
void *handle)
__attribute__((__nonnull__ (1, 2 /* not 3 */)));
diff --git a/server/backend.c b/server/backend.c
index 749b1f15..ebdef63a 100644
--- a/server/backend.c
+++ b/server/backend.c
@@ -167,6 +167,20 @@ backend_unload (struct backend *b, void (*unload) (void))
free (b->name);
}
+int
+backend_open (struct backend *b, struct connection *conn, int readonly)
+{
+ struct b_conn_handle *h = &conn->handles[b->i];
+
+ debug ("%s: open readonly=%d", b->name, readonly);
+
+ assert (h->handle == NULL);
+ assert (h->can_write == -1);
+ if (readonly)
+ h->can_write = 0;
+ return b->open (b, conn, readonly);
+}
+
void
backend_set_handle (struct backend *b, struct connection *conn, void *handle)
{
@@ -195,12 +209,8 @@ backend_can_write (struct backend *b, struct connection *conn)
debug ("%s: can_write", b->name);
- if (h->can_write == -1) {
- /* Special case for outermost backend when -r is in effect. */
- if (readonly && b == backend)
- return h->can_write = 0;
+ if (h->can_write == -1)
h->can_write = b->can_write (b, conn);
- }
return h->can_write;
}
diff --git a/server/connections.c b/server/connections.c
index 7609e9a7..0c1f2413 100644
--- a/server/connections.c
+++ b/server/connections.c
@@ -149,7 +149,7 @@ _handle_single_connection (int sockin, int sockout)
goto done;
lock_request (conn);
- r = backend->open (backend, conn, readonly);
+ r = backend_open (backend, conn, readonly);
unlock_request (conn);
if (r == -1)
goto done;
diff --git a/server/filters.c b/server/filters.c
index 0e10816f..a8d7dd7c 100644
--- a/server/filters.c
+++ b/server/filters.c
@@ -195,7 +195,7 @@ next_open (void *nxdata, int readonly)
{
struct b_conn *b_conn = nxdata;
- return b_conn->b->open (b_conn->b, b_conn->conn, readonly);
+ return backend_open (b_conn->b, b_conn->conn, readonly);
}
static int
@@ -205,8 +205,6 @@ filter_open (struct backend *b, struct connection *conn, int
readonly)
struct b_conn nxdata = { .b = b->next, .conn = conn };
void *handle;
- debug ("%s: open readonly=%d", b->name, readonly);
-
if (f->filter.open) {
handle = f->filter.open (next_open, &nxdata, readonly);
if (handle == NULL)
@@ -215,7 +213,7 @@ filter_open (struct backend *b, struct connection *conn, int
readonly)
return 0;
}
else
- return b->next->open (b->next, conn, readonly);
+ return backend_open (b->next, conn, readonly);
}
static void
diff --git a/server/plugins.c b/server/plugins.c
index 1dec4008..1c4b5f50 100644
--- a/server/plugins.c
+++ b/server/plugins.c
@@ -241,8 +241,6 @@ plugin_open (struct backend *b, struct connection *conn, int
readonly)
assert (connection_get_handle (conn, 0) == NULL);
assert (p->plugin.open != NULL);
- debug ("%s: open readonly=%d", b->name, readonly);
-
handle = p->plugin.open (readonly);
if (!handle)
return -1;
--
2.21.0