[Libguestfs] [nbdkit PATCH v2 2/2] server: Remember .open(readonly) status

Eric Blake eblake at redhat.com
Fri Aug 30 22:55:08 UTC 2019


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 at 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




More information about the Libguestfs mailing list