[Libguestfs] [nbdkit PATCH v3 11/16] filters: Use context rather than connection to track c_next

Eric Blake eblake at redhat.com
Fri Mar 5 23:31:15 UTC 2021


This is another API/ABI change to filters, but that doesn't matter.
Instead of having a 1:1 correspondence of automatic backend context to
the current connection (which means filters.c has to consult GET_CONN
on every action), switch things so that a given context tracks the
next context.  This requires another signature change to the internal
backend_open and backend_reopen functions, as well as a public change
to the type of the argument handed to filter .open calls.  A given
connection now only needs to track the top_context, and we no longer
need get_context()/set_context().  Internally, nbdkit_context and
nbdkit_next are the same type, but the public interface for filters
keeps them separate for type-safety reasons (assigning a backend
handle to the current filter's context is different than calling into
the backend via next_ops/nxdata as the backend's context).

A few filters were already using the typedef name 'nbdkit_backend *'
instead of 'void *'; while they would still compile as-is, updating
their type makes it look nicer.  A later patch will force type-safety
on all the remaining filters, but it's better to save that mechanical
churn separately from this ABI change.  Also, with this in place, an
upcoming patch can finally allow filters to open up a context
independently of the current client connection.
---
 docs/nbdkit-filter.pod               | 12 ++--
 include/nbdkit-filter.h              |  9 ++-
 server/internal.h                    | 12 ++--
 server/backend.c                     | 70 +++++++++-------------
 server/connections.c                 | 33 ++---------
 server/filters.c                     | 87 +++++++++++-----------------
 server/plugins.c                     |  3 +-
 server/protocol-handshake-newstyle.c | 17 +++---
 server/protocol-handshake.c          | 30 +++++-----
 server/protocol.c                    |  9 ++-
 filters/checkwrite/checkwrite.c      |  2 +-
 filters/exitlast/exitlast.c          |  2 +-
 filters/exitwhen/exitwhen.c          |  2 +-
 filters/gzip/gzip.c                  |  2 +-
 filters/limit/limit.c                |  2 +-
 filters/retry/retry.c                |  4 +-
 filters/tar/tar.c                    |  2 +-
 17 files changed, 116 insertions(+), 182 deletions(-)

diff --git a/docs/nbdkit-filter.pod b/docs/nbdkit-filter.pod
index e801965d..0b120efe 100644
--- a/docs/nbdkit-filter.pod
+++ b/docs/nbdkit-filter.pod
@@ -132,7 +132,7 @@ C<nbdkit_next_after_fork>, C<nbdkit_next_preconnect>,
 C<nbdkit_next_list_exports>, C<nbdkit_next_default_export>,
 C<nbdkit_next_open>) and a structure called C<struct nbdkit_next_ops>.
 These abstract the next plugin or filter in the chain.  There is also
-an opaque pointer C<backend> or C<nxdata> which must be passed along
+an opaque pointer C<context> or C<nxdata> which must be passed along
 when calling these functions.  The value of C<nxdata> passed to
 C<.prepare> has a stable lifetime that lasts to the corresponding
 C<.finalize>, with all intermediate functions (such as C<.pread>)
@@ -141,7 +141,7 @@ is not reused are C<.config>, C<.config_complete>, C<.get_ready>, and
 C<.after_fork>, which are called during initialization outside any
 connections, and C<.preconnect>, C<.list_exports>, C<.default_export>,
 and C<.open> which are called based on client connections but prior to
-the stable lifetime of C<.prepare>.  The value of C<backend> passed to
+the stable lifetime of C<.prepare>.  The value of C<context> passed to
 C<.open> has a lifetime that lasts until the matching C<.close> for
 use by C<nbdkit_backend_reopen>.

@@ -429,7 +429,7 @@ C<next> because it cannot be altered.

 =head2 C<.open>

- void * (*open) (nbdkit_next_open *next, nbdkit_backend *backend,
+ void * (*open) (nbdkit_next_open *next, nbdkit_context *context,
                  int readonly, const char *exportname, int is_tls);

 This is called when a new client connection is opened and can be used
@@ -471,7 +471,7 @@ outer filter to the plugin will be in reverse.  Skipping a call to
 C<next> is acceptable if the filter will not access C<next_ops>
 during any of the remaining callbacks reached on the same connection.

-The value of C<backend> in this call has a lifetime that lasts until
+The value of C<context> in this call has a lifetime that lasts until
 the counterpart C<.close>, and it is this value (and not the distinct
 C<nxdata> of C<.pread> and friends) that must be passed as the first
 parameter to C<nbdkit_backend_reopen> by a filter attempting to retry
@@ -481,14 +481,14 @@ a connection into the backend.

 Filters have access to a function for reopening the backend:

-  int (nbdkit_backend *backend, int readonly, const char *exportname,
+  int (nbdkit_context *context, int readonly, const char *exportname,
        void **nxdata);

 This function is used by L<nbdkit-retry-filter(1)> to close and reopen
 the underlying plugin, with possible changes to the C<readonly> and
 C<exportname> parameters in relation to the original opening.  It
 should be used with caution because it is difficult to use safely.
-The C<backend> parameter to this function should be the C<backend>
+The C<context> parameter to this function should be the C<context>
 parameter originally passed in to C<.open>; while the C<nxdata>
 pointer should be the address of C<nxdata> from any function with a
 C<next_ops> parameter (such as C<.pread>) that wants to call into the
diff --git a/include/nbdkit-filter.h b/include/nbdkit-filter.h
index b47e78c3..3f3f61cd 100644
--- a/include/nbdkit-filter.h
+++ b/include/nbdkit-filter.h
@@ -54,12 +54,15 @@ extern "C" {
  * the next filter or plugin.
  */
 typedef struct backend nbdkit_backend;
+typedef struct context nbdkit_context;
 typedef struct context nbdkit_next;
 #elif defined NBDKIT_RETRY_FILTER /* Hack to expose reopen to retry filter */
 typedef struct nbdkit_backend nbdkit_backend;
+typedef struct nbdkit_context nbdkit_context;
 typedef struct nbdkit_next_ops nbdkit_next;
 #else
 typedef void nbdkit_backend;
+typedef void nbdkit_context;
 typedef void nbdkit_next;
 #endif

@@ -74,7 +77,7 @@ typedef int nbdkit_next_list_exports (nbdkit_backend *nxdata, int readonly,
                                       struct nbdkit_exports *exports);
 typedef const char *nbdkit_next_default_export (nbdkit_backend *nxdata,
                                                 int readonly);
-typedef int nbdkit_next_open (nbdkit_backend *backend,
+typedef int nbdkit_next_open (nbdkit_context *context,
                               int readonly, const char *exportname);

 struct nbdkit_next_ops {
@@ -155,7 +158,7 @@ NBDKIT_EXTERN_DECL (const struct nbdkit_export, nbdkit_get_export,
  * Used by the retry filter.
  */
 NBDKIT_EXTERN_DECL (int, nbdkit_backend_reopen,
-                    (nbdkit_backend *backend, int readonly,
+                    (nbdkit_context *context, int readonly,
                      const char *exportname, nbdkit_next **nxdata));
 #endif

@@ -199,7 +202,7 @@ struct nbdkit_filter {
                                   nbdkit_backend *nxdata,
                                   int readonly, int is_tls);

-  void * (*open) (nbdkit_next_open *next, nbdkit_backend *backend,
+  void * (*open) (nbdkit_next_open *next, nbdkit_context *context,
                   int readonly, const char *exportname, int is_tls);
   void (*close) (void *handle);

diff --git a/server/internal.h b/server/internal.h
index 23639bcd..b944e56d 100644
--- a/server/internal.h
+++ b/server/internal.h
@@ -207,6 +207,7 @@ struct context {

   void *handle;         /* Plugin or filter handle. */
   struct backend *b;    /* Backend that provided handle. */
+  struct context *c_next; /* Underlying context, only when b->next != NULL. */

   unsigned char state;  /* Bitmask of HANDLE_* values */

@@ -235,7 +236,7 @@ struct connection {
   void *crypto_session;
   int nworkers;

-  struct context **contexts;    /* One per plugin and filter. */
+  struct context *top_context;  /* The context tied to 'top'. */
   char **default_exportname;    /* One per plugin and filter. */

   uint32_t cflags;
@@ -255,11 +256,6 @@ struct connection {
   connection_close_function close;
 };

-extern struct context *get_context (struct connection *conn, struct backend *b)
-  __attribute__((__nonnull__(1)));
-extern void set_context (struct connection *conn, struct backend *b,
-                         struct context *c)
-  __attribute__((__nonnull__(1)));
 extern void handle_single_connection (int sockin, int sockout);
 extern int connection_get_status (void);
 extern int connection_set_status (int value);
@@ -366,7 +362,7 @@ struct backend {
   int (*list_exports) (struct backend *, int readonly, int is_tls,
                        struct nbdkit_exports *exports);
   const char *(*default_export) (struct backend *, int readonly, int is_tls);
-  void *(*open) (struct backend *, int readonly, const char *exportname,
+  void *(*open) (struct context *, int readonly, const char *exportname,
                  int is_tls);
   int (*prepare) (struct context *, int readonly);
   int (*finalize) (struct context *);
@@ -434,7 +430,7 @@ extern bool backend_valid_range (struct context *c,
                                  uint64_t offset, uint32_t count)
   __attribute__((__nonnull__ (1)));

-extern int backend_reopen (struct backend *b,
+extern int backend_reopen (struct context *c,
                            int readonly, const char *exportname)
   __attribute__((__nonnull__ (1, 3)));
 extern const char *backend_export_description (struct context *c)
diff --git a/server/backend.c b/server/backend.c
index 58d10a3f..1c78556f 100644
--- a/server/backend.c
+++ b/server/backend.c
@@ -163,13 +163,12 @@ backend_list_exports (struct backend *b, int readonly,
                       struct nbdkit_exports *exports)
 {
   GET_CONN;
-  struct context *c = get_context (conn, b);
   size_t count;

   controlpath_debug ("%s: list_exports readonly=%d tls=%d",
                      b->name, readonly, conn->using_tls);

-  assert (c == NULL);
+  assert (conn->top_context == NULL);

   if (b->list_exports (b, readonly, conn->using_tls, exports) == -1 ||
       exports_resolve_default (exports, b, readonly) == -1) {
@@ -186,14 +185,13 @@ const char *
 backend_default_export (struct backend *b, int readonly)
 {
   GET_CONN;
-  struct context *c = get_context (conn, b);
   const char *s;

   controlpath_debug ("%s: default_export readonly=%d tls=%d",
                      b->name, readonly, conn->using_tls);

   if (conn->default_exportname[b->i] == NULL) {
-    assert (c == NULL);
+    assert (conn->top_context == NULL);
     s = b->default_export (b, readonly, conn->using_tls);
     /* Ignore over-length strings. XXX Also ignore non-UTF8? */
     if (s && strnlen (s, NBD_MAX_STRING + 1) > NBD_MAX_STRING) {
@@ -247,10 +245,10 @@ backend_open (struct backend *b, int readonly, const char *exportname)
   controlpath_debug ("%s: open readonly=%d exportname=\"%s\" tls=%d",
                      b->name, readonly, exportname, conn->using_tls);

-  assert (conn->contexts[b->i] == NULL);
   c->next = next_ops;
   c->handle = NULL;
   c->b = b;
+  c->c_next = NULL;
   c->state = 0;
   c->exportsize = -1;
   c->can_write = readonly ? 0 : -1;
@@ -277,15 +275,12 @@ backend_open (struct backend *b, int readonly, const char *exportname)
   /* Most filters will call next_open first, resulting in
    * inner-to-outer ordering.
    */
-  c->handle = b->open (b, readonly, exportname, conn->using_tls);
+  c->handle = b->open (c, readonly, exportname, conn->using_tls);
   controlpath_debug ("%s: open returned handle %p", b->name, c->handle);

   if (c->handle == NULL) {
-    if (b->i) { /* Do not strand backend if this layer failed */
-      struct context *c2 = get_context (conn, b->next);
-      if (c2 != NULL)
-        backend_close (c2);
-    }
+    if (b->i && c->c_next != NULL)
+      backend_close (c->c_next);
     free (c);
     return NULL;
   }
@@ -297,7 +292,6 @@ backend_open (struct backend *b, int readonly, const char *exportname)
 int
 backend_prepare (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;

   assert (c->handle);
@@ -307,11 +301,8 @@ backend_prepare (struct context *c)
    * plugin, similar to typical .open order.  But remember that
    * a filter may skip opening its backend.
    */
-  if (b->i) {
-    struct context *c2 = get_context (conn, b->next);
-    if (c2 != NULL && backend_prepare (c2) == -1)
-      return -1;
-  }
+  if (b->i && c->c_next != NULL && backend_prepare (c->c_next) == -1)
+    return -1;

   controlpath_debug ("%s: prepare readonly=%d", b->name, c->can_write == 0);

@@ -324,7 +315,6 @@ backend_prepare (struct context *c)
 int
 backend_finalize (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;

   /* Call these in reverse order to .prepare above, starting from the
@@ -344,19 +334,16 @@ backend_finalize (struct context *c)
     }
   }

-  if (b->i) {
-    struct context *c2 = get_context (conn, b->next);
-    if (c2 != NULL)
-      return backend_finalize (c2);
-  }
+  if (b->i && c->c_next != NULL)
+    return backend_finalize (c->c_next);
   return 0;
 }

 void
 backend_close (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
+  struct context *c_next = c->c_next;

   /* outer-to-inner order, opposite .open */
   assert (c->handle);
@@ -364,12 +351,8 @@ backend_close (struct context *c)
   controlpath_debug ("%s: close", b->name);
   b->close (c);
   free (c);
-  set_context (conn, b, NULL);
-  if (b->i) {
-    struct context *c2 = get_context (conn, b->next);
-    if (c2 != NULL)
-      backend_close (c2);
-  }
+  if (c_next != NULL)
+    backend_close (c_next);
 }

 bool
@@ -383,27 +366,26 @@ backend_valid_range (struct context *c, uint64_t offset, uint32_t count)
 /* Core functionality of nbdkit_backend_reopen for retry filter */

 int
-backend_reopen (struct backend *b, int readonly, const char *exportname)
+backend_reopen (struct context *c, int readonly, const char *exportname)
 {
-  GET_CONN;
-  struct context *c;
+  struct backend *b = c->b;

   controlpath_debug ("%s: reopen readonly=%d exportname=\"%s\"",
-                     b->name, readonly, exportname);
+                     b->next->name, readonly, exportname);

-  c = get_context (conn, b);
-  if (c) {
-    if (backend_finalize (c) == -1)
+  if (c->c_next) {
+    if (backend_finalize (c->c_next) == -1)
       return -1;
-    backend_close (c);
+    backend_close (c->c_next);
+    c->c_next = NULL;
   }
-  c = backend_open (b, readonly, exportname);
-  if (c == NULL)
+  c->c_next = backend_open (b->next, readonly, exportname);
+  if (c->c_next == NULL)
     return -1;
-  set_context (conn, b, c);
-  if (backend_prepare (c) == -1) {
-    backend_finalize (c);
-    backend_close (c);
+  if (backend_prepare (c->c_next) == -1) {
+    backend_finalize (c->c_next);
+    backend_close (c->c_next);
+    c->c_next = NULL;
     return -1;
   }
   return 0;
diff --git a/server/connections.c b/server/connections.c
index 930491a6..aca4b24b 100644
--- a/server/connections.c
+++ b/server/connections.c
@@ -224,7 +224,7 @@ handle_single_connection (int sockin, int sockout)

   /* Finalize (for filters), called just before close. */
   lock_request ();
-  r = backend_finalize (get_context (conn, top));
+  r = backend_finalize (conn->top_context);
   unlock_request ();
   if (r == -1)
     goto done;
@@ -253,16 +253,10 @@ new_connection (int sockin, int sockout, int nworkers)
   pthread_mutex_init (&conn->write_lock, NULL);
   pthread_mutex_init (&conn->status_lock, NULL);

-  conn->contexts = calloc (top->i + 1, sizeof *conn->contexts);
-  if (conn->contexts == NULL) {
-    perror ("malloc");
-    goto error1;
-  }
   conn->default_exportname = calloc (top->i + 1,
                                      sizeof *conn->default_exportname);
   if (conn->default_exportname == NULL) {
     perror ("malloc");
-    free (conn->contexts);
     goto error1;
   }

@@ -332,7 +326,6 @@ new_connection (int sockin, int sockout, int nworkers)
     close (conn->status_pipe[0]);
   if (conn->status_pipe[1] >= 0)
     close (conn->status_pipe[1]);
-  free (conn->contexts);
   free (conn->default_exportname);

  error1:
@@ -348,7 +341,6 @@ static void
 free_connection (struct connection *conn)
 {
   struct backend *b;
-  struct context *c;

   if (!conn)
     return;
@@ -361,9 +353,10 @@ free_connection (struct connection *conn)
    */
   if (!quit) {
     lock_request ();
-    c = get_context (conn, top);
-    if (c)
-      backend_close (c);
+    if (conn->top_context) {
+      backend_close (conn->top_context);
+      conn->top_context = NULL;
+    }
     unlock_request ();
   }

@@ -383,7 +376,6 @@ free_connection (struct connection *conn)
   for_each_backend (b)
     free (conn->default_exportname[b->i]);
   free (conn->default_exportname);
-  free (conn->contexts);

   free (conn);
   threadlocal_set_conn (NULL);
@@ -501,18 +493,3 @@ raw_close (void)
   if (conn->sockout >= 0 && conn->sockin != conn->sockout)
     closesocket (conn->sockout);
 }
-
-struct context *
-get_context (struct connection *conn, struct backend *b)
-{
-  struct context *c = conn->contexts[b->i];
-  assert (!c || c->b == b);
-  return c;
-}
-
-void
-set_context (struct connection *conn, struct backend *b, struct context *c)
-{
-  assert (!c || c->b == b);
-  conn->contexts[b->i] = c;
-}
diff --git a/server/filters.c b/server/filters.c
index a200d61b..228e2610 100644
--- a/server/filters.c
+++ b/server/filters.c
@@ -261,21 +261,22 @@ filter_default_export (struct backend *b, int readonly, int is_tls)
 }

 static int
-next_open (struct backend *b, int readonly, const char *exportname)
+next_open (struct context *c, int readonly, const char *exportname)
 {
-  GET_CONN;
-  struct context *c = backend_open (b, readonly, exportname);
+  struct backend *b = c->b;
+  struct context *c_next = backend_open (b->next, readonly, exportname);

-  if (c == NULL)
+  if (c_next == NULL)
     return -1;
-  set_context (conn, b, c);
+  c->c_next = c_next;
   return 0;
 }

 static void *
-filter_open (struct backend *b, int readonly, const char *exportname,
+filter_open (struct context *c, int readonly, const char *exportname,
              int is_tls)
 {
+  struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
   void *handle;

@@ -283,9 +284,9 @@ filter_open (struct backend *b, int readonly, const char *exportname,
    * inner-to-outer ordering.
    */
   if (f->filter.open)
-    handle = f->filter.open (next_open, b->next, readonly, exportname,
+    handle = f->filter.open (next_open, c, readonly, exportname,
                              is_tls);
-  else if (next_open (b->next, readonly, exportname) == -1)
+  else if (next_open (c, readonly, exportname) == -1)
     handle = NULL;
   else
     handle = NBDKIT_HANDLE_NOT_NEEDED;
@@ -306,10 +307,9 @@ filter_close (struct context *c)
 static int
 filter_prepare (struct context *c, int readonly)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.prepare &&
       f->filter.prepare (&c_next->next, c_next, c->handle, readonly) == -1)
@@ -321,10 +321,9 @@ filter_prepare (struct context *c, int readonly)
 static int
 filter_finalize (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.finalize &&
       f->filter.finalize (&c_next->next, c_next, c->handle) == -1)
@@ -335,10 +334,9 @@ filter_finalize (struct context *c)
 static const char *
 filter_export_description (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.export_description)
     return f->filter.export_description (&c_next->next, c_next, c->handle);
@@ -349,10 +347,9 @@ filter_export_description (struct context *c)
 static int64_t
 filter_get_size (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.get_size)
     return f->filter.get_size (&c_next->next, c_next, c->handle);
@@ -363,10 +360,9 @@ filter_get_size (struct context *c)
 static int
 filter_can_write (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.can_write)
     return f->filter.can_write (&c_next->next, c_next, c->handle);
@@ -377,10 +373,9 @@ filter_can_write (struct context *c)
 static int
 filter_can_flush (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.can_flush)
     return f->filter.can_flush (&c_next->next, c_next, c->handle);
@@ -391,10 +386,9 @@ filter_can_flush (struct context *c)
 static int
 filter_is_rotational (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.is_rotational)
     return f->filter.is_rotational (&c_next->next, c_next, c->handle);
@@ -405,10 +399,9 @@ filter_is_rotational (struct context *c)
 static int
 filter_can_trim (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.can_trim)
     return f->filter.can_trim (&c_next->next, c_next, c->handle);
@@ -419,10 +412,9 @@ filter_can_trim (struct context *c)
 static int
 filter_can_zero (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.can_zero)
     return f->filter.can_zero (&c_next->next, c_next, c->handle);
@@ -433,10 +425,9 @@ filter_can_zero (struct context *c)
 static int
 filter_can_fast_zero (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.can_fast_zero)
     return f->filter.can_fast_zero (&c_next->next, c_next, c->handle);
@@ -447,10 +438,9 @@ filter_can_fast_zero (struct context *c)
 static int
 filter_can_extents (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.can_extents)
     return f->filter.can_extents (&c_next->next, c_next, c->handle);
@@ -461,10 +451,9 @@ filter_can_extents (struct context *c)
 static int
 filter_can_fua (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.can_fua)
     return f->filter.can_fua (&c_next->next, c_next, c->handle);
@@ -475,10 +464,9 @@ filter_can_fua (struct context *c)
 static int
 filter_can_multi_conn (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.can_multi_conn)
     return f->filter.can_multi_conn (&c_next->next, c_next, c->handle);
@@ -489,10 +477,9 @@ filter_can_multi_conn (struct context *c)
 static int
 filter_can_cache (struct context *c)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.can_cache)
     return f->filter.can_cache (&c_next->next, c_next, c->handle);
@@ -505,10 +492,9 @@ filter_pread (struct context *c,
               void *buf, uint32_t count, uint64_t offset,
               uint32_t flags, int *err)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.pread)
     return f->filter.pread (&c_next->next, c_next, c->handle,
@@ -522,10 +508,9 @@ filter_pwrite (struct context *c,
                const void *buf, uint32_t count, uint64_t offset,
                uint32_t flags, int *err)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.pwrite)
     return f->filter.pwrite (&c_next->next, c_next, c->handle,
@@ -538,10 +523,9 @@ static int
 filter_flush (struct context *c,
               uint32_t flags, int *err)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.flush)
     return f->filter.flush (&c_next->next, c_next, c->handle, flags, err);
@@ -554,10 +538,9 @@ filter_trim (struct context *c,
              uint32_t count, uint64_t offset,
              uint32_t flags, int *err)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.trim)
     return f->filter.trim (&c_next->next, c_next, c->handle, count, offset,
@@ -570,10 +553,9 @@ static int
 filter_zero (struct context *c,
              uint32_t count, uint64_t offset, uint32_t flags, int *err)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.zero)
     return f->filter.zero (&c_next->next, c_next, c->handle,
@@ -587,10 +569,9 @@ filter_extents (struct context *c,
                 uint32_t count, uint64_t offset, uint32_t flags,
                 struct nbdkit_extents *extents, int *err)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.extents)
     return f->filter.extents (&c_next->next, c_next, c->handle,
@@ -606,10 +587,9 @@ filter_cache (struct context *c,
               uint32_t count, uint64_t offset,
               uint32_t flags, int *err)
 {
-  GET_CONN;
   struct backend *b = c->b;
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct context *c_next = get_context (conn, b->next);
+  struct context *c_next = c->c_next;

   if (f->filter.cache)
     return f->filter.cache (&c_next->next, c_next, c->handle,
@@ -715,12 +695,11 @@ filter_register (struct backend *next, size_t index, const char *filename,
 }

 int
-nbdkit_backend_reopen (struct backend *b, int readonly,
+nbdkit_backend_reopen (struct context *c, int readonly,
                        const char *exportname, struct context **nxdata)
 {
-  GET_CONN;
-  int r = backend_reopen (b, readonly, exportname);
+  int r = backend_reopen (c, readonly, exportname);

-  *nxdata = get_context (conn, b);
+  *nxdata = c->c_next;
   return r;
 }
diff --git a/server/plugins.c b/server/plugins.c
index 9144cdae..b5cb5971 100644
--- a/server/plugins.c
+++ b/server/plugins.c
@@ -310,10 +310,11 @@ plugin_default_export (struct backend *b, int readonly, int is_tls)
 }

 static void *
-plugin_open (struct backend *b, int readonly, const char *exportname,
+plugin_open (struct context *c, int readonly, const char *exportname,
              int is_tls)
 {
   GET_CONN;
+  struct backend *b = c->b;
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
   void *r;

diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
index cfcd090d..a2c89c9a 100644
--- a/server/protocol-handshake-newstyle.c
+++ b/server/protocol-handshake-newstyle.c
@@ -341,7 +341,6 @@ negotiate_handshake_newstyle_options (void)
   const char *optname;
   uint64_t exportsize;
   struct backend *b;
-  struct context *c;

   for (nr_options = MAX_NR_OPTIONS; nr_options > 0; --nr_options) {
     CLEANUP_FREE char *data = NULL;
@@ -568,11 +567,11 @@ negotiate_handshake_newstyle_options (void)
          */
         if (finish_newstyle_options (&exportsize,
                                      &data[4], exportnamelen) == -1) {
-          c = get_context (conn, top);
-          if (c) {
-            if (backend_finalize (c) == -1)
+          if (conn->top_context) {
+            if (backend_finalize (conn->top_context) == -1)
               return -1;
-            backend_close (c);
+            backend_close (conn->top_context);
+            conn->top_context = NULL;
           }
           if (send_newstyle_option_reply (option, NBD_REP_ERR_UNKNOWN) == -1)
             return -1;
@@ -590,7 +589,6 @@ negotiate_handshake_newstyle_options (void)
          * NBD_INFO_EXPORT if it was requested, because we replied
          * already above).
          */
-        c = get_context (conn, top);
         for (i = 0; i < nrinfos; ++i) {
           memcpy (&info, &data[4 + exportnamelen + 2 + i*2], 2);
           info = be16toh (info);
@@ -619,7 +617,7 @@ negotiate_handshake_newstyle_options (void)
             break;
           case NBD_INFO_DESCRIPTION:
             {
-              const char *desc = backend_export_description (c);
+              const char *desc = backend_export_description (conn->top_context);

               if (!desc) {
                 debug ("newstyle negotiation: %s: "
@@ -650,9 +648,10 @@ negotiate_handshake_newstyle_options (void)
         return -1;

       if (option == NBD_OPT_INFO) {
-        if (backend_finalize (c) == -1)
+        if (backend_finalize (conn->top_context) == -1)
           return -1;
-        backend_close (c);
+        backend_close (conn->top_context);
+        conn->top_context = NULL;
       }

       break;
diff --git a/server/protocol-handshake.c b/server/protocol-handshake.c
index 61521d43..e0183173 100644
--- a/server/protocol-handshake.c
+++ b/server/protocol-handshake.c
@@ -79,18 +79,16 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags,
   int64_t size;
   uint16_t eflags = NBD_FLAG_HAS_FLAGS;
   int fl;
-  struct context *c;

-  c = backend_open (top, read_only, exportname);
-  if (c == NULL)
+  conn->top_context = backend_open (top, read_only, exportname);
+  if (conn->top_context == NULL)
     return -1;
-  set_context (conn, top, c);

   /* Prepare (for filters), called just after open. */
-  if (backend_prepare (c) == -1)
+  if (backend_prepare (conn->top_context) == -1)
     return -1;

-  size = backend_get_size (c);
+  size = backend_get_size (conn->top_context);
   if (size == -1)
     return -1;
   if (size < 0) {
@@ -102,56 +100,56 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags,
   /* Check all flags even if they won't be advertised, to prime the
    * cache and make later request validation easier.
    */
-  fl = backend_can_write (c);
+  fl = backend_can_write (conn->top_context);
   if (fl == -1)
     return -1;
   if (!fl)
     eflags |= NBD_FLAG_READ_ONLY;

-  fl = backend_can_zero (c);
+  fl = backend_can_zero (conn->top_context);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_WRITE_ZEROES;

-  fl = backend_can_fast_zero (c);
+  fl = backend_can_fast_zero (conn->top_context);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_FAST_ZERO;

-  fl = backend_can_trim (c);
+  fl = backend_can_trim (conn->top_context);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_TRIM;

-  fl = backend_can_fua (c);
+  fl = backend_can_fua (conn->top_context);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_FUA;

-  fl = backend_can_flush (c);
+  fl = backend_can_flush (conn->top_context);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_FLUSH;

-  fl = backend_is_rotational (c);
+  fl = backend_is_rotational (conn->top_context);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_ROTATIONAL;

   /* multi-conn is useless if parallel connections are not allowed. */
-  fl = backend_can_multi_conn (c);
+  fl = backend_can_multi_conn (conn->top_context);
   if (fl == -1)
     return -1;
   if (fl && (thread_model > NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS))
     eflags |= NBD_FLAG_CAN_MULTI_CONN;

-  fl = backend_can_cache (c);
+  fl = backend_can_cache (conn->top_context);
   if (fl == -1)
     return -1;
   if (fl)
@@ -162,7 +160,7 @@ protocol_common_open (uint64_t *exportsize, uint16_t *flags,
    * not have to worry about errors, and makes test-layers easier to
    * write.
    */
-  fl = backend_can_extents (c);
+  fl = backend_can_extents (conn->top_context);
   if (fl == -1)
     return -1;

diff --git a/server/protocol.c b/server/protocol.c
index fedc701a..2ac77055 100644
--- a/server/protocol.c
+++ b/server/protocol.c
@@ -53,7 +53,6 @@ validate_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count,
                   uint32_t *error)
 {
   GET_CONN;
-  struct context *c = get_context (conn, top);

   /* Readonly connection? */
   if (conn->eflags & NBD_FLAG_READ_ONLY &&
@@ -73,7 +72,7 @@ validate_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count,
   case NBD_CMD_TRIM:
   case NBD_CMD_WRITE_ZEROES:
   case NBD_CMD_BLOCK_STATUS:
-    if (!backend_valid_range (c, offset, count)) {
+    if (!backend_valid_range (conn->top_context, offset, count)) {
       /* XXX Allow writes to extend the disk? */
       nbdkit_error ("invalid request: %s: offset and count are out of range: "
                     "offset=%" PRIu64 " count=%" PRIu32,
@@ -231,7 +230,7 @@ handle_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count,
                 void *buf, struct nbdkit_extents *extents)
 {
   GET_CONN;
-  struct context *c = get_context (conn, top);
+  struct context *c = conn->top_context;
   uint32_t f = 0;
   int err = 0;

@@ -686,8 +685,8 @@ protocol_recv_request_send_reply (void)

     /* Allocate the extents list for block status only. */
     if (cmd == NBD_CMD_BLOCK_STATUS) {
-      struct context *c = get_context (conn, top);
-      extents = nbdkit_extents_new (offset, backend_get_size (c));
+      extents = nbdkit_extents_new (offset,
+                                    backend_get_size (conn->top_context));
       if (extents == NULL) {
         error = ENOMEM;
         goto send_reply;
diff --git a/filters/checkwrite/checkwrite.c b/filters/checkwrite/checkwrite.c
index bbd7f1cd..2dc93ab1 100644
--- a/filters/checkwrite/checkwrite.c
+++ b/filters/checkwrite/checkwrite.c
@@ -44,7 +44,7 @@
 #include "minmax.h"

 static void *
-checkwrite_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
+checkwrite_open (nbdkit_next_open *next, nbdkit_context *nxdata,
                  int readonly, const char *exportname, int is_tls)
 {
   /* Ignore readonly flag passed in, open the plugin readonly. */
diff --git a/filters/exitlast/exitlast.c b/filters/exitlast/exitlast.c
index 4c879cc9..12571242 100644
--- a/filters/exitlast/exitlast.c
+++ b/filters/exitlast/exitlast.c
@@ -50,7 +50,7 @@
 static _Atomic unsigned connections;

 static void *
-exitlast_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
+exitlast_open (nbdkit_next_open *next, nbdkit_context *nxdata,
                int readonly, const char *exportname, int is_tls)
 {
   if (next (nxdata, readonly, exportname) == -1)
diff --git a/filters/exitwhen/exitwhen.c b/filters/exitwhen/exitwhen.c
index ca199a8c..67e87dde 100644
--- a/filters/exitwhen/exitwhen.c
+++ b/filters/exitwhen/exitwhen.c
@@ -482,7 +482,7 @@ exitwhen_preconnect (nbdkit_next_preconnect *next, void *nxdata, int readonly)
 }

 static void *
-exitwhen_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
+exitwhen_open (nbdkit_next_open *next, nbdkit_context *nxdata,
                int readonly, const char *exportname, int is_tls)
 {
   if (next (nxdata, readonly, exportname) == -1)
diff --git a/filters/gzip/gzip.c b/filters/gzip/gzip.c
index 03e023e5..0b3f48b7 100644
--- a/filters/gzip/gzip.c
+++ b/filters/gzip/gzip.c
@@ -75,7 +75,7 @@ gzip_thread_model (void)
 }

 static void *
-gzip_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
+gzip_open (nbdkit_next_open *next, nbdkit_context *nxdata,
            int readonly, const char *exportname, int is_tls)
 {
   /* Always pass readonly=1 to the underlying plugin. */
diff --git a/filters/limit/limit.c b/filters/limit/limit.c
index fb862df7..dc07f436 100644
--- a/filters/limit/limit.c
+++ b/filters/limit/limit.c
@@ -90,7 +90,7 @@ limit_preconnect (nbdkit_next_preconnect *next, nbdkit_backend *nxdata,
 }

 static void *
-limit_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
+limit_open (nbdkit_next_open *next, nbdkit_context *nxdata,
             int readonly, const char *exportname, int is_tls)
 {
   if (next (nxdata, readonly, exportname) == -1)
diff --git a/filters/retry/retry.c b/filters/retry/retry.c
index a2b5dc66..cfaea7d4 100644
--- a/filters/retry/retry.c
+++ b/filters/retry/retry.c
@@ -109,13 +109,13 @@ retry_config (nbdkit_next_config *next, nbdkit_backend *nxdata,
 struct retry_handle {
   int readonly;                 /* Save original readonly setting. */
   char *exportname;             /* Client exportname. */
-  nbdkit_backend *backend;      /* Backend learned during .open. */
+  nbdkit_context *backend;      /* Backend learned during .open. */
   unsigned reopens;
   bool open;
 };

 static void *
-retry_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
+retry_open (nbdkit_next_open *next, nbdkit_context *nxdata,
             int readonly, const char *exportname, int is_tls)
 {
   struct retry_handle *h;
diff --git a/filters/tar/tar.c b/filters/tar/tar.c
index fa4b61dc..7cf2cd26 100644
--- a/filters/tar/tar.c
+++ b/filters/tar/tar.c
@@ -112,7 +112,7 @@ struct handle {
 };

 static void *
-tar_open (nbdkit_next_open *next, nbdkit_backend *nxdata,
+tar_open (nbdkit_next_open *next, nbdkit_context *nxdata,
           int readonly, const char *exportname, int is_tls)
 {
   struct handle *h;
-- 
2.30.1




More information about the Libguestfs mailing list