83 lines
3.1 KiB
Diff
83 lines
3.1 KiB
Diff
From 2cc6528030c91406031698e047896faa99fc0092 Mon Sep 17 00:00:00 2001
|
|
From: Shyam Prasad N <sprasad@microsoft.com>
|
|
Date: Mon, 2 Jun 2025 22:37:15 +0530
|
|
Subject: cifs: serialize other channels when query server interfaces is
|
|
pending
|
|
|
|
Today, during smb2_reconnect, session_mutex is released as soon as
|
|
the tcon is reconnected and is in a good state. However, in case
|
|
multichannel is enabled, there is also a query of server interfaces that
|
|
follows. We've seen that this query can race with reconnects of other
|
|
channels, causing them to step on each other with reconnects.
|
|
|
|
This change extends the hold of session_mutex till after the query of
|
|
server interfaces is complete. In order to avoid recursive smb2_reconnect
|
|
checks during query ioctl, this change also introduces a session flag
|
|
for sessions where such a query is in progress.
|
|
|
|
Signed-off-by: Shyam Prasad N <sprasad@microsoft.com>
|
|
Cc: stable@vger.kernel.org
|
|
Signed-off-by: Steve French <stfrench@microsoft.com>
|
|
---
|
|
fs/smb/client/cifsglob.h | 1 +
|
|
fs/smb/client/smb2pdu.c | 24 ++++++++++++++++++------
|
|
2 files changed, 19 insertions(+), 6 deletions(-)
|
|
|
|
--- a/fs/smb/client/cifsglob.h
|
|
+++ b/fs/smb/client/cifsglob.h
|
|
@@ -1084,6 +1084,7 @@ struct cifs_chan {
|
|
};
|
|
|
|
#define CIFS_SES_FLAG_SCALE_CHANNELS (0x1)
|
|
+#define CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES (0x2)
|
|
|
|
/*
|
|
* Session structure. One of these for each uid session with a particular host
|
|
--- a/fs/smb/client/smb2pdu.c
|
|
+++ b/fs/smb/client/smb2pdu.c
|
|
@@ -411,14 +411,19 @@ skip_sess_setup:
|
|
if (!rc &&
|
|
(server->capabilities & SMB2_GLOBAL_CAP_MULTI_CHANNEL) &&
|
|
server->ops->query_server_interfaces) {
|
|
- mutex_unlock(&ses->session_mutex);
|
|
-
|
|
/*
|
|
- * query server network interfaces, in case they change
|
|
+ * query server network interfaces, in case they change.
|
|
+ * Also mark the session as pending this update while the query
|
|
+ * is in progress. This will be used to avoid calling
|
|
+ * smb2_reconnect recursively.
|
|
*/
|
|
+ ses->flags |= CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES;
|
|
xid = get_xid();
|
|
rc = server->ops->query_server_interfaces(xid, tcon, false);
|
|
free_xid(xid);
|
|
+ ses->flags &= ~CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES;
|
|
+
|
|
+ mutex_unlock(&ses->session_mutex);
|
|
|
|
if (rc == -EOPNOTSUPP && ses->chan_count > 1) {
|
|
/*
|
|
@@ -560,11 +565,18 @@ static int smb2_ioctl_req_init(u32 opcod
|
|
struct TCP_Server_Info *server,
|
|
void **request_buf, unsigned int *total_len)
|
|
{
|
|
- /* Skip reconnect only for FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs */
|
|
- if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO) {
|
|
+ /*
|
|
+ * Skip reconnect in one of the following cases:
|
|
+ * 1. For FSCTL_VALIDATE_NEGOTIATE_INFO IOCTLs
|
|
+ * 2. For FSCTL_QUERY_NETWORK_INTERFACE_INFO IOCTL when called from
|
|
+ * smb2_reconnect (indicated by CIFS_SES_FLAG_SCALE_CHANNELS ses flag)
|
|
+ */
|
|
+ if (opcode == FSCTL_VALIDATE_NEGOTIATE_INFO ||
|
|
+ (opcode == FSCTL_QUERY_NETWORK_INTERFACE_INFO &&
|
|
+ (tcon->ses->flags & CIFS_SES_FLAGS_PENDING_QUERY_INTERFACES)))
|
|
return __smb2_plain_req_init(SMB2_IOCTL, tcon, server,
|
|
request_buf, total_len);
|
|
- }
|
|
+
|
|
return smb2_plain_req_init(SMB2_IOCTL, tcon, server,
|
|
request_buf, total_len);
|
|
}
|