smb/server: fix session counter on session removal

See the procedure below:

  smb2_sess_setup
    ksmbd_smb2_session_create
      __session_create
        hash_add(sessions_table, &sess->hlist, sess->id)
        ksmbd_counter_inc(KSMBD_COUNTER_SESSIONS)
  ksmbd_conn_handler_loop
    ksmbd_server_terminate_conn
      ksmbd_sessions_deregister
        hash_del(&sess->hlist)
        // do not decrement KSMBD_COUNTER_SESSIONS

KSMBD_COUNTER_SESSIONS tracks sessions published in sessions_table, but
session removal does not decrement it. The value therefore keeps growing
after sessions are expired, rejected during registration, or removed on
the last channel disconnect.

Fixes: b38f99c121 ("ksmbd: add procfs interface for runtime monitoring and statistics")
Signed-off-by: Ze Tan <tanze@kylinos.cn>
Reviewed-by: ChenXiaoSong <chenxiaosong@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Ze Tan 2026-08-14 13:51:44 +00:00 committed by Namjae Jeon
parent 492b24b5b6
commit 7de5cf9bcf

View File

@ -413,6 +413,12 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)
kfree_sensitive(sess);
}
static void ksmbd_session_remove_from_table(struct ksmbd_session *sess)
{
hash_del(&sess->hlist);
ksmbd_counter_dec(KSMBD_COUNTER_SESSIONS);
}
struct ksmbd_session *__session_lookup(unsigned long long id)
{
struct ksmbd_session *sess;
@ -439,7 +445,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn)
time_after(jiffies,
sess->last_active + SMB2_SESSION_TIMEOUT))) {
xa_erase(&conn->sessions, sess->id);
hash_del(&sess->hlist);
ksmbd_session_remove_from_table(sess);
ksmbd_session_destroy(sess);
continue;
}
@ -460,7 +466,7 @@ int ksmbd_session_register(struct ksmbd_conn *conn,
KSMBD_DEFAULT_GFP));
if (ret) {
down_write(&sessions_table_lock);
hash_del(&sess->hlist);
ksmbd_session_remove_from_table(sess);
up_write(&sessions_table_lock);
ksmbd_user_session_put(sess);
}
@ -493,7 +499,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
hash_for_each_safe(sessions_table, bkt, tmp, sess, hlist) {
if (!ksmbd_chann_del(conn, sess) &&
xa_empty(&sess->ksmbd_chann_list)) {
hash_del(&sess->hlist);
ksmbd_session_remove_from_table(sess);
down_write(&conn->session_lock);
xa_erase(&conn->sessions, sess->id);
up_write(&conn->session_lock);
@ -507,7 +513,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
ksmbd_chann_del(conn, sess);
if (xa_empty(&sess->ksmbd_chann_list)) {
xa_erase(&conn->sessions, sess->id);
hash_del(&sess->hlist);
ksmbd_session_remove_from_table(sess);
if (atomic_dec_and_test(&sess->refcnt))
ksmbd_session_destroy(sess);
}