ksmbd: Implements sess->ksmbd_chann_list as xarray

[ 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>
This commit is contained in:
Dawei Li 2023-01-15 18:32:04 +08:00 committed by Greg Kroah-Hartman
parent 3db734e4d9
commit 91bbf9cb23
3 changed files with 29 additions and 68 deletions

View File

@ -30,15 +30,15 @@ struct ksmbd_session_rpc {
static void free_channel_list(struct ksmbd_session *sess) static void free_channel_list(struct ksmbd_session *sess)
{ {
struct channel *chann, *tmp; struct channel *chann;
unsigned long index;
write_lock(&sess->chann_lock); xa_for_each(&sess->ksmbd_chann_list, index, chann) {
list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, xa_erase(&sess->ksmbd_chann_list, index);
chann_list) {
list_del(&chann->chann_list);
kfree(chann); kfree(chann);
} }
write_unlock(&sess->chann_lock);
xa_destroy(&sess->ksmbd_chann_list);
} }
static void __session_rpc_close(struct ksmbd_session *sess, 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) static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess)
{ {
struct channel *chann, *tmp; struct channel *chann;
write_lock(&sess->chann_lock); chann = xa_erase(&sess->ksmbd_chann_list, (long)conn);
list_for_each_entry_safe(chann, tmp, &sess->ksmbd_chann_list, if (!chann)
chann_list) { return -ENOENT;
if (chann->conn == conn) {
list_del(&chann->chann_list);
kfree(chann);
write_unlock(&sess->chann_lock);
return 0;
}
}
write_unlock(&sess->chann_lock);
return -ENOENT; kfree(chann);
return 0;
} }
void ksmbd_sessions_deregister(struct ksmbd_conn *conn) void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
@ -234,7 +228,7 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn)
return; return;
sess_destroy: sess_destroy:
if (list_empty(&sess->ksmbd_chann_list)) { if (xa_empty(&sess->ksmbd_chann_list)) {
xa_erase(&conn->sessions, sess->id); xa_erase(&conn->sessions, sess->id);
ksmbd_session_destroy(sess); ksmbd_session_destroy(sess);
} }
@ -320,6 +314,9 @@ static struct ksmbd_session *__session_create(int protocol)
struct ksmbd_session *sess; struct ksmbd_session *sess;
int ret; int ret;
if (protocol != CIFDS_SESSION_FLAG_SMB2)
return NULL;
sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL); sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL);
if (!sess) if (!sess)
return NULL; return NULL;
@ -329,30 +326,20 @@ static struct ksmbd_session *__session_create(int protocol)
set_session_flag(sess, protocol); set_session_flag(sess, protocol);
xa_init(&sess->tree_conns); 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); INIT_LIST_HEAD(&sess->rpc_handle_list);
sess->sequence_number = 1; 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) if (ret)
goto error; goto error;
ida_init(&sess->tree_conn_ida); ida_init(&sess->tree_conn_ida);
if (protocol == CIFDS_SESSION_FLAG_SMB2) { down_write(&sessions_table_lock);
down_write(&sessions_table_lock); hash_add(sessions_table, &sess->hlist, sess->id);
hash_add(sessions_table, &sess->hlist, sess->id); up_write(&sessions_table_lock);
up_write(&sessions_table_lock);
}
return sess; return sess;
error: error:

View File

@ -21,7 +21,6 @@ struct ksmbd_file_table;
struct channel { struct channel {
__u8 smb3signingkey[SMB3_SIGN_KEY_SIZE]; __u8 smb3signingkey[SMB3_SIGN_KEY_SIZE];
struct ksmbd_conn *conn; struct ksmbd_conn *conn;
struct list_head chann_list;
}; };
struct preauth_session { struct preauth_session {
@ -50,8 +49,7 @@ struct ksmbd_session {
char sess_key[CIFS_KEY_SIZE]; char sess_key[CIFS_KEY_SIZE];
struct hlist_node hlist; struct hlist_node hlist;
rwlock_t chann_lock; struct xarray ksmbd_chann_list;
struct list_head ksmbd_chann_list;
struct xarray tree_conns; struct xarray tree_conns;
struct ida tree_conn_ida; struct ida tree_conn_ida;
struct list_head rpc_handle_list; struct list_head rpc_handle_list;

View 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 *lookup_chann_list(struct ksmbd_session *sess, struct ksmbd_conn *conn)
{ {
struct channel *chann; return xa_load(&sess->ksmbd_chann_list, (long)conn);
list_for_each_entry(chann, &sess->ksmbd_chann_list, chann_list) {
if (chann->conn == conn)
return chann;
}
return NULL;
} }
/** /**
@ -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_session *prev_sess = ksmbd_session_lookup_slowpath(id);
struct ksmbd_user *prev_user; struct ksmbd_user *prev_user;
struct channel *chann; struct channel *chann;
long index;
if (!prev_sess) if (!prev_sess)
return; return;
@ -605,10 +599,8 @@ static void destroy_previous_session(struct ksmbd_conn *conn,
return; return;
prev_sess->state = SMB2_SESSION_EXPIRED; prev_sess->state = SMB2_SESSION_EXPIRED;
write_lock(&prev_sess->chann_lock); xa_for_each(&prev_sess->ksmbd_chann_list, index, chann)
list_for_each_entry(chann, &prev_sess->ksmbd_chann_list, chann_list)
chann->conn->status = KSMBD_SESS_EXITING; 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: binding_session:
if (conn->dialect >= SMB30_PROT_ID) { if (conn->dialect >= SMB30_PROT_ID) {
read_lock(&sess->chann_lock);
chann = lookup_chann_list(sess, conn); chann = lookup_chann_list(sess, conn);
read_unlock(&sess->chann_lock);
if (!chann) { if (!chann) {
chann = kmalloc(sizeof(struct channel), GFP_KERNEL); chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
if (!chann) if (!chann)
return -ENOMEM; return -ENOMEM;
chann->conn = conn; chann->conn = conn;
INIT_LIST_HEAD(&chann->chann_list); xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL);
write_lock(&sess->chann_lock);
list_add(&chann->chann_list, &sess->ksmbd_chann_list);
write_unlock(&sess->chann_lock);
} }
} }
@ -1606,19 +1593,14 @@ static int krb5_authenticate(struct ksmbd_work *work)
} }
if (conn->dialect >= SMB30_PROT_ID) { if (conn->dialect >= SMB30_PROT_ID) {
read_lock(&sess->chann_lock);
chann = lookup_chann_list(sess, conn); chann = lookup_chann_list(sess, conn);
read_unlock(&sess->chann_lock);
if (!chann) { if (!chann) {
chann = kmalloc(sizeof(struct channel), GFP_KERNEL); chann = kmalloc(sizeof(struct channel), GFP_KERNEL);
if (!chann) if (!chann)
return -ENOMEM; return -ENOMEM;
chann->conn = conn; chann->conn = conn;
INIT_LIST_HEAD(&chann->chann_list); xa_store(&sess->ksmbd_chann_list, (long)conn, chann, GFP_KERNEL);
write_lock(&sess->chann_lock);
list_add(&chann->chann_list, &sess->ksmbd_chann_list);
write_unlock(&sess->chann_lock);
} }
} }
@ -8428,14 +8410,11 @@ int smb3_check_sign_req(struct ksmbd_work *work)
if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) { if (le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
signing_key = work->sess->smb3signingkey; signing_key = work->sess->smb3signingkey;
} else { } else {
read_lock(&work->sess->chann_lock);
chann = lookup_chann_list(work->sess, conn); chann = lookup_chann_list(work->sess, conn);
if (!chann) { if (!chann) {
read_unlock(&work->sess->chann_lock);
return 0; return 0;
} }
signing_key = chann->smb3signingkey; signing_key = chann->smb3signingkey;
read_unlock(&work->sess->chann_lock);
} }
if (!signing_key) { 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) { le16_to_cpu(hdr->Command) == SMB2_SESSION_SETUP_HE) {
signing_key = work->sess->smb3signingkey; signing_key = work->sess->smb3signingkey;
} else { } else {
read_lock(&work->sess->chann_lock);
chann = lookup_chann_list(work->sess, work->conn); chann = lookup_chann_list(work->sess, work->conn);
if (!chann) { if (!chann) {
read_unlock(&work->sess->chann_lock);
return; return;
} }
signing_key = chann->smb3signingkey; signing_key = chann->smb3signingkey;
read_unlock(&work->sess->chann_lock);
} }
if (!signing_key) if (!signing_key)