]> git.itanic.dy.fi Git - linux-stable/commitdiff
ksmbd: replace sessions list in connection with xarray
authorNamjae Jeon <linkinjeon@kernel.org>
Fri, 22 Jul 2022 01:15:10 +0000 (10:15 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 May 2023 09:50:28 +0000 (11:50 +0200)
[ Upstream commit e4d3e6b524c0c928f7fc9e03e047885c4951ae60 ]

Replace sessions list in connection with xarray.

Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Steve French <stfrench@microsoft.com>
Stable-dep-of: 7b4323373d84 ("ksmbd: fix deadlock in ksmbd_find_crypto_ctx()")
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/ksmbd/connection.c
fs/ksmbd/connection.h
fs/ksmbd/mgmt/user_session.c
fs/ksmbd/mgmt/user_session.h
fs/ksmbd/smb2pdu.c

index 21cda82f156dee74f00564ba7c07214e32c4fafa..b4c79359ef8b740fa2d788d7c50b05eccf71bb99 100644 (file)
@@ -36,6 +36,7 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)
        list_del(&conn->conns_list);
        write_unlock(&conn_list_lock);
 
+       xa_destroy(&conn->sessions);
        kvfree(conn->request_buf);
        kfree(conn->preauth_info);
        kfree(conn);
@@ -66,12 +67,12 @@ struct ksmbd_conn *ksmbd_conn_alloc(void)
 
        init_waitqueue_head(&conn->req_running_q);
        INIT_LIST_HEAD(&conn->conns_list);
-       INIT_LIST_HEAD(&conn->sessions);
        INIT_LIST_HEAD(&conn->requests);
        INIT_LIST_HEAD(&conn->async_requests);
        spin_lock_init(&conn->request_lock);
        spin_lock_init(&conn->credits_lock);
        ida_init(&conn->async_ida);
+       xa_init(&conn->sessions);
 
        spin_lock_init(&conn->llist_lock);
        INIT_LIST_HEAD(&conn->lock_list);
index f3367d7760d7e7fd34c5cdf372d202740fce9f8c..7838cc46497d6286132e7f92fa701ec522fe7552 100644 (file)
@@ -55,7 +55,7 @@ struct ksmbd_conn {
        struct nls_table                *local_nls;
        struct list_head                conns_list;
        /* smb session 1 per user */
-       struct list_head                sessions;
+       struct xarray                   sessions;
        unsigned long                   last_active;
        /* How many request are running currently */
        atomic_t                        req_running;
index 0fa467f2c897378f14d99ea7d8a5a5e0cead9496..8fe08df668582b2cb636b69efb8e72a1ee8844ed 100644 (file)
@@ -154,8 +154,6 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
        if (!atomic_dec_and_test(&sess->refcnt))
                return;
 
-       list_del(&sess->sessions_entry);
-
        down_write(&sessions_table_lock);
        hash_del(&sess->hlist);
        up_write(&sessions_table_lock);
@@ -183,42 +181,28 @@ static struct ksmbd_session *__session_lookup(unsigned long long id)
        return NULL;
 }
 
-void ksmbd_session_register(struct ksmbd_conn *conn,
-                           struct ksmbd_session *sess)
+int ksmbd_session_register(struct ksmbd_conn *conn,
+                          struct ksmbd_session *sess)
 {
        sess->conn = conn;
-       list_add(&sess->sessions_entry, &conn->sessions);
+       return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL));
 }
 
 void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
 {
        struct ksmbd_session *sess;
+       unsigned long id;
 
-       while (!list_empty(&conn->sessions)) {
-               sess = list_entry(conn->sessions.next,
-                                 struct ksmbd_session,
-                                 sessions_entry);
-
+       xa_for_each(&conn->sessions, id, sess) {
+               xa_erase(&conn->sessions, sess->id);
                ksmbd_session_destroy(sess);
        }
 }
 
-static bool ksmbd_session_id_match(struct ksmbd_session *sess,
-                                  unsigned long long id)
-{
-       return sess->id == id;
-}
-
 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
                                           unsigned long long id)
 {
-       struct ksmbd_session *sess = NULL;
-
-       list_for_each_entry(sess, &conn->sessions, sessions_entry) {
-               if (ksmbd_session_id_match(sess, id))
-                       return sess;
-       }
-       return NULL;
+       return xa_load(&conn->sessions, id);
 }
 
 int get_session(struct ksmbd_session *sess)
@@ -316,7 +300,6 @@ static struct ksmbd_session *__session_create(int protocol)
                goto error;
 
        set_session_flag(sess, protocol);
-       INIT_LIST_HEAD(&sess->sessions_entry);
        xa_init(&sess->tree_conns);
        INIT_LIST_HEAD(&sess->ksmbd_chann_list);
        INIT_LIST_HEAD(&sess->rpc_handle_list);
index e241f16a3851284646bdea9a347f8334a173e5b8..8b08189be3fc27f694e27d1303853d5f8f6c7c22 100644 (file)
@@ -57,7 +57,6 @@ struct ksmbd_session {
        __u8                            smb3decryptionkey[SMB3_ENC_DEC_KEY_SIZE];
        __u8                            smb3signingkey[SMB3_SIGN_KEY_SIZE];
 
-       struct list_head                sessions_entry;
        struct ksmbd_file_table         file_table;
        atomic_t                        refcnt;
 };
@@ -84,8 +83,8 @@ void ksmbd_session_destroy(struct ksmbd_session *sess);
 struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id);
 struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
                                           unsigned long long id);
-void ksmbd_session_register(struct ksmbd_conn *conn,
-                           struct ksmbd_session *sess);
+int ksmbd_session_register(struct ksmbd_conn *conn,
+                          struct ksmbd_session *sess);
 void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
                                               unsigned long long id);
index bb8126deeaf29141458e4b1318a29e46e798bd38..d41995f89befedee53548f81aff2592ac624760b 100644 (file)
@@ -595,7 +595,8 @@ int smb2_check_user_session(struct ksmbd_work *work)
        return -EINVAL;
 }
 
-static void destroy_previous_session(struct ksmbd_user *user, u64 id)
+static void destroy_previous_session(struct ksmbd_conn *conn,
+                                    struct ksmbd_user *user, u64 id)
 {
        struct ksmbd_session *prev_sess = ksmbd_session_lookup_slowpath(id);
        struct ksmbd_user *prev_user;
@@ -614,6 +615,7 @@ static void destroy_previous_session(struct ksmbd_user *user, u64 id)
        }
 
        put_session(prev_sess);
+       xa_erase(&conn->sessions, prev_sess->id);
        ksmbd_session_destroy(prev_sess);
 }
 
@@ -1452,7 +1454,7 @@ static int ntlm_authenticate(struct ksmbd_work *work)
        /* Check for previous session */
        prev_id = le64_to_cpu(req->PreviousSessionId);
        if (prev_id && prev_id != sess->id)
-               destroy_previous_session(user, prev_id);
+               destroy_previous_session(conn, user, prev_id);
 
        if (sess->state == SMB2_SESSION_VALID) {
                /*
@@ -1575,7 +1577,7 @@ static int krb5_authenticate(struct ksmbd_work *work)
        /* Check previous session */
        prev_sess_id = le64_to_cpu(req->PreviousSessionId);
        if (prev_sess_id && prev_sess_id != sess->id)
-               destroy_previous_session(sess->user, prev_sess_id);
+               destroy_previous_session(conn, sess->user, prev_sess_id);
 
        if (sess->state == SMB2_SESSION_VALID)
                ksmbd_free_user(sess->user);
@@ -1664,7 +1666,9 @@ int smb2_sess_setup(struct ksmbd_work *work)
                        goto out_err;
                }
                rsp->hdr.SessionId = cpu_to_le64(sess->id);
-               ksmbd_session_register(conn, sess);
+               rc = ksmbd_session_register(conn, sess);
+               if (rc)
+                       goto out_err;
        } else if (conn->dialect >= SMB30_PROT_ID &&
                   (server_conf.flags & KSMBD_GLOBAL_FLAG_SMB3_MULTICHANNEL) &&
                   req->Flags & SMB2_SESSION_REQ_FLAG_BINDING) {
@@ -1845,6 +1849,7 @@ int smb2_sess_setup(struct ksmbd_work *work)
                        if (sess->user && sess->user->flags & KSMBD_USER_FLAG_DELAY_SESSION)
                                try_delay = true;
 
+                       xa_erase(&conn->sessions, sess->id);
                        ksmbd_session_destroy(sess);
                        work->sess = NULL;
                        if (try_delay)