ksmbd: mark SMB2_SESSION_EXPIRED to session when destroying previous session
authorNamjae Jeon <linkinjeon@kernel.org>
Sun, 10 Mar 2024 10:30:51 +0000 (19:30 +0900)
committerSteve French <stfrench@microsoft.com>
Tue, 12 Mar 2024 05:36:39 +0000 (00:36 -0500)
Currently ksmbd exit connection as well destroying previous session.
When testing durable handle feaure, I found that
destroy_previous_session() should destroy only session, i.e. the
connection should be still alive. This patch mark SMB2_SESSION_EXPIRED
on the previous session to be destroyed later and not used anymore.

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

index 15f68ee0508946843983b7d773dc6837f12b3bf0..83074672fe81221c6eda898893f956c5663e03d9 100644 (file)
@@ -156,7 +156,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
        kfree(sess);
 }
 
-static struct ksmbd_session *__session_lookup(unsigned long long id)
+struct ksmbd_session *__session_lookup(unsigned long long id)
 {
        struct ksmbd_session *sess;
 
@@ -305,6 +305,31 @@ struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
        return sess;
 }
 
+void destroy_previous_session(struct ksmbd_conn *conn,
+                             struct ksmbd_user *user, u64 id)
+{
+       struct ksmbd_session *prev_sess;
+       struct ksmbd_user *prev_user;
+
+       down_write(&sessions_table_lock);
+       down_write(&conn->session_lock);
+       prev_sess = __session_lookup(id);
+       if (!prev_sess || prev_sess->state == SMB2_SESSION_EXPIRED)
+               goto out;
+
+       prev_user = prev_sess->user;
+       if (!prev_user ||
+           strcmp(user->name, prev_user->name) ||
+           user->passkey_sz != prev_user->passkey_sz ||
+           memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
+               goto out;
+
+       prev_sess->state = SMB2_SESSION_EXPIRED;
+out:
+       up_write(&conn->session_lock);
+       up_write(&sessions_table_lock);
+}
+
 static bool ksmbd_preauth_session_id_match(struct preauth_session *sess,
                                           unsigned long long id)
 {
index 63cb08fffde84c4a5f03b936577fe02288885b6e..dc9fded2cd4379a66342e3c3f87aa1423400ac1f 100644 (file)
@@ -88,8 +88,11 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn,
 int ksmbd_session_register(struct ksmbd_conn *conn,
                           struct ksmbd_session *sess);
 void ksmbd_sessions_deregister(struct ksmbd_conn *conn);
+struct ksmbd_session *__session_lookup(unsigned long long id);
 struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,
                                               unsigned long long id);
+void destroy_previous_session(struct ksmbd_conn *conn,
+                             struct ksmbd_user *user, u64 id);
 struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn,
                                                    u64 sess_id);
 struct preauth_session *ksmbd_preauth_session_lookup(struct ksmbd_conn *conn,
index 199c31c275e5bef4230ea97f26169ee91965714a..201d78310bde19e6a6391815ffc0b36e7a5fe709 100644 (file)
@@ -607,30 +607,6 @@ int smb2_check_user_session(struct ksmbd_work *work)
        return -ENOENT;
 }
 
-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;
-       struct channel *chann;
-       long index;
-
-       if (!prev_sess)
-               return;
-
-       prev_user = prev_sess->user;
-
-       if (!prev_user ||
-           strcmp(user->name, prev_user->name) ||
-           user->passkey_sz != prev_user->passkey_sz ||
-           memcmp(user->passkey, prev_user->passkey, user->passkey_sz))
-               return;
-
-       prev_sess->state = SMB2_SESSION_EXPIRED;
-       xa_for_each(&prev_sess->ksmbd_chann_list, index, chann)
-               ksmbd_conn_set_exiting(chann->conn);
-}
-
 /**
  * smb2_get_name() - get filename string from on the wire smb format
  * @src:       source buffer