]> git.itanic.dy.fi Git - linux-stable/commitdiff
ksmbd: Implements sess->ksmbd_chann_list as xarray
authorDawei Li <set_pte_at@outlook.com>
Sun, 15 Jan 2023 10:32:04 +0000 (18:32 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 May 2023 09:53:56 +0000 (11:53 +0200)
[ Upstream commit 1d9c4172110e645b383ff13eee759728d74f1a5d ]

For some ops on channel:
1. lookup_chann_list(), possibly on high frequency.
2. ksmbd_chann_del().

Connection is used as indexing key to lookup channel, in that case,
linear search based on list may suffer a bit for performance.

Implements sess->ksmbd_chann_list as xarray.

Signed-off-by: Dawei Li <set_pte_at@outlook.com>
Acked-by: Namjae Jeon <linkinjeon@kernel.org>
Signed-off-by: Steve French <stfrench@microsoft.com>
Stable-dep-of: f5c779b7ddbd ("ksmbd: fix racy issue from session setup and logoff")
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/ksmbd/mgmt/user_session.c
fs/ksmbd/mgmt/user_session.h
fs/ksmbd/smb2pdu.c

index 92b1603b5abeb7142adb0e8e2bbc73add37d89d7..a2b128dedcfcf92a3b17144d59b09cd891b2d597 100644 (file)
@@ -30,15 +30,15 @@ struct ksmbd_session_rpc {
 
 static void free_channel_list(struct ksmbd_session *sess)
 {
-       struct channel *chann, *tmp;
+       struct channel *chann;
+       unsigned long index;
 
-       write_lock(&sess->chann_lock);
-       list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
-                                chann_list) {
-               list_del(&chann->chann_list);
+       xa_for_each(&sess->ksmbd_chann_list, index, chann) {
+               xa_erase(&sess->ksmbd_chann_list, index);
                kfree(chann);
        }
-       write_unlock(&sess->chann_lock);
+
+       xa_destroy(&sess->ksmbd_chann_list);
 }
 
 static void __session_rpc_close(struct ksmbd_session *sess,
@@ -190,21 +190,15 @@ int ksmbd_session_register(struct ksmbd_conn *conn,
 
 static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
 {
-       struct channel *chann, *tmp;
-
-       write_lock(&sess->chann_lock);
-       list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list,
-                                chann_list) {
-               if (chann->conn == conn) {
-                       list_del(&chann->chann_list);
-                       kfree(chann);
-                       write_unlock(&sess->chann_lock);
-                       return 0;
-               }
-       }
-       write_unlock(&sess->chann_lock);
+       struct channel *chann;
+
+       chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
+       if (!chann)
+               return -ENOENT;
 
-       return -ENOENT;
+       kfree(chann);
+
+       return 0;
 }
 
 void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
@@ -234,7 +228,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
        return;
 
 sess_destroy:
-       if (list_empty(&sess->ksmbd_chann_list)) {
+       if (xa_empty(&sess->ksmbd_chann_list)) {
                xa_erase(&conn->sessions, sess->id);
                ksmbd_session_destroy(sess);
        }
@@ -320,6 +314,9 @@ static struct ksmbd_session *__session_create(int protocol)
        struct ksmbd_session *sess;
        int ret;
 
+       if (protocol != CIFDS_SESSION_FLAG_SMB2)
+               return NULL;
+
        sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
        if (!sess)
                return NULL;
@@ -329,30 +326,20 @@ static struct ksmbd_session *__session_create(int protocol)
 
        set_session_flag(sess, protocol);
        xa_init(&sess->tree_conns);
-       INIT_LIST_HEAD(&sess->ksmbd_chann_list);
+       xa_init(&sess->ksmbd_chann_list);
        INIT_LIST_HEAD(&sess->rpc_handle_list);
        sess->sequence_number = 1;
-       rwlock_init(&sess->chann_lock);
-
-       switch (protocol) {
-       case CIFDS_SESSION_FLAG_SMB2:
-               ret = __init_smb2_session(sess);
-               break;
-       default:
-               ret = -EINVAL;
-               break;
-       }
 
+       ret = __init_smb2_session(sess);
        if (ret)
                goto error;
 
        ida_init(&sess->tree_conn_ida);
 
-       if (protocol == CIFDS_SESSION_FLAG_SMB2) {
-               down_write(&sessions_table_lock);
-               hash_add(sessions_table, &sess->hlist, sess->id);
-               up_write(&sessions_table_lock);
-       }
+       down_write(&sessions_table_lock);
+       hash_add(sessions_table, &sess->hlist, sess->id);
+       up_write(&sessions_table_lock);
+
        return sess;
 
 error:
index 8934b8ee275ba12fa12a0c25179cd2622d3086f9..44a3c67b2bd9232714660df959ad098c593d07fa 100644 (file)
@@ -21,7 +21,6 @@ struct ksmbd_file_table;
 struct channel {
        __u8                    smb3signingkey[SMB3_SIGN_KEY_SIZE];
        struct ksmbd_conn       *conn;
-       struct list_head        chann_list;
 };
 
 struct preauth_session {
@@ -50,8 +49,7 @@ struct ksmbd_session {
        char                            sess_key[CIFS_KEY_SIZE];
 
        struct hlist_node               hlist;
-       rwlock_t                        chann_lock;
-       struct list_head                ksmbd_chann_list;
+       struct xarray                   ksmbd_chann_list;
        struct xarray                   tree_conns;
        struct ida                      tree_conn_ida;
        struct list_head                rpc_handle_list;
index acd66fb40c5f06bc1f4d116e09bd342d5707f529..ac79d4c86067f37aa884d8644383245d8625cdb6 100644 (file)
@@ -74,14 +74,7 @@ static inline bool check_session_id(struct ksmbd_conn *conn, u64 id)
 
 struct channel *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn)
 {
-       struct channel *chann;
-
-       list_for_each_entry(chann, &sess->ksmbd_chann_list, chann_list) {
-               if (chann->conn == conn)
-                       return chann;
-       }
-
-       return NULL;
+       return xa_load(&sess->ksmbd_chann_list, (long)conn);
 }
 
 /**
@@ -592,6 +585,7 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
        struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
        struct ksmbd_user *prev_user;
        struct channel *chann;
+       long index;
 
        if (!prev_sess)
                return;
@@ -605,10 +599,8 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
                return;
 
        prev_sess->state = SMB2_SESSION_EXPIRED;
-       write_lock(&prev_sess->chann_lock);
-       list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list)
+       xa_for_each(&prev_sess->ksmbd_chann_list, index, chann)
                chann->conn->status = KSMBD_SESS_EXITING;
-       write_unlock(&prev_sess->chann_lock);
 }
 
 /**
@@ -1520,19 +1512,14 @@ static int ntlm_authenticate(struct ksmbd_work *work)
 
 binding_session:
        if (conn->dialect >= SMB30_PROT_ID) {
-               read_lock(&sess->chann_lock);
                chann = lookup_chann_list(sess, conn);
-               read_unlock(&sess->chann_lock);
                if (!chann) {
                        chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
                        if (!chann)
                                return -ENOMEM;
 
                        chann->conn = conn;
-                       INIT_LIST_HEAD(&chann->chann_list);
-                       write_lock(&sess->chann_lock);
-                       list_add(&chann->chann_list, &sess->ksmbd_chann_list);
-                       write_unlock(&sess->chann_lock);
+                       xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL);
                }
        }
 
@@ -1606,19 +1593,14 @@ static int krb5_authenticate(struct ksmbd_work *work)
        }
 
        if (conn->dialect >= SMB30_PROT_ID) {
-               read_lock(&sess->chann_lock);
                chann = lookup_chann_list(sess, conn);
-               read_unlock(&sess->chann_lock);
                if (!chann) {
                        chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
                        if (!chann)
                                return -ENOMEM;
 
                        chann->conn = conn;
-                       INIT_LIST_HEAD(&chann->chann_list);
-                       write_lock(&sess->chann_lock);
-                       list_add(&chann->chann_list, &sess->ksmbd_chann_list);
-                       write_unlock(&sess->chann_lock);
+                       xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL);
                }
        }
 
@@ -8428,14 +8410,11 @@ int smb3_check_sign_req(struct ksmbd_work *work)
        if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
                signing_key = work->sess->smb3signingkey;
        } else {
-               read_lock(&work->sess->chann_lock);
                chann = lookup_chann_list(work->sess, conn);
                if (!chann) {
-                       read_unlock(&work->sess->chann_lock);
                        return 0;
                }
                signing_key = chann->smb3signingkey;
-               read_unlock(&work->sess->chann_lock);
        }
 
        if (!signing_key) {
@@ -8495,14 +8474,11 @@ void smb3_set_sign_rsp(struct ksmbd_work *work)
            le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
                signing_key = work->sess->smb3signingkey;
        } else {
-               read_lock(&work->sess->chann_lock);
                chann = lookup_chann_list(work->sess, work->conn);
                if (!chann) {
-                       read_unlock(&work->sess->chann_lock);
                        return;
                }
                signing_key = chann->smb3signingkey;
-               read_unlock(&work->sess->chann_lock);
        }
 
        if (!signing_key)