@@ -78,6 +78,8 @@ static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
7878 int rc ;
7979 int len ;
8080 char * unc , * ipaddr = NULL ;
81+ time64_t expiry , now ;
82+ unsigned long ttl = SMB_DNS_RESOLVE_INTERVAL_DEFAULT ;
8183
8284 if (!server -> hostname )
8385 return - EINVAL ;
@@ -91,13 +93,13 @@ static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
9193 }
9294 scnprintf (unc , len , "\\\\%s" , server -> hostname );
9395
94- rc = dns_resolve_server_name_to_ip (unc , & ipaddr );
96+ rc = dns_resolve_server_name_to_ip (unc , & ipaddr , & expiry );
9597 kfree (unc );
9698
9799 if (rc < 0 ) {
98100 cifs_dbg (FYI , "%s: failed to resolve server part of %s to IP: %d\n" ,
99101 __func__ , server -> hostname , rc );
100- return rc ;
102+ goto requeue_resolve ;
101103 }
102104
103105 spin_lock (& cifs_tcp_ses_lock );
@@ -106,7 +108,45 @@ static int reconn_set_ipaddr_from_hostname(struct TCP_Server_Info *server)
106108 spin_unlock (& cifs_tcp_ses_lock );
107109 kfree (ipaddr );
108110
109- return !rc ? -1 : 0 ;
111+ /* rc == 1 means success here */
112+ if (rc ) {
113+ now = ktime_get_real_seconds ();
114+ if (expiry && expiry > now )
115+ /*
116+ * To make sure we don't use the cached entry, retry 1s
117+ * after expiry.
118+ */
119+ ttl = (expiry - now + 1 );
120+ }
121+ rc = !rc ? -1 : 0 ;
122+
123+ requeue_resolve :
124+ cifs_dbg (FYI , "%s: next dns resolution scheduled for %lu seconds in the future\n" ,
125+ __func__ , ttl );
126+ mod_delayed_work (cifsiod_wq , & server -> resolve , (ttl * HZ ));
127+
128+ return rc ;
129+ }
130+
131+
132+ static void cifs_resolve_server (struct work_struct * work )
133+ {
134+ int rc ;
135+ struct TCP_Server_Info * server = container_of (work ,
136+ struct TCP_Server_Info , resolve .work );
137+
138+ mutex_lock (& server -> srv_mutex );
139+
140+ /*
141+ * Resolve the hostname again to make sure that IP address is up-to-date.
142+ */
143+ rc = reconn_set_ipaddr_from_hostname (server );
144+ if (rc ) {
145+ cifs_dbg (FYI , "%s: failed to resolve hostname: %d\n" ,
146+ __func__ , rc );
147+ }
148+
149+ mutex_unlock (& server -> srv_mutex );
110150}
111151
112152#ifdef CONFIG_CIFS_DFS_UPCALL
@@ -680,6 +720,7 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server)
680720 spin_unlock (& cifs_tcp_ses_lock );
681721
682722 cancel_delayed_work_sync (& server -> echo );
723+ cancel_delayed_work_sync (& server -> resolve );
683724
684725 spin_lock (& GlobalMid_Lock );
685726 server -> tcpStatus = CifsExiting ;
@@ -1227,6 +1268,16 @@ cifs_find_tcp_session(struct smb3_fs_context *ctx)
12271268
12281269 spin_lock (& cifs_tcp_ses_lock );
12291270 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
12301281 /*
12311282 * Skip ses channels since they're only handled in lower layers
12321283 * (e.g. cifs_send_recv).
@@ -1254,12 +1305,16 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
12541305 return ;
12551306 }
12561307
1308+ /* srv_count can never go negative */
1309+ WARN_ON (server -> srv_count < 0 );
1310+
12571311 put_net (cifs_net_ns (server ));
12581312
12591313 list_del_init (& server -> tcp_ses_list );
12601314 spin_unlock (& cifs_tcp_ses_lock );
12611315
12621316 cancel_delayed_work_sync (& server -> echo );
1317+ cancel_delayed_work_sync (& server -> resolve );
12631318
12641319 if (from_reconnect )
12651320 /*
@@ -1342,6 +1397,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx)
13421397 INIT_LIST_HEAD (& tcp_ses -> tcp_ses_list );
13431398 INIT_LIST_HEAD (& tcp_ses -> smb_ses_list );
13441399 INIT_DELAYED_WORK (& tcp_ses -> echo , cifs_echo_request );
1400+ INIT_DELAYED_WORK (& tcp_ses -> resolve , cifs_resolve_server );
13451401 INIT_DELAYED_WORK (& tcp_ses -> reconnect , smb2_reconnect_server );
13461402 mutex_init (& tcp_ses -> reconnect_mutex );
13471403 memcpy (& tcp_ses -> srcaddr , & ctx -> srcaddr ,
@@ -1427,6 +1483,12 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx)
14271483 /* queue echo request delayed work */
14281484 queue_delayed_work (cifsiod_wq , & tcp_ses -> echo , tcp_ses -> echo_interval );
14291485
1486+ /* queue dns resolution delayed work */
1487+ cifs_dbg (FYI , "%s: next dns resolution scheduled for %d seconds in the future\n" ,
1488+ __func__ , SMB_DNS_RESOLVE_INTERVAL_DEFAULT );
1489+
1490+ queue_delayed_work (cifsiod_wq , & tcp_ses -> resolve , (SMB_DNS_RESOLVE_INTERVAL_DEFAULT * HZ ));
1491+
14301492 return tcp_ses ;
14311493
14321494out_err_crypto_release :
@@ -1605,6 +1667,9 @@ void cifs_put_smb_ses(struct cifs_ses *ses)
16051667 }
16061668 spin_unlock (& cifs_tcp_ses_lock );
16071669
1670+ /* ses_count can never go negative */
1671+ WARN_ON (ses -> ses_count < 0 );
1672+
16081673 spin_lock (& GlobalMid_Lock );
16091674 if (ses -> status == CifsGood )
16101675 ses -> status = CifsExiting ;
@@ -1972,6 +2037,9 @@ cifs_put_tcon(struct cifs_tcon *tcon)
19722037 return ;
19732038 }
19742039
2040+ /* tc_count can never go negative */
2041+ WARN_ON (tcon -> tc_count < 0 );
2042+
19752043 if (tcon -> use_witness ) {
19762044 int rc ;
19772045
@@ -2910,6 +2978,23 @@ static int mount_setup_tlink(struct cifs_sb_info *cifs_sb, struct cifs_ses *ses,
29102978}
29112979
29122980#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+
29132998/*
29142999 * cifs_build_path_to_root returns full path to root when we do not have an
29153000 * existing connection (tcon)
@@ -3105,7 +3190,7 @@ static int do_dfs_failover(const char *path, const char *full_path, struct cifs_
31053190 tmp_ctx .prepath );
31063191
31073192 mount_put_conns (cifs_sb , * xid , * server , * ses , * tcon );
3108- 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 );
31093194 if (!rc || (* server && * ses )) {
31103195 /*
31113196 * We were able to connect to new target server. Update current context with
@@ -3404,7 +3489,12 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34043489 goto error ;
34053490 }
34063491
3407- 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 );
34083498
34093499 /* Get path of DFS root */
34103500 ref_path = build_unc_path_to_root (ctx , cifs_sb , false);
@@ -3433,7 +3523,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34333523 /* Connect to new DFS target only if we were redirected */
34343524 if (oldmnt != cifs_sb -> ctx -> mount_options ) {
34353525 mount_put_conns (cifs_sb , xid , server , ses , tcon );
3436- rc = mount_get_conns (ctx , cifs_sb , & xid , & server , & ses , & tcon );
3526+ rc = mount_get_dfs_conns (ctx , cifs_sb , & xid , & server , & ses , & tcon );
34373527 }
34383528 if (rc && !server && !ses ) {
34393529 /* Failed to connect. Try to connect to other targets in the referral. */
@@ -3459,7 +3549,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
34593549 rc = - ELOOP ;
34603550 } while (rc == - EREMOTE );
34613551
3462- if (rc || !tcon )
3552+ if (rc || !tcon || ! ses )
34633553 goto error ;
34643554
34653555 kfree (ref_path );
@@ -4095,7 +4185,8 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
40954185 if (!tree )
40964186 return - ENOMEM ;
40974187
4098- if (!tcon -> dfs_path ) {
4188+ /* If it is not dfs or there was no cached dfs referral, then reconnect to same share */
4189+ if (!tcon -> dfs_path || dfs_cache_noreq_find (tcon -> dfs_path + 1 , & ref , & tl )) {
40994190 if (tcon -> ipc ) {
41004191 scnprintf (tree , MAX_TREE_SIZE , "\\\\%s\\IPC$" , server -> hostname );
41014192 rc = ops -> tree_connect (xid , tcon -> ses , tree , tcon , nlsc );
@@ -4105,9 +4196,6 @@ int cifs_tree_connect(const unsigned int xid, struct cifs_tcon *tcon, const stru
41054196 goto out ;
41064197 }
41074198
4108- rc = dfs_cache_noreq_find (tcon -> dfs_path + 1 , & ref , & tl );
4109- if (rc )
4110- goto out ;
41114199 isroot = ref .server_type == DFS_TYPE_ROOT ;
41124200 free_dfs_info_param (& ref );
41134201
0 commit comments