Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cifs: Add tracing for the cifs_tcon struct refcounting

Add tracing for the refcounting/lifecycle of the cifs_tcon struct, marking
different events with different labels and giving each tcon its own debug
ID so that the tracelines corresponding to individual tcons can be
distinguished. This can be enabled with:

echo 1 >/sys/kernel/debug/tracing/events/cifs/smb3_tcon_ref/enable

Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
cc: Shyam Prasad N <nspmangalore@gmail.com>
cc: linux-cifs@vger.kernel.org
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

David Howells and committed by
Steve French
afc23feb dad80c6b

+143 -26
+2
fs/smb/client/cifsfs.c
··· 739 739 740 740 spin_lock(&cifs_tcp_ses_lock); 741 741 spin_lock(&tcon->tc_lock); 742 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 743 + netfs_trace_tcon_ref_see_umount); 742 744 if ((tcon->tc_count > 1) || (tcon->status == TID_EXITING)) { 743 745 /* we have other mounts to same share or we have 744 746 already tried to umount this and woken up
+1
fs/smb/client/cifsglob.h
··· 1190 1190 */ 1191 1191 struct cifs_tcon { 1192 1192 struct list_head tcon_list; 1193 + int debug_id; /* Debugging for tracing */ 1193 1194 int tc_count; 1194 1195 struct list_head rlist; /* reconnect list */ 1195 1196 spinlock_t tc_lock; /* protect anything here that is not protected */
+4 -5
fs/smb/client/cifsproto.h
··· 303 303 struct TCP_Server_Info *primary_server); 304 304 extern void cifs_put_tcp_session(struct TCP_Server_Info *server, 305 305 int from_reconnect); 306 - extern void cifs_put_tcon(struct cifs_tcon *tcon); 306 + extern void cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace); 307 307 308 308 extern void cifs_release_automount_timer(void); 309 309 ··· 530 530 531 531 extern struct cifs_ses *sesInfoAlloc(void); 532 532 extern void sesInfoFree(struct cifs_ses *); 533 - extern struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled); 534 - extern void tconInfoFree(struct cifs_tcon *); 533 + extern struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled, 534 + enum smb3_tcon_ref_trace trace); 535 + extern void tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace); 535 536 536 537 extern int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, 537 538 __u32 *pexpected_response_sequence_number); ··· 722 721 return options; 723 722 } 724 723 725 - struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon); 726 - void cifs_put_tcon_super(struct super_block *sb); 727 724 int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry); 728 725 729 726 /* Put references of @ses and its children */
+12 -9
fs/smb/client/connect.c
··· 1943 1943 } 1944 1944 1945 1945 /* no need to setup directory caching on IPC share, so pass in false */ 1946 - tcon = tcon_info_alloc(false); 1946 + tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_ipc); 1947 1947 if (tcon == NULL) 1948 1948 return -ENOMEM; 1949 1949 ··· 1960 1960 1961 1961 if (rc) { 1962 1962 cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc); 1963 - tconInfoFree(tcon); 1963 + tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc_fail); 1964 1964 goto out; 1965 1965 } 1966 1966 ··· 2043 2043 * files on session close, as specified in MS-SMB2 3.3.5.6 Receiving an 2044 2044 * SMB2 LOGOFF Request. 2045 2045 */ 2046 - tconInfoFree(tcon); 2046 + tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc); 2047 2047 if (do_logoff) { 2048 2048 xid = get_xid(); 2049 2049 rc = server->ops->logoff(xid, ses); ··· 2432 2432 continue; 2433 2433 } 2434 2434 ++tcon->tc_count; 2435 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 2436 + netfs_trace_tcon_ref_get_find); 2435 2437 spin_unlock(&tcon->tc_lock); 2436 2438 spin_unlock(&cifs_tcp_ses_lock); 2437 2439 return tcon; ··· 2443 2441 } 2444 2442 2445 2443 void 2446 - cifs_put_tcon(struct cifs_tcon *tcon) 2444 + cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace) 2447 2445 { 2448 2446 unsigned int xid; 2449 2447 struct cifs_ses *ses; ··· 2459 2457 cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count); 2460 2458 spin_lock(&cifs_tcp_ses_lock); 2461 2459 spin_lock(&tcon->tc_lock); 2460 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count - 1, trace); 2462 2461 if (--tcon->tc_count > 0) { 2463 2462 spin_unlock(&tcon->tc_lock); 2464 2463 spin_unlock(&cifs_tcp_ses_lock); ··· 2496 2493 _free_xid(xid); 2497 2494 2498 2495 cifs_fscache_release_super_cookie(tcon); 2499 - tconInfoFree(tcon); 2496 + tconInfoFree(tcon, netfs_trace_tcon_ref_free); 2500 2497 cifs_put_smb_ses(ses); 2501 2498 } 2502 2499 ··· 2550 2547 nohandlecache = ctx->nohandlecache; 2551 2548 else 2552 2549 nohandlecache = true; 2553 - tcon = tcon_info_alloc(!nohandlecache); 2550 + tcon = tcon_info_alloc(!nohandlecache, netfs_trace_tcon_ref_new); 2554 2551 if (tcon == NULL) { 2555 2552 rc = -ENOMEM; 2556 2553 goto out_fail; ··· 2740 2737 return tcon; 2741 2738 2742 2739 out_fail: 2743 - tconInfoFree(tcon); 2740 + tconInfoFree(tcon, netfs_trace_tcon_ref_free_fail); 2744 2741 return ERR_PTR(rc); 2745 2742 } 2746 2743 ··· 2757 2754 } 2758 2755 2759 2756 if (!IS_ERR(tlink_tcon(tlink))) 2760 - cifs_put_tcon(tlink_tcon(tlink)); 2757 + cifs_put_tcon(tlink_tcon(tlink), netfs_trace_tcon_ref_put_tlink); 2761 2758 kfree(tlink); 2762 2759 } 2763 2760 ··· 3322 3319 int rc = 0; 3323 3320 3324 3321 if (mnt_ctx->tcon) 3325 - cifs_put_tcon(mnt_ctx->tcon); 3322 + cifs_put_tcon(mnt_ctx->tcon, netfs_trace_tcon_ref_put_mnt_ctx); 3326 3323 else if (mnt_ctx->ses) 3327 3324 cifs_put_smb_ses(mnt_ctx->ses); 3328 3325 else if (mnt_ctx->server)
+7
fs/smb/client/fscache.c
··· 94 94 } 95 95 pr_err("Cache volume key already in use (%s)\n", key); 96 96 vcookie = NULL; 97 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 98 + netfs_trace_tcon_ref_see_fscache_collision); 99 + } else { 100 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 101 + netfs_trace_tcon_ref_see_fscache_okay); 97 102 } 98 103 99 104 tcon->fscache = vcookie; ··· 120 115 cifs_fscache_fill_volume_coherency(tcon, &cd); 121 116 fscache_relinquish_volume(tcon->fscache, &cd, false); 122 117 tcon->fscache = NULL; 118 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 119 + netfs_trace_tcon_ref_see_fscache_relinq); 123 120 } 124 121 125 122 void cifs_fscache_get_inode_cookie(struct inode *inode)
+7 -3
fs/smb/client/misc.c
··· 111 111 } 112 112 113 113 struct cifs_tcon * 114 - tcon_info_alloc(bool dir_leases_enabled) 114 + tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace) 115 115 { 116 116 struct cifs_tcon *ret_buf; 117 + static atomic_t tcon_debug_id; 117 118 118 119 ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL); 119 120 if (!ret_buf) ··· 131 130 132 131 atomic_inc(&tconInfoAllocCount); 133 132 ret_buf->status = TID_NEW; 134 - ++ret_buf->tc_count; 133 + ret_buf->debug_id = atomic_inc_return(&tcon_debug_id); 134 + ret_buf->tc_count = 1; 135 135 spin_lock_init(&ret_buf->tc_lock); 136 136 INIT_LIST_HEAD(&ret_buf->openFileList); 137 137 INIT_LIST_HEAD(&ret_buf->tcon_list); ··· 144 142 #ifdef CONFIG_CIFS_FSCACHE 145 143 mutex_init(&ret_buf->fscache_lock); 146 144 #endif 145 + trace_smb3_tcon_ref(ret_buf->debug_id, ret_buf->tc_count, trace); 147 146 148 147 return ret_buf; 149 148 } 150 149 151 150 void 152 - tconInfoFree(struct cifs_tcon *tcon) 151 + tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace) 153 152 { 154 153 if (tcon == NULL) { 155 154 cifs_dbg(FYI, "Null buffer passed to tconInfoFree\n"); 156 155 return; 157 156 } 157 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, trace); 158 158 free_cached_dirs(tcon->cfids); 159 159 atomic_dec(&tconInfoAllocCount); 160 160 kfree(tcon->nativeFileSystem);
+7 -3
fs/smb/client/smb2misc.c
··· 767 767 if (rc) 768 768 cifs_tcon_dbg(VFS, "Close cancelled mid failed rc:%d\n", rc); 769 769 770 - cifs_put_tcon(tcon); 770 + cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_close_fid); 771 771 kfree(cancelled); 772 772 } 773 773 ··· 811 811 if (tcon->tc_count <= 0) { 812 812 struct TCP_Server_Info *server = NULL; 813 813 814 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 815 + netfs_trace_tcon_ref_see_cancelled_close); 814 816 WARN_ONCE(tcon->tc_count < 0, "tcon refcount is negative"); 815 817 spin_unlock(&cifs_tcp_ses_lock); 816 818 ··· 825 823 return 0; 826 824 } 827 825 tcon->tc_count++; 826 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 827 + netfs_trace_tcon_ref_get_cancelled_close); 828 828 spin_unlock(&cifs_tcp_ses_lock); 829 829 830 830 rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE_HE, 0, 831 831 persistent_fid, volatile_fid); 832 832 if (rc) 833 - cifs_put_tcon(tcon); 833 + cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_close); 834 834 835 835 return rc; 836 836 } ··· 860 856 rsp->PersistentFileId, 861 857 rsp->VolatileFileId); 862 858 if (rc) 863 - cifs_put_tcon(tcon); 859 + cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_mid); 864 860 865 861 return rc; 866 862 }
+6 -1
fs/smb/client/smb2ops.c
··· 2915 2915 tcon = list_first_entry_or_null(&ses->tcon_list, 2916 2916 struct cifs_tcon, 2917 2917 tcon_list); 2918 - if (tcon) 2918 + if (tcon) { 2919 2919 tcon->tc_count++; 2920 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 2921 + netfs_trace_tcon_ref_get_dfs_refer); 2922 + } 2920 2923 spin_unlock(&cifs_tcp_ses_lock); 2921 2924 } 2922 2925 ··· 2983 2980 /* ipc tcons are not refcounted */ 2984 2981 spin_lock(&cifs_tcp_ses_lock); 2985 2982 tcon->tc_count--; 2983 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 2984 + netfs_trace_tcon_ref_dec_dfs_refer); 2986 2985 /* tc_count can never go negative */ 2987 2986 WARN_ON(tcon->tc_count < 0); 2988 2987 spin_unlock(&cifs_tcp_ses_lock);
+5 -3
fs/smb/client/smb2pdu.c
··· 4138 4138 list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { 4139 4139 if (tcon->need_reconnect || tcon->need_reopen_files) { 4140 4140 tcon->tc_count++; 4141 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 4142 + netfs_trace_tcon_ref_get_reconnect_server); 4141 4143 list_add_tail(&tcon->rlist, &tmp_list); 4142 4144 tcon_selected = true; 4143 4145 } ··· 4178 4176 if (tcon->ipc) 4179 4177 cifs_put_smb_ses(tcon->ses); 4180 4178 else 4181 - cifs_put_tcon(tcon); 4179 + cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_reconnect_server); 4182 4180 } 4183 4181 4184 4182 if (!ses_exist) 4185 4183 goto done; 4186 4184 4187 4185 /* allocate a dummy tcon struct used for reconnect */ 4188 - tcon = tcon_info_alloc(false); 4186 + tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_reconnect_server); 4189 4187 if (!tcon) { 4190 4188 resched = true; 4191 4189 list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) { ··· 4208 4206 list_del_init(&ses->rlist); 4209 4207 cifs_put_smb_ses(ses); 4210 4208 } 4211 - tconInfoFree(tcon); 4209 + tconInfoFree(tcon, netfs_trace_tcon_ref_free_reconnect_server); 4212 4210 4213 4211 done: 4214 4212 cifs_dbg(FYI, "Reconnecting tcons and channels finished\n");
+2
fs/smb/client/smb2transport.c
··· 189 189 if (tcon->tid != tid) 190 190 continue; 191 191 ++tcon->tc_count; 192 + trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, 193 + netfs_trace_tcon_ref_get_find_sess_tcon); 192 194 return tcon; 193 195 } 194 196
+90 -2
fs/smb/client/trace.h
··· 3 3 * Copyright (C) 2018, Microsoft Corporation. 4 4 * 5 5 * Author(s): Steve French <stfrench@microsoft.com> 6 + * 7 + * Please use this 3-part article as a reference for writing new tracepoints: 8 + * https://lwn.net/Articles/379903/ 6 9 */ 7 10 #undef TRACE_SYSTEM 8 11 #define TRACE_SYSTEM cifs ··· 18 15 #include <linux/inet.h> 19 16 20 17 /* 21 - * Please use this 3-part article as a reference for writing new tracepoints: 22 - * https://lwn.net/Articles/379903/ 18 + * Specify enums for tracing information. 23 19 */ 20 + #define smb3_tcon_ref_traces \ 21 + EM(netfs_trace_tcon_ref_dec_dfs_refer, "DEC DfsRef") \ 22 + EM(netfs_trace_tcon_ref_free, "FRE ") \ 23 + EM(netfs_trace_tcon_ref_free_fail, "FRE Fail ") \ 24 + EM(netfs_trace_tcon_ref_free_ipc, "FRE Ipc ") \ 25 + EM(netfs_trace_tcon_ref_free_ipc_fail, "FRE Ipc-F ") \ 26 + EM(netfs_trace_tcon_ref_free_reconnect_server, "FRE Reconn") \ 27 + EM(netfs_trace_tcon_ref_get_cancelled_close, "GET Cn-Cls") \ 28 + EM(netfs_trace_tcon_ref_get_dfs_refer, "GET DfsRef") \ 29 + EM(netfs_trace_tcon_ref_get_find, "GET Find ") \ 30 + EM(netfs_trace_tcon_ref_get_find_sess_tcon, "GET FndSes") \ 31 + EM(netfs_trace_tcon_ref_get_reconnect_server, "GET Reconn") \ 32 + EM(netfs_trace_tcon_ref_new, "NEW ") \ 33 + EM(netfs_trace_tcon_ref_new_ipc, "NEW Ipc ") \ 34 + EM(netfs_trace_tcon_ref_new_reconnect_server, "NEW Reconn") \ 35 + EM(netfs_trace_tcon_ref_put_cancelled_close, "PUT Cn-Cls") \ 36 + EM(netfs_trace_tcon_ref_put_cancelled_close_fid, "PUT Cn-Fid") \ 37 + EM(netfs_trace_tcon_ref_put_cancelled_mid, "PUT Cn-Mid") \ 38 + EM(netfs_trace_tcon_ref_put_mnt_ctx, "PUT MntCtx") \ 39 + EM(netfs_trace_tcon_ref_put_reconnect_server, "PUT Reconn") \ 40 + EM(netfs_trace_tcon_ref_put_tlink, "PUT Tlink ") \ 41 + EM(netfs_trace_tcon_ref_see_cancelled_close, "SEE Cn-Cls") \ 42 + EM(netfs_trace_tcon_ref_see_fscache_collision, "SEE FV-CO!") \ 43 + EM(netfs_trace_tcon_ref_see_fscache_okay, "SEE FV-Ok ") \ 44 + EM(netfs_trace_tcon_ref_see_fscache_relinq, "SEE FV-Rlq") \ 45 + E_(netfs_trace_tcon_ref_see_umount, "SEE Umount") 46 + 47 + #undef EM 48 + #undef E_ 49 + 50 + /* 51 + * Define those tracing enums. 52 + */ 53 + #ifndef __SMB3_DECLARE_TRACE_ENUMS_ONCE_ONLY 54 + #define __SMB3_DECLARE_TRACE_ENUMS_ONCE_ONLY 55 + 56 + #define EM(a, b) a, 57 + #define E_(a, b) a 58 + 59 + enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte); 60 + 61 + #undef EM 62 + #undef E_ 63 + #endif 64 + 65 + /* 66 + * Export enum symbols via userspace. 67 + */ 68 + #define EM(a, b) TRACE_DEFINE_ENUM(a); 69 + #define E_(a, b) TRACE_DEFINE_ENUM(a); 70 + 71 + smb3_tcon_ref_traces; 72 + 73 + #undef EM 74 + #undef E_ 75 + 76 + /* 77 + * Now redefine the EM() and E_() macros to map the enums to the strings that 78 + * will be printed in the output. 79 + */ 80 + #define EM(a, b) { a, b }, 81 + #define E_(a, b) { a, b } 24 82 25 83 /* For logging errors in read or write */ 26 84 DECLARE_EVENT_CLASS(smb3_rw_err_class, ··· 1189 1125 DEFINE_SMB3_CREDIT_EVENT(overflow_credits); 1190 1126 DEFINE_SMB3_CREDIT_EVENT(set_credits); 1191 1127 1128 + 1129 + TRACE_EVENT(smb3_tcon_ref, 1130 + TP_PROTO(unsigned int tcon_debug_id, int ref, 1131 + enum smb3_tcon_ref_trace trace), 1132 + TP_ARGS(tcon_debug_id, ref, trace), 1133 + TP_STRUCT__entry( 1134 + __field(unsigned int, tcon) 1135 + __field(int, ref) 1136 + __field(enum smb3_tcon_ref_trace, trace) 1137 + ), 1138 + TP_fast_assign( 1139 + __entry->tcon = tcon_debug_id; 1140 + __entry->ref = ref; 1141 + __entry->trace = trace; 1142 + ), 1143 + TP_printk("TC=%08x %s r=%u", 1144 + __entry->tcon, 1145 + __print_symbolic(__entry->trace, smb3_tcon_ref_traces), 1146 + __entry->ref) 1147 + ); 1148 + 1149 + 1150 + #undef EM 1151 + #undef E_ 1192 1152 #endif /* _CIFS_TRACE_H */ 1193 1153 1194 1154 #undef TRACE_INCLUDE_PATH