Skip to content

Commit

Permalink
cifs: Add tracing for the cifs_tcon struct refcounting
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Howells authored and Steve French committed Apr 19, 2024
1 parent dad80c6 commit afc23fe
Show file tree
Hide file tree
Showing 11 changed files with 143 additions and 26 deletions.
2 changes: 2 additions & 0 deletions fs/smb/client/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,8 @@ static void cifs_umount_begin(struct super_block *sb)

spin_lock(&cifs_tcp_ses_lock);
spin_lock(&tcon->tc_lock);
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_see_umount);
if ((tcon->tc_count > 1) || (tcon->status == TID_EXITING)) {
/* we have other mounts to same share or we have
already tried to umount this and woken up
Expand Down
1 change: 1 addition & 0 deletions fs/smb/client/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,7 @@ struct cifs_fattr {
*/
struct cifs_tcon {
struct list_head tcon_list;
int debug_id; /* Debugging for tracing */
int tc_count;
struct list_head rlist; /* reconnect list */
spinlock_t tc_lock; /* protect anything here that is not protected */
Expand Down
9 changes: 4 additions & 5 deletions fs/smb/client/cifsproto.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx,
struct TCP_Server_Info *primary_server);
extern void cifs_put_tcp_session(struct TCP_Server_Info *server,
int from_reconnect);
extern void cifs_put_tcon(struct cifs_tcon *tcon);
extern void cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace);

extern void cifs_release_automount_timer(void);

Expand Down Expand Up @@ -530,8 +530,9 @@ extern int CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *ses);

extern struct cifs_ses *sesInfoAlloc(void);
extern void sesInfoFree(struct cifs_ses *);
extern struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled);
extern void tconInfoFree(struct cifs_tcon *);
extern struct cifs_tcon *tcon_info_alloc(bool dir_leases_enabled,
enum smb3_tcon_ref_trace trace);
extern void tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace);

extern int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server,
__u32 *pexpected_response_sequence_number);
Expand Down Expand Up @@ -721,8 +722,6 @@ static inline int cifs_create_options(struct cifs_sb_info *cifs_sb, int options)
return options;
}

struct super_block *cifs_get_tcon_super(struct cifs_tcon *tcon);
void cifs_put_tcon_super(struct super_block *sb);
int cifs_wait_for_server_reconnect(struct TCP_Server_Info *server, bool retry);

/* Put references of @ses and its children */
Expand Down
21 changes: 12 additions & 9 deletions fs/smb/client/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -1943,7 +1943,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)
}

/* no need to setup directory caching on IPC share, so pass in false */
tcon = tcon_info_alloc(false);
tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_ipc);
if (tcon == NULL)
return -ENOMEM;

Expand All @@ -1960,7 +1960,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb3_fs_context *ctx)

if (rc) {
cifs_server_dbg(VFS, "failed to connect to IPC (rc=%d)\n", rc);
tconInfoFree(tcon);
tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc_fail);
goto out;
}

Expand Down Expand Up @@ -2043,7 +2043,7 @@ void __cifs_put_smb_ses(struct cifs_ses *ses)
* files on session close, as specified in MS-SMB2 3.3.5.6 Receiving an
* SMB2 LOGOFF Request.
*/
tconInfoFree(tcon);
tconInfoFree(tcon, netfs_trace_tcon_ref_free_ipc);
if (do_logoff) {
xid = get_xid();
rc = server->ops->logoff(xid, ses);
Expand Down Expand Up @@ -2432,6 +2432,8 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
continue;
}
++tcon->tc_count;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_get_find);
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
return tcon;
Expand All @@ -2441,7 +2443,7 @@ cifs_find_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
}

void
cifs_put_tcon(struct cifs_tcon *tcon)
cifs_put_tcon(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace)
{
unsigned int xid;
struct cifs_ses *ses;
Expand All @@ -2457,6 +2459,7 @@ cifs_put_tcon(struct cifs_tcon *tcon)
cifs_dbg(FYI, "%s: tc_count=%d\n", __func__, tcon->tc_count);
spin_lock(&cifs_tcp_ses_lock);
spin_lock(&tcon->tc_lock);
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count - 1, trace);
if (--tcon->tc_count > 0) {
spin_unlock(&tcon->tc_lock);
spin_unlock(&cifs_tcp_ses_lock);
Expand Down Expand Up @@ -2493,7 +2496,7 @@ cifs_put_tcon(struct cifs_tcon *tcon)
_free_xid(xid);

cifs_fscache_release_super_cookie(tcon);
tconInfoFree(tcon);
tconInfoFree(tcon, netfs_trace_tcon_ref_free);
cifs_put_smb_ses(ses);
}

Expand Down Expand Up @@ -2547,7 +2550,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
nohandlecache = ctx->nohandlecache;
else
nohandlecache = true;
tcon = tcon_info_alloc(!nohandlecache);
tcon = tcon_info_alloc(!nohandlecache, netfs_trace_tcon_ref_new);
if (tcon == NULL) {
rc = -ENOMEM;
goto out_fail;
Expand Down Expand Up @@ -2737,7 +2740,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
return tcon;

out_fail:
tconInfoFree(tcon);
tconInfoFree(tcon, netfs_trace_tcon_ref_free_fail);
return ERR_PTR(rc);
}

Expand All @@ -2754,7 +2757,7 @@ cifs_put_tlink(struct tcon_link *tlink)
}

if (!IS_ERR(tlink_tcon(tlink)))
cifs_put_tcon(tlink_tcon(tlink));
cifs_put_tcon(tlink_tcon(tlink), netfs_trace_tcon_ref_put_tlink);
kfree(tlink);
}

Expand Down Expand Up @@ -3319,7 +3322,7 @@ void cifs_mount_put_conns(struct cifs_mount_ctx *mnt_ctx)
int rc = 0;

if (mnt_ctx->tcon)
cifs_put_tcon(mnt_ctx->tcon);
cifs_put_tcon(mnt_ctx->tcon, netfs_trace_tcon_ref_put_mnt_ctx);
else if (mnt_ctx->ses)
cifs_put_smb_ses(mnt_ctx->ses);
else if (mnt_ctx->server)
Expand Down
7 changes: 7 additions & 0 deletions fs/smb/client/fscache.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ int cifs_fscache_get_super_cookie(struct cifs_tcon *tcon)
}
pr_err("Cache volume key already in use (%s)\n", key);
vcookie = NULL;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_see_fscache_collision);
} else {
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_see_fscache_okay);
}

tcon->fscache = vcookie;
Expand All @@ -115,6 +120,8 @@ void cifs_fscache_release_super_cookie(struct cifs_tcon *tcon)
cifs_fscache_fill_volume_coherency(tcon, &cd);
fscache_relinquish_volume(tcon->fscache, &cd, false);
tcon->fscache = NULL;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_see_fscache_relinq);
}

void cifs_fscache_get_inode_cookie(struct inode *inode)
Expand Down
10 changes: 7 additions & 3 deletions fs/smb/client/misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,10 @@ sesInfoFree(struct cifs_ses *buf_to_free)
}

struct cifs_tcon *
tcon_info_alloc(bool dir_leases_enabled)
tcon_info_alloc(bool dir_leases_enabled, enum smb3_tcon_ref_trace trace)
{
struct cifs_tcon *ret_buf;
static atomic_t tcon_debug_id;

ret_buf = kzalloc(sizeof(*ret_buf), GFP_KERNEL);
if (!ret_buf)
Expand All @@ -130,7 +131,8 @@ tcon_info_alloc(bool dir_leases_enabled)

atomic_inc(&tconInfoAllocCount);
ret_buf->status = TID_NEW;
++ret_buf->tc_count;
ret_buf->debug_id = atomic_inc_return(&tcon_debug_id);
ret_buf->tc_count = 1;
spin_lock_init(&ret_buf->tc_lock);
INIT_LIST_HEAD(&ret_buf->openFileList);
INIT_LIST_HEAD(&ret_buf->tcon_list);
Expand All @@ -142,17 +144,19 @@ tcon_info_alloc(bool dir_leases_enabled)
#ifdef CONFIG_CIFS_FSCACHE
mutex_init(&ret_buf->fscache_lock);
#endif
trace_smb3_tcon_ref(ret_buf->debug_id, ret_buf->tc_count, trace);

return ret_buf;
}

void
tconInfoFree(struct cifs_tcon *tcon)
tconInfoFree(struct cifs_tcon *tcon, enum smb3_tcon_ref_trace trace)
{
if (tcon == NULL) {
cifs_dbg(FYI, "Null buffer passed to tconInfoFree\n");
return;
}
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, trace);
free_cached_dirs(tcon->cfids);
atomic_dec(&tconInfoAllocCount);
kfree(tcon->nativeFileSystem);
Expand Down
10 changes: 7 additions & 3 deletions fs/smb/client/smb2misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ smb2_cancelled_close_fid(struct work_struct *work)
if (rc)
cifs_tcon_dbg(VFS, "Close cancelled mid failed rc:%d\n", rc);

cifs_put_tcon(tcon);
cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_close_fid);
kfree(cancelled);
}

Expand Down Expand Up @@ -811,6 +811,8 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
if (tcon->tc_count <= 0) {
struct TCP_Server_Info *server = NULL;

trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_see_cancelled_close);
WARN_ONCE(tcon->tc_count < 0, "tcon refcount is negative");
spin_unlock(&cifs_tcp_ses_lock);

Expand All @@ -823,12 +825,14 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_fid,
return 0;
}
tcon->tc_count++;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_get_cancelled_close);
spin_unlock(&cifs_tcp_ses_lock);

rc = __smb2_handle_cancelled_cmd(tcon, SMB2_CLOSE_HE, 0,
persistent_fid, volatile_fid);
if (rc)
cifs_put_tcon(tcon);
cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_close);

return rc;
}
Expand Down Expand Up @@ -856,7 +860,7 @@ smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info *serve
rsp->PersistentFileId,
rsp->VolatileFileId);
if (rc)
cifs_put_tcon(tcon);
cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_cancelled_mid);

return rc;
}
Expand Down
7 changes: 6 additions & 1 deletion fs/smb/client/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -2915,8 +2915,11 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
tcon = list_first_entry_or_null(&ses->tcon_list,
struct cifs_tcon,
tcon_list);
if (tcon)
if (tcon) {
tcon->tc_count++;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_get_dfs_refer);
}
spin_unlock(&cifs_tcp_ses_lock);
}

Expand Down Expand Up @@ -2980,6 +2983,8 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses,
/* ipc tcons are not refcounted */
spin_lock(&cifs_tcp_ses_lock);
tcon->tc_count--;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_dec_dfs_refer);
/* tc_count can never go negative */
WARN_ON(tcon->tc_count < 0);
spin_unlock(&cifs_tcp_ses_lock);
Expand Down
8 changes: 5 additions & 3 deletions fs/smb/client/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -4138,6 +4138,8 @@ void smb2_reconnect_server(struct work_struct *work)
list_for_each_entry(tcon, &ses->tcon_list, tcon_list) {
if (tcon->need_reconnect || tcon->need_reopen_files) {
tcon->tc_count++;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_get_reconnect_server);
list_add_tail(&tcon->rlist, &tmp_list);
tcon_selected = true;
}
Expand Down Expand Up @@ -4176,14 +4178,14 @@ void smb2_reconnect_server(struct work_struct *work)
if (tcon->ipc)
cifs_put_smb_ses(tcon->ses);
else
cifs_put_tcon(tcon);
cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_reconnect_server);
}

if (!ses_exist)
goto done;

/* allocate a dummy tcon struct used for reconnect */
tcon = tcon_info_alloc(false);
tcon = tcon_info_alloc(false, netfs_trace_tcon_ref_new_reconnect_server);
if (!tcon) {
resched = true;
list_for_each_entry_safe(ses, ses2, &tmp_ses_list, rlist) {
Expand All @@ -4206,7 +4208,7 @@ void smb2_reconnect_server(struct work_struct *work)
list_del_init(&ses->rlist);
cifs_put_smb_ses(ses);
}
tconInfoFree(tcon);
tconInfoFree(tcon, netfs_trace_tcon_ref_free_reconnect_server);

done:
cifs_dbg(FYI, "Reconnecting tcons and channels finished\n");
Expand Down
2 changes: 2 additions & 0 deletions fs/smb/client/smb2transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,8 @@ smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid)
if (tcon->tid != tid)
continue;
++tcon->tc_count;
trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count,
netfs_trace_tcon_ref_get_find_sess_tcon);
return tcon;
}

Expand Down
Loading

0 comments on commit afc23fe

Please sign in to comment.