Blob Blame History Raw
From 28eb24ff75c5ac130eb326b3b4d0dcecfc0f427d Mon Sep 17 00:00:00 2001
From: Paulo Alcantara <paulo@paulo.ac>
Date: Tue, 20 Nov 2018 15:16:36 -0200
Subject: cifs: Always resolve hostname before reconnecting
Git-commit: 28eb24ff75c5ac130eb326b3b4d0dcecfc0f427d
Patch-mainline: v5.0-rc1
References: bsc#1051510, bsc#1144333

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 <stfrench@microsoft.com>
Signed-off-by: Paulo Alcantara <palcantara@suse.de>
Signed-off-by: Steve French <stfrench@microsoft.com>
Acked-by: Paulo Alcantara <palcantara@suse.de>
---
 fs/cifs/connect.c | 84 ++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 52 insertions(+), 32 deletions(-)

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 {
-- 
2.16.4