Skip to content

Commit 506c1da

Browse files
sprasad-microsoftsmfrench
authored andcommitted
cifs: use the expiry output of dns_query to schedule next resolution
We recently fixed DNS resolution of the server hostname during reconnect. However, server IP address may change, even when the old one continues to server (although sub-optimally). We should schedule the next DNS resolution based on the TTL of the DNS record used for the last resolution. This way, we resolve the server hostname again when a DNS record expires. Signed-off-by: Shyam Prasad N <[email protected]> Reviewed-by: Paulo Alcantara (SUSE) <[email protected]> Cc: <[email protected]> # v5.11+ Signed-off-by: Steve French <[email protected]>
1 parent e73f0f0 commit 506c1da

File tree

6 files changed

+65
-10
lines changed

6 files changed

+65
-10
lines changed

fs/cifs/cifs_dfs_ref.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ char *cifs_compose_mount_options(const char *sb_mountdata,
176176
}
177177
}
178178

179-
rc = dns_resolve_server_name_to_ip(name, &srvIP);
179+
rc = dns_resolve_server_name_to_ip(name, &srvIP, NULL);
180180
if (rc < 0) {
181181
cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n",
182182
__func__, name, rc);

fs/cifs/cifsglob.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@
7575
#define SMB_ECHO_INTERVAL_MAX 600
7676
#define SMB_ECHO_INTERVAL_DEFAULT 60
7777

78+
/* dns resolution interval in seconds */
79+
#define SMB_DNS_RESOLVE_INTERVAL_DEFAULT 600
80+
7881
/* maximum number of PDUs in one compound */
7982
#define MAX_COMPOUND 5
8083

@@ -646,6 +649,7 @@ struct TCP_Server_Info {
646649
/* point to the SMBD connection if RDMA is used instead of socket */
647650
struct smbd_connection *smbd_conn;
648651
struct delayed_work echo; /* echo ping workqueue job */
652+
struct delayed_work resolve; /* dns resolution workqueue job */
649653
char *smallbuf; /* pointer to current "small" buffer */
650654
char *bigbuf; /* pointer to current "big" buffer */
651655
/* Total size of this PDU. Only valid from cifs_demultiplex_thread */

fs/cifs/connect.c

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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;
@@ -1260,6 +1301,7 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect)
12601301
spin_unlock(&cifs_tcp_ses_lock);
12611302

12621303
cancel_delayed_work_sync(&server->echo);
1304+
cancel_delayed_work_sync(&server->resolve);
12631305

12641306
if (from_reconnect)
12651307
/*
@@ -1342,6 +1384,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx)
13421384
INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
13431385
INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
13441386
INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request);
1387+
INIT_DELAYED_WORK(&tcp_ses->resolve, cifs_resolve_server);
13451388
INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server);
13461389
mutex_init(&tcp_ses->reconnect_mutex);
13471390
memcpy(&tcp_ses->srcaddr, &ctx->srcaddr,
@@ -1427,6 +1470,12 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx)
14271470
/* queue echo request delayed work */
14281471
queue_delayed_work(cifsiod_wq, &tcp_ses->echo, tcp_ses->echo_interval);
14291472

1473+
/* queue dns resolution delayed work */
1474+
cifs_dbg(FYI, "%s: next dns resolution scheduled for %d seconds in the future\n",
1475+
__func__, SMB_DNS_RESOLVE_INTERVAL_DEFAULT);
1476+
1477+
queue_delayed_work(cifsiod_wq, &tcp_ses->resolve, (SMB_DNS_RESOLVE_INTERVAL_DEFAULT * HZ));
1478+
14301479
return tcp_ses;
14311480

14321481
out_err_crypto_release:

fs/cifs/dns_resolve.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,15 @@
2424
* dns_resolve_server_name_to_ip - Resolve UNC server name to ip address.
2525
* @unc: UNC path specifying the server (with '/' as delimiter)
2626
* @ip_addr: Where to return the IP address.
27+
* @expiry: Where to return the expiry time for the dns record.
2728
*
2829
* The IP address will be returned in string form, and the caller is
2930
* responsible for freeing it.
3031
*
3132
* Returns length of result on success, -ve on error.
3233
*/
3334
int
34-
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
35+
dns_resolve_server_name_to_ip(const char *unc, char **ip_addr, time64_t *expiry)
3536
{
3637
struct sockaddr_storage ss;
3738
const char *hostname, *sep;
@@ -66,13 +67,14 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
6667

6768
/* Perform the upcall */
6869
rc = dns_query(current->nsproxy->net_ns, NULL, hostname, len,
69-
NULL, ip_addr, NULL, false);
70+
NULL, ip_addr, expiry, false);
7071
if (rc < 0)
7172
cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
7273
__func__, len, len, hostname);
7374
else
74-
cifs_dbg(FYI, "%s: resolved: %*.*s to %s\n",
75-
__func__, len, len, hostname, *ip_addr);
75+
cifs_dbg(FYI, "%s: resolved: %*.*s to %s expiry %llu\n",
76+
__func__, len, len, hostname, *ip_addr,
77+
expiry ? (*expiry) : 0);
7678
return rc;
7779

7880
name_is_IP_address:

fs/cifs/dns_resolve.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#define _DNS_RESOLVE_H
1313

1414
#ifdef __KERNEL__
15-
extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr);
15+
extern int dns_resolve_server_name_to_ip(const char *unc, char **ip_addr, time64_t *expiry);
1616
#endif /* KERNEL */
1717

1818
#endif /* _DNS_RESOLVE_H */

fs/cifs/misc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,7 @@ int match_target_ip(struct TCP_Server_Info *server,
11871187

11881188
cifs_dbg(FYI, "%s: target name: %s\n", __func__, target + 2);
11891189

1190-
rc = dns_resolve_server_name_to_ip(target, &tip);
1190+
rc = dns_resolve_server_name_to_ip(target, &tip, NULL);
11911191
if (rc < 0)
11921192
goto out;
11931193

0 commit comments

Comments
 (0)