]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ksmbd: convert tree_conns_lock to rw_semaphore
authorNamjae Jeon <linkinjeon@kernel.org>
Mon, 9 Feb 2026 12:33:44 +0000 (21:33 +0900)
committerSteve French <stfrench@microsoft.com>
Mon, 9 Feb 2026 23:48:53 +0000 (17:48 -0600)
Converts tree_conns_lock to an rw_semaphore to allow sleeping while
the lock is held. Additionally, it simplifies the locking logic in
ksmbd_tree_conn_session_logoff() and introduces
__ksmbd_tree_conn_disconnect() to avoid redundant locking.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
fs/smb/server/mgmt/tree_connect.c
fs/smb/server/mgmt/user_session.c
fs/smb/server/mgmt/user_session.h
fs/smb/server/smb2pdu.c

index 62b97936b5451b2bb11223605df959a0cd762659..57dd47ef688cee11548f4880c51d233de1b01a1a 100644 (file)
@@ -80,8 +80,10 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name)
        status.tree_conn = tree_conn;
        atomic_set(&tree_conn->refcount, 1);
 
+       down_write(&sess->tree_conns_lock);
        ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn,
                              KSMBD_DEFAULT_GFP));
+       up_write(&sess->tree_conns_lock);
        if (ret) {
                status.ret = -ENOMEM;
                goto out_error;
@@ -105,15 +107,11 @@ void ksmbd_tree_connect_put(struct ksmbd_tree_connect *tcon)
                kfree(tcon);
 }
 
-int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
-                              struct ksmbd_tree_connect *tree_conn)
+static int __ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
+                                       struct ksmbd_tree_connect *tree_conn)
 {
        int ret;
 
-       write_lock(&sess->tree_conns_lock);
-       xa_erase(&sess->tree_conns, tree_conn->id);
-       write_unlock(&sess->tree_conns_lock);
-
        ret = ksmbd_ipc_tree_disconnect_request(sess->id, tree_conn->id);
        ksmbd_release_tree_conn_id(sess, tree_conn->id);
        ksmbd_share_config_put(tree_conn->share_conf);
@@ -123,12 +121,22 @@ int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
        return ret;
 }
 
+int ksmbd_tree_conn_disconnect(struct ksmbd_session *sess,
+                              struct ksmbd_tree_connect *tree_conn)
+{
+       down_write(&sess->tree_conns_lock);
+       xa_erase(&sess->tree_conns, tree_conn->id);
+       up_write(&sess->tree_conns_lock);
+
+       return __ksmbd_tree_conn_disconnect(sess, tree_conn);
+}
+
 struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
                                                  unsigned int id)
 {
        struct ksmbd_tree_connect *tcon;
 
-       read_lock(&sess->tree_conns_lock);
+       down_read(&sess->tree_conns_lock);
        tcon = xa_load(&sess->tree_conns, id);
        if (tcon) {
                if (tcon->t_state != TREE_CONNECTED)
@@ -136,7 +144,7 @@ struct ksmbd_tree_connect *ksmbd_tree_conn_lookup(struct ksmbd_session *sess,
                else if (!atomic_inc_not_zero(&tcon->refcount))
                        tcon = NULL;
        }
-       read_unlock(&sess->tree_conns_lock);
+       up_read(&sess->tree_conns_lock);
 
        return tcon;
 }
@@ -150,18 +158,19 @@ int ksmbd_tree_conn_session_logoff(struct ksmbd_session *sess)
        if (!sess)
                return -EINVAL;
 
+       down_write(&sess->tree_conns_lock);
        xa_for_each(&sess->tree_conns, id, tc) {
-               write_lock(&sess->tree_conns_lock);
                if (tc->t_state == TREE_DISCONNECTED) {
-                       write_unlock(&sess->tree_conns_lock);
                        ret = -ENOENT;
                        continue;
                }
                tc->t_state = TREE_DISCONNECTED;
-               write_unlock(&sess->tree_conns_lock);
 
-               ret |= ksmbd_tree_conn_disconnect(sess, tc);
+               xa_erase(&sess->tree_conns, tc->id);
+               ret |= __ksmbd_tree_conn_disconnect(sess, tc);
        }
        xa_destroy(&sess->tree_conns);
+       up_write(&sess->tree_conns_lock);
+
        return ret;
 }
index c35083f576c32289f2b7d31d55d79c6a51bc9de7..b02fa4dcc2d69009550a0b74600b40280d55a603 100644 (file)
@@ -135,6 +135,7 @@ static int show_proc_session(struct seq_file *m, void *v)
        seq_printf(m, "%-20s\t%d\n", "channels", i);
 
        i = 0;
+       down_read(&sess->tree_conns_lock);
        xa_for_each(&sess->tree_conns, id, tree_conn) {
                share_conf = tree_conn->share_conf;
                seq_printf(m, "%-20s\t%s\t%8d", "share",
@@ -145,6 +146,7 @@ static int show_proc_session(struct seq_file *m, void *v)
                        seq_printf(m, " %s ", "disk");
                seq_putc(m, '\n');
        }
+       up_read(&sess->tree_conns_lock);
 
        ksmbd_user_session_put(sess);
        return 0;
@@ -673,8 +675,8 @@ static struct ksmbd_session *__session_create(int protocol)
        xa_init(&sess->ksmbd_chann_list);
        xa_init(&sess->rpc_handle_list);
        sess->sequence_number = 1;
-       rwlock_init(&sess->tree_conns_lock);
        atomic_set(&sess->refcnt, 2);
+       init_rwsem(&sess->tree_conns_lock);
        init_rwsem(&sess->rpc_lock);
        init_rwsem(&sess->chann_lock);
 
index d94f5e128a9b42a67b7ef4d0f92a3a7025a0a251..6aebd385be8474898894359139d1a8a53948aec9 100644 (file)
@@ -60,7 +60,7 @@ struct ksmbd_session {
 
        struct ksmbd_file_table         file_table;
        unsigned long                   last_active;
-       rwlock_t                        tree_conns_lock;
+       struct rw_semaphore             tree_conns_lock;
 
 #ifdef CONFIG_PROC_FS
        struct proc_dir_entry           *proc_entry;
index 3efcc7da1b9f64850b90ab3a81cc5f9327065be3..cbb31efdbaa2e3ae8040e63155da9742084140d9 100644 (file)
@@ -2037,9 +2037,9 @@ int smb2_tree_connect(struct ksmbd_work *work)
        if (conn->posix_ext_supported)
                status.tree_conn->posix_extensions = true;
 
-       write_lock(&sess->tree_conns_lock);
+       down_write(&sess->tree_conns_lock);
        status.tree_conn->t_state = TREE_CONNECTED;
-       write_unlock(&sess->tree_conns_lock);
+       up_write(&sess->tree_conns_lock);
        rsp->StructureSize = cpu_to_le16(16);
 out_err1:
        if (server_conf.flags & KSMBD_GLOBAL_FLAG_DURABLE_HANDLE && share &&
@@ -2193,16 +2193,16 @@ int smb2_tree_disconnect(struct ksmbd_work *work)
 
        ksmbd_close_tree_conn_fds(work);
 
-       write_lock(&sess->tree_conns_lock);
+       down_write(&sess->tree_conns_lock);
        if (tcon->t_state == TREE_DISCONNECTED) {
-               write_unlock(&sess->tree_conns_lock);
+               up_write(&sess->tree_conns_lock);
                rsp->hdr.Status = STATUS_NETWORK_NAME_DELETED;
                err = -ENOENT;
                goto err_out;
        }
 
        tcon->t_state = TREE_DISCONNECTED;
-       write_unlock(&sess->tree_conns_lock);
+       up_write(&sess->tree_conns_lock);
 
        err = ksmbd_tree_conn_disconnect(sess, tcon);
        if (err) {