diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 412d141e1adc..2cf74028ce70 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -128,114 +128,22 @@ cifs_mark_open_files_invalid(struct cifs_tcon *tcon)
 static int
 cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
 {
-	int rc;
-	struct cifs_ses *ses;
-	struct TCP_Server_Info *server;
-	struct nls_table *nls_codepage;
-	int retries;
-
-	/*
-	 * SMBs NegProt, SessSetup, uLogoff do not have tcon yet so check for
-	 * tcp and smb session status done differently for those three - in the
-	 * calling routine
-	 */
-	if (!tcon)
-		return 0;
-
-	ses = tcon->ses;
-	server = ses->server;
+	struct cifs_tcon_reconnect_params params = {
+		.skip_reconnect = false,
+	};
 
 	/*
 	 * only tree disconnect, open, and write, (and ulogoff which does not
 	 * have tcon) are allowed as we start force umount
 	 */
-	if (tcon->tidStatus == CifsExiting) {
-		if (smb_command != SMB_COM_WRITE_ANDX &&
-		    smb_command != SMB_COM_OPEN_ANDX &&
-		    smb_command != SMB_COM_TREE_DISCONNECT) {
-			cifs_dbg(FYI, "can not send cmd %d while umounting\n",
-				 smb_command);
-			return -ENODEV;
-		}
-	}
-
-	retries = server->nr_targets;
-
-	/*
-	 * Give demultiplex thread up to 10 seconds to each target available for
-	 * reconnect -- should be greater than cifs socket timeout which is 7
-	 * seconds.
-	 */
-	while (server->tcpStatus == CifsNeedReconnect) {
-		rc = wait_event_interruptible_timeout(server->response_q,
-						      (server->tcpStatus != CifsNeedReconnect),
-						      10 * HZ);
-		if (rc < 0) {
-			cifs_dbg(FYI, "%s: aborting reconnect due to a received"
-				 " signal by the process\n", __func__);
-			return -ERESTARTSYS;
-		}
-
-		/* are we still trying to reconnect? */
-		if (server->tcpStatus != CifsNeedReconnect)
-			break;
-
-		if (retries && --retries)
-			continue;
-
-		/*
-		 * on "soft" mounts we wait once. Hard mounts keep
-		 * retrying until process is killed or server comes
-		 * back on-line
-		 */
-		if (!tcon->retry) {
-			cifs_dbg(FYI, "gave up waiting on reconnect in smb_init\n");
-			return -EHOSTDOWN;
-		}
-		retries = server->nr_targets;
-	}
-
-	if (!ses->need_reconnect && !tcon->need_reconnect)
-		return 0;
-
-	nls_codepage = load_nls_default();
-
-	/*
-	 * need to prevent multiple threads trying to simultaneously
-	 * reconnect the same SMB session
-	 */
-	mutex_lock(&ses->session_mutex);
-
-	/*
-	 * Recheck after acquire mutex. If another thread is negotiating
-	 * and the server never sends an answer the socket will be closed
-	 * and tcpStatus set to reconnect.
-	 */
-	rc = cifs_connect_session_locked(0, ses,
-					 nls_codepage,
-					 tcon->retry);
-	/* do we need to reconnect tcon? */
-	if (rc || !tcon->need_reconnect) {
-		mutex_unlock(&ses->session_mutex);
-		goto out;
-	}
-
-	cifs_mark_open_files_invalid(tcon);
-	rc = cifs_tree_connect(0, tcon, nls_codepage);
-	mutex_unlock(&ses->session_mutex);
-	cifs_dbg(FYI, "reconnect tcon rc = %d\n", rc);
-
-	if (rc) {
-		printk_once(KERN_WARNING "reconnect tcon failed rc = %d\n", rc);
-		goto out;
+	switch (smb_command) {
+	case SMB_COM_WRITE_ANDX:
+	case SMB_COM_OPEN_ANDX:
+	case SMB_COM_TREE_DISCONNECT:
+		params.exit_nodev = true;
+		break;
 	}
 
-	atomic_inc(&tconInfoReconnectCount);
-
-	/* tell server Unix caps we support */
-	if (cap_unix(ses))
-		reset_cifs_unix_caps(0, tcon, NULL, NULL);
-
 	/*
 	 * Removed call to reopen open files here. It is safer (and faster) to
 	 * reopen files one at a time as needed in read and write.
@@ -243,7 +151,6 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
 	 * FIXME: what about file locks? don't we need to reclaim them ASAP?
 	 */
 
-out:
 	/*
 	 * Check if handle based operation so we know whether we can continue
 	 * or not without returning to caller to reset file handle
@@ -254,11 +161,11 @@ cifs_reconnect_tcon(struct cifs_tcon *tcon, int smb_command)
 	case SMB_COM_CLOSE:
 	case SMB_COM_FIND_CLOSE2:
 	case SMB_COM_LOCKING_ANDX:
-		rc = -EAGAIN;
+		params.late_eagain = true;
+		break;
 	}
 
-	unload_nls(nls_codepage);
-	return rc;
+	return cifs_tcon_reconnect(tcon, &params);
 }
 
 /* Allocate and return pointer to an SMB request buffer, and set basic
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 67d2ad330f33..e920335384d7 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -5510,6 +5510,13 @@ cifs_tcon_reconnect(struct cifs_tcon *tcon,
 		goto out;
 	}
 
+	/*
+	 * tell server Unix caps we support,
+	 * note it's a noop for SMB2.
+	 */
+	if (cap_unix(ses))
+		reset_cifs_unix_caps(0, tcon, NULL, NULL);
+
 	if (params->start_timer)
 		mod_delayed_work(cifsiod_wq, &server->reconnect, 0);
 
