Linux CIFS filesystem development
 help / color / mirror / Atom feed
From: Enzo Matsumiya <ematsumiya@suse.de>
To: linux-cifs@vger.kernel.org
Cc: pc@manguebit.org, linkinjeon@kernel.org,
	ronniesahlberg@gmail.com, sprasad@microsoft.com, tom@talpey.com,
	bharathsm@microsoft.com, henrique.carvalho@suse.com,
	Enzo Matsumiya <ematsumiya@suse.de>
Subject: [PATCH v2 1/2] smb: client: fast fail sends if need to reconnect
Date: Mon, 28 Sep 2026 12:03:54 -0300	[thread overview]
Message-ID: <20260928150355.850472-2-ematsumiya@suse.de> (raw)
In-Reply-To: <20260928150355.850472-1-ematsumiya@suse.de>

smb_send_kvec() keeps retrying when server needs to reconnect, which
makes no sense as cifs_reconnect() will never run in parallel (because
both need server mutex).
IOW, retrying will never succeed, but only delay reconnects further.

Bail out early from smb_send_kvec() when need to reconnect.

Also shutdown socket queues when CifsNeedReconnect is first set, so any
sends/receives fails immediately (don't wait for socket to timeout).

Consequential change:
To shutdown the socket, we need to hold server mutex. Since not all
callers hold it when calling cifs_signal_cifsd_for_reconnect(), we
need to keep track of the owner task, so we can lock it as needed.

Add TCP_Server_Info::mutex_owner for that.

Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
---
v1 -> v2 (fix issues detected by sashiko):
- move kernel_sock_shutdown() call out of cifs_tcp_ses_lock
- use server mutex to check/shutdown socket


 fs/smb/client/cifsglob.h  |  3 +++
 fs/smb/client/connect.c   | 54 +++++++++++++++++++++++++++++++--------
 fs/smb/client/transport.c |  8 ++++++
 3 files changed, 55 insertions(+), 10 deletions(-)

diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h
index 79e4e84f8985..d279b5c92a08 100644
--- a/fs/smb/client/cifsglob.h
+++ b/fs/smb/client/cifsglob.h
@@ -711,6 +711,7 @@ struct TCP_Server_Info {
 	spinlock_t req_lock;  /* protect the two values above */
 	struct mutex _srv_mutex;
 	unsigned int nofs_flag;
+	struct task_struct *mutex_owner;
 	struct task_struct *tsk;
 	char server_GUID[16];
 	__u16 sec_mode;
@@ -847,12 +848,14 @@ static inline void cifs_server_lock(struct TCP_Server_Info *server)
 
 	mutex_lock(&server->_srv_mutex);
 	server->nofs_flag = nofs_flag;
+	server->mutex_owner = current;
 }
 
 static inline void cifs_server_unlock(struct TCP_Server_Info *server)
 {
 	unsigned int nofs_flag = server->nofs_flag;
 
+	server->mutex_owner = NULL;
 	mutex_unlock(&server->_srv_mutex);
 	memalloc_nofs_restore(nofs_flag);
 }
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 28e1ddeb6182..4cc433308c96 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -127,13 +127,42 @@ void smb2_query_server_interfaces(struct work_struct *work)
 			   (SMB_INTERFACE_POLL_INTERVAL * HZ));
 }
 
-#define set_need_reco(server) \
-do { \
-	spin_lock(&server->srv_lock); \
-	if (server->tcpStatus != CifsExiting) \
-		server->tcpStatus = CifsNeedReconnect; \
-	spin_unlock(&server->srv_lock); \
-} while (0)
+static inline bool __set_need_reco(struct TCP_Server_Info *server)
+{
+	bool need_reco = false;
+
+	spin_lock(&server->srv_lock);
+	if (server->tcpStatus != CifsExiting) {
+		need_reco = (server->tcpStatus != CifsNeedReconnect);
+		server->tcpStatus = CifsNeedReconnect;
+	}
+	spin_unlock(&server->srv_lock);
+
+	return need_reco;
+}
+
+static inline void kill_socket_queues(struct TCP_Server_Info *server)
+{
+	bool locked = false;
+
+	if (server->mutex_owner != current) {
+		cifs_server_lock(server);
+		locked = true;
+	}
+
+	if (server->ssocket)
+		/* Don't release it yet! */
+		kernel_sock_shutdown(server->ssocket, SHUT_RDWR);
+
+	if (locked)
+		cifs_server_unlock(server);
+}
+
+static inline void set_need_reco(struct TCP_Server_Info *server)
+{
+	if (__set_need_reco(server))
+		kill_socket_queues(server);
+}
 
 /*
  * Update the tcpStatus for the server.
@@ -151,6 +180,7 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
 	struct TCP_Server_Info *nserver;
 	struct cifs_ses *ses;
 	LIST_HEAD(reco);
+	bool shutdown;
 	int i;
 
 	/* if we need to signal just this channel */
@@ -162,7 +192,7 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
 	if (SERVER_IS_CHAN(server))
 		server = server->primary_server;
 	scoped_guard(spinlock, &cifs_tcp_ses_lock) {
-		set_need_reco(server);
+		shutdown = __set_need_reco(server);
 		list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
 			spin_lock(&ses->ses_lock);
 			if (ses->ses_status == SES_EXITING) {
@@ -184,6 +214,9 @@ cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server,
 		}
 	}
 
+	if (shutdown)
+		kill_socket_queues(server);
+
 	spin_lock(&cifs_tcp_ses_lock);
 	list_for_each_entry_safe(server, nserver, &reco, rlist) {
 		list_del_init(&server->rlist);
@@ -365,9 +398,10 @@ static bool cifs_tcp_ses_needs_reconnect(struct TCP_Server_Info *server, int num
 	cifs_dbg(FYI, "Mark tcp session as need reconnect\n");
 	trace_smb3_reconnect(server->current_mid, server->conn_id,
 			     server->hostname);
-	server->tcpStatus = CifsNeedReconnect;
-
 	spin_unlock(&server->srv_lock);
+
+	set_need_reco(server);
+
 	return true;
 }
 
diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c
index 6e21b5f8754a..c6e0ee6d0ef4 100644
--- a/fs/smb/client/transport.c
+++ b/fs/smb/client/transport.c
@@ -180,6 +180,10 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
 		 */
 		rc = sock_sendmsg(ssocket, smb_msg);
 		if (rc == -EAGAIN || unlikely(rc == -EINTR && task_work_pending(current))) {
+			/* Don't retry if need to reconnect */
+			if (unlikely(server->tcpStatus == CifsNeedReconnect))
+				return -ECONNRESET;
+
 			retries++;
 			if (retries >= 14 ||
 			    (!server->noblocksnd && (retries > 2))) {
@@ -191,6 +195,10 @@ smb_send_kvec(struct TCP_Server_Info *server, struct msghdr *smb_msg,
 			continue;
 		}
 
+		/* Blame the need to reconnect for any non-interrupt error */
+		if (unlikely(server->tcpStatus == CifsNeedReconnect && !is_interrupt_error(rc)))
+			rc = -ECONNRESET;
+
 		if (rc < 0)
 			return rc;
 
-- 
2.55.0


  reply	other threads:[~2026-09-28 15:04 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-28 15:03 [PATCH v2 0/2] reconnect fixes and improvements Enzo Matsumiya
2026-09-28 15:03 ` Enzo Matsumiya [this message]
2026-09-29  4:14   ` [PATCH v2 1/2] smb: client: fast fail sends if need to reconnect Namjae Jeon
2026-09-29 12:25     ` Enzo Matsumiya
2026-09-28 15:03 ` [PATCH v2 2/2] smb: client: prevent premature discard of requests if reconnecting Enzo Matsumiya
2026-10-06 13:49 ` [PATCH v2 0/2] reconnect fixes and improvements Enzo Matsumiya
2026-10-06 15:51   ` Paulo Alcantara
2026-10-06 15:57     ` Enzo Matsumiya

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260928150355.850472-2-ematsumiya@suse.de \
    --to=ematsumiya@suse.de \
    --cc=bharathsm@microsoft.com \
    --cc=henrique.carvalho@suse.com \
    --cc=linkinjeon@kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=pc@manguebit.org \
    --cc=ronniesahlberg@gmail.com \
    --cc=sprasad@microsoft.com \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox