From 28eb24ff75c5ac130eb326b3b4d0dcecfc0f427d Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Tue, 20 Nov 2018 15:16:36 -0200 Subject: cifs: Always resolve hostname before reconnecting In case a hostname resolves to a different IP address (e.g. long running mounts), make sure to resolve it every time prior to calling generic_ip_connect() in reconnect. Suggested-by: Steve French Signed-off-by: Paulo Alcantara Signed-off-by: Steve French --- fs/cifs/connect.c | 84 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 32 deletions(-) (limited to 'fs/cifs/connect.c') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 80ef165d5f33..69b9d5606eba 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -325,6 +325,53 @@ static int cifs_setup_volume_info(struct smb_vol *volume_info, char *mount_data, const char *devname, bool is_smb3); static char *extract_hostname(const char *unc); +/* + * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may + * get their ip addresses changed at some point. + * + * This should be called with server->srv_mutex held. + */ +#ifdef CONFIG_CIFS_DFS_UPCALL +static int reconn_set_ipaddr(struct TCP_Server_Info *server) +{ + int rc; + int len; + char *unc, *ipaddr = NULL; + + if (!server->hostname) + return -EINVAL; + + len = strlen(server->hostname) + 3; + + unc = kmalloc(len, GFP_KERNEL); + if (!unc) { + cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__); + return -ENOMEM; + } + snprintf(unc, len, "\\\\%s", server->hostname); + + rc = dns_resolve_server_name_to_ip(unc, &ipaddr); + kfree(unc); + + if (rc < 0) { + cifs_dbg(FYI, "%s: failed to resolve server part of %s to IP: %d\n", + __func__, server->hostname, rc); + return rc; + } + + rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr, + strlen(ipaddr)); + kfree(ipaddr); + + return !rc ? -1 : 0; +} +#else +static inline int reconn_set_ipaddr(struct TCP_Server_Info *server) +{ + return 0; +} +#endif + #ifdef CONFIG_CIFS_DFS_UPCALL struct super_cb_data { struct TCP_Server_Info *server; @@ -366,10 +413,6 @@ static void reconn_inval_dfs_target(struct TCP_Server_Info *server, struct dfs_cache_tgt_iterator **tgt_it) { const char *name; - int rc; - char *ipaddr = NULL; - char *unc; - int len; if (!cifs_sb || !cifs_sb->origin_fullpath || !tgt_list || !server->nr_targets) @@ -393,34 +436,6 @@ static void reconn_inval_dfs_target(struct TCP_Server_Info *server, if (!server->hostname) { cifs_dbg(FYI, "%s: failed to extract hostname from target: %d\n", __func__, -ENOMEM); - return; - } - - len = strlen(server->hostname) + 3; - - unc = kmalloc(len, GFP_KERNEL); - if (!unc) { - cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__); - return; - } - snprintf(unc, len, "\\\\%s", server->hostname); - - rc = dns_resolve_server_name_to_ip(unc, &ipaddr); - kfree(unc); - - if (rc < 0) { - cifs_dbg(FYI, "%s: Failed to resolve server part of %s to IP: %d\n", - __func__, server->hostname, rc); - return; - } - - rc = cifs_convert_address((struct sockaddr *)&server->dstaddr, ipaddr, - strlen(ipaddr)); - kfree(ipaddr); - - if (!rc) { - cifs_dbg(FYI, "%s: failed to get ipaddr out of hostname\n", - __func__); } } @@ -567,6 +582,11 @@ cifs_reconnect(struct TCP_Server_Info *server) reconn_inval_dfs_target(server, cifs_sb, &tgt_list, &tgt_it); #endif + rc = reconn_set_ipaddr(server); + if (rc) { + cifs_dbg(FYI, "%s: failed to resolve hostname: %d\n", + __func__, rc); + } mutex_unlock(&server->srv_mutex); msleep(3000); } else { -- cgit v1.2.3-55-g7522