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:
parent
3db734e4d9
commit
91bbf9cb23
@ -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:
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user