Skip to content

Commit

Permalink
cifs: serialize other channels when query server interfaces is pending
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Shyam Prasad N authored and Steve French committed Jun 3, 2025
1 parent 66d590b commit b5e3e6e
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 6 deletions.
1 change: 1 addition & 0 deletions fs/smb/client/cifsglob.h
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,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
Expand Down
24 changes: 18 additions & 6 deletions fs/smb/client/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -412,14 +412,19 @@ smb2_reconnect(__le16 smb2_command, struct cifs_tcon *tcon,
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) {
/*
Expand Down Expand Up @@ -561,11 +566,18 @@ static int smb2_ioctl_req_init(u32 opcode, struct cifs_tcon *tcon,
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);
}
Expand Down

0 comments on commit b5e3e6e

Please sign in to comment.