Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ksmbd: reset rcount per connection in ksmbd_conn_wait_idle_sess_id()

rcount is intended to be connection-specific: 2 for curr_conn, 1 for
every other connection sharing the same session. However, it is
initialised only once before the hash iteration and is never reset.
After the loop visits curr_conn, later sibling connections are also
checked against rcount == 2, so a sibling with req_running == 1 is
incorrectly treated as idle. This makes the outcome depend on the
hash iteration order: whether a given sibling is checked against the
loose (< 2) or the strict (< 1) threshold is decided by whether it
happens to be visited before or after curr_conn.

The function's contract is "wait until every connection sharing this
session is idle" so that destroy_previous_session() can safely tear
the session down. The latched rcount violates that contract and
reopens the teardown race window the wait logic was meant to close:
destroy_previous_session() may proceed before sibling channels have
actually quiesced, overlapping session teardown with in-flight work
on those connections.

Recompute rcount inside the loop so each connection is compared
against its own threshold regardless of iteration order.

This is a code-inspection fix for an iteration-order-dependent logic
error; a targeted reproducer would require SMB3 multichannel with
in-flight work on a sibling channel landing after curr_conn in hash
order, which is not something that can be triggered reliably.

Fixes: 76e98a158b20 ("ksmbd: fix race condition between destroy_previous_session() and smb2 operations()")
Cc: stable@vger.kernel.org
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

DaeMyung Kang and committed by
Steve French
def036ef 30010c95

+2 -3
+2 -3
fs/smb/server/connection.c
··· 237 237 { 238 238 struct ksmbd_conn *conn; 239 239 int rc, retry_count = 0, max_timeout = 120; 240 - int rcount = 1, bkt; 240 + int rcount, bkt; 241 241 242 242 retry_idle: 243 243 if (retry_count >= max_timeout) ··· 246 246 down_read(&conn_list_lock); 247 247 hash_for_each(conn_list, bkt, conn, hlist) { 248 248 if (conn->binding || xa_load(&conn->sessions, sess_id)) { 249 - if (conn == curr_conn) 250 - rcount = 2; 249 + rcount = (conn == curr_conn) ? 2 : 1; 251 250 if (atomic_read(&conn->req_running) >= rcount) { 252 251 rc = wait_event_timeout(conn->req_running_q, 253 252 atomic_read(&conn->req_running) < rcount,