smb: client: don't retry DFS targets on server shutdown
authorPaulo Alcantara <pc@manguebit.com>
Mon, 13 Jan 2025 22:00:29 +0000 (19:00 -0300)
committerSteve French <stfrench@microsoft.com>
Mon, 20 Jan 2025 01:34:00 +0000 (19:34 -0600)
If TCP Server is about to be destroyed (e.g. CifsExiting was set) and
it is reconnecting, stop retrying DFS targets from cached DFS referral
as this would potentially delay server shutdown in several seconds.

Signed-off-by: Paulo Alcantara (Red Hat) <pc@manguebit.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/client/connect.c

index 004fec3..73d07d9 100644 (file)
@@ -422,7 +422,8 @@ static int __cifs_reconnect(struct TCP_Server_Info *server,
 }
 
 #ifdef CONFIG_CIFS_DFS_UPCALL
-static int __reconnect_target_unlocked(struct TCP_Server_Info *server, const char *target)
+static int __reconnect_target_locked(struct TCP_Server_Info *server,
+                                    const char *target)
 {
        int rc;
        char *hostname;
@@ -455,27 +456,36 @@ static int __reconnect_target_unlocked(struct TCP_Server_Info *server, const cha
        return rc;
 }
 
-static int reconnect_target_unlocked(struct TCP_Server_Info *server, struct dfs_cache_tgt_list *tl,
-                                    struct dfs_cache_tgt_iterator **target_hint)
+static int reconnect_target_locked(struct TCP_Server_Info *server,
+                                  struct dfs_cache_tgt_list *tl,
+                                  struct dfs_cache_tgt_iterator **target_hint)
 {
-       int rc;
        struct dfs_cache_tgt_iterator *tit;
+       int rc;
 
        *target_hint = NULL;
 
        /* If dfs target list is empty, then reconnect to last server */
        tit = dfs_cache_get_tgt_iterator(tl);
        if (!tit)
-               return __reconnect_target_unlocked(server, server->hostname);
+               return __reconnect_target_locked(server, server->hostname);
 
        /* Otherwise, try every dfs target in @tl */
-       for (; tit; tit = dfs_cache_get_next_tgt(tl, tit)) {
-               rc = __reconnect_target_unlocked(server, dfs_cache_get_tgt_name(tit));
+       do {
+               const char *target = dfs_cache_get_tgt_name(tit);
+
+               spin_lock(&server->srv_lock);
+               if (server->tcpStatus != CifsNeedReconnect) {
+                       spin_unlock(&server->srv_lock);
+                       return -ECONNRESET;
+               }
+               spin_unlock(&server->srv_lock);
+               rc = __reconnect_target_locked(server, target);
                if (!rc) {
                        *target_hint = tit;
                        break;
                }
-       }
+       } while ((tit = dfs_cache_get_next_tgt(tl, tit)));
        return rc;
 }
 
@@ -518,7 +528,7 @@ static int reconnect_dfs_server(struct TCP_Server_Info *server)
                try_to_freeze();
                cifs_server_lock(server);
 
-               rc = reconnect_target_unlocked(server, &tl, &target_hint);
+               rc = reconnect_target_locked(server, &tl, &target_hint);
                if (rc) {
                        /* Failed to reconnect socket */
                        cifs_server_unlock(server);