[Libguestfs] [PATCH nbdkit v2 3/3] server: Remove explicit connection parameter, use TLS instead.

Richard W.M. Jones rjones at redhat.com
Tue Feb 11 17:39:43 UTC 2020


Since commit 86fdb48c6a5362d66865493d9d2172166f99722e we have stored
the connection object in thread-local storage.

In this very large, but mostly mechanical change we stop passing the
connection pointer around everywhere, and instead use the value stored
in thread-local storage.

This assumes a 1-1 mapping between the connection and the current
thread which is true in *most* places.  Occasionally we still have the
explicit connection pointer, especially just before we launch a thread
or call threadlocal_set_conn.
---
 server/internal.h                    | 191 +++++++++----------
 server/backend.c                     | 160 +++++++++-------
 server/connections.c                 |  68 ++++---
 server/crypto.c                      |  14 +-
 server/filters.c                     | 270 +++++++++++++--------------
 server/locks.c                       |   8 +-
 server/plugins.c                     |  64 +++----
 server/protocol-handshake-newstyle.c | 172 +++++++++--------
 server/protocol-handshake-oldstyle.c |   7 +-
 server/protocol-handshake.c          |  40 ++--
 server/protocol.c                    | 127 ++++++-------
 server/public.c                      |   2 +-
 server/test-public.c                 |   2 +-
 13 files changed, 570 insertions(+), 555 deletions(-)

diff --git a/server/internal.h b/server/internal.h
index 52c16a4e..d47ef9ab 100644
--- a/server/internal.h
+++ b/server/internal.h
@@ -154,15 +154,12 @@ enum {
   SEND_MORE = 1, /* Hint to use MSG_MORE/corking to group send()s */
 };
 
-typedef int (*connection_recv_function) (struct connection *,
-                                         void *buf, size_t len)
-  __attribute__((__nonnull__ (1, 2)));
-typedef int (*connection_send_function) (struct connection *,
-                                         const void *buf, size_t len,
+typedef int (*connection_recv_function) (void *buf, size_t len)
+  __attribute__((__nonnull__ (1)));
+typedef int (*connection_send_function) (const void *buf, size_t len,
                                          int flags)
-  __attribute__((__nonnull__ (1, 2)));
-typedef void (*connection_close_function) (struct connection *)
   __attribute__((__nonnull__ (1)));
+typedef void (*connection_close_function) (void);
 
 enum {
   HANDLE_OPEN = 1,      /* Set if .open passed, so .close is needed */
@@ -234,29 +231,22 @@ struct connection {
 };
 
 extern void handle_single_connection (int sockin, int sockout);
-extern int connection_get_status (struct connection *conn)
-  __attribute__((__nonnull__ (1)));
-extern int connection_set_status (struct connection *conn, int value)
-  __attribute__((__nonnull__ (1)));
+extern int connection_get_status (void);
+extern int connection_set_status (int value);
 
 /* protocol-handshake.c */
-extern int protocol_handshake (struct connection *conn)
-  __attribute__((__nonnull__ (1)));
-extern int protocol_common_open (struct connection *conn,
-                                 uint64_t *exportsize, uint16_t *flags)
-  __attribute__((__nonnull__ (1, 2, 3)));
+extern int protocol_handshake (void);
+extern int protocol_common_open (uint64_t *exportsize, uint16_t *flags)
+  __attribute__((__nonnull__ (1, 2)));
 
 /* protocol-handshake-oldstyle.c */
-extern int protocol_handshake_oldstyle (struct connection *conn)
-  __attribute__((__nonnull__ (1)));
+extern int protocol_handshake_oldstyle (void);
 
 /* protocol-handshake-newstyle.c */
-extern int protocol_handshake_newstyle (struct connection *conn)
-  __attribute__((__nonnull__ (1)));
+extern int protocol_handshake_newstyle (void);
 
 /* protocol.c */
-extern int protocol_recv_request_send_reply (struct connection *conn)
-  __attribute__((__nonnull__ (1)));
+extern int protocol_recv_request_send_reply (void);
 
 /* The context ID of base:allocation.  As far as I can tell it doesn't
  * matter what this is as long as nbdkit always returns the same
@@ -268,9 +258,7 @@ extern int protocol_recv_request_send_reply (struct connection *conn)
 #define root_tls_certificates_dir sysconfdir "/pki/" PACKAGE_NAME
 extern void crypto_init (bool tls_set_on_cli);
 extern void crypto_free (void);
-extern int crypto_negotiate_tls (struct connection *conn,
-                                 int sockin, int sockout)
-  __attribute__((__nonnull__ (1)));
+extern int crypto_negotiate_tls (int sockin, int sockout);
 
 /* debug.c */
 #define debug(fs, ...)                                   \
@@ -332,44 +320,39 @@ struct backend {
   void (*config) (struct backend *, const char *key, const char *value);
   void (*config_complete) (struct backend *);
   const char *(*magic_config_key) (struct backend *);
-  int (*preconnect) (struct backend *, struct connection *conn, int readonly);
-  void *(*open) (struct backend *, struct connection *conn, int readonly);
-  int (*prepare) (struct backend *, struct connection *conn, void *handle,
-                  int readonly);
-  int (*finalize) (struct backend *, struct connection *conn, void *handle);
-  void (*close) (struct backend *, struct connection *conn, void *handle);
+  int (*preconnect) (struct backend *, int readonly);
+  void *(*open) (struct backend *, int readonly);
+  int (*prepare) (struct backend *, void *handle, int readonly);
+  int (*finalize) (struct backend *, void *handle);
+  void (*close) (struct backend *, void *handle);
 
-  int64_t (*get_size) (struct backend *, struct connection *conn, void *handle);
-  int (*can_write) (struct backend *, struct connection *conn, void *handle);
-  int (*can_flush) (struct backend *, struct connection *conn, void *handle);
-  int (*is_rotational) (struct backend *, struct connection *conn,
-                        void *handle);
-  int (*can_trim) (struct backend *, struct connection *conn, void *handle);
-  int (*can_zero) (struct backend *, struct connection *conn, void *handle);
-  int (*can_fast_zero) (struct backend *, struct connection *conn,
-                        void *handle);
-  int (*can_extents) (struct backend *, struct connection *conn, void *handle);
-  int (*can_fua) (struct backend *, struct connection *conn, void *handle);
-  int (*can_multi_conn) (struct backend *, struct connection *conn,
-                         void *handle);
-  int (*can_cache) (struct backend *, struct connection *conn, void *handle);
+  int64_t (*get_size) (struct backend *, void *handle);
+  int (*can_write) (struct backend *, void *handle);
+  int (*can_flush) (struct backend *, void *handle);
+  int (*is_rotational) (struct backend *, void *handle);
+  int (*can_trim) (struct backend *, void *handle);
+  int (*can_zero) (struct backend *, void *handle);
+  int (*can_fast_zero) (struct backend *, void *handle);
+  int (*can_extents) (struct backend *, void *handle);
+  int (*can_fua) (struct backend *, void *handle);
+  int (*can_multi_conn) (struct backend *, void *handle);
+  int (*can_cache) (struct backend *, void *handle);
 
-  int (*pread) (struct backend *, struct connection *conn, void *handle,
+  int (*pread) (struct backend *, void *handle,
                 void *buf, uint32_t count, uint64_t offset,
                 uint32_t flags, int *err);
-  int (*pwrite) (struct backend *, struct connection *conn, void *handle,
+  int (*pwrite) (struct backend *, void *handle,
                  const void *buf, uint32_t count, uint64_t offset,
                  uint32_t flags, int *err);
-  int (*flush) (struct backend *, struct connection *conn, void *handle,
-                uint32_t flags, int *err);
-  int (*trim) (struct backend *, struct connection *conn, void *handle,
+  int (*flush) (struct backend *, void *handle, uint32_t flags, int *err);
+  int (*trim) (struct backend *, void *handle,
                uint32_t count, uint64_t offset, uint32_t flags, int *err);
-  int (*zero) (struct backend *, struct connection *conn, void *handle,
+  int (*zero) (struct backend *, void *handle,
                uint32_t count, uint64_t offset, uint32_t flags, int *err);
-  int (*extents) (struct backend *, struct connection *conn, void *handle,
+  int (*extents) (struct backend *, void *handle,
                   uint32_t count, uint64_t offset, uint32_t flags,
                   struct nbdkit_extents *extents, int *err);
-  int (*cache) (struct backend *, struct connection *conn, void *handle,
+  int (*cache) (struct backend *, void *handle,
                 uint32_t count, uint64_t offset, uint32_t flags, int *err);
 };
 
@@ -382,72 +365,70 @@ 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 int backend_prepare (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_finalize (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern void backend_close (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern bool backend_valid_range (struct backend *b, struct connection *conn,
+extern int backend_open (struct backend *b, int readonly)
+  __attribute__((__nonnull__ (1)));
+extern int backend_prepare (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_finalize (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern void backend_close (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern bool backend_valid_range (struct backend *b,
                                  uint64_t offset, uint32_t count)
-  __attribute__((__nonnull__ (1, 2)));
+  __attribute__((__nonnull__ (1)));
 
-extern int backend_reopen (struct backend *b, struct connection *conn,
-                           int readonly)
-  __attribute__((__nonnull__ (1, 2)));
-extern int64_t backend_get_size (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_can_write (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_can_flush (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_is_rotational (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_can_trim (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_can_zero (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_can_fast_zero (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_can_extents (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_can_fua (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_can_multi_conn (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
-extern int backend_can_cache (struct backend *b, struct connection *conn)
-  __attribute__((__nonnull__ (1, 2)));
+extern int backend_reopen (struct backend *b, int readonly)
+  __attribute__((__nonnull__ (1)));
+extern int64_t backend_get_size (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_can_write (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_can_flush (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_is_rotational (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_can_trim (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_can_zero (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_can_fast_zero (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_can_extents (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_can_fua (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_can_multi_conn (struct backend *b)
+  __attribute__((__nonnull__ (1)));
+extern int backend_can_cache (struct backend *b)
+  __attribute__((__nonnull__ (1)));
 
-extern int backend_pread (struct backend *b, struct connection *conn,
+extern int backend_pread (struct backend *b,
                           void *buf, uint32_t count, uint64_t offset,
                           uint32_t flags, int *err)
-  __attribute__((__nonnull__ (1, 2, 3, 7)));
-extern int backend_pwrite (struct backend *b, struct connection *conn,
+  __attribute__((__nonnull__ (1, 2, 6)));
+extern int backend_pwrite (struct backend *b,
                            const void *buf, uint32_t count, uint64_t offset,
                            uint32_t flags, int *err)
-  __attribute__((__nonnull__ (1, 2, 3, 7)));
-extern int backend_flush (struct backend *b, struct connection *conn,
+  __attribute__((__nonnull__ (1, 2, 6)));
+extern int backend_flush (struct backend *b,
                           uint32_t flags, int *err)
-  __attribute__((__nonnull__ (1, 2, 4)));
-extern int backend_trim (struct backend *b, struct connection *conn,
+  __attribute__((__nonnull__ (1, 3)));
+extern int backend_trim (struct backend *b,
                          uint32_t count, uint64_t offset, uint32_t flags,
                          int *err)
-  __attribute__((__nonnull__ (1, 2, 6)));
-extern int backend_zero (struct backend *b, struct connection *conn,
+  __attribute__((__nonnull__ (1, 5)));
+extern int backend_zero (struct backend *b,
                          uint32_t count, uint64_t offset, uint32_t flags,
                          int *err)
-  __attribute__((__nonnull__ (1, 2, 6)));
-extern int backend_extents (struct backend *b, struct connection *conn,
+  __attribute__((__nonnull__ (1, 5)));
+extern int backend_extents (struct backend *b,
                             uint32_t count, uint64_t offset, uint32_t flags,
                             struct nbdkit_extents *extents, int *err)
-  __attribute__((__nonnull__ (1, 2, 6, 7)));
-extern int backend_cache (struct backend *b, struct connection *conn,
+  __attribute__((__nonnull__ (1, 5, 6)));
+extern int backend_cache (struct backend *b,
                           uint32_t count, uint64_t offset,
                           uint32_t flags, int *err)
-  __attribute__((__nonnull__ (1, 2, 6)));
+  __attribute__((__nonnull__ (1, 5)));
 
 /* plugins.c */
 extern struct backend *plugin_register (size_t index, const char *filename,
@@ -465,8 +446,8 @@ extern void lock_init_thread_model (void);
 extern const char *name_of_thread_model (int model);
 extern void lock_connection (void);
 extern void unlock_connection (void);
-extern void lock_request (struct connection *conn);
-extern void unlock_request (struct connection *conn);
+extern void lock_request (void);
+extern void unlock_request (void);
 extern void lock_unload (void);
 extern void unlock_unload (void);
 
diff --git a/server/backend.c b/server/backend.c
index 208c07b1..8bfa8525 100644
--- a/server/backend.c
+++ b/server/backend.c
@@ -151,8 +151,9 @@ backend_unload (struct backend *b, void (*unload) (void))
 }
 
 int
-backend_open (struct backend *b, struct connection *conn, int readonly)
+backend_open (struct backend *b, int readonly)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   controlpath_debug ("%s: open readonly=%d", b->name, readonly);
@@ -166,12 +167,12 @@ backend_open (struct backend *b, struct connection *conn, int readonly)
   /* Most filters will call next_open first, resulting in
    * inner-to-outer ordering.
    */
-  h->handle = b->open (b, conn, readonly);
+  h->handle = b->open (b, readonly);
   controlpath_debug ("%s: open returned handle %p", b->name, h->handle);
 
   if (h->handle == NULL) {
     if (b->i) /* Do not strand backend if this layer failed */
-      backend_close (b->next, conn);
+      backend_close (b->next);
     return -1;
   }
 
@@ -182,8 +183,9 @@ backend_open (struct backend *b, struct connection *conn, int readonly)
 }
 
 int
-backend_prepare (struct backend *b, struct connection *conn)
+backend_prepare (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   assert (h->handle);
@@ -192,20 +194,21 @@ backend_prepare (struct backend *b, struct connection *conn)
   /* Call these in order starting from the filter closest to the
    * plugin, similar to typical .open order.
    */
-  if (b->i && backend_prepare (b->next, conn) == -1)
+  if (b->i && backend_prepare (b->next) == -1)
     return -1;
 
   controlpath_debug ("%s: prepare readonly=%d", b->name, h->can_write == 0);
 
-  if (b->prepare (b, conn, h->handle, h->can_write == 0) == -1)
+  if (b->prepare (b, h->handle, h->can_write == 0) == -1)
     return -1;
   h->state |= HANDLE_CONNECTED;
   return 0;
 }
 
 int
-backend_finalize (struct backend *b, struct connection *conn)
+backend_finalize (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   /* Call these in reverse order to .prepare above, starting from the
@@ -220,7 +223,7 @@ backend_finalize (struct backend *b, struct connection *conn)
 
   if (h->handle) {
     assert (h->state & HANDLE_CONNECTED);
-    if (b->finalize (b, conn, h->handle) == -1) {
+    if (b->finalize (b, h->handle) == -1) {
       h->state |= HANDLE_FAILED;
       return -1;
     }
@@ -229,13 +232,14 @@ backend_finalize (struct backend *b, struct connection *conn)
     assert (! (h->state & HANDLE_CONNECTED));
 
   if (b->i)
-    return backend_finalize (b->next, conn);
+    return backend_finalize (b->next);
   return 0;
 }
 
 void
-backend_close (struct backend *b, struct connection *conn)
+backend_close (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   /* outer-to-inner order, opposite .open */
@@ -243,19 +247,19 @@ backend_close (struct backend *b, struct connection *conn)
 
   if (h->handle) {
     assert (h->state & HANDLE_OPEN);
-    b->close (b, conn, h->handle);
+    b->close (b, h->handle);
   }
   else
     assert (! (h->state & HANDLE_OPEN));
   reset_b_conn_handle (h);
   if (b->i)
-    backend_close (b->next, conn);
+    backend_close (b->next);
 }
 
 bool
-backend_valid_range (struct backend *b, struct connection *conn,
-                     uint64_t offset, uint32_t count)
+backend_valid_range (struct backend *b, uint64_t offset, uint32_t count)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   assert (h->exportsize <= INT64_MAX); /* Guaranteed by negotiation phase */
@@ -266,80 +270,85 @@ backend_valid_range (struct backend *b, struct connection *conn,
 /* Wrappers for all callbacks in a filter's struct nbdkit_next_ops. */
 
 int
-backend_reopen (struct backend *b, struct connection *conn, int readonly)
+backend_reopen (struct backend *b, int readonly)
 {
   controlpath_debug ("%s: reopen readonly=%d", b->name, readonly);
 
-  if (backend_finalize (b, conn) == -1)
+  if (backend_finalize (b) == -1)
     return -1;
-  backend_close (b, conn);
-  if (backend_open (b, conn, readonly) == -1) {
-    backend_close (b, conn);
+  backend_close (b);
+  if (backend_open (b, readonly) == -1) {
+    backend_close (b);
     return -1;
   }
-  if (backend_prepare (b, conn) == -1) {
-    backend_finalize (b, conn);
-    backend_close (b, conn);
+  if (backend_prepare (b) == -1) {
+    backend_finalize (b);
+    backend_close (b);
     return -1;
   }
   return 0;
 }
 
 int64_t
-backend_get_size (struct backend *b, struct connection *conn)
+backend_get_size (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   controlpath_debug ("%s: get_size", b->name);
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->exportsize == -1)
-    h->exportsize = b->get_size (b, conn, h->handle);
+    h->exportsize = b->get_size (b, h->handle);
   return h->exportsize;
 }
 
 int
-backend_can_write (struct backend *b, struct connection *conn)
+backend_can_write (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   controlpath_debug ("%s: can_write", b->name);
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->can_write == -1)
-    h->can_write = b->can_write (b, conn, h->handle);
+    h->can_write = b->can_write (b, h->handle);
   return h->can_write;
 }
 
 int
-backend_can_flush (struct backend *b, struct connection *conn)
+backend_can_flush (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   controlpath_debug ("%s: can_flush", b->name);
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->can_flush == -1)
-    h->can_flush = b->can_flush (b, conn, h->handle);
+    h->can_flush = b->can_flush (b, h->handle);
   return h->can_flush;
 }
 
 int
-backend_is_rotational (struct backend *b, struct connection *conn)
+backend_is_rotational (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   controlpath_debug ("%s: is_rotational", b->name);
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->is_rotational == -1)
-    h->is_rotational = b->is_rotational (b, conn, h->handle);
+    h->is_rotational = b->is_rotational (b, h->handle);
   return h->is_rotational;
 }
 
 int
-backend_can_trim (struct backend *b, struct connection *conn)
+backend_can_trim (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   int r;
 
@@ -347,19 +356,20 @@ backend_can_trim (struct backend *b, struct connection *conn)
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->can_trim == -1) {
-    r = backend_can_write (b, conn);
+    r = backend_can_write (b);
     if (r != 1) {
       h->can_trim = 0;
       return r;
     }
-    h->can_trim = b->can_trim (b, conn, h->handle);
+    h->can_trim = b->can_trim (b, h->handle);
   }
   return h->can_trim;
 }
 
 int
-backend_can_zero (struct backend *b, struct connection *conn)
+backend_can_zero (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   int r;
 
@@ -367,19 +377,20 @@ backend_can_zero (struct backend *b, struct connection *conn)
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->can_zero == -1) {
-    r = backend_can_write (b, conn);
+    r = backend_can_write (b);
     if (r != 1) {
       h->can_zero = NBDKIT_ZERO_NONE;
       return r; /* Relies on 0 == NBDKIT_ZERO_NONE */
     }
-    h->can_zero = b->can_zero (b, conn, h->handle);
+    h->can_zero = b->can_zero (b, h->handle);
   }
   return h->can_zero;
 }
 
 int
-backend_can_fast_zero (struct backend *b, struct connection *conn)
+backend_can_fast_zero (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   int r;
 
@@ -387,32 +398,34 @@ backend_can_fast_zero (struct backend *b, struct connection *conn)
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->can_fast_zero == -1) {
-    r = backend_can_zero (b, conn);
+    r = backend_can_zero (b);
     if (r < NBDKIT_ZERO_EMULATE) {
       h->can_fast_zero = 0;
       return r; /* Relies on 0 == NBDKIT_ZERO_NONE */
     }
-    h->can_fast_zero = b->can_fast_zero (b, conn, h->handle);
+    h->can_fast_zero = b->can_fast_zero (b, h->handle);
   }
   return h->can_fast_zero;
 }
 
 int
-backend_can_extents (struct backend *b, struct connection *conn)
+backend_can_extents (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   controlpath_debug ("%s: can_extents", b->name);
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->can_extents == -1)
-    h->can_extents = b->can_extents (b, conn, h->handle);
+    h->can_extents = b->can_extents (b, h->handle);
   return h->can_extents;
 }
 
 int
-backend_can_fua (struct backend *b, struct connection *conn)
+backend_can_fua (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   int r;
 
@@ -420,90 +433,95 @@ backend_can_fua (struct backend *b, struct connection *conn)
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->can_fua == -1) {
-    r = backend_can_write (b, conn);
+    r = backend_can_write (b);
     if (r != 1) {
       h->can_fua = NBDKIT_FUA_NONE;
       return r; /* Relies on 0 == NBDKIT_FUA_NONE */
     }
-    h->can_fua = b->can_fua (b, conn, h->handle);
+    h->can_fua = b->can_fua (b, h->handle);
   }
   return h->can_fua;
 }
 
 int
-backend_can_multi_conn (struct backend *b, struct connection *conn)
+backend_can_multi_conn (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   controlpath_debug ("%s: can_multi_conn", b->name);
 
   if (h->can_multi_conn == -1)
-    h->can_multi_conn = b->can_multi_conn (b, conn, h->handle);
+    h->can_multi_conn = b->can_multi_conn (b, h->handle);
   return h->can_multi_conn;
 }
 
 int
-backend_can_cache (struct backend *b, struct connection *conn)
+backend_can_cache (struct backend *b)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
 
   controlpath_debug ("%s: can_cache", b->name);
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   if (h->can_cache == -1)
-    h->can_cache = b->can_cache (b, conn, h->handle);
+    h->can_cache = b->can_cache (b, h->handle);
   return h->can_cache;
 }
 
 int
-backend_pread (struct backend *b, struct connection *conn,
+backend_pread (struct backend *b,
                void *buf, uint32_t count, uint64_t offset,
                uint32_t flags, int *err)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   int r;
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
-  assert (backend_valid_range (b, conn, offset, count));
+  assert (backend_valid_range (b, offset, count));
   assert (flags == 0);
   datapath_debug ("%s: pread count=%" PRIu32 " offset=%" PRIu64,
                   b->name, count, offset);
 
-  r = b->pread (b, conn, h->handle, buf, count, offset, flags, err);
+  r = b->pread (b, h->handle, buf, count, offset, flags, err);
   if (r == -1)
     assert (*err);
   return r;
 }
 
 int
-backend_pwrite (struct backend *b, struct connection *conn,
+backend_pwrite (struct backend *b,
                 const void *buf, uint32_t count, uint64_t offset,
                 uint32_t flags, int *err)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   bool fua = !!(flags & NBDKIT_FLAG_FUA);
   int r;
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   assert (h->can_write == 1);
-  assert (backend_valid_range (b, conn, offset, count));
+  assert (backend_valid_range (b, offset, count));
   assert (!(flags & ~NBDKIT_FLAG_FUA));
   if (fua)
     assert (h->can_fua > NBDKIT_FUA_NONE);
   datapath_debug ("%s: pwrite count=%" PRIu32 " offset=%" PRIu64 " fua=%d",
                   b->name, count, offset, fua);
 
-  r = b->pwrite (b, conn, h->handle, buf, count, offset, flags, err);
+  r = b->pwrite (b, h->handle, buf, count, offset, flags, err);
   if (r == -1)
     assert (*err);
   return r;
 }
 
 int
-backend_flush (struct backend *b, struct connection *conn,
+backend_flush (struct backend *b,
                uint32_t flags, int *err)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   int r;
 
@@ -512,17 +530,18 @@ backend_flush (struct backend *b, struct connection *conn,
   assert (flags == 0);
   datapath_debug ("%s: flush", b->name);
 
-  r = b->flush (b, conn, h->handle, flags, err);
+  r = b->flush (b, h->handle, flags, err);
   if (r == -1)
     assert (*err);
   return r;
 }
 
 int
-backend_trim (struct backend *b, struct connection *conn,
+backend_trim (struct backend *b,
               uint32_t count, uint64_t offset, uint32_t flags,
               int *err)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   bool fua = !!(flags & NBDKIT_FLAG_FUA);
   int r;
@@ -530,24 +549,25 @@ backend_trim (struct backend *b, struct connection *conn,
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   assert (h->can_write == 1);
   assert (h->can_trim == 1);
-  assert (backend_valid_range (b, conn, offset, count));
+  assert (backend_valid_range (b, offset, count));
   assert (!(flags & ~NBDKIT_FLAG_FUA));
   if (fua)
     assert (h->can_fua > NBDKIT_FUA_NONE);
   datapath_debug ("%s: trim count=%" PRIu32 " offset=%" PRIu64 " fua=%d",
                   b->name, count, offset, fua);
 
-  r = b->trim (b, conn, h->handle, count, offset, flags, err);
+  r = b->trim (b, h->handle, count, offset, flags, err);
   if (r == -1)
     assert (*err);
   return r;
 }
 
 int
-backend_zero (struct backend *b, struct connection *conn,
+backend_zero (struct backend *b,
               uint32_t count, uint64_t offset, uint32_t flags,
               int *err)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   bool fua = !!(flags & NBDKIT_FLAG_FUA);
   bool fast = !!(flags & NBDKIT_FLAG_FAST_ZERO);
@@ -556,7 +576,7 @@ backend_zero (struct backend *b, struct connection *conn,
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   assert (h->can_write == 1);
   assert (h->can_zero > NBDKIT_ZERO_NONE);
-  assert (backend_valid_range (b, conn, offset, count));
+  assert (backend_valid_range (b, offset, count));
   assert (!(flags & ~(NBDKIT_FLAG_MAY_TRIM | NBDKIT_FLAG_FUA |
                       NBDKIT_FLAG_FAST_ZERO)));
   if (fua)
@@ -568,7 +588,7 @@ backend_zero (struct backend *b, struct connection *conn,
                   b->name, count, offset,
                   !!(flags & NBDKIT_FLAG_MAY_TRIM), fua, fast);
 
-  r = b->zero (b, conn, h->handle, count, offset, flags, err);
+  r = b->zero (b, h->handle, count, offset, flags, err);
   if (r == -1) {
     assert (*err);
     if (!fast)
@@ -578,16 +598,17 @@ backend_zero (struct backend *b, struct connection *conn,
 }
 
 int
-backend_extents (struct backend *b, struct connection *conn,
+backend_extents (struct backend *b,
                  uint32_t count, uint64_t offset, uint32_t flags,
                  struct nbdkit_extents *extents, int *err)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   int r;
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   assert (h->can_extents >= 0);
-  assert (backend_valid_range (b, conn, offset, count));
+  assert (backend_valid_range (b, offset, count));
   assert (!(flags & ~NBDKIT_FLAG_REQ_ONE));
   datapath_debug ("%s: extents count=%" PRIu32 " offset=%" PRIu64 " req_one=%d",
                   b->name, count, offset, !!(flags & NBDKIT_FLAG_REQ_ONE));
@@ -601,23 +622,24 @@ backend_extents (struct backend *b, struct connection *conn,
       *err = errno;
     return r;
   }
-  r = b->extents (b, conn, h->handle, count, offset, flags, extents, err);
+  r = b->extents (b, h->handle, count, offset, flags, extents, err);
   if (r == -1)
     assert (*err);
   return r;
 }
 
 int
-backend_cache (struct backend *b, struct connection *conn,
+backend_cache (struct backend *b,
                uint32_t count, uint64_t offset,
                uint32_t flags, int *err)
 {
+  GET_CONN;
   struct b_conn_handle *h = &conn->handles[b->i];
   int r;
 
   assert (h->handle && (h->state & HANDLE_CONNECTED));
   assert (h->can_cache > NBDKIT_CACHE_NONE);
-  assert (backend_valid_range (b, conn, offset, count));
+  assert (backend_valid_range (b, offset, count));
   assert (flags == 0);
   datapath_debug ("%s: cache count=%" PRIu32 " offset=%" PRIu64,
                   b->name, count, offset);
@@ -628,13 +650,13 @@ backend_cache (struct backend *b, struct connection *conn,
 
     while (count) {
       limit = MIN (count, sizeof buf);
-      if (backend_pread (b, conn, buf, limit, offset, flags, err) == -1)
+      if (backend_pread (b, buf, limit, offset, flags, err) == -1)
         return -1;
       count -= limit;
     }
     return 0;
   }
-  r = b->cache (b, conn, h->handle, count, offset, flags, err);
+  r = b->cache (b, h->handle, count, offset, flags, err);
   if (r == -1)
     assert (*err);
   return r;
diff --git a/server/connections.c b/server/connections.c
index 9978afb4..a2049325 100644
--- a/server/connections.c
+++ b/server/connections.c
@@ -53,23 +53,24 @@ static struct connection *new_connection (int sockin, int sockout,
 static void free_connection (struct connection *conn);
 
 /* Don't call these raw socket functions directly.  Use conn->recv etc. */
-static int raw_recv (struct connection *, void *buf, size_t len);
-static int raw_send_socket (struct connection *, const void *buf, size_t len,
-                            int flags);
-static int raw_send_other (struct connection *, const void *buf, size_t len,
-                           int flags);
-static void raw_close (struct connection *);
+static int raw_recv ( void *buf, size_t len);
+static int raw_send_socket (const void *buf, size_t len, int flags);
+static int raw_send_other (const void *buf, size_t len, int flags);
+static void raw_close (void);
 
 void *
-connection_get_handle (struct connection *conn, size_t i)
+connection_get_handle (size_t i)
 {
+  GET_CONN;
+
   assert (i < conn->nr_handles);
   return conn->handles[i].handle;
 }
 
 int
-connection_get_status (struct connection *conn)
+connection_get_status (void)
 {
+  GET_CONN;
   int r;
 
   if (conn->nworkers &&
@@ -86,8 +87,10 @@ connection_get_status (struct connection *conn)
  * For convenience, return the incoming value.
  */
 int
-connection_set_status (struct connection *conn, int value)
+connection_set_status (int value)
 {
+  GET_CONN;
+
   if (conn->nworkers &&
       pthread_mutex_lock (&conn->status_lock))
     abort ();
@@ -125,8 +128,8 @@ connection_worker (void *data)
   threadlocal_set_conn (conn);
   free (worker);
 
-  while (!quit && connection_get_status (conn) > 0)
-    protocol_recv_request_send_reply (conn);
+  while (!quit && connection_get_status () > 0)
+    protocol_recv_request_send_reply ();
   debug ("exiting worker thread %s", threadlocal_get_name ());
   free (name);
   return NULL;
@@ -159,7 +162,7 @@ handle_single_connection (int sockin, int sockout)
     plugin_name = "(unknown)";
   threadlocal_set_name (plugin_name);
 
-  if (backend && backend->preconnect (backend, conn, read_only) == -1)
+  if (backend && backend->preconnect (backend, read_only) == -1)
     goto done;
 
   /* NBD handshake.
@@ -167,14 +170,14 @@ handle_single_connection (int sockin, int sockout)
    * Note that this calls the backend .open callback when it is safe
    * to do so (eg. after TLS authentication).
    */
-  if (protocol_handshake (conn) == -1)
+  if (protocol_handshake () == -1)
     goto done;
 
   if (!nworkers) {
     /* No need for a separate thread. */
     debug ("handshake complete, processing requests serially");
-    while (!quit && connection_get_status (conn) > 0)
-      protocol_recv_request_send_reply (conn);
+    while (!quit && connection_get_status () > 0)
+      protocol_recv_request_send_reply ();
   }
   else {
     /* Create thread pool to process requests. */
@@ -192,13 +195,13 @@ handle_single_connection (int sockin, int sockout)
 
       if (unlikely (!worker)) {
         perror ("malloc");
-        connection_set_status (conn, -1);
+        connection_set_status (-1);
         goto wait;
       }
       if (unlikely (asprintf (&worker->name, "%s.%d", plugin_name, nworkers)
                     < 0)) {
         perror ("asprintf");
-        connection_set_status (conn, -1);
+        connection_set_status (-1);
         free (worker);
         goto wait;
       }
@@ -208,7 +211,7 @@ handle_single_connection (int sockin, int sockout)
       if (unlikely (err)) {
         errno = err;
         perror ("pthread_create");
-        connection_set_status (conn, -1);
+        connection_set_status (-1);
         free (worker);
         goto wait;
       }
@@ -221,9 +224,9 @@ handle_single_connection (int sockin, int sockout)
   }
 
   /* Finalize (for filters), called just before close. */
-  lock_request (conn);
-  r = backend_finalize (backend, conn);
-  unlock_request (conn);
+  lock_request ();
+  r = backend_finalize (backend);
+  unlock_request ();
   if (r == -1)
     goto done;
 
@@ -331,7 +334,7 @@ free_connection (struct connection *conn)
   if (!conn)
     return;
 
-  conn->close (conn);
+  conn->close ();
   if (listen_stdin) {
     int fd;
 
@@ -350,9 +353,9 @@ free_connection (struct connection *conn)
    * callback should always be called.
    */
   if (!quit) {
-    lock_request (conn);
-    backend_close (backend, conn);
-    unlock_request (conn);
+    lock_request ();
+    backend_close (backend);
+    unlock_request ();
   }
 
   if (conn->status_pipe[0] >= 0) {
@@ -375,9 +378,9 @@ free_connection (struct connection *conn)
  * that this send will be followed by related data.
  */
 static int
-raw_send_socket (struct connection *conn, const void *vbuf, size_t len,
-                 int flags)
+raw_send_socket (const void *vbuf, size_t len, int flags)
 {
+  GET_CONN;
   int sock = conn->sockout;
   const char *buf = vbuf;
   ssize_t r;
@@ -405,9 +408,9 @@ raw_send_socket (struct connection *conn, const void *vbuf, size_t len,
  * (returns 0) or fail (returns -1). flags is ignored.
  */
 static int
-raw_send_other (struct connection *conn, const void *vbuf, size_t len,
-                int flags)
+raw_send_other (const void *vbuf, size_t len, int flags)
 {
+  GET_CONN;
   int sock = conn->sockout;
   const char *buf = vbuf;
   ssize_t r;
@@ -430,8 +433,9 @@ raw_send_other (struct connection *conn, const void *vbuf, size_t len,
  * (returns > 0), read an EOF (returns 0), or fail (returns -1).
  */
 static int
-raw_recv (struct connection *conn, void *vbuf, size_t len)
+raw_recv (void *vbuf, size_t len)
 {
+  GET_CONN;
   int sock = conn->sockin;
   char *buf = vbuf;
   ssize_t r;
@@ -463,8 +467,10 @@ raw_recv (struct connection *conn, void *vbuf, size_t len)
  * close, so this function ignores errors.
  */
 static void
-raw_close (struct connection *conn)
+raw_close (void)
 {
+  GET_CONN;
+
   if (conn->sockin >= 0)
     close (conn->sockin);
   if (conn->sockout >= 0 && conn->sockin != conn->sockout)
diff --git a/server/crypto.c b/server/crypto.c
index 9cd1bb08..d291f4e7 100644
--- a/server/crypto.c
+++ b/server/crypto.c
@@ -312,8 +312,9 @@ crypto_free (void)
  * (returns > 0), read an EOF (returns 0), or fail (returns -1).
  */
 static int
-crypto_recv (struct connection *conn, void *vbuf, size_t len)
+crypto_recv (void *vbuf, size_t len)
 {
+  GET_CONN;
   gnutls_session_t session = conn->crypto_session;
   char *buf = vbuf;
   ssize_t r;
@@ -355,8 +356,9 @@ crypto_recv (struct connection *conn, void *vbuf, size_t len)
  * (returns 0) or fail (returns -1). flags is ignored for now.
  */
 static int
-crypto_send (struct connection *conn, const void *vbuf, size_t len, int flags)
+crypto_send (const void *vbuf, size_t len, int flags)
 {
+  GET_CONN;
   gnutls_session_t session = conn->crypto_session;
   const char *buf = vbuf;
   ssize_t r;
@@ -392,8 +394,9 @@ crypto_send (struct connection *conn, const void *vbuf, size_t len, int flags)
  * close, so this function ignores errors.
  */
 static void
-crypto_close (struct connection *conn)
+crypto_close (void)
 {
+  GET_CONN;
   gnutls_session_t session = conn->crypto_session;
   int sockin, sockout;
 
@@ -417,8 +420,9 @@ crypto_close (struct connection *conn)
  * only be called once per connection.
  */
 int
-crypto_negotiate_tls (struct connection *conn, int sockin, int sockout)
+crypto_negotiate_tls (int sockin, int sockout)
 {
+  GET_CONN;
   gnutls_session_t session;
   CLEANUP_FREE char *priority = NULL;
   int err;
@@ -559,7 +563,7 @@ crypto_free (void)
 }
 
 int
-crypto_negotiate_tls (struct connection *conn, int sockin, int sockout)
+crypto_negotiate_tls (int sockin, int sockout)
 {
   /* Should never be called because tls == 0. */
   abort ();
diff --git a/server/filters.c b/server/filters.c
index 2f65818e..c916217c 100644
--- a/server/filters.c
+++ b/server/filters.c
@@ -49,13 +49,13 @@ struct backend_filter {
   struct nbdkit_filter filter;
 };
 
-/* Literally a backend, a connection pointer, and the filter's handle.
+/* Literally a backend and the filter's handle.
+ *
  * This is the implementation of our handle in .open, and serves as
  * a stable ‘void *nxdata’ in the filter API.
  */
-struct b_conn {
+struct b_h {
   struct backend *b;
-  struct connection *conn;
   void *handle;
 };
 
@@ -186,22 +186,22 @@ filter_config_complete (struct backend *b)
 static int
 next_preconnect (void *nxdata, int readonly)
 {
-  struct b_conn *b_conn = nxdata;
-  return b_conn->b->preconnect (b_conn->b, b_conn->conn, readonly);
+  struct b_h *b_h = nxdata;
+  return b_h->b->preconnect (b_h->b, readonly);
 }
 
 static int
-filter_preconnect (struct backend *b, struct connection *conn, int readonly)
+filter_preconnect (struct backend *b, int readonly)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn nxdata = { .b = b->next, .conn = conn };
+  struct b_h nxdata = { .b = b->next };
 
   debug ("%s: preconnect", b->name);
 
   if (f->filter.preconnect)
     return f->filter.preconnect (next_preconnect, &nxdata, readonly);
   else
-    return b->next->preconnect (b->next, conn, readonly);
+    return b->next->preconnect (b->next, readonly);
 }
 
 /* magic_config_key only applies to plugins, so this passes the
@@ -216,16 +216,16 @@ plugin_magic_config_key (struct backend *b)
 static int
 next_open (void *nxdata, int readonly)
 {
-  struct b_conn *b_conn = nxdata;
+  struct b_h *b_h = nxdata;
 
-  return backend_open (b_conn->b, b_conn->conn, readonly);
+  return backend_open (b_h->b, readonly);
 }
 
 static void *
-filter_open (struct backend *b, struct connection *conn, int readonly)
+filter_open (struct backend *b, int readonly)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = malloc (sizeof *nxdata);
+  struct b_h *nxdata = malloc (sizeof *nxdata);
 
   if (!nxdata) {
     nbdkit_error ("malloc: %m");
@@ -233,7 +233,6 @@ filter_open (struct backend *b, struct connection *conn, int readonly)
   }
 
   nxdata->b = b->next;
-  nxdata->conn = conn;
   nxdata->handle = NULL;
 
   /* Most filters will call next_open first, resulting in
@@ -241,7 +240,7 @@ filter_open (struct backend *b, struct connection *conn, int readonly)
    */
   if (f->filter.open)
     nxdata->handle = f->filter.open (next_open, nxdata, readonly);
-  else if (backend_open (b->next, conn, readonly) == -1)
+  else if (backend_open (b->next, readonly) == -1)
     nxdata->handle = NULL;
   else
     nxdata->handle = NBDKIT_HANDLE_NOT_NEEDED;
@@ -253,13 +252,13 @@ filter_open (struct backend *b, struct connection *conn, int readonly)
 }
 
 static void
-filter_close (struct backend *b, struct connection *conn, void *handle)
+filter_close (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
   if (handle && f->filter.close) {
-    assert (nxdata->b == b->next && nxdata->conn == conn);
+    assert (nxdata->b == b->next);
     f->filter.close (nxdata->handle);
     free (nxdata);
   }
@@ -267,101 +266,101 @@ filter_close (struct backend *b, struct connection *conn, void *handle)
 
 /* The next_functions structure contains pointers to backend
  * functions.  However because these functions are all expecting a
- * backend and a connection, we cannot call them directly, but must
+ * backend and a handle, we cannot call them directly, but must
  * write some next_* functions that unpack the two parameters from a
- * single ‘void *nxdata’ struct pointer (‘b_conn’).
+ * single ‘void *nxdata’ struct pointer (‘b_h’).
  */
 
 static int
 next_reopen (void *nxdata, int readonly)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_reopen (b_conn->b, b_conn->conn, readonly);
+  struct b_h *b_h = nxdata;
+  return backend_reopen (b_h->b, readonly);
 }
 
 static int64_t
 next_get_size (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_get_size (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_get_size (b_h->b);
 }
 
 static int
 next_can_write (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_can_write (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_can_write (b_h->b);
 }
 
 static int
 next_can_flush (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_can_flush (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_can_flush (b_h->b);
 }
 
 static int
 next_is_rotational (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_is_rotational (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_is_rotational (b_h->b);
 }
 
 static int
 next_can_trim (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_can_trim (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_can_trim (b_h->b);
 }
 
 static int
 next_can_zero (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_can_zero (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_can_zero (b_h->b);
 }
 
 static int
 next_can_fast_zero (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_can_fast_zero (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_can_fast_zero (b_h->b);
 }
 
 static int
 next_can_extents (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_can_extents (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_can_extents (b_h->b);
 }
 
 static int
 next_can_fua (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_can_fua (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_can_fua (b_h->b);
 }
 
 static int
 next_can_multi_conn (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_can_multi_conn (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_can_multi_conn (b_h->b);
 }
 
 static int
 next_can_cache (void *nxdata)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_can_cache (b_conn->b, b_conn->conn);
+  struct b_h *b_h = nxdata;
+  return backend_can_cache (b_h->b);
 }
 
 static int
 next_pread (void *nxdata, void *buf, uint32_t count, uint64_t offset,
             uint32_t flags, int *err)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_pread (b_conn->b, b_conn->conn, buf, count, offset, flags,
+  struct b_h *b_h = nxdata;
+  return backend_pread (b_h->b, buf, count, offset, flags,
                         err);
 }
 
@@ -369,40 +368,40 @@ static int
 next_pwrite (void *nxdata, const void *buf, uint32_t count, uint64_t offset,
              uint32_t flags, int *err)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_pwrite (b_conn->b, b_conn->conn, buf, count, offset, flags,
+  struct b_h *b_h = nxdata;
+  return backend_pwrite (b_h->b, buf, count, offset, flags,
                          err);
 }
 
 static int
 next_flush (void *nxdata, uint32_t flags, int *err)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_flush (b_conn->b, b_conn->conn, flags, err);
+  struct b_h *b_h = nxdata;
+  return backend_flush (b_h->b, flags, err);
 }
 
 static int
 next_trim (void *nxdata, uint32_t count, uint64_t offset, uint32_t flags,
            int *err)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_trim (b_conn->b, b_conn->conn, count, offset, flags, err);
+  struct b_h *b_h = nxdata;
+  return backend_trim (b_h->b, count, offset, flags, err);
 }
 
 static int
 next_zero (void *nxdata, uint32_t count, uint64_t offset, uint32_t flags,
            int *err)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_zero (b_conn->b, b_conn->conn, count, offset, flags, err);
+  struct b_h *b_h = nxdata;
+  return backend_zero (b_h->b, count, offset, flags, err);
 }
 
 static int
 next_extents (void *nxdata, uint32_t count, uint64_t offset, uint32_t flags,
               struct nbdkit_extents *extents, int *err)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_extents (b_conn->b, b_conn->conn, count, offset, flags,
+  struct b_h *b_h = nxdata;
+  return backend_extents (b_h->b, count, offset, flags,
                           extents, err);
 }
 
@@ -410,8 +409,8 @@ static int
 next_cache (void *nxdata, uint32_t count, uint64_t offset,
             uint32_t flags, int *err)
 {
-  struct b_conn *b_conn = nxdata;
-  return backend_cache (b_conn->b, b_conn->conn, count, offset, flags, err);
+  struct b_h *b_h = nxdata;
+  return backend_cache (b_h->b, count, offset, flags, err);
 }
 
 static struct nbdkit_next_ops next_ops = {
@@ -437,13 +436,12 @@ static struct nbdkit_next_ops next_ops = {
 };
 
 static int
-filter_prepare (struct backend *b, struct connection *conn, void *handle,
-                int readonly)
+filter_prepare (struct backend *b, void *handle, int readonly)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.prepare &&
       f->filter.prepare (&next_ops, nxdata, nxdata->handle, readonly) == -1)
     return -1;
@@ -452,12 +450,12 @@ filter_prepare (struct backend *b, struct connection *conn, void *handle,
 }
 
 static int
-filter_finalize (struct backend *b, struct connection *conn, void *handle)
+filter_finalize (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.finalize &&
       f->filter.finalize (&next_ops, nxdata, nxdata->handle) == -1)
     return -1;
@@ -465,257 +463,257 @@ filter_finalize (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int64_t
-filter_get_size (struct backend *b, struct connection *conn, void *handle)
+filter_get_size (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.get_size)
     return f->filter.get_size (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_get_size (b->next, conn);
+    return backend_get_size (b->next);
 }
 
 static int
-filter_can_write (struct backend *b, struct connection *conn, void *handle)
+filter_can_write (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.can_write)
     return f->filter.can_write (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_can_write (b->next, conn);
+    return backend_can_write (b->next);
 }
 
 static int
-filter_can_flush (struct backend *b, struct connection *conn, void *handle)
+filter_can_flush (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.can_flush)
     return f->filter.can_flush (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_can_flush (b->next, conn);
+    return backend_can_flush (b->next);
 }
 
 static int
-filter_is_rotational (struct backend *b, struct connection *conn, void *handle)
+filter_is_rotational (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.is_rotational)
     return f->filter.is_rotational (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_is_rotational (b->next, conn);
+    return backend_is_rotational (b->next);
 }
 
 static int
-filter_can_trim (struct backend *b, struct connection *conn, void *handle)
+filter_can_trim (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.can_trim)
     return f->filter.can_trim (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_can_trim (b->next, conn);
+    return backend_can_trim (b->next);
 }
 
 static int
-filter_can_zero (struct backend *b, struct connection *conn, void *handle)
+filter_can_zero (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.can_zero)
     return f->filter.can_zero (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_can_zero (b->next, conn);
+    return backend_can_zero (b->next);
 }
 
 static int
-filter_can_fast_zero (struct backend *b, struct connection *conn, void *handle)
+filter_can_fast_zero (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.can_fast_zero)
     return f->filter.can_fast_zero (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_can_fast_zero (b->next, conn);
+    return backend_can_fast_zero (b->next);
 }
 
 static int
-filter_can_extents (struct backend *b, struct connection *conn, void *handle)
+filter_can_extents (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.can_extents)
     return f->filter.can_extents (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_can_extents (b->next, conn);
+    return backend_can_extents (b->next);
 }
 
 static int
-filter_can_fua (struct backend *b, struct connection *conn, void *handle)
+filter_can_fua (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.can_fua)
     return f->filter.can_fua (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_can_fua (b->next, conn);
+    return backend_can_fua (b->next);
 }
 
 static int
-filter_can_multi_conn (struct backend *b, struct connection *conn, void *handle)
+filter_can_multi_conn (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.can_multi_conn)
     return f->filter.can_multi_conn (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_can_multi_conn (b->next, conn);
+    return backend_can_multi_conn (b->next);
 }
 
 static int
-filter_can_cache (struct backend *b, struct connection *conn, void *handle)
+filter_can_cache (struct backend *b, void *handle)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.can_cache)
     return f->filter.can_cache (&next_ops, nxdata, nxdata->handle);
   else
-    return backend_can_cache (b->next, conn);
+    return backend_can_cache (b->next);
 }
 
 static int
-filter_pread (struct backend *b, struct connection *conn, void *handle,
+filter_pread (struct backend *b, void *handle,
               void *buf, uint32_t count, uint64_t offset,
               uint32_t flags, int *err)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.pread)
     return f->filter.pread (&next_ops, nxdata, nxdata->handle,
                             buf, count, offset, flags, err);
   else
-    return backend_pread (b->next, conn, buf, count, offset, flags, err);
+    return backend_pread (b->next, buf, count, offset, flags, err);
 }
 
 static int
-filter_pwrite (struct backend *b, struct connection *conn, void *handle,
+filter_pwrite (struct backend *b, void *handle,
                const void *buf, uint32_t count, uint64_t offset,
                uint32_t flags, int *err)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.pwrite)
     return f->filter.pwrite (&next_ops, nxdata, nxdata->handle,
                              buf, count, offset, flags, err);
   else
-    return backend_pwrite (b->next, conn, buf, count, offset, flags, err);
+    return backend_pwrite (b->next, buf, count, offset, flags, err);
 }
 
 static int
-filter_flush (struct backend *b, struct connection *conn, void *handle,
+filter_flush (struct backend *b, void *handle,
               uint32_t flags, int *err)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.flush)
     return f->filter.flush (&next_ops, nxdata, nxdata->handle, flags, err);
   else
-    return backend_flush (b->next, conn, flags, err);
+    return backend_flush (b->next, flags, err);
 }
 
 static int
-filter_trim (struct backend *b, struct connection *conn, void *handle,
+filter_trim (struct backend *b, void *handle,
              uint32_t count, uint64_t offset,
              uint32_t flags, int *err)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.trim)
     return f->filter.trim (&next_ops, nxdata, nxdata->handle, count, offset,
                            flags, err);
   else
-    return backend_trim (b->next, conn, count, offset, flags, err);
+    return backend_trim (b->next, count, offset, flags, err);
 }
 
 static int
-filter_zero (struct backend *b, struct connection *conn, void *handle,
+filter_zero (struct backend *b, void *handle,
              uint32_t count, uint64_t offset, uint32_t flags, int *err)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.zero)
     return f->filter.zero (&next_ops, nxdata, nxdata->handle,
                            count, offset, flags, err);
   else
-    return backend_zero (b->next, conn, count, offset, flags, err);
+    return backend_zero (b->next, count, offset, flags, err);
 }
 
 static int
-filter_extents (struct backend *b, struct connection *conn, void *handle,
+filter_extents (struct backend *b, void *handle,
                 uint32_t count, uint64_t offset, uint32_t flags,
                 struct nbdkit_extents *extents, int *err)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.extents)
     return f->filter.extents (&next_ops, nxdata, nxdata->handle,
                               count, offset, flags,
                               extents, err);
   else
-    return backend_extents (b->next, conn, count, offset, flags,
+    return backend_extents (b->next, count, offset, flags,
                             extents, err);
 }
 
 static int
-filter_cache (struct backend *b, struct connection *conn, void *handle,
+filter_cache (struct backend *b, void *handle,
               uint32_t count, uint64_t offset,
               uint32_t flags, int *err)
 {
   struct backend_filter *f = container_of (b, struct backend_filter, backend);
-  struct b_conn *nxdata = handle;
+  struct b_h *nxdata = handle;
 
-  assert (nxdata->b == b->next && nxdata->conn == conn);
+  assert (nxdata->b == b->next);
   if (f->filter.cache)
     return f->filter.cache (&next_ops, nxdata, nxdata->handle,
                             count, offset, flags, err);
   else
-    return backend_cache (b->next, conn, count, offset, flags, err);
+    return backend_cache (b->next, count, offset, flags, err);
 }
 
 static struct backend filter_functions = {
diff --git a/server/locks.c b/server/locks.c
index ef6726d8..f005710d 100644
--- a/server/locks.c
+++ b/server/locks.c
@@ -91,8 +91,10 @@ unlock_connection (void)
 }
 
 void
-lock_request (struct connection *conn)
+lock_request (void)
 {
+  GET_CONN;
+
   assert (thread_model >= 0);
   if (thread_model <= NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS &&
       pthread_mutex_lock (&all_requests_lock))
@@ -107,8 +109,10 @@ lock_request (struct connection *conn)
 }
 
 void
-unlock_request (struct connection *conn)
+unlock_request ()
 {
+  GET_CONN;
+
   if (pthread_rwlock_unlock (&unload_prevention_lock))
     abort ();
 
diff --git a/server/plugins.c b/server/plugins.c
index 79d98b8c..9595269c 100644
--- a/server/plugins.c
+++ b/server/plugins.c
@@ -235,7 +235,7 @@ plugin_magic_config_key (struct backend *b)
 }
 
 static int
-plugin_preconnect (struct backend *b, struct connection *conn, int readonly)
+plugin_preconnect (struct backend *b, int readonly)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -248,7 +248,7 @@ plugin_preconnect (struct backend *b, struct connection *conn, int readonly)
 }
 
 static void *
-plugin_open (struct backend *b, struct connection *conn, int readonly)
+plugin_open (struct backend *b, int readonly)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -262,20 +262,20 @@ plugin_open (struct backend *b, struct connection *conn, int readonly)
  * .close.
  */
 static int
-plugin_prepare (struct backend *b, struct connection *conn, void *handle,
+plugin_prepare (struct backend *b, void *handle,
                 int readonly)
 {
   return 0;
 }
 
 static int
-plugin_finalize (struct backend *b, struct connection *conn, void *handle)
+plugin_finalize (struct backend *b, void *handle)
 {
   return 0;
 }
 
 static void
-plugin_close (struct backend *b, struct connection *conn, void *handle)
+plugin_close (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -284,7 +284,7 @@ plugin_close (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int64_t
-plugin_get_size (struct backend *b, struct connection *conn, void *handle)
+plugin_get_size (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -294,7 +294,7 @@ plugin_get_size (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int
-plugin_can_write (struct backend *b, struct connection *conn, void *handle)
+plugin_can_write (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -305,7 +305,7 @@ plugin_can_write (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int
-plugin_can_flush (struct backend *b, struct connection *conn, void *handle)
+plugin_can_flush (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -316,7 +316,7 @@ plugin_can_flush (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int
-plugin_is_rotational (struct backend *b, struct connection *conn, void *handle)
+plugin_is_rotational (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -327,7 +327,7 @@ plugin_is_rotational (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int
-plugin_can_trim (struct backend *b, struct connection *conn, void *handle)
+plugin_can_trim (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -338,7 +338,7 @@ plugin_can_trim (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int
-plugin_can_zero (struct backend *b, struct connection *conn, void *handle)
+plugin_can_zero (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
   int r;
@@ -359,7 +359,7 @@ plugin_can_zero (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int
-plugin_can_fast_zero (struct backend *b, struct connection *conn, void *handle)
+plugin_can_fast_zero (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
   int r;
@@ -372,14 +372,14 @@ plugin_can_fast_zero (struct backend *b, struct connection *conn, void *handle)
    */
   if (p->plugin.zero == NULL)
     return 1;
-  r = backend_can_zero (b, conn);
+  r = backend_can_zero (b);
   if (r == -1)
     return -1;
   return !r;
 }
 
 static int
-plugin_can_extents (struct backend *b, struct connection *conn, void *handle)
+plugin_can_extents (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -390,7 +390,7 @@ plugin_can_extents (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int
-plugin_can_fua (struct backend *b, struct connection *conn, void *handle)
+plugin_can_fua (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
   int r;
@@ -410,7 +410,7 @@ plugin_can_fua (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int
-plugin_can_multi_conn (struct backend *b, struct connection *conn, void *handle)
+plugin_can_multi_conn (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -421,7 +421,7 @@ plugin_can_multi_conn (struct backend *b, struct connection *conn, void *handle)
 }
 
 static int
-plugin_can_cache (struct backend *b, struct connection *conn, void *handle)
+plugin_can_cache (struct backend *b, void *handle)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
 
@@ -454,7 +454,7 @@ get_error (struct backend_plugin *p)
 }
 
 static int
-plugin_pread (struct backend *b, struct connection *conn, void *handle,
+plugin_pread (struct backend *b, void *handle,
               void *buf, uint32_t count, uint64_t offset, uint32_t flags,
               int *err)
 {
@@ -473,7 +473,7 @@ plugin_pread (struct backend *b, struct connection *conn, void *handle,
 }
 
 static int
-plugin_flush (struct backend *b, struct connection *conn, void *handle,
+plugin_flush (struct backend *b, void *handle,
               uint32_t flags, int *err)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
@@ -493,7 +493,7 @@ plugin_flush (struct backend *b, struct connection *conn, void *handle,
 }
 
 static int
-plugin_pwrite (struct backend *b, struct connection *conn, void *handle,
+plugin_pwrite (struct backend *b, void *handle,
                const void *buf, uint32_t count, uint64_t offset, uint32_t flags,
                int *err)
 {
@@ -502,7 +502,7 @@ plugin_pwrite (struct backend *b, struct connection *conn, void *handle,
   bool fua = flags & NBDKIT_FLAG_FUA;
   bool need_flush = false;
 
-  if (fua && backend_can_fua (b, conn) != NBDKIT_FUA_NATIVE) {
+  if (fua && backend_can_fua (b) != NBDKIT_FUA_NATIVE) {
     flags &= ~NBDKIT_FLAG_FUA;
     need_flush = true;
   }
@@ -515,14 +515,14 @@ plugin_pwrite (struct backend *b, struct connection *conn, void *handle,
     return -1;
   }
   if (r != -1 && need_flush)
-    r = plugin_flush (b, conn, handle, 0, err);
+    r = plugin_flush (b, handle, 0, err);
   if (r == -1 && !*err)
     *err = get_error (p);
   return r;
 }
 
 static int
-plugin_trim (struct backend *b, struct connection *conn, void *handle,
+plugin_trim (struct backend *b, void *handle,
              uint32_t count, uint64_t offset, uint32_t flags, int *err)
 {
   int r;
@@ -530,7 +530,7 @@ plugin_trim (struct backend *b, struct connection *conn, void *handle,
   bool fua = flags & NBDKIT_FLAG_FUA;
   bool need_flush = false;
 
-  if (fua && backend_can_fua (b, conn) != NBDKIT_FUA_NATIVE) {
+  if (fua && backend_can_fua (b) != NBDKIT_FUA_NATIVE) {
     flags &= ~NBDKIT_FLAG_FUA;
     need_flush = true;
   }
@@ -543,14 +543,14 @@ plugin_trim (struct backend *b, struct connection *conn, void *handle,
     return -1;
   }
   if (r != -1 && need_flush)
-    r = plugin_flush (b, conn, handle, 0, err);
+    r = plugin_flush (b, handle, 0, err);
   if (r == -1 && !*err)
     *err = get_error (p);
   return r;
 }
 
 static int
-plugin_zero (struct backend *b, struct connection *conn, void *handle,
+plugin_zero (struct backend *b, void *handle,
              uint32_t count, uint64_t offset, uint32_t flags, int *err)
 {
   struct backend_plugin *p = container_of (b, struct backend_plugin, backend);
@@ -561,14 +561,14 @@ plugin_zero (struct backend *b, struct connection *conn, void *handle,
   bool emulate = false;
   bool need_flush = false;
 
-  if (fua && backend_can_fua (b, conn) != NBDKIT_FUA_NATIVE) {
+  if (fua && backend_can_fua (b) != NBDKIT_FUA_NATIVE) {
     flags &= ~NBDKIT_FLAG_FUA;
     need_flush = true;
   }
   if (!count)
     return 0;
 
-  if (backend_can_zero (b, conn) == NBDKIT_ZERO_NATIVE) {
+  if (backend_can_zero (b) == NBDKIT_ZERO_NATIVE) {
     errno = 0;
     if (p->plugin.zero)
       r = p->plugin.zero (handle, count, offset, flags);
@@ -605,7 +605,7 @@ plugin_zero (struct backend *b, struct connection *conn, void *handle,
     static /* const */ char buf[MAX_REQUEST_SIZE];
     uint32_t limit = MIN (count, sizeof buf);
 
-    r = plugin_pwrite (b, conn, handle, buf, limit, offset, flags, err);
+    r = plugin_pwrite (b, handle, buf, limit, offset, flags, err);
     if (r == -1)
       break;
     count -= limit;
@@ -613,14 +613,14 @@ plugin_zero (struct backend *b, struct connection *conn, void *handle,
 
  done:
   if (r != -1 && need_flush)
-    r = plugin_flush (b, conn, handle, 0, err);
+    r = plugin_flush (b, handle, 0, err);
   if (r == -1 && !*err)
     *err = get_error (p);
   return r;
 }
 
 static int
-plugin_extents (struct backend *b, struct connection *conn, void *handle,
+plugin_extents (struct backend *b, void *handle,
                 uint32_t count, uint64_t offset, uint32_t flags,
                 struct nbdkit_extents *extents, int *err)
 {
@@ -642,7 +642,7 @@ plugin_extents (struct backend *b, struct connection *conn, void *handle,
 }
 
 static int
-plugin_cache (struct backend *b, struct connection *conn, void *handle,
+plugin_cache (struct backend *b, void *handle,
               uint32_t count, uint64_t offset, uint32_t flags,
               int *err)
 {
diff --git a/server/protocol-handshake-newstyle.c b/server/protocol-handshake-newstyle.c
index 7179186f..41b2a6e4 100644
--- a/server/protocol-handshake-newstyle.c
+++ b/server/protocol-handshake-newstyle.c
@@ -49,9 +49,9 @@
 
 /* Receive newstyle options. */
 static int
-send_newstyle_option_reply (struct connection *conn,
-                            uint32_t option, uint32_t reply)
+send_newstyle_option_reply (uint32_t option, uint32_t reply)
 {
+  GET_CONN;
   struct nbd_fixed_new_option_reply fixed_new_option_reply;
 
   fixed_new_option_reply.magic = htobe64 (NBD_REP_MAGIC);
@@ -59,8 +59,7 @@ send_newstyle_option_reply (struct connection *conn,
   fixed_new_option_reply.reply = htobe32 (reply);
   fixed_new_option_reply.replylen = htobe32 (0);
 
-  if (conn->send (conn,
-                  &fixed_new_option_reply,
+  if (conn->send (&fixed_new_option_reply,
                   sizeof fixed_new_option_reply, 0) == -1) {
     /* The protocol document says that the client is allowed to simply
      * drop the connection after sending NBD_OPT_ABORT, or may read
@@ -77,9 +76,9 @@ send_newstyle_option_reply (struct connection *conn,
 }
 
 static int
-send_newstyle_option_reply_exportname (struct connection *conn,
-                                       uint32_t option, uint32_t reply)
+send_newstyle_option_reply_exportname (uint32_t option, uint32_t reply)
 {
+  GET_CONN;
   struct nbd_fixed_new_option_reply fixed_new_option_reply;
   size_t name_len = strlen (exportname);
   uint32_t len;
@@ -89,20 +88,19 @@ send_newstyle_option_reply_exportname (struct connection *conn,
   fixed_new_option_reply.reply = htobe32 (reply);
   fixed_new_option_reply.replylen = htobe32 (name_len + sizeof (len));
 
-  if (conn->send (conn,
-                  &fixed_new_option_reply,
+  if (conn->send (&fixed_new_option_reply,
                   sizeof fixed_new_option_reply, SEND_MORE) == -1) {
     nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
     return -1;
   }
 
   len = htobe32 (name_len);
-  if (conn->send (conn, &len, sizeof len, SEND_MORE) == -1) {
+  if (conn->send (&len, sizeof len, SEND_MORE) == -1) {
     nbdkit_error ("write: %s: %s: %m",
                   name_of_nbd_opt (option), "sending length");
     return -1;
   }
-  if (conn->send (conn, exportname, name_len, 0) == -1) {
+  if (conn->send (exportname, name_len, 0) == -1) {
     nbdkit_error ("write: %s: %s: %m",
                   name_of_nbd_opt (option), "sending export name");
     return -1;
@@ -112,10 +110,10 @@ send_newstyle_option_reply_exportname (struct connection *conn,
 }
 
 static int
-send_newstyle_option_reply_info_export (struct connection *conn,
-                                        uint32_t option, uint32_t reply,
+send_newstyle_option_reply_info_export (uint32_t option, uint32_t reply,
                                         uint16_t info, uint64_t exportsize)
 {
+  GET_CONN;
   struct nbd_fixed_new_option_reply fixed_new_option_reply;
   struct nbd_fixed_new_option_reply_info_export export;
 
@@ -127,10 +125,9 @@ send_newstyle_option_reply_info_export (struct connection *conn,
   export.exportsize = htobe64 (exportsize);
   export.eflags = htobe16 (conn->eflags);
 
-  if (conn->send (conn,
-                  &fixed_new_option_reply,
+  if (conn->send (&fixed_new_option_reply,
                   sizeof fixed_new_option_reply, SEND_MORE) == -1 ||
-      conn->send (conn, &export, sizeof export, 0) == -1) {
+      conn->send (&export, sizeof export, 0) == -1) {
     nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
     return -1;
   }
@@ -139,11 +136,11 @@ send_newstyle_option_reply_info_export (struct connection *conn,
 }
 
 static int
-send_newstyle_option_reply_meta_context (struct connection *conn,
-                                         uint32_t option, uint32_t reply,
+send_newstyle_option_reply_meta_context (uint32_t option, uint32_t reply,
                                          uint32_t context_id,
                                          const char *name)
 {
+  GET_CONN;
   struct nbd_fixed_new_option_reply fixed_new_option_reply;
   struct nbd_fixed_new_option_reply_meta_context context;
   const size_t namelen = strlen (name);
@@ -156,11 +153,10 @@ send_newstyle_option_reply_meta_context (struct connection *conn,
   fixed_new_option_reply.replylen = htobe32 (sizeof context + namelen);
   context.context_id = htobe32 (context_id);
 
-  if (conn->send (conn,
-                  &fixed_new_option_reply,
+  if (conn->send (&fixed_new_option_reply,
                   sizeof fixed_new_option_reply, SEND_MORE) == -1 ||
-      conn->send (conn, &context, sizeof context, SEND_MORE) == -1 ||
-      conn->send (conn, name, namelen, 0) == -1) {
+      conn->send (&context, sizeof context, SEND_MORE) == -1 ||
+      conn->send (name, namelen, 0) == -1) {
     nbdkit_error ("write: %s: %m", name_of_nbd_opt (option));
     return -1;
   }
@@ -171,11 +167,11 @@ send_newstyle_option_reply_meta_context (struct connection *conn,
 /* Sub-function during negotiate_handshake_newstyle, to uniformly handle
  * a client hanging up on a message boundary.
  */
-static int __attribute__ ((format (printf, 4, 5)))
-conn_recv_full (struct connection *conn, void *buf, size_t len,
-                const char *fmt, ...)
+static int __attribute__ ((format (printf, 3, 4)))
+conn_recv_full (void *buf, size_t len, const char *fmt, ...)
 {
-  int r = conn->recv (conn, buf, len);
+  GET_CONN;
+  int r = conn->recv (buf, len);
   va_list args;
 
   if (r == -1) {
@@ -198,9 +194,11 @@ conn_recv_full (struct connection *conn, void *buf, size_t len,
  * in that function, and must not cause any wire traffic.
  */
 static int
-finish_newstyle_options (struct connection *conn, uint64_t *exportsize)
+finish_newstyle_options (uint64_t *exportsize)
 {
-  if (protocol_common_open (conn, exportsize, &conn->eflags) == -1)
+  GET_CONN;
+
+  if (protocol_common_open (exportsize, &conn->eflags) == -1)
     return -1;
 
   debug ("newstyle negotiation: flags: export 0x%x", conn->eflags);
@@ -233,9 +231,11 @@ check_string (uint32_t option, char *buf, uint32_t len, uint32_t maxlen,
  * validate an export name.
  */
 static int
-check_export_name (struct connection *conn, uint32_t option, char *buf,
+check_export_name (uint32_t option, char *buf,
                    uint32_t exportnamelen, uint32_t maxlen, bool save)
 {
+  GET_CONN;
+
   if (check_string (option, buf, exportnamelen, maxlen, "export name") == -1)
     return -1;
 
@@ -254,8 +254,9 @@ check_export_name (struct connection *conn, uint32_t option, char *buf,
 }
 
 static int
-negotiate_handshake_newstyle_options (struct connection *conn)
+negotiate_handshake_newstyle_options (void)
 {
+  GET_CONN;
   struct nbd_new_option new_option;
   size_t nr_options;
   uint64_t version;
@@ -268,7 +269,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
   for (nr_options = 0; nr_options < MAX_NR_OPTIONS; ++nr_options) {
     CLEANUP_FREE char *data = NULL;
 
-    if (conn_recv_full (conn, &new_option, sizeof new_option,
+    if (conn_recv_full (&new_option, sizeof new_option,
                         "reading option: conn->recv: %m") == -1)
       return -1;
 
@@ -302,7 +303,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
      */
     if (!(conn->cflags & NBD_FLAG_FIXED_NEWSTYLE) &&
         option != NBD_OPT_EXPORT_NAME) {
-      if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID))
+      if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID))
         return -1;
       continue;
     }
@@ -312,31 +313,30 @@ negotiate_handshake_newstyle_options (struct connection *conn)
      */
     if (tls == 2 && !conn->using_tls &&
         !(option == NBD_OPT_ABORT || option == NBD_OPT_STARTTLS)) {
-      if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_TLS_REQD))
+      if (send_newstyle_option_reply (option, NBD_REP_ERR_TLS_REQD))
         return -1;
       continue;
     }
 
     switch (option) {
     case NBD_OPT_EXPORT_NAME:
-      if (conn_recv_full (conn, data, optlen,
+      if (conn_recv_full (data, optlen,
                           "read: %s: %m", name_of_nbd_opt (option)) == -1)
         return -1;
-      if (check_export_name (conn, option, data, optlen, optlen, true) == -1)
+      if (check_export_name (option, data, optlen, optlen, true) == -1)
         return -1;
 
       /* We have to finish the handshake by sending handshake_finish.
        * On failure, we have to disconnect.
        */
-      if (finish_newstyle_options (conn, &exportsize) == -1)
+      if (finish_newstyle_options (&exportsize) == -1)
         return -1;
 
       memset (&handshake_finish, 0, sizeof handshake_finish);
       handshake_finish.exportsize = htobe64 (exportsize);
       handshake_finish.eflags = htobe16 (conn->eflags);
 
-      if (conn->send (conn,
-                      &handshake_finish,
+      if (conn->send (&handshake_finish,
                       (conn->cflags & NBD_FLAG_NO_ZEROES)
                       ? offsetof (struct nbd_export_name_option_reply, zeroes)
                       : sizeof handshake_finish, 0) == -1) {
@@ -346,7 +346,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
       break;
 
     case NBD_OPT_ABORT:
-      if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+      if (send_newstyle_option_reply (option, NBD_REP_ACK) == -1)
         return -1;
       debug ("client sent %s to abort the connection",
              name_of_nbd_opt (option));
@@ -354,10 +354,10 @@ negotiate_handshake_newstyle_options (struct connection *conn)
 
     case NBD_OPT_LIST:
       if (optlen != 0) {
-        if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+        if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID)
             == -1)
           return -1;
-        if (conn_recv_full (conn, data, optlen,
+        if (conn_recv_full (data, optlen,
                             "read: %s: %m", name_of_nbd_opt (option)) == -1)
           return -1;
         continue;
@@ -366,20 +366,19 @@ negotiate_handshake_newstyle_options (struct connection *conn)
       /* Send back the exportname. */
       debug ("newstyle negotiation: %s: advertising export '%s'",
              name_of_nbd_opt (option), exportname);
-      if (send_newstyle_option_reply_exportname (conn, option,
-                                                 NBD_REP_SERVER) == -1)
+      if (send_newstyle_option_reply_exportname (option, NBD_REP_SERVER) == -1)
         return -1;
 
-      if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+      if (send_newstyle_option_reply (option, NBD_REP_ACK) == -1)
         return -1;
       break;
 
     case NBD_OPT_STARTTLS:
       if (optlen != 0) {
-        if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+        if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID)
             == -1)
           return -1;
-        if (conn_recv_full (conn, data, optlen,
+        if (conn_recv_full (data, optlen,
                             "read: %s: %m", name_of_nbd_opt (option)) == -1)
           return -1;
         continue;
@@ -391,14 +390,13 @@ negotiate_handshake_newstyle_options (struct connection *conn)
 #else
 #define NO_TLS_REPLY NBD_REP_ERR_UNSUP
 #endif
-        if (send_newstyle_option_reply (conn, option, NO_TLS_REPLY) == -1)
+        if (send_newstyle_option_reply (option, NO_TLS_REPLY) == -1)
           return -1;
       }
       else /* --tls=on or --tls=require */ {
         /* We can't upgrade to TLS twice on the same connection. */
         if (conn->using_tls) {
-          if (send_newstyle_option_reply (conn, option,
-                                          NBD_REP_ERR_INVALID) == -1)
+          if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID) == -1)
             return -1;
           continue;
         }
@@ -406,11 +404,11 @@ negotiate_handshake_newstyle_options (struct connection *conn)
         /* We have to send the (unencrypted) reply before starting
          * the handshake.
          */
-        if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+        if (send_newstyle_option_reply (option, NBD_REP_ACK) == -1)
           return -1;
 
         /* Upgrade the connection to TLS.  Also performs access control. */
-        if (crypto_negotiate_tls (conn, conn->sockin, conn->sockout) == -1)
+        if (crypto_negotiate_tls (conn->sockin, conn->sockout) == -1)
           return -1;
         conn->using_tls = true;
         debug ("using TLS on this connection");
@@ -419,14 +417,13 @@ negotiate_handshake_newstyle_options (struct connection *conn)
 
     case NBD_OPT_INFO:
     case NBD_OPT_GO:
-      if (conn_recv_full (conn, data, optlen,
-                          "read: %s: %m", optname) == -1)
+      if (conn_recv_full (data, optlen, "read: %s: %m", optname) == -1)
         return -1;
 
       if (optlen < 6) { /* 32 bit export length + 16 bit nr info */
         debug ("newstyle negotiation: %s option length < 6", optname);
 
-        if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+        if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID)
             == -1)
           return -1;
         continue;
@@ -443,7 +440,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
         exportnamelen = be32toh (exportnamelen);
         if (exportnamelen > optlen-6 /* NB optlen >= 6, see above */) {
           debug ("newstyle negotiation: %s: export name too long", optname);
-          if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+          if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID)
               == -1)
             return -1;
           continue;
@@ -453,7 +450,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
         if (optlen != 4 + exportnamelen + 2 + 2*nrinfos) {
           debug ("newstyle negotiation: %s: "
                  "number of information requests incorrect", optname);
-          if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+          if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID)
               == -1)
             return -1;
           continue;
@@ -464,9 +461,9 @@ negotiate_handshake_newstyle_options (struct connection *conn)
          * NBD_OPT_SET_META_CONTEXT used an export name, it must match
          * or else we drop the support for that context.
          */
-        if (check_export_name (conn, option, &data[4], exportnamelen,
+        if (check_export_name (option, &data[4], exportnamelen,
                                optlen - 6, true) == -1) {
-          if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+          if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID)
               == -1)
             return -1;
           continue;
@@ -480,17 +477,16 @@ negotiate_handshake_newstyle_options (struct connection *conn)
          * client and let them try another NBD_OPT, rather than
          * disconnecting.
          */
-        if (finish_newstyle_options (conn, &exportsize) == -1) {
-          if (backend_finalize (backend, conn) == -1)
+        if (finish_newstyle_options (&exportsize) == -1) {
+          if (backend_finalize (backend) == -1)
             return -1;
-          backend_close (backend, conn);
-          if (send_newstyle_option_reply (conn, option,
-                                          NBD_REP_ERR_UNKNOWN) == -1)
+          backend_close (backend);
+          if (send_newstyle_option_reply (option, NBD_REP_ERR_UNKNOWN) == -1)
             return -1;
           continue;
         }
 
-        if (send_newstyle_option_reply_info_export (conn, option,
+        if (send_newstyle_option_reply_info_export (option,
                                                     NBD_REP_INFO,
                                                     NBD_INFO_EXPORT,
                                                     exportsize) == -1)
@@ -518,23 +514,23 @@ negotiate_handshake_newstyle_options (struct connection *conn)
       /* Unlike NBD_OPT_EXPORT_NAME, NBD_OPT_GO sends back an ACK
        * or ERROR packet.  If this was NBD_OPT_LIST, call .close.
        */
-      if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+      if (send_newstyle_option_reply (option, NBD_REP_ACK) == -1)
         return -1;
 
       if (option == NBD_OPT_INFO) {
-        if (backend_finalize (backend, conn) == -1)
+        if (backend_finalize (backend) == -1)
           return -1;
-        backend_close (backend, conn);
+        backend_close (backend);
       }
 
       break;
 
     case NBD_OPT_STRUCTURED_REPLY:
       if (optlen != 0) {
-        if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+        if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID)
             == -1)
           return -1;
-        if (conn_recv_full (conn, data, optlen,
+        if (conn_recv_full (data, optlen,
                             "read: %s: %m", name_of_nbd_opt (option)) == -1)
           return -1;
         continue;
@@ -547,14 +543,14 @@ negotiate_handshake_newstyle_options (struct connection *conn)
         /* Must fail with ERR_UNSUP for qemu 4.2 to remain happy;
          * but failing with ERR_POLICY would have been nicer.
          */
-        if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
+        if (send_newstyle_option_reply (option, NBD_REP_ERR_UNSUP) == -1)
           return -1;
         debug ("newstyle negotiation: %s: structured replies are disabled",
                name_of_nbd_opt (option));
         break;
       }
 
-      if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+      if (send_newstyle_option_reply (option, NBD_REP_ACK) == -1)
         return -1;
 
       conn->structured_replies = true;
@@ -569,14 +565,14 @@ negotiate_handshake_newstyle_options (struct connection *conn)
         uint32_t querylen;
         const char *what;
 
-        if (conn_recv_full (conn, data, optlen, "read: %s: %m", optname) == -1)
+        if (conn_recv_full (data, optlen, "read: %s: %m", optname) == -1)
           return -1;
 
         /* Note that we support base:allocation whether or not the plugin
          * supports can_extents.
          */
         if (!conn->structured_replies) {
-          if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+          if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID)
               == -1)
             return -1;
           continue;
@@ -593,7 +589,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
           debug ("newstyle negotiation: %s: invalid option length: %s",
                  optname, what);
 
-          if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_INVALID)
+          if (send_newstyle_option_reply (option, NBD_REP_ERR_INVALID)
               == -1)
             return -1;
           continue;
@@ -606,7 +602,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
         memcpy (&exportnamelen, &data[0], 4);
         exportnamelen = be32toh (exportnamelen);
         what = "validating export name";
-        if (check_export_name (conn, option, &data[4], exportnamelen,
+        if (check_export_name (option, &data[4], exportnamelen,
                                optlen - 8,
                                option == NBD_OPT_SET_META_CONTEXT) == -1)
           goto opt_meta_invalid_option_len;
@@ -630,13 +626,14 @@ negotiate_handshake_newstyle_options (struct connection *conn)
           conn->meta_context_base_allocation = false;
         if (nr_queries == 0) {
           if (option == NBD_OPT_LIST_META_CONTEXT) {
-            if (send_newstyle_option_reply_meta_context
-                (conn, option, NBD_REP_META_CONTEXT,
-                 0, "base:allocation") == -1)
+            if (send_newstyle_option_reply_meta_context (option,
+                                                         NBD_REP_META_CONTEXT,
+                                                         0, "base:allocation")
+                == -1)
               return -1;
           }
 
-          if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+          if (send_newstyle_option_reply (option, NBD_REP_ACK) == -1)
             return -1;
         }
         else {
@@ -665,7 +662,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
                 querylen == 5 &&
                 strncmp (&data[opt_index], "base:", 5) == 0) {
               if (send_newstyle_option_reply_meta_context
-                  (conn, option, NBD_REP_META_CONTEXT,
+                  (option, NBD_REP_META_CONTEXT,
                    0, "base:allocation") == -1)
                 return -1;
             }
@@ -673,7 +670,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
             else if (querylen == 15 &&
                      strncmp (&data[opt_index], "base:allocation", 15) == 0) {
               if (send_newstyle_option_reply_meta_context
-                  (conn, option, NBD_REP_META_CONTEXT,
+                  (option, NBD_REP_META_CONTEXT,
                    option == NBD_OPT_SET_META_CONTEXT
                    ? base_allocation_id : 0,
                    "base:allocation") == -1)
@@ -686,7 +683,7 @@ negotiate_handshake_newstyle_options (struct connection *conn)
             opt_index += querylen;
             nr_queries--;
           }
-          if (send_newstyle_option_reply (conn, option, NBD_REP_ACK) == -1)
+          if (send_newstyle_option_reply (option, NBD_REP_ACK) == -1)
             return -1;
         }
         debug ("newstyle negotiation: %s: reply complete", optname);
@@ -695,9 +692,9 @@ negotiate_handshake_newstyle_options (struct connection *conn)
 
     default:
       /* Unknown option. */
-      if (send_newstyle_option_reply (conn, option, NBD_REP_ERR_UNSUP) == -1)
+      if (send_newstyle_option_reply (option, NBD_REP_ERR_UNSUP) == -1)
         return -1;
-      if (conn_recv_full (conn, data, optlen,
+      if (conn_recv_full (data, optlen,
                           "reading unknown option data: conn->recv: %m") == -1)
         return -1;
     }
@@ -728,8 +725,9 @@ negotiate_handshake_newstyle_options (struct connection *conn)
 }
 
 int
-protocol_handshake_newstyle (struct connection *conn)
+protocol_handshake_newstyle (void)
 {
+  GET_CONN;
   struct nbd_new_handshake handshake;
   uint16_t gflags;
 
@@ -741,13 +739,13 @@ protocol_handshake_newstyle (struct connection *conn)
   handshake.version = htobe64 (NBD_NEW_VERSION);
   handshake.gflags = htobe16 (gflags);
 
-  if (conn->send (conn, &handshake, sizeof handshake, 0) == -1) {
+  if (conn->send (&handshake, sizeof handshake, 0) == -1) {
     nbdkit_error ("write: %s: %m", "sending newstyle handshake");
     return -1;
   }
 
   /* Client now sends us its 32 bit flags word ... */
-  if (conn_recv_full (conn, &conn->cflags, sizeof conn->cflags,
+  if (conn_recv_full (&conn->cflags, sizeof conn->cflags,
                       "reading initial client flags: conn->recv: %m") == -1)
     return -1;
   conn->cflags = be32toh (conn->cflags);
@@ -759,7 +757,7 @@ protocol_handshake_newstyle (struct connection *conn)
   }
 
   /* Receive newstyle options. */
-  if (negotiate_handshake_newstyle_options (conn) == -1)
+  if (negotiate_handshake_newstyle_options () == -1)
     return -1;
 
   return 0;
diff --git a/server/protocol-handshake-oldstyle.c b/server/protocol-handshake-oldstyle.c
index 45a1a486..5a5fa5fa 100644
--- a/server/protocol-handshake-oldstyle.c
+++ b/server/protocol-handshake-oldstyle.c
@@ -44,8 +44,9 @@
 #include "nbd-protocol.h"
 
 int
-protocol_handshake_oldstyle (struct connection *conn)
+protocol_handshake_oldstyle (void)
 {
+  GET_CONN;
   struct nbd_old_handshake handshake;
   uint64_t exportsize;
   uint16_t gflags, eflags;
@@ -55,7 +56,7 @@ protocol_handshake_oldstyle (struct connection *conn)
   /* With oldstyle, our only option if .open or friends fail is to
    * disconnect, as we cannot report the problem to the client.
    */
-  if (protocol_common_open (conn, &exportsize, &eflags) == -1)
+  if (protocol_common_open (&exportsize, &eflags) == -1)
     return -1;
 
   gflags = 0;
@@ -69,7 +70,7 @@ protocol_handshake_oldstyle (struct connection *conn)
   handshake.gflags = htobe16 (gflags);
   handshake.eflags = htobe16 (eflags);
 
-  if (conn->send (conn, &handshake, sizeof handshake, 0) == -1) {
+  if (conn->send (&handshake, sizeof handshake, 0) == -1) {
     nbdkit_error ("write: %m");
     return -1;
   }
diff --git a/server/protocol-handshake.c b/server/protocol-handshake.c
index 2c2f35ee..a32fcde0 100644
--- a/server/protocol-handshake.c
+++ b/server/protocol-handshake.c
@@ -44,16 +44,16 @@
 #include "nbd-protocol.h"
 
 int
-protocol_handshake (struct connection *conn)
+protocol_handshake ()
 {
   int r;
 
-  lock_request (conn);
+  lock_request ();
   if (!newstyle)
-    r = protocol_handshake_oldstyle (conn);
+    r = protocol_handshake_oldstyle ();
   else
-    r = protocol_handshake_newstyle (conn);
-  unlock_request (conn);
+    r = protocol_handshake_newstyle ();
+  unlock_request ();
 
   return r;
 }
@@ -72,21 +72,21 @@ protocol_handshake (struct connection *conn)
  * simply opening a TCP connection.
  */
 int
-protocol_common_open (struct connection *conn,
-                      uint64_t *exportsize, uint16_t *flags)
+protocol_common_open (uint64_t *exportsize, uint16_t *flags)
 {
+  GET_CONN;
   int64_t size;
   uint16_t eflags = NBD_FLAG_HAS_FLAGS;
   int fl;
 
-  if (backend_open (backend, conn, read_only) == -1)
+  if (backend_open (backend, read_only) == -1)
     return -1;
 
   /* Prepare (for filters), called just after open. */
-  if (backend_prepare (backend, conn) == -1)
+  if (backend_prepare (backend) == -1)
     return -1;
 
-  size = backend_get_size (backend, conn);
+  size = backend_get_size (backend);
   if (size == -1)
     return -1;
   if (size < 0) {
@@ -98,57 +98,57 @@ protocol_common_open (struct connection *conn,
   /* Check all flags even if they won't be advertised, to prime the
    * cache and make later request validation easier.
    */
-  fl = backend_can_write (backend, conn);
+  fl = backend_can_write (backend);
   if (fl == -1)
     return -1;
   if (!fl)
     eflags |= NBD_FLAG_READ_ONLY;
 
-  fl = backend_can_zero (backend, conn);
+  fl = backend_can_zero (backend);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_WRITE_ZEROES;
 
-  fl = backend_can_fast_zero (backend, conn);
+  fl = backend_can_fast_zero (backend);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_FAST_ZERO;
 
-  fl = backend_can_trim (backend, conn);
+  fl = backend_can_trim (backend);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_TRIM;
 
-  fl = backend_can_fua (backend, conn);
+  fl = backend_can_fua (backend);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_FUA;
 
-  fl = backend_can_flush (backend, conn);
+  fl = backend_can_flush (backend);
   if (fl == -1)
     return -1;
   if (fl)
     eflags |= NBD_FLAG_SEND_FLUSH;
 
-  fl = backend_is_rotational (backend, conn);
+  fl = backend_is_rotational (backend);
   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 (backend, conn);
+  fl = backend_can_multi_conn (backend);
   if (fl == -1)
     return -1;
   if (fl && (backend->thread_model (backend) >
              NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS))
     eflags |= NBD_FLAG_CAN_MULTI_CONN;
 
-  fl = backend_can_cache (backend, conn);
+  fl = backend_can_cache (backend);
   if (fl == -1)
     return -1;
   if (fl)
@@ -159,7 +159,7 @@ protocol_common_open (struct connection *conn,
    * not have to worry about errors, and makes test-layers easier to
    * write.
    */
-  fl = backend_can_extents (backend, conn);
+  fl = backend_can_extents (backend);
   if (fl == -1)
     return -1;
 
diff --git a/server/protocol.c b/server/protocol.c
index f6ea35cb..d41ad569 100644
--- a/server/protocol.c
+++ b/server/protocol.c
@@ -49,10 +49,11 @@
 #include "protostrings.h"
 
 static bool
-validate_request (struct connection *conn,
-                  uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count,
+validate_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count,
                   uint32_t *error)
 {
+  GET_CONN;
+
   /* Readonly connection? */
   if (conn->eflags & NBD_FLAG_READ_ONLY &&
       (cmd == NBD_CMD_WRITE || cmd == NBD_CMD_TRIM ||
@@ -71,7 +72,7 @@ validate_request (struct connection *conn,
   case NBD_CMD_TRIM:
   case NBD_CMD_WRITE_ZEROES:
   case NBD_CMD_BLOCK_STATUS:
-    if (!backend_valid_range (backend, conn, offset, count)) {
+    if (!backend_valid_range (backend, 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,
@@ -225,8 +226,7 @@ validate_request (struct connection *conn,
  * for success).
  */
 static uint32_t
-handle_request (struct connection *conn,
-                uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count,
+handle_request (uint16_t cmd, uint16_t flags, uint64_t offset, uint32_t count,
                 void *buf, struct nbdkit_extents *extents)
 {
   uint32_t f = 0;
@@ -238,31 +238,31 @@ handle_request (struct connection *conn,
 
   switch (cmd) {
   case NBD_CMD_READ:
-    if (backend_pread (backend, conn, buf, count, offset, 0, &err) == -1)
+    if (backend_pread (backend, buf, count, offset, 0, &err) == -1)
       return err;
     break;
 
   case NBD_CMD_WRITE:
     if (flags & NBD_CMD_FLAG_FUA)
       f |= NBDKIT_FLAG_FUA;
-    if (backend_pwrite (backend, conn, buf, count, offset, f, &err) == -1)
+    if (backend_pwrite (backend, buf, count, offset, f, &err) == -1)
       return err;
     break;
 
   case NBD_CMD_FLUSH:
-    if (backend_flush (backend, conn, 0, &err) == -1)
+    if (backend_flush (backend, 0, &err) == -1)
       return err;
     break;
 
   case NBD_CMD_TRIM:
     if (flags & NBD_CMD_FLAG_FUA)
       f |= NBDKIT_FLAG_FUA;
-    if (backend_trim (backend, conn, count, offset, f, &err) == -1)
+    if (backend_trim (backend, count, offset, f, &err) == -1)
       return err;
     break;
 
   case NBD_CMD_CACHE:
-    if (backend_cache (backend, conn, count, offset, 0, &err) == -1)
+    if (backend_cache (backend, count, offset, 0, &err) == -1)
       return err;
     break;
 
@@ -273,14 +273,14 @@ handle_request (struct connection *conn,
       f |= NBDKIT_FLAG_FUA;
     if (flags & NBD_CMD_FLAG_FAST_ZERO)
       f |= NBDKIT_FLAG_FAST_ZERO;
-    if (backend_zero (backend, conn, count, offset, f, &err) == -1)
+    if (backend_zero (backend, count, offset, f, &err) == -1)
       return err;
     break;
 
   case NBD_CMD_BLOCK_STATUS:
     if (flags & NBD_CMD_FLAG_REQ_ONE)
       f |= NBDKIT_FLAG_REQ_ONE;
-    if (backend_extents (backend, conn, count, offset, f,
+    if (backend_extents (backend, count, offset, f,
                          extents, &err) == -1)
       return err;
     break;
@@ -361,11 +361,11 @@ nbd_errno (int error, uint16_t flags)
 }
 
 static int
-send_simple_reply (struct connection *conn,
-                   uint64_t handle, uint16_t cmd, uint16_t flags,
+send_simple_reply (uint64_t handle, uint16_t cmd, uint16_t flags,
                    const char *buf, uint32_t count,
                    uint32_t error)
 {
+  GET_CONN;
   ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&conn->write_lock);
   struct nbd_simple_reply reply;
   int r;
@@ -375,18 +375,18 @@ send_simple_reply (struct connection *conn,
   reply.handle = handle;
   reply.error = htobe32 (nbd_errno (error, flags));
 
-  r = conn->send (conn, &reply, sizeof reply, f);
+  r = conn->send (&reply, sizeof reply, f);
   if (r == -1) {
     nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
-    return connection_set_status (conn, -1);
+    return connection_set_status (-1);
   }
 
   /* Send the read data buffer. */
   if (cmd == NBD_CMD_READ && !error) {
-    r = conn->send (conn, buf, count, 0);
+    r = conn->send (buf, count, 0);
     if (r == -1) {
       nbdkit_error ("write data: %s: %m", name_of_nbd_cmd (cmd));
-      return connection_set_status (conn, -1);
+      return connection_set_status (-1);
     }
   }
 
@@ -394,10 +394,10 @@ send_simple_reply (struct connection *conn,
 }
 
 static int
-send_structured_reply_read (struct connection *conn,
-                            uint64_t handle, uint16_t cmd,
+send_structured_reply_read (uint64_t handle, uint16_t cmd,
                             const char *buf, uint32_t count, uint64_t offset)
 {
+  GET_CONN;
   /* Once we are really using structured replies and sending data back
    * in chunks, we'll be able to grab the write lock for each chunk,
    * allowing other threads to interleave replies.  As we're not doing
@@ -416,24 +416,24 @@ send_structured_reply_read (struct connection *conn,
   reply.type = htobe16 (NBD_REPLY_TYPE_OFFSET_DATA);
   reply.length = htobe32 (count + sizeof offset_data);
 
-  r = conn->send (conn, &reply, sizeof reply, SEND_MORE);
+  r = conn->send (&reply, sizeof reply, SEND_MORE);
   if (r == -1) {
     nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
-    return connection_set_status (conn, -1);
+    return connection_set_status (-1);
   }
 
   /* Send the offset + read data buffer. */
   offset_data.offset = htobe64 (offset);
-  r = conn->send (conn, &offset_data, sizeof offset_data, SEND_MORE);
+  r = conn->send (&offset_data, sizeof offset_data, SEND_MORE);
   if (r == -1) {
     nbdkit_error ("write data: %s: %m", name_of_nbd_cmd (cmd));
-    return connection_set_status (conn, -1);
+    return connection_set_status (-1);
   }
 
-  r = conn->send (conn, buf, count, 0);
+  r = conn->send (buf, count, 0);
   if (r == -1) {
     nbdkit_error ("write data: %s: %m", name_of_nbd_cmd (cmd));
-    return connection_set_status (conn, -1);
+    return connection_set_status (-1);
   }
 
   return 1;                     /* command processed ok */
@@ -522,12 +522,12 @@ extents_to_block_descriptors (struct nbdkit_extents *extents,
 }
 
 static int
-send_structured_reply_block_status (struct connection *conn,
-                                    uint64_t handle,
+send_structured_reply_block_status (uint64_t handle,
                                     uint16_t cmd, uint16_t flags,
                                     uint32_t count, uint64_t offset,
                                     struct nbdkit_extents *extents)
 {
+  GET_CONN;
   ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&conn->write_lock);
   struct nbd_structured_reply reply;
   CLEANUP_FREE struct nbd_block_descriptor *blocks = NULL;
@@ -542,7 +542,7 @@ send_structured_reply_block_status (struct connection *conn,
   blocks = extents_to_block_descriptors (extents, flags, count, offset,
                                          &nr_blocks);
   if (blocks == NULL)
-    return connection_set_status (conn, -1);
+    return connection_set_status (-1);
 
   reply.magic = htobe32 (NBD_STRUCTURED_REPLY_MAGIC);
   reply.handle = handle;
@@ -551,27 +551,27 @@ send_structured_reply_block_status (struct connection *conn,
   reply.length = htobe32 (sizeof context_id +
                           nr_blocks * sizeof (struct nbd_block_descriptor));
 
-  r = conn->send (conn, &reply, sizeof reply, SEND_MORE);
+  r = conn->send (&reply, sizeof reply, SEND_MORE);
   if (r == -1) {
     nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
-    return connection_set_status (conn, -1);
+    return connection_set_status (-1);
   }
 
   /* Send the base:allocation context ID. */
   context_id = htobe32 (base_allocation_id);
-  r = conn->send (conn, &context_id, sizeof context_id, SEND_MORE);
+  r = conn->send (&context_id, sizeof context_id, SEND_MORE);
   if (r == -1) {
     nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
-    return connection_set_status (conn, -1);
+    return connection_set_status (-1);
   }
 
   /* Send each block descriptor. */
   for (i = 0; i < nr_blocks; ++i) {
-    r = conn->send (conn, &blocks[i], sizeof blocks[i],
+    r = conn->send (&blocks[i], sizeof blocks[i],
                     i == nr_blocks - 1 ? 0 : SEND_MORE);
     if (r == -1) {
       nbdkit_error ("write reply: %s: %m", name_of_nbd_cmd (cmd));
-      return connection_set_status (conn, -1);
+      return connection_set_status (-1);
     }
   }
 
@@ -579,10 +579,10 @@ send_structured_reply_block_status (struct connection *conn,
 }
 
 static int
-send_structured_reply_error (struct connection *conn,
-                             uint64_t handle, uint16_t cmd, uint16_t flags,
+send_structured_reply_error (uint64_t handle, uint16_t cmd, uint16_t flags,
                              uint32_t error)
 {
+  GET_CONN;
   ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&conn->write_lock);
   struct nbd_structured_reply reply;
   struct nbd_structured_reply_error error_data;
@@ -594,19 +594,19 @@ send_structured_reply_error (struct connection *conn,
   reply.type = htobe16 (NBD_REPLY_TYPE_ERROR);
   reply.length = htobe32 (0 /* no human readable error */ + sizeof error_data);
 
-  r = conn->send (conn, &reply, sizeof reply, SEND_MORE);
+  r = conn->send (&reply, sizeof reply, SEND_MORE);
   if (r == -1) {
     nbdkit_error ("write error reply: %m");
-    return connection_set_status (conn, -1);
+    return connection_set_status (-1);
   }
 
   /* Send the error. */
   error_data.error = htobe32 (nbd_errno (error, flags));
   error_data.len = htobe16 (0);
-  r = conn->send (conn, &error_data, sizeof error_data, 0);
+  r = conn->send (&error_data, sizeof error_data, 0);
   if (r == -1) {
     nbdkit_error ("write data: %s: %m", name_of_nbd_cmd (cmd));
-    return connection_set_status (conn, -1);
+    return connection_set_status (-1);
   }
   /* No human readable error message at the moment. */
 
@@ -614,8 +614,9 @@ send_structured_reply_error (struct connection *conn,
 }
 
 int
-protocol_recv_request_send_reply (struct connection *conn)
+protocol_recv_request_send_reply (void)
 {
+  GET_CONN;
   int r;
   struct nbd_request request;
   uint16_t cmd, flags;
@@ -627,24 +628,24 @@ protocol_recv_request_send_reply (struct connection *conn)
   /* Read the request packet. */
   {
     ACQUIRE_LOCK_FOR_CURRENT_SCOPE (&conn->read_lock);
-    r = connection_get_status (conn);
+    r = connection_get_status ();
     if (r <= 0)
       return r;
-    r = conn->recv (conn, &request, sizeof request);
+    r = conn->recv (&request, sizeof request);
     if (r == -1) {
       nbdkit_error ("read request: %m");
-      return connection_set_status (conn, -1);
+      return connection_set_status (-1);
     }
     if (r == 0) {
       debug ("client closed input socket, closing connection");
-      return connection_set_status (conn, 0); /* disconnect */
+      return connection_set_status (0); /* disconnect */
     }
 
     magic = be32toh (request.magic);
     if (magic != NBD_REQUEST_MAGIC) {
       nbdkit_error ("invalid request: 'magic' field is incorrect (0x%x)",
                     magic);
-      return connection_set_status (conn, -1);
+      return connection_set_status (-1);
     }
 
     flags = be16toh (request.flags);
@@ -655,14 +656,14 @@ protocol_recv_request_send_reply (struct connection *conn)
 
     if (cmd == NBD_CMD_DISC) {
       debug ("client sent %s, closing connection", name_of_nbd_cmd (cmd));
-      return connection_set_status (conn, 0); /* disconnect */
+      return connection_set_status (0); /* disconnect */
     }
 
     /* Validate the request. */
-    if (!validate_request (conn, cmd, flags, offset, count, &error)) {
+    if (!validate_request (cmd, flags, offset, count, &error)) {
       if (cmd == NBD_CMD_WRITE &&
           skip_over_write_buffer (conn->sockin, count) < 0)
-        return connection_set_status (conn, -1);
+        return connection_set_status (-1);
       goto send_reply;
     }
 
@@ -675,14 +676,14 @@ protocol_recv_request_send_reply (struct connection *conn)
         error = ENOMEM;
         if (cmd == NBD_CMD_WRITE &&
             skip_over_write_buffer (conn->sockin, count) < 0)
-          return connection_set_status (conn, -1);
+          return connection_set_status (-1);
         goto send_reply;
       }
     }
 
     /* Allocate the extents list for block status only. */
     if (cmd == NBD_CMD_BLOCK_STATUS) {
-      extents = nbdkit_extents_new (offset, backend_get_size (backend, conn));
+      extents = nbdkit_extents_new (offset, backend_get_size (backend));
       if (extents == NULL) {
         error = ENOMEM;
         goto send_reply;
@@ -691,32 +692,32 @@ protocol_recv_request_send_reply (struct connection *conn)
 
     /* Receive the write data buffer. */
     if (cmd == NBD_CMD_WRITE) {
-      r = conn->recv (conn, buf, count);
+      r = conn->recv (buf, count);
       if (r == 0) {
         errno = EBADMSG;
         r = -1;
       }
       if (r == -1) {
         nbdkit_error ("read data: %s: %m", name_of_nbd_cmd (cmd));
-        return connection_set_status (conn, -1);
+        return connection_set_status (-1);
       }
     }
   }
 
   /* Perform the request.  Only this part happens inside the request lock. */
-  if (quit || !connection_get_status (conn)) {
+  if (quit || !connection_get_status ()) {
     error = ESHUTDOWN;
   }
   else {
-    lock_request (conn);
-    error = handle_request (conn, cmd, flags, offset, count, buf, extents);
+    lock_request ();
+    error = handle_request (cmd, flags, offset, count, buf, extents);
     assert ((int) error >= 0);
-    unlock_request (conn);
+    unlock_request ();
   }
 
   /* Send the reply packet. */
  send_reply:
-  if (connection_get_status (conn) < 0)
+  if (connection_get_status () < 0)
     return -1;
 
   if (error != 0) {
@@ -738,19 +739,19 @@ protocol_recv_request_send_reply (struct connection *conn)
       (cmd == NBD_CMD_READ || cmd == NBD_CMD_BLOCK_STATUS)) {
     if (!error) {
       if (cmd == NBD_CMD_READ)
-        return send_structured_reply_read (conn, request.handle, cmd,
+        return send_structured_reply_read (request.handle, cmd,
                                            buf, count, offset);
       else /* NBD_CMD_BLOCK_STATUS */
-        return send_structured_reply_block_status (conn, request.handle,
+        return send_structured_reply_block_status (request.handle,
                                                    cmd, flags,
                                                    count, offset,
                                                    extents);
     }
     else
-      return send_structured_reply_error (conn, request.handle, cmd, flags,
+      return send_structured_reply_error (request.handle, cmd, flags,
                                           error);
   }
   else
-    return send_simple_reply (conn, request.handle, cmd, flags, buf, count,
+    return send_simple_reply (request.handle, cmd, flags, buf, count,
                               error);
 }
diff --git a/server/public.c b/server/public.c
index 418945fe..3fd11253 100644
--- a/server/public.c
+++ b/server/public.c
@@ -562,7 +562,7 @@ nbdkit_nanosleep (unsigned sec, unsigned nsec)
    * event, we know the connection should be shutting down.
    */
   assert (quit ||
-          (conn && conn->nworkers > 0 && connection_get_status (conn) < 1) ||
+          (conn && conn->nworkers > 0 && connection_get_status () < 1) ||
           (conn && (fds[2].revents & (POLLRDHUP | POLLHUP | POLLERR))));
   nbdkit_error ("aborting sleep to shut down");
   errno = ESHUTDOWN;
diff --git a/server/test-public.c b/server/test-public.c
index 4a7eb173..fe347d44 100644
--- a/server/test-public.c
+++ b/server/test-public.c
@@ -62,7 +62,7 @@ threadlocal_get_conn (void)
   abort ();
 }
 
-int connection_get_status (struct connection *conn)
+int connection_get_status (void)
 {
   abort ();
 }
-- 
2.25.0




More information about the Libguestfs mailing list