afs: Add a tracepoint for struct afs_addr_list
authorDavid Howells <dhowells@redhat.com>
Thu, 19 Oct 2023 12:59:03 +0000 (13:59 +0100)
committerDavid Howells <dhowells@redhat.com>
Sun, 24 Dec 2023 15:22:54 +0000 (15:22 +0000)
Add a tracepoint to track the lifetime of the afs_addr_list struct.

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

fs/afs/addr_list.c
fs/afs/fs_probe.c
fs/afs/internal.h
fs/afs/rotate.c
fs/afs/rxrpc.c
fs/afs/server.c
fs/afs/vl_list.c
fs/afs/vl_rotate.c
fs/afs/vlclient.c
include/trace/events/afs.h

index a1f3c995e328c2da32f84a8f61fef80dc8c2c233..41ef0c8792394f7b9b005ae4151661132c6b2d0e 100644 (file)
@@ -20,17 +20,39 @@ static void afs_free_addrlist(struct rcu_head *rcu)
 
        for (i = 0; i < alist->nr_addrs; i++)
                rxrpc_kernel_put_peer(alist->addrs[i].peer);
+       trace_afs_alist(alist->debug_id, refcount_read(&alist->usage), afs_alist_trace_free);
+       kfree(alist);
 }
 
 /*
  * Release an address list.
  */
-void afs_put_addrlist(struct afs_addr_list *alist)
+void afs_put_addrlist(struct afs_addr_list *alist, enum afs_alist_trace reason)
 {
-       if (alist && refcount_dec_and_test(&alist->usage))
+       unsigned int debug_id;
+       bool dead;
+       int r;
+
+       if (!alist)
+               return;
+       debug_id = alist->debug_id;
+       dead = __refcount_dec_and_test(&alist->usage, &r);
+       trace_afs_alist(debug_id, r - 1, reason);
+       if (dead)
                call_rcu(&alist->rcu, afs_free_addrlist);
 }
 
+struct afs_addr_list *afs_get_addrlist(struct afs_addr_list *alist, enum afs_alist_trace reason)
+{
+       int r;
+
+       if (alist) {
+               __refcount_inc(&alist->usage, &r);
+               trace_afs_alist(alist->debug_id, r + 1, reason);
+       }
+       return alist;
+}
+
 /*
  * Allocate an address list.
  */
@@ -38,6 +60,7 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr, u16 service_id)
 {
        struct afs_addr_list *alist;
        unsigned int i;
+       static atomic_t debug_id;
 
        _enter("%u,%u", nr, service_id);
 
@@ -50,9 +73,11 @@ struct afs_addr_list *afs_alloc_addrlist(unsigned int nr, u16 service_id)
 
        refcount_set(&alist->usage, 1);
        alist->max_addrs = nr;
+       alist->debug_id = atomic_inc_return(&debug_id);
 
        for (i = 0; i < nr; i++)
                alist->addrs[i].service_id = service_id;
+       trace_afs_alist(alist->debug_id, 1, afs_alist_trace_alloc);
        return alist;
 }
 
@@ -217,7 +242,7 @@ bad_address:
               problem, p - text, (int)len, (int)len, text);
        ret = -EINVAL;
 error:
-       afs_put_addrlist(alist);
+       afs_put_addrlist(alist, afs_alist_trace_put_parse_error);
 error_vl:
        afs_put_vlserverlist(net, vllist);
        return ERR_PTR(ret);
@@ -403,7 +428,7 @@ void afs_end_cursor(struct afs_addr_cursor *ac)
                    ac->index != alist->preferred &&
                    test_bit(ac->alist->preferred, &ac->tried))
                        WRITE_ONCE(alist->preferred, ac->index);
-               afs_put_addrlist(alist);
+               afs_put_addrlist(alist, afs_alist_trace_put_end_cursor);
                ac->alist = NULL;
        }
 }
index fbb91ad775b9ee774a843dbc998f7f56e31dcf2d..18891492c0b4bfaf30635148d665ab9782528aee 100644 (file)
@@ -205,7 +205,7 @@ void afs_fs_probe_fileserver(struct afs_net *net, struct afs_server *server,
        read_lock(&server->fs_lock);
        ac.alist = rcu_dereference_protected(server->addresses,
                                             lockdep_is_held(&server->fs_lock));
-       afs_get_addrlist(ac.alist);
+       afs_get_addrlist(ac.alist, afs_alist_trace_get_probe);
        read_unlock(&server->fs_lock);
 
        server->probed_at = jiffies;
@@ -226,7 +226,7 @@ void afs_fs_probe_fileserver(struct afs_net *net, struct afs_server *server,
                        afs_fs_probe_not_done(net, server, &ac);
        }
 
-       afs_put_addrlist(ac.alist);
+       afs_put_addrlist(ac.alist, afs_alist_trace_put_probe);
 }
 
 /*
index d67c75d4d2bdd2a1f2ea85bf4463cd1826bcb22d..d00fda99f401a00988299360925c15a54c2d8b83 100644 (file)
@@ -85,6 +85,7 @@ struct afs_addr_list {
        struct rcu_head         rcu;
        refcount_t              usage;
        u32                     version;        /* Version */
+       unsigned int            debug_id;
        unsigned char           max_addrs;
        unsigned char           nr_addrs;
        unsigned char           preferred;      /* Preferred address */
@@ -969,14 +970,9 @@ static inline bool afs_is_folio_dirty_mmapped(unsigned long priv)
 /*
  * addr_list.c
  */
-static inline struct afs_addr_list *afs_get_addrlist(struct afs_addr_list *alist)
-{
-       if (alist)
-               refcount_inc(&alist->usage);
-       return alist;
-}
+struct afs_addr_list *afs_get_addrlist(struct afs_addr_list *alist, enum afs_alist_trace reason);
 extern struct afs_addr_list *afs_alloc_addrlist(unsigned int nr, u16 service_id);
-extern void afs_put_addrlist(struct afs_addr_list *);
+extern void afs_put_addrlist(struct afs_addr_list *alist, enum afs_alist_trace reason);
 extern struct afs_vlserver_list *afs_parse_text_addrs(struct afs_net *,
                                                      const char *, size_t, char,
                                                      unsigned short, unsigned short);
index a778d53681fe0e177f3bb443c73b6923fbdc60b6..fa2ba45a5941f9aa25497047f8001191a690651f 100644 (file)
@@ -484,7 +484,7 @@ selected_server:
        read_lock(&server->fs_lock);
        alist = rcu_dereference_protected(server->addresses,
                                          lockdep_is_held(&server->fs_lock));
-       afs_get_addrlist(alist);
+       afs_get_addrlist(alist, afs_alist_trace_get_fsrotate_set);
        read_unlock(&server->fs_lock);
 
 retry_server:
@@ -493,7 +493,7 @@ retry_server:
        if (!op->ac.alist)
                op->ac.alist = alist;
        else
-               afs_put_addrlist(alist);
+               afs_put_addrlist(alist, afs_alist_trace_put_retry_server);
 
        op->ac.index = -1;
 
index 0b3e2f20b0e082d54c868bf866d9ce0cc7f321ee..5bbf5a23af8551400aaa7bc59ce0dc984e4a4d15 100644 (file)
@@ -187,7 +187,7 @@ void afs_put_call(struct afs_call *call)
                        call->type->destructor(call);
 
                afs_unuse_server_notime(call->net, call->server, afs_server_trace_put_call);
-               afs_put_addrlist(call->alist);
+               afs_put_addrlist(call->alist, afs_alist_trace_put_call);
                kfree(call->request);
 
                trace_afs_call(call->debug_id, afs_call_trace_free, 0, o,
@@ -315,7 +315,7 @@ void afs_make_call(struct afs_addr_cursor *ac, struct afs_call *call, gfp_t gfp)
               atomic_read(&call->net->nr_outstanding_calls));
 
        call->addr_ix = ac->index;
-       call->alist = afs_get_addrlist(ac->alist);
+       call->alist = afs_get_addrlist(ac->alist, afs_alist_trace_get_make_call);
 
        /* Work out the length we're going to transmit.  This is awkward for
         * calls such as FS.StoreData where there's an extra injection of data
index f7791ef13618ab53ebfa21e238882e07925e16c5..6c13f00b10d826e1ba90ea533e9d2d62bdf0518c 100644 (file)
@@ -275,13 +275,13 @@ struct afs_server *afs_lookup_server(struct afs_cell *cell, struct key *key,
 
        candidate = afs_alloc_server(cell, uuid, alist);
        if (!candidate) {
-               afs_put_addrlist(alist);
+               afs_put_addrlist(alist, afs_alist_trace_put_server_oom);
                return ERR_PTR(-ENOMEM);
        }
 
        server = afs_install_server(cell, candidate);
        if (server != candidate) {
-               afs_put_addrlist(alist);
+               afs_put_addrlist(alist, afs_alist_trace_put_server_dup);
                kfree(candidate);
        } else {
                /* Immediately dispatch an asynchronous probe to each interface
@@ -421,7 +421,8 @@ static void afs_server_rcu(struct rcu_head *rcu)
 
        trace_afs_server(server->debug_id, refcount_read(&server->ref),
                         atomic_read(&server->active), afs_server_trace_free);
-       afs_put_addrlist(rcu_access_pointer(server->addresses));
+       afs_put_addrlist(rcu_access_pointer(server->addresses),
+                        afs_alist_trace_put_server);
        kfree(server);
 }
 
@@ -643,7 +644,7 @@ static noinline bool afs_update_server_record(struct afs_operation *op,
                write_unlock(&server->fs_lock);
        }
 
-       afs_put_addrlist(discard);
+       afs_put_addrlist(discard, afs_alist_trace_put_server_update);
        _leave(" = t");
        return true;
 }
index ba89140eee9e9a4afc1a48e4d5b6a63b19cb9ce2..3a2875933261d6bdb521040f3e0622b717daacf1 100644 (file)
@@ -33,7 +33,8 @@ static void afs_vlserver_rcu(struct rcu_head *rcu)
 {
        struct afs_vlserver *vlserver = container_of(rcu, struct afs_vlserver, rcu);
 
-       afs_put_addrlist(rcu_access_pointer(vlserver->addresses));
+       afs_put_addrlist(rcu_access_pointer(vlserver->addresses),
+                        afs_alist_trace_put_vlserver);
        kfree_rcu(vlserver, rcu);
 }
 
@@ -145,7 +146,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(struct afs_net *net,
 
 error:
        *_b = b;
-       afs_put_addrlist(alist);
+       afs_put_addrlist(alist, afs_alist_trace_put_parse_error);
        return ERR_PTR(ret);
 }
 
@@ -260,7 +261,7 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
 
                if (vllist->nr_servers >= nr_servers) {
                        _debug("skip %u >= %u", vllist->nr_servers, nr_servers);
-                       afs_put_addrlist(addrs);
+                       afs_put_addrlist(addrs, afs_alist_trace_put_parse_empty);
                        afs_put_vlserver(cell->net, server);
                        continue;
                }
@@ -269,7 +270,7 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
                addrs->status = bs.status;
 
                if (addrs->nr_addrs == 0) {
-                       afs_put_addrlist(addrs);
+                       afs_put_addrlist(addrs, afs_alist_trace_put_parse_empty);
                        if (!rcu_access_pointer(server->addresses)) {
                                afs_put_vlserver(cell->net, server);
                                continue;
@@ -281,7 +282,7 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell,
                        old = rcu_replace_pointer(server->addresses, old,
                                                  lockdep_is_held(&server->lock));
                        write_unlock(&server->lock);
-                       afs_put_addrlist(old);
+                       afs_put_addrlist(old, afs_alist_trace_put_vlserver_old);
                }
 
 
index 7ae73418697dfa6f1b137fe9ec73740a1f9f066c..e8fbbeb551bbba352f517a27acd1b641f739c68a 100644 (file)
@@ -231,16 +231,11 @@ selected_server:
        read_lock(&vlserver->lock);
        alist = rcu_dereference_protected(vlserver->addresses,
                                          lockdep_is_held(&vlserver->lock));
-       afs_get_addrlist(alist);
+       afs_get_addrlist(alist, afs_alist_trace_get_vlrotate_set);
        read_unlock(&vlserver->lock);
 
        memset(&vc->ac, 0, sizeof(vc->ac));
-
-       if (!vc->ac.alist)
-               vc->ac.alist = alist;
-       else
-               afs_put_addrlist(alist);
-
+       vc->ac.alist = alist;
        vc->ac.index = -1;
 
 iterate_address:
index db7e94584e874643d07ecf897bfc00d5c843fd31..8dea7b56b75a890249cdf01d40ce71c7484e6089 100644 (file)
@@ -314,7 +314,7 @@ struct afs_addr_list *afs_vl_get_addrs_u(struct afs_vl_cursor *vc,
        alist                   = call->ret_alist;
        afs_put_call(call);
        if (vc->call_error) {
-               afs_put_addrlist(alist);
+               afs_put_addrlist(alist, afs_alist_trace_put_getaddru);
                return ERR_PTR(vc->call_error);
        }
        return alist;
@@ -668,7 +668,7 @@ struct afs_addr_list *afs_yfsvl_get_endpoints(struct afs_vl_cursor *vc,
        alist                   = call->ret_alist;
        afs_put_call(call);
        if (vc->call_error) {
-               afs_put_addrlist(alist);
+               afs_put_addrlist(alist, afs_alist_trace_put_getaddru);
                return ERR_PTR(vc->call_error);
        }
        return alist;
index 597677acc6b17680b5a4bbb0a7eb79b43fddcd50..ed91666ca4ccd14ba7fdf4ae86cec2c363c7a1e6 100644 (file)
@@ -202,6 +202,27 @@ enum yfs_cm_operation {
        EM(afs_cell_trace_use_sbi,              "USE sbi   ") \
        E_(afs_cell_trace_wait,                 "WAIT      ")
 
+#define afs_alist_traces \
+       EM(afs_alist_trace_alloc,               "ALLOC     ") \
+       EM(afs_alist_trace_get_fsrotate_set,    "GET fs-rot") \
+       EM(afs_alist_trace_get_make_call,       "GET mkcall") \
+       EM(afs_alist_trace_get_probe,           "GET probe ") \
+       EM(afs_alist_trace_get_vlrotate_set,    "GET vl-rot") \
+       EM(afs_alist_trace_put_call,            "PUT call  ") \
+       EM(afs_alist_trace_put_end_cursor,      "PUT endcur") \
+       EM(afs_alist_trace_put_getaddru,        "PUT GtAdrU") \
+       EM(afs_alist_trace_put_parse_empty,     "PUT p-empt") \
+       EM(afs_alist_trace_put_parse_error,     "PUT p-err ") \
+       EM(afs_alist_trace_put_probe,           "PUT probe ") \
+       EM(afs_alist_trace_put_retry_server,    "PUT retry ") \
+       EM(afs_alist_trace_put_server,          "PUT server") \
+       EM(afs_alist_trace_put_server_dup,      "PUT sv-dup") \
+       EM(afs_alist_trace_put_server_oom,      "PUT sv-oom") \
+       EM(afs_alist_trace_put_server_update,   "PUT sv-upd") \
+       EM(afs_alist_trace_put_vlserver,        "PUT vlsrvr") \
+       EM(afs_alist_trace_put_vlserver_old,    "PUT vs-old") \
+       E_(afs_alist_trace_free,                "FREE      ")
+
 #define afs_fs_operations \
        EM(afs_FS_FetchData,                    "FS.FetchData") \
        EM(afs_FS_FetchStatus,                  "FS.FetchStatus") \
@@ -420,6 +441,7 @@ enum yfs_cm_operation {
 #define EM(a, b) a,
 #define E_(a, b) a
 
+enum afs_alist_trace           { afs_alist_traces } __mode(byte);
 enum afs_call_trace            { afs_call_traces } __mode(byte);
 enum afs_cb_break_reason       { afs_cb_break_reasons } __mode(byte);
 enum afs_cell_trace            { afs_cell_traces } __mode(byte);
@@ -443,6 +465,7 @@ enum afs_volume_trace               { afs_volume_traces } __mode(byte);
 #define EM(a, b) TRACE_DEFINE_ENUM(a);
 #define E_(a, b) TRACE_DEFINE_ENUM(a);
 
+afs_alist_traces;
 afs_call_traces;
 afs_server_traces;
 afs_cell_traces;
@@ -1330,6 +1353,30 @@ TRACE_EVENT(afs_cell,
                      __entry->active)
            );
 
+TRACE_EVENT(afs_alist,
+           TP_PROTO(unsigned int alist_debug_id, int ref, enum afs_alist_trace reason),
+
+           TP_ARGS(alist_debug_id, ref, reason),
+
+           TP_STRUCT__entry(
+                   __field(unsigned int,               alist)
+                   __field(int,                        ref)
+                   __field(int,                        active)
+                   __field(int,                        reason)
+                            ),
+
+           TP_fast_assign(
+                   __entry->alist = alist_debug_id;
+                   __entry->ref = ref;
+                   __entry->reason = reason;
+                          ),
+
+           TP_printk("AL=%08x %s r=%d",
+                     __entry->alist,
+                     __print_symbolic(__entry->reason, afs_alist_traces),
+                     __entry->ref)
+           );
+
 #endif /* _TRACE_AFS_H */
 
 /* This part must be outside protection */