rxrpc: Create a procfile to display outstanding client conn bundles
authorDavid Howells <dhowells@redhat.com>
Thu, 26 Oct 2023 21:53:02 +0000 (22:53 +0100)
committerDavid Howells <dhowells@redhat.com>
Sun, 24 Dec 2023 15:22:56 +0000 (15:22 +0000)
Create /proc/net/rxrpc/bundles to display outstanding rxrpc client
connection bundles.

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

net/rxrpc/ar-internal.h
net/rxrpc/conn_client.c
net/rxrpc/net_ns.c
net/rxrpc/proc.c

index 8eea7a4..2f8b39a 100644 (file)
@@ -68,6 +68,7 @@ struct rxrpc_net {
        atomic_t                nr_calls;       /* Count of allocated calls */
 
        atomic_t                nr_conns;
+       struct list_head        bundle_proc_list; /* List of bundles for proc */
        struct list_head        conn_proc_list; /* List of conns in this namespace for proc */
        struct list_head        service_conns;  /* Service conns in this namespace */
        rwlock_t                conn_lock;      /* Lock for ->conn_proc_list, ->service_conns */
@@ -432,6 +433,7 @@ struct rxrpc_bundle {
        struct rxrpc_local      *local;         /* Representation of local endpoint */
        struct rxrpc_peer       *peer;          /* Remote endpoint */
        struct key              *key;           /* Security details */
+       struct list_head        proc_link;      /* Link in net->bundle_proc_list */
        const struct rxrpc_security *security;  /* applied security module */
        refcount_t              ref;
        atomic_t                active;         /* Number of active users */
@@ -445,6 +447,7 @@ struct rxrpc_bundle {
        struct rb_node          local_node;     /* Node in local->client_conns */
        struct list_head        waiting_calls;  /* Calls waiting for channels */
        unsigned long           avail_chans;    /* Mask of available channels */
+       unsigned int            conn_ids[4];    /* Connection IDs. */
        struct rxrpc_connection *conns[4];      /* The connections in the bundle (max 4) */
 };
 
@@ -1167,6 +1170,7 @@ void rxrpc_put_peer(struct rxrpc_peer *, enum rxrpc_peer_trace);
  */
 extern const struct seq_operations rxrpc_call_seq_ops;
 extern const struct seq_operations rxrpc_connection_seq_ops;
+extern const struct seq_operations rxrpc_bundle_seq_ops;
 extern const struct seq_operations rxrpc_peer_seq_ops;
 extern const struct seq_operations rxrpc_local_seq_ops;
 
index 1d95f8b..3b9b267 100644 (file)
@@ -91,6 +91,10 @@ static struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_call *call,
                atomic_set(&bundle->active, 1);
                INIT_LIST_HEAD(&bundle->waiting_calls);
                trace_rxrpc_bundle(bundle->debug_id, 1, rxrpc_bundle_new);
+
+               write_lock(&bundle->local->rxnet->conn_lock);
+               list_add_tail(&bundle->proc_link, &bundle->local->rxnet->bundle_proc_list);
+               write_unlock(&bundle->local->rxnet->conn_lock);
        }
        return bundle;
 }
@@ -109,6 +113,9 @@ static void rxrpc_free_bundle(struct rxrpc_bundle *bundle)
 {
        trace_rxrpc_bundle(bundle->debug_id, refcount_read(&bundle->ref),
                           rxrpc_bundle_free);
+       write_lock(&bundle->local->rxnet->conn_lock);
+       list_del(&bundle->proc_link);
+       write_unlock(&bundle->local->rxnet->conn_lock);
        rxrpc_put_peer(bundle->peer, rxrpc_peer_put_bundle);
        key_put(bundle->key);
        kfree(bundle);
@@ -338,6 +345,7 @@ static bool rxrpc_add_conn_to_bundle(struct rxrpc_bundle *bundle,
        old = bundle->conns[slot];
        if (old) {
                bundle->conns[slot] = NULL;
+               bundle->conn_ids[slot] = 0;
                trace_rxrpc_client(old, -1, rxrpc_client_replace);
                rxrpc_put_connection(old, rxrpc_conn_put_noreuse);
        }
@@ -351,6 +359,7 @@ static bool rxrpc_add_conn_to_bundle(struct rxrpc_bundle *bundle,
        rxrpc_activate_bundle(bundle);
        conn->bundle_shift = shift;
        bundle->conns[slot] = conn;
+       bundle->conn_ids[slot] = conn->debug_id;
        for (i = 0; i < RXRPC_MAXCALLS; i++)
                set_bit(shift + i, &bundle->avail_chans);
        return true;
@@ -671,6 +680,7 @@ static void rxrpc_unbundle_conn(struct rxrpc_connection *conn)
        if (bundle->conns[bindex] == conn) {
                _debug("clear slot %u", bindex);
                bundle->conns[bindex] = NULL;
+               bundle->conn_ids[bindex] = 0;
                for (i = 0; i < RXRPC_MAXCALLS; i++)
                        clear_bit(conn->bundle_shift + i, &bundle->avail_chans);
                rxrpc_put_client_connection_id(bundle->local, conn);
index a0319c0..a4c135d 100644 (file)
@@ -45,6 +45,7 @@ static __net_init int rxrpc_init_net(struct net *net)
        atomic_set(&rxnet->nr_calls, 1);
 
        atomic_set(&rxnet->nr_conns, 1);
+       INIT_LIST_HEAD(&rxnet->bundle_proc_list);
        INIT_LIST_HEAD(&rxnet->conn_proc_list);
        INIT_LIST_HEAD(&rxnet->service_conns);
        rwlock_init(&rxnet->conn_lock);
@@ -78,6 +79,9 @@ static __net_init int rxrpc_init_net(struct net *net)
        proc_create_net("conns", 0444, rxnet->proc_net,
                        &rxrpc_connection_seq_ops,
                        sizeof(struct seq_net_private));
+       proc_create_net("bundles", 0444, rxnet->proc_net,
+                       &rxrpc_bundle_seq_ops,
+                       sizeof(struct seq_net_private));
        proc_create_net("peers", 0444, rxnet->proc_net,
                        &rxrpc_peer_seq_ops,
                        sizeof(struct seq_net_private));
index 682636d..6c86cbb 100644 (file)
@@ -198,6 +198,82 @@ const struct seq_operations rxrpc_connection_seq_ops = {
        .show   = rxrpc_connection_seq_show,
 };
 
+/*
+ * generate a list of extant virtual bundles in /proc/net/rxrpc/bundles
+ */
+static void *rxrpc_bundle_seq_start(struct seq_file *seq, loff_t *_pos)
+       __acquires(rxnet->conn_lock)
+{
+       struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+
+       read_lock(&rxnet->conn_lock);
+       return seq_list_start_head(&rxnet->bundle_proc_list, *_pos);
+}
+
+static void *rxrpc_bundle_seq_next(struct seq_file *seq, void *v,
+                                      loff_t *pos)
+{
+       struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+
+       return seq_list_next(v, &rxnet->bundle_proc_list, pos);
+}
+
+static void rxrpc_bundle_seq_stop(struct seq_file *seq, void *v)
+       __releases(rxnet->conn_lock)
+{
+       struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+
+       read_unlock(&rxnet->conn_lock);
+}
+
+static int rxrpc_bundle_seq_show(struct seq_file *seq, void *v)
+{
+       struct rxrpc_bundle *bundle;
+       struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
+       char lbuff[50], rbuff[50];
+
+       if (v == &rxnet->bundle_proc_list) {
+               seq_puts(seq,
+                        "Proto Local                                          "
+                        " Remote                                         "
+                        " SvID Ref Act Flg Key      |"
+                        " Bundle   Conn_0   Conn_1   Conn_2   Conn_3\n"
+                        );
+               return 0;
+       }
+
+       bundle = list_entry(v, struct rxrpc_bundle, proc_link);
+
+       sprintf(lbuff, "%pISpc", &bundle->local->srx.transport);
+       sprintf(rbuff, "%pISpc", &bundle->peer->srx.transport);
+       seq_printf(seq,
+                  "UDP   %-47.47s %-47.47s %4x %3u %3d"
+                  " %c%c%c %08x | %08x %08x %08x %08x %08x\n",
+                  lbuff,
+                  rbuff,
+                  bundle->service_id,
+                  refcount_read(&bundle->ref),
+                  atomic_read(&bundle->active),
+                  bundle->try_upgrade ? 'U' : '-',
+                  bundle->exclusive ? 'e' : '-',
+                  bundle->upgrade ? 'u' : '-',
+                  key_serial(bundle->key),
+                  bundle->debug_id,
+                  bundle->conn_ids[0],
+                  bundle->conn_ids[1],
+                  bundle->conn_ids[2],
+                  bundle->conn_ids[3]);
+
+       return 0;
+}
+
+const struct seq_operations rxrpc_bundle_seq_ops = {
+       .start  = rxrpc_bundle_seq_start,
+       .next   = rxrpc_bundle_seq_next,
+       .stop   = rxrpc_bundle_seq_stop,
+       .show   = rxrpc_bundle_seq_show,
+};
+
 /*
  * generate a list of extant virtual peers in /proc/net/rxrpc/peers
  */