@@ -66,33 +66,20 @@ static int get_session(struct cifs_mount_ctx *mnt_ctx, const char *full_path)
6666}
6767
6868/*
69- * Track individual DFS referral servers used by new DFS mount.
70- *
71- * On success, their lifetime will be shared by final tcon (dfs_ses_list).
72- * Otherwise, they will be put by dfs_put_root_smb_sessions() in cifs_mount().
69+ * Get an active reference of @ses so that next call to cifs_put_tcon() won't
70+ * release it as any new DFS referrals must go through its IPC tcon.
7371 */
74- static int add_root_smb_session (struct cifs_mount_ctx * mnt_ctx )
72+ static void add_root_smb_session (struct cifs_mount_ctx * mnt_ctx )
7573{
7674 struct smb3_fs_context * ctx = mnt_ctx -> fs_ctx ;
77- struct dfs_root_ses * root_ses ;
7875 struct cifs_ses * ses = mnt_ctx -> ses ;
7976
8077 if (ses ) {
81- root_ses = kmalloc (sizeof (* root_ses ), GFP_KERNEL );
82- if (!root_ses )
83- return - ENOMEM ;
84-
85- INIT_LIST_HEAD (& root_ses -> list );
86-
8778 spin_lock (& cifs_tcp_ses_lock );
8879 cifs_smb_ses_inc_refcount (ses );
8980 spin_unlock (& cifs_tcp_ses_lock );
90- root_ses -> ses = ses ;
91- list_add_tail (& root_ses -> list , & mnt_ctx -> dfs_ses_list );
9281 }
93- /* Select new DFS referral server so that new referrals go through it */
9482 ctx -> dfs_root_ses = ses ;
95- return 0 ;
9683}
9784
9885static inline int parse_dfs_target (struct smb3_fs_context * ctx ,
@@ -185,11 +172,8 @@ static int __dfs_referral_walk(struct cifs_mount_ctx *mnt_ctx,
185172 continue ;
186173 }
187174
188- if (is_refsrv ) {
189- rc = add_root_smb_session (mnt_ctx );
190- if (rc )
191- goto out ;
192- }
175+ if (is_refsrv )
176+ add_root_smb_session (mnt_ctx );
193177
194178 rc = ref_walk_advance (rw );
195179 if (!rc ) {
@@ -232,13 +216,26 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
232216 struct smb3_fs_context * ctx = mnt_ctx -> fs_ctx ;
233217 struct cifs_tcon * tcon ;
234218 char * origin_fullpath ;
219+ bool new_tcon = true;
235220 int rc ;
236221
237222 origin_fullpath = dfs_get_path (cifs_sb , ctx -> source );
238223 if (IS_ERR (origin_fullpath ))
239224 return PTR_ERR (origin_fullpath );
240225
241226 rc = dfs_referral_walk (mnt_ctx );
227+ if (!rc ) {
228+ /*
229+ * Prevent superblock from being created with any missing
230+ * connections.
231+ */
232+ if (WARN_ON (!mnt_ctx -> server ))
233+ rc = - EHOSTDOWN ;
234+ else if (WARN_ON (!mnt_ctx -> ses ))
235+ rc = - EACCES ;
236+ else if (WARN_ON (!mnt_ctx -> tcon ))
237+ rc = - ENOENT ;
238+ }
242239 if (rc )
243240 goto out ;
244241
@@ -247,15 +244,14 @@ static int __dfs_mount_share(struct cifs_mount_ctx *mnt_ctx)
247244 if (!tcon -> origin_fullpath ) {
248245 tcon -> origin_fullpath = origin_fullpath ;
249246 origin_fullpath = NULL ;
247+ } else {
248+ new_tcon = false;
250249 }
251250 spin_unlock (& tcon -> tc_lock );
252251
253- if (list_empty (& tcon -> dfs_ses_list )) {
254- list_replace_init (& mnt_ctx -> dfs_ses_list , & tcon -> dfs_ses_list );
252+ if (new_tcon ) {
255253 queue_delayed_work (dfscache_wq , & tcon -> dfs_cache_work ,
256254 dfs_cache_get_ttl () * HZ );
257- } else {
258- dfs_put_root_smb_sessions (& mnt_ctx -> dfs_ses_list );
259255 }
260256
261257out :
@@ -298,7 +294,6 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
298294 if (rc )
299295 return rc ;
300296
301- ctx -> dfs_root_ses = mnt_ctx -> ses ;
302297 /*
303298 * If called with 'nodfs' mount option, then skip DFS resolving. Otherwise unconditionally
304299 * try to get an DFS referral (even cached) to determine whether it is an DFS mount.
@@ -324,7 +319,9 @@ int dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs)
324319
325320 * isdfs = true;
326321 add_root_smb_session (mnt_ctx );
327- return __dfs_mount_share (mnt_ctx );
322+ rc = __dfs_mount_share (mnt_ctx );
323+ dfs_put_root_smb_sessions (mnt_ctx );
324+ return rc ;
328325}
329326
330327/* Update dfs referral path of superblock */
0 commit comments