rxrpc: Make the set of connection IDs per local endpoint
authorDavid Howells <dhowells@redhat.com>
Thu, 20 Oct 2022 21:58:56 +0000 (22:58 +0100)
committerDavid Howells <dhowells@redhat.com>
Fri, 6 Jan 2023 09:43:32 +0000 (09:43 +0000)
Make the set of connection IDs per local endpoint so that endpoints don't
cause each other's connections to get dismissed.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org

net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/conn_client.c
net/rxrpc/conn_object.c
net/rxrpc/local_object.c

index 7ea576f..6f6a6b7 100644 (file)
@@ -957,16 +957,9 @@ static const struct net_proto_family rxrpc_family_ops = {
 static int __init af_rxrpc_init(void)
 {
        int ret = -1;
-       unsigned int tmp;
 
        BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof_field(struct sk_buff, cb));
 
-       get_random_bytes(&tmp, sizeof(tmp));
-       tmp &= 0x3fffffff;
-       if (tmp == 0)
-               tmp = 1;
-       idr_set_cursor(&rxrpc_client_conn_ids, tmp);
-
        ret = -ENOMEM;
        rxrpc_call_jar = kmem_cache_create(
                "rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
@@ -1062,7 +1055,6 @@ static void __exit af_rxrpc_exit(void)
         * are released.
         */
        rcu_barrier();
-       rxrpc_destroy_client_conn_ids();
 
        destroy_workqueue(rxrpc_workqueue);
        rxrpc_exit_security();
index 120ce3c..e9ab061 100644 (file)
@@ -300,6 +300,8 @@ struct rxrpc_local {
        int                     debug_id;       /* debug ID for printks */
        bool                    dead;
        bool                    service_closed; /* Service socket closed */
+       struct idr              conn_ids;       /* List of connection IDs */
+       spinlock_t              conn_lock;      /* Lock for client connection pool */
        struct sockaddr_rxrpc   srx;            /* local address */
 };
 
@@ -887,9 +889,8 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
 extern unsigned int rxrpc_reap_client_connections;
 extern unsigned long rxrpc_conn_idle_client_expiry;
 extern unsigned long rxrpc_conn_idle_client_fast_expiry;
-extern struct idr rxrpc_client_conn_ids;
 
-void rxrpc_destroy_client_conn_ids(void);
+void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local);
 struct rxrpc_bundle *rxrpc_get_bundle(struct rxrpc_bundle *, enum rxrpc_bundle_trace);
 void rxrpc_put_bundle(struct rxrpc_bundle *, enum rxrpc_bundle_trace);
 int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_call *,
index 1edd658..59ce5c0 100644 (file)
@@ -34,12 +34,6 @@ __read_mostly unsigned int rxrpc_reap_client_connections = 900;
 __read_mostly unsigned long rxrpc_conn_idle_client_expiry = 2 * 60 * HZ;
 __read_mostly unsigned long rxrpc_conn_idle_client_fast_expiry = 2 * HZ;
 
-/*
- * We use machine-unique IDs for our client connections.
- */
-DEFINE_IDR(rxrpc_client_conn_ids);
-static DEFINE_SPINLOCK(rxrpc_conn_id_lock);
-
 static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle);
 
 /*
@@ -51,65 +45,65 @@ static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle);
 static int rxrpc_get_client_connection_id(struct rxrpc_connection *conn,
                                          gfp_t gfp)
 {
-       struct rxrpc_net *rxnet = conn->rxnet;
+       struct rxrpc_local *local = conn->local;
        int id;
 
        _enter("");
 
        idr_preload(gfp);
-       spin_lock(&rxrpc_conn_id_lock);
+       spin_lock(&local->conn_lock);
 
-       id = idr_alloc_cyclic(&rxrpc_client_conn_ids, conn,
+       id = idr_alloc_cyclic(&local->conn_ids, conn,
                              1, 0x40000000, GFP_NOWAIT);
        if (id < 0)
                goto error;
 
-       spin_unlock(&rxrpc_conn_id_lock);
+       spin_unlock(&local->conn_lock);
        idr_preload_end();
 
-       conn->proto.epoch = rxnet->epoch;
+       conn->proto.epoch = local->rxnet->epoch;
        conn->proto.cid = id << RXRPC_CIDSHIFT;
        set_bit(RXRPC_CONN_HAS_IDR, &conn->flags);
        _leave(" [CID %x]", conn->proto.cid);
        return 0;
 
 error:
-       spin_unlock(&rxrpc_conn_id_lock);
+       spin_unlock(&local->conn_lock);
        idr_preload_end();
        _leave(" = %d", id);
        return id;
 }
 
 /*
- * Release a connection ID for a client connection from the global pool.
+ * Release a connection ID for a client connection.
  */
-static void rxrpc_put_client_connection_id(struct rxrpc_connection *conn)
+static void rxrpc_put_client_connection_id(struct rxrpc_local *local,
+                                          struct rxrpc_connection *conn)
 {
        if (test_bit(RXRPC_CONN_HAS_IDR, &conn->flags)) {
-               spin_lock(&rxrpc_conn_id_lock);
-               idr_remove(&rxrpc_client_conn_ids,
-                          conn->proto.cid >> RXRPC_CIDSHIFT);
-               spin_unlock(&rxrpc_conn_id_lock);
+               spin_lock(&local->conn_lock);
+               idr_remove(&local->conn_ids, conn->proto.cid >> RXRPC_CIDSHIFT);
+               spin_unlock(&local->conn_lock);
        }
 }
 
 /*
  * Destroy the client connection ID tree.
  */
-void rxrpc_destroy_client_conn_ids(void)
+void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local)
 {
        struct rxrpc_connection *conn;
        int id;
 
-       if (!idr_is_empty(&rxrpc_client_conn_ids)) {
-               idr_for_each_entry(&rxrpc_client_conn_ids, conn, id) {
+       if (!idr_is_empty(&local->conn_ids)) {
+               idr_for_each_entry(&local->conn_ids, conn, id) {
                        pr_err("AF_RXRPC: Leaked client conn %p {%d}\n",
                               conn, refcount_read(&conn->ref));
                }
                BUG();
        }
 
-       idr_destroy(&rxrpc_client_conn_ids);
+       idr_destroy(&local->conn_ids);
 }
 
 /*
@@ -225,7 +219,7 @@ rxrpc_alloc_client_connection(struct rxrpc_bundle *bundle, gfp_t gfp)
        return conn;
 
 error_1:
-       rxrpc_put_client_connection_id(conn);
+       rxrpc_put_client_connection_id(bundle->local, conn);
 error_0:
        kfree(conn);
        _leave(" = %d", ret);
@@ -257,7 +251,7 @@ static bool rxrpc_may_reuse_conn(struct rxrpc_connection *conn)
         * times the maximum number of client conns away from the current
         * allocation point to try and keep the IDs concentrated.
         */
-       id_cursor = idr_get_cursor(&rxrpc_client_conn_ids);
+       id_cursor = idr_get_cursor(&conn->local->conn_ids);
        id = conn->proto.cid >> RXRPC_CIDSHIFT;
        distance = id - id_cursor;
        if (distance < 0)
@@ -982,7 +976,7 @@ void rxrpc_kill_client_conn(struct rxrpc_connection *conn)
        trace_rxrpc_client(conn, -1, rxrpc_client_cleanup);
        atomic_dec(&rxnet->nr_client_conns);
 
-       rxrpc_put_client_connection_id(conn);
+       rxrpc_put_client_connection_id(local, conn);
 }
 
 /*
index 281f59e..2e3f0a2 100644 (file)
@@ -100,10 +100,10 @@ struct rxrpc_connection *rxrpc_find_client_connection_rcu(struct rxrpc_local *lo
 
        _enter(",%x", sp->hdr.cid & RXRPC_CIDMASK);
 
-       /* Look up client connections by connection ID alone as their IDs are
-        * unique for this machine.
+       /* Look up client connections by connection ID alone as their
+        * IDs are unique for this machine.
         */
-       conn = idr_find(&rxrpc_client_conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
+       conn = idr_find(&local->conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
        if (!conn || refcount_read(&conn->ref) == 0) {
                _debug("no conn");
                goto not_found;
index 8ef6cd8..ca8b3ee 100644 (file)
@@ -89,6 +89,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
                                             const struct sockaddr_rxrpc *srx)
 {
        struct rxrpc_local *local;
+       u32 tmp;
 
        local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
        if (local) {
@@ -109,6 +110,14 @@ static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
                local->debug_id = atomic_inc_return(&rxrpc_debug_id);
                memcpy(&local->srx, srx, sizeof(*srx));
                local->srx.srx_service = 0;
+               idr_init(&local->conn_ids);
+               get_random_bytes(&tmp, sizeof(tmp));
+               tmp &= 0x3fffffff;
+               if (tmp == 0)
+                       tmp = 1;
+               idr_set_cursor(&local->conn_ids, tmp);
+               spin_lock_init(&local->conn_lock);
+
                trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, 1);
        }
 
@@ -409,6 +418,7 @@ void rxrpc_destroy_local(struct rxrpc_local *local)
         * local endpoint.
         */
        rxrpc_purge_queue(&local->rx_queue);
+       rxrpc_destroy_client_conn_ids(local);
 }
 
 /*