
mainline inclusion from mainline-v6.15-rc1 commit a091d9711bdee46a76fa14fad31cb261a6dad74a category: bugfix bugzilla: https://gitee.com/openeuler/kernel/issues/IC1OPD CVE: NA Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i... -------------------------------- 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> Conflicts: fs/cifs/cifs_fs_sb.h fs/cifs/cifsglob.h fs/cifs/connect.c fs/cifs/misc.c fs/smb/client/cifs_fs_sb.h fs/smb/client/cifsglob.h fs/smb/client/connect.c fs/smb/client/misc.c [The mainline code has already undergone multiple refactoring sessions.] Signed-off-by: Wang Zhaolong <wangzhaolong1@huawei.com> --- fs/cifs/cifs_fs_sb.h | 1 + fs/cifs/cifsglob.h | 3 ++- fs/cifs/connect.c | 15 +++++++++++++++ fs/cifs/misc.c | 2 ++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 6e7c4427369d..369011b48425 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -56,10 +56,11 @@ #define CIFS_MOUNT_RO_CACHE 0x20000000 /* assumes share will not change */ #define CIFS_MOUNT_RW_CACHE 0x40000000 /* assumes only client accessing */ struct cifs_sb_info { struct rb_root tlink_tree; + struct list_head tcon_sb_link; spinlock_t tlink_tree_lock; struct tcon_link *master_tlink; struct nls_table *local_nls; unsigned int bsize; unsigned int rsize; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index a6697954fd68..807e2b024012 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -1172,11 +1172,12 @@ struct cifs_tcon { u64 resource_id; /* server resource id */ struct fscache_cookie *fscache; /* cookie for share */ #endif struct list_head pending_opens; /* list of incomplete opens */ struct cached_fid crfid; /* Cached root fid */ - /* BB add field for back pointer to sb struct(s)? */ + struct list_head cifs_sb_list; + spinlock_t sb_list_lock; #ifdef CONFIG_CIFS_DFS_UPCALL char *dfs_path; int remap:2; struct list_head ulist; /* cache update list */ #endif diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 07b56705bcb0..c3cb2333af98 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3965,10 +3965,11 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs_tcon *tcon, int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, struct cifs_sb_info *cifs_sb) { INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); + INIT_LIST_HEAD(&cifs_sb->tcon_sb_link); spin_lock_init(&cifs_sb->tlink_tree_lock); cifs_sb->tlink_tree = RB_ROOT; cifs_sb->bsize = pvolume_info->bsize; @@ -4230,10 +4231,14 @@ static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses, cifs_sb->master_tlink = tlink; spin_lock(&cifs_sb->tlink_tree_lock); tlink_rb_insert(&cifs_sb->tlink_tree, tlink); spin_unlock(&cifs_sb->tlink_tree_lock); + spin_lock(&tcon->sb_list_lock); + list_add(&cifs_sb->tcon_sb_link, &tcon->cifs_sb_list); + spin_unlock(&tcon->sb_list_lock); + queue_delayed_work(cifsiod_wq, &cifs_sb->prune_tlinks, TLINK_IDLE_EXPIRE); return 0; } @@ -5047,13 +5052,23 @@ void cifs_umount(struct cifs_sb_info *cifs_sb) { struct rb_root *root = &cifs_sb->tlink_tree; struct rb_node *node; struct tcon_link *tlink; + struct cifs_tcon *tcon = NULL; cancel_delayed_work_sync(&cifs_sb->prune_tlinks); + if (cifs_sb->master_tlink) { + tcon = cifs_sb->master_tlink->tl_tcon; + if (tcon) { + spin_lock(&tcon->sb_list_lock); + list_del_init(&cifs_sb->tcon_sb_link); + spin_unlock(&tcon->sb_list_lock); + } + } + spin_lock(&cifs_sb->tlink_tree_lock); while ((node = rb_first(root))) { tlink = rb_entry(node, struct tcon_link, tl_rbnode); cifs_get_tlink(tlink); clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 2d46018b0283..12131a5d5073 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -128,11 +128,13 @@ tconInfoAlloc(void) atomic_inc(&tconInfoAllocCount); ret_buf->tidStatus = CifsNew; ++ret_buf->tc_count; INIT_LIST_HEAD(&ret_buf->openFileList); INIT_LIST_HEAD(&ret_buf->tcon_list); + INIT_LIST_HEAD(&ret_buf->cifs_sb_list); spin_lock_init(&ret_buf->open_file_lock); + spin_lock_init(&ret_buf->sb_list_lock); mutex_init(&ret_buf->crfid.fid_mutex); spin_lock_init(&ret_buf->stat_lock); atomic_set(&ret_buf->num_local_opens, 0); atomic_set(&ret_buf->num_remote_opens, 0); -- 2.39.2