@@ -1268,6 +1268,16 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx)
12681268
12691269 spin_lock (& cifs_tcp_ses_lock );
12701270 list_for_each_entry (server , & cifs_tcp_ses_list , tcp_ses_list ) {
1271+ #ifdef CONFIG_CIFS_DFS_UPCALL
1272+ /*
1273+ * DFS failover implementation in cifs_reconnect() requires unique tcp sessions for
1274+ * DFS connections to do failover properly, so avoid sharing them with regular
1275+ * shares or even links that may connect to same server but having completely
1276+ * different failover targets.
1277+ */
1278+ if (server -> is_dfs_conn )
1279+ continue ;
1280+ #endif
12711281 /*
12721282 * Skip ses channels since they're only handled in lower layers
12731283 * (e.g. cifs_send_recv).
@@ -2968,6 +2978,23 @@ static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
29682978}
29692979
29702980#ifdef CONFIG_CIFS_DFS_UPCALL
2981+ static int mount_get_dfs_conns (struct smb3_fs_context * ctx , struct cifs_sb_info * cifs_sb ,
2982+ unsigned int * xid , struct TCP_Server_Info * * nserver ,
2983+ struct cifs_ses * * nses , struct cifs_tcon * * ntcon )
2984+ {
2985+ int rc ;
2986+
2987+ ctx -> nosharesock = true;
2988+ rc = mount_get_conns (ctx , cifs_sb , xid , nserver , nses , ntcon );
2989+ if (* nserver ) {
2990+ cifs_dbg (FYI , "%s: marking tcp session as a dfs connection\n" , __func__ );
2991+ spin_lock (& cifs_tcp_ses_lock );
2992+ (* nserver )-> is_dfs_conn = true;
2993+ spin_unlock (& cifs_tcp_ses_lock );
2994+ }
2995+ return rc ;
2996+ }
2997+
29712998/*
29722999 * cifs_build_path_to_root returns full path to root when we do not have an
29733000 * existing connection (tcon)
@@ -3163,7 +3190,7 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
31633190 tmp_ctx .prepath );
31643191
31653192 mount_put_conns (cifs_sb , * xid , * server , * ses , * tcon );
3166- rc = mount_get_conns (& tmp_ctx , cifs_sb , xid , server , ses , tcon );
3193+ rc = mount_get_dfs_conns (& tmp_ctx , cifs_sb , xid , server , ses , tcon );
31673194 if (!rc || (* server && * ses )) {
31683195 /*
31693196 * We were able to connect to new target server. Update current context with
@@ -3462,7 +3489,12 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34623489 goto error ;
34633490 }
34643491
3465- ctx -> nosharesock = true;
3492+ mount_put_conns (cifs_sb , xid , server , ses , tcon );
3493+ /*
3494+ * Ignore error check here because we may failover to other targets from cached a
3495+ * referral.
3496+ */
3497+ (void )mount_get_dfs_conns (ctx , cifs_sb , & xid , & server , & ses , & tcon );
34663498
34673499 /* Get path of DFS root */
34683500 ref_path = build_unc_path_to_root (ctx , cifs_sb , false);
@@ -3491,7 +3523,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34913523 /* Connect to new DFS target only if we were redirected */
34923524 if (oldmnt != cifs_sb -> ctx -> mount_options ) {
34933525 mount_put_conns (cifs_sb , xid , server , ses , tcon );
3494- rc = mount_get_conns (ctx , cifs_sb , & xid , & server , & ses , & tcon );
3526+ rc = mount_get_dfs_conns (ctx , cifs_sb , & xid , & server , & ses , & tcon );
34953527 }
34963528 if (rc && !server && !ses ) {
34973529 /* Failed to connect. Try to connect to other targets in the referral. */
0 commit comments