#endif
        struct mutex refpath_lock; /* protects leaf_fullpath */
        /*
-        * Canonical DFS full paths that were used to chase referrals in mount and reconnect.
+        * origin_fullpath: Canonical copy of smb3_fs_context::source.
+        *                  It is used for matching existing DFS tcons.
         *
-        * origin_fullpath: first or original referral path
-        * leaf_fullpath: last referral path (might be changed due to nested links in reconnect)
+        * leaf_fullpath: Canonical DFS referral path related to this
+        *                connection.
+        *                It is used in DFS cache refresher, reconnect and may
+        *                change due to nested DFS links.
         *
-        * current_fullpath: pointer to either origin_fullpath or leaf_fullpath
-        * NOTE: cannot be accessed outside cifs_reconnect() and smb2_reconnect()
+        * Both protected by @refpath_lock and @srv_lock.  The @refpath_lock is
+        * mosly used for not requiring a copy of @leaf_fullpath when getting
+        * cached or new DFS referrals (which might also sleep during I/O).
+        * While @srv_lock is held for making string and NULL comparions against
+        * both fields as in mount(2) and cache refresh.
         *
-        * format: \\HOST\SHARE\[OPTIONAL PATH]
+        * format: \\HOST\SHARE[\OPTIONAL PATH]
         */
-       char *origin_fullpath, *leaf_fullpath, *current_fullpath;
+       char *origin_fullpath, *leaf_fullpath;
 };
 
 static inline bool is_smb1(struct TCP_Server_Info *server)
 
 static int reconnect_dfs_server(struct TCP_Server_Info *server)
 {
        int rc = 0;
-       const char *refpath = server->current_fullpath + 1;
        struct dfs_cache_tgt_list tl = DFS_CACHE_TGT_LIST_INIT(tl);
        struct dfs_cache_tgt_iterator *target_hint = NULL;
        int num_targets = 0;
         * through /proc/fs/cifs/dfscache or the target list is empty due to server settings after
         * refreshing the referral, so, in this case, default it to 1.
         */
-       if (!dfs_cache_noreq_find(refpath, NULL, &tl))
+       mutex_lock(&server->refpath_lock);
+       if (!dfs_cache_noreq_find(server->leaf_fullpath + 1, NULL, &tl))
                num_targets = dfs_cache_get_nr_tgts(&tl);
+       mutex_unlock(&server->refpath_lock);
        if (!num_targets)
                num_targets = 1;
 
                mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
        } while (server->tcpStatus == CifsNeedReconnect);
 
-       dfs_cache_noreq_update_tgthint(refpath, target_hint);
+       mutex_lock(&server->refpath_lock);
+       dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, target_hint);
+       mutex_unlock(&server->refpath_lock);
        dfs_cache_free_tgts(&tl);
 
        /* Need to set up echo worker again once connection has been established */
                        rc = -ENOMEM;
                        goto out_err;
                }
-               tcp_ses->current_fullpath = tcp_ses->leaf_fullpath;
        }
 
        if (ctx->nosharesock)
 
                tcon = mnt_ctx->tcon;
 
                mutex_lock(&server->refpath_lock);
+               spin_lock(&server->srv_lock);
                if (!server->origin_fullpath) {
                        server->origin_fullpath = origin_fullpath;
-                       server->current_fullpath = server->leaf_fullpath;
                        origin_fullpath = NULL;
                }
+               spin_unlock(&server->srv_lock);
                mutex_unlock(&server->refpath_lock);
 
                if (list_empty(&tcon->dfs_ses_list)) {
                rc = PTR_ERR(npath);
        } else {
                mutex_lock(&server->refpath_lock);
+               spin_lock(&server->srv_lock);
                kfree(server->leaf_fullpath);
                server->leaf_fullpath = npath;
+               spin_unlock(&server->srv_lock);
                mutex_unlock(&server->refpath_lock);
-               server->current_fullpath = server->leaf_fullpath;
        }
        return rc;
 }
                share = prefix = NULL;
 
                /* Check if share matches with tcp ses */
-               rc = dfs_cache_get_tgt_share(server->current_fullpath + 1, tit, &share, &prefix);
+               rc = dfs_cache_get_tgt_share(server->leaf_fullpath + 1, tit, &share, &prefix);
                if (rc) {
                        cifs_dbg(VFS, "%s: failed to parse target share: %d\n", __func__, rc);
                        break;
                        continue;
                }
 
-               dfs_cache_noreq_update_tgthint(server->current_fullpath + 1, tit);
+               dfs_cache_noreq_update_tgthint(server->leaf_fullpath + 1, tit);
                tree_connect_ipc(xid, tree, cifs_sb, tcon);
 
                scnprintf(tree, MAX_TREE_SIZE, "\\%s", share);
        cifs_sb = CIFS_SB(sb);
 
        /* If it is not dfs or there was no cached dfs referral, then reconnect to same share */
-       if (!server->current_fullpath ||
-           dfs_cache_noreq_find(server->current_fullpath + 1, &ref, &tl)) {
+       if (!server->leaf_fullpath ||
+           dfs_cache_noreq_find(server->leaf_fullpath + 1, &ref, &tl)) {
                rc = ops->tree_connect(xid, tcon->ses, tcon->tree_name, tcon, cifs_sb->local_nls);
                goto out;
        }
 
        size_t len;
        char *s;
 
-       if (unlikely(!server->origin_fullpath))
+       spin_lock(&server->srv_lock);
+       if (unlikely(!server->origin_fullpath)) {
+               spin_unlock(&server->srv_lock);
                return ERR_PTR(-EREMOTE);
+       }
+       spin_unlock(&server->srv_lock);
 
        s = dentry_path_raw(dentry, page, PATH_MAX);
        if (IS_ERR(s))
        if (!s[1])
                s++;
 
+       spin_lock(&server->srv_lock);
        len = strlen(server->origin_fullpath);
-       if (s < (char *)page + len)
+       if (s < (char *)page + len) {
+               spin_unlock(&server->srv_lock);
                return ERR_PTR(-ENAMETOOLONG);
+       }
 
        s -= len;
        memcpy(s, server->origin_fullpath, len);
+       spin_unlock(&server->srv_lock);
        convert_delimiter(s, '/');
+
        return s;
 }
 
 
 
        spin_lock(&cifs_tcp_ses_lock);
        list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
-               if (!server->leaf_fullpath)
+               spin_lock(&server->srv_lock);
+               if (!server->leaf_fullpath) {
+                       spin_unlock(&server->srv_lock);
                        continue;
+               }
+               spin_unlock(&server->srv_lock);
 
                list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
                        if (ses->tcon_ipc) {