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

smb:client: smb: client: Add reverse mapping from tcon to superblocks

Currently, when a SMB connection is reset and renegotiated with the
server, there's no way to update all related mount points with new
negotiated sizes. This is because while superblocks (cifs_sb_info)
maintain references to tree connections (tcon) through tcon_link
structures, there is no reverse mapping from a tcon back to all the
superblocks using it.

This patch adds a bidirectional relationship between tcon and
cifs_sb_info structures by:

1. Adding a cifs_sb_list to tcon structure with appropriate locking
2. Adding tcon_sb_link to cifs_sb_info to join the list
3. Managing the list entries during mount and umount operations

The bidirectional relationship enables future functionality to locate and
update all superblocks connected to a specific tree connection, such as:

- Updating negotiated parameters after reconnection
- Efficiently notifying all affected mounts of capability changes

This is the first part of a series to improve connection resilience
by keeping all mount parameters in sync with server capabilities
after reconnection.

Signed-off-by: Wang Zhaolong <wangzhaolong1@huawei.com>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Wang Zhaolong and committed by
Steve French
a091d971 be5d361e

+20 -1
+1
fs/smb/client/cifs_fs_sb.h
··· 49 49 50 50 struct cifs_sb_info { 51 51 struct rb_root tlink_tree; 52 + struct list_head tcon_sb_link; 52 53 spinlock_t tlink_tree_lock; 53 54 struct tcon_link *master_tlink; 54 55 struct nls_table *local_nls;
+2 -1
fs/smb/client/cifsglob.h
··· 1321 1321 #endif 1322 1322 struct list_head pending_opens; /* list of incomplete opens */ 1323 1323 struct cached_fids *cfids; 1324 - /* BB add field for back pointer to sb struct(s)? */ 1324 + struct list_head cifs_sb_list; 1325 + spinlock_t sb_list_lock; 1325 1326 #ifdef CONFIG_CIFS_DFS_UPCALL 1326 1327 struct delayed_work dfs_cache_work; 1327 1328 struct list_head dfs_ses_list;
+15
fs/smb/client/connect.c
··· 3477 3477 struct smb3_fs_context *ctx = cifs_sb->ctx; 3478 3478 3479 3479 INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); 3480 + INIT_LIST_HEAD(&cifs_sb->tcon_sb_link); 3480 3481 3481 3482 spin_lock_init(&cifs_sb->tlink_tree_lock); 3482 3483 cifs_sb->tlink_tree = RB_ROOT; ··· 3709 3708 spin_lock(&cifs_sb->tlink_tree_lock); 3710 3709 tlink_rb_insert(&cifs_sb->tlink_tree, tlink); 3711 3710 spin_unlock(&cifs_sb->tlink_tree_lock); 3711 + 3712 + spin_lock(&tcon->sb_list_lock); 3713 + list_add(&cifs_sb->tcon_sb_link, &tcon->cifs_sb_list); 3714 + spin_unlock(&tcon->sb_list_lock); 3712 3715 3713 3716 queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, 3714 3717 TLINK_IDLE_EXPIRE); ··· 4055 4050 struct rb_root *root = &cifs_sb->tlink_tree; 4056 4051 struct rb_node *node; 4057 4052 struct tcon_link *tlink; 4053 + struct cifs_tcon *tcon = NULL; 4058 4054 4059 4055 cancel_delayed_work_sync(&cifs_sb->prune_tlinks); 4056 + 4057 + if (cifs_sb->master_tlink) { 4058 + tcon = cifs_sb->master_tlink->tl_tcon; 4059 + if (tcon) { 4060 + spin_lock(&tcon->sb_list_lock); 4061 + list_del_init(&cifs_sb->tcon_sb_link); 4062 + spin_unlock(&tcon->sb_list_lock); 4063 + } 4064 + } 4060 4065 4061 4066 spin_lock(&cifs_sb->tlink_tree_lock); 4062 4067 while ((node = rb_first(root))) {
+2
fs/smb/client/misc.c
··· 137 137 spin_lock_init(&ret_buf->tc_lock); 138 138 INIT_LIST_HEAD(&ret_buf->openFileList); 139 139 INIT_LIST_HEAD(&ret_buf->tcon_list); 140 + INIT_LIST_HEAD(&ret_buf->cifs_sb_list); 140 141 spin_lock_init(&ret_buf->open_file_lock); 141 142 spin_lock_init(&ret_buf->stat_lock); 143 + spin_lock_init(&ret_buf->sb_list_lock); 142 144 atomic_set(&ret_buf->num_local_opens, 0); 143 145 atomic_set(&ret_buf->num_remote_opens, 0); 144 146 ret_buf->stats_from_time = ktime_get_real_seconds();