diff options
Diffstat (limited to 'fs/smb/server/mgmt')
-rw-r--r-- | fs/smb/server/mgmt/ksmbd_ida.c | 11 | ||||
-rw-r--r-- | fs/smb/server/mgmt/share_config.c | 10 | ||||
-rw-r--r-- | fs/smb/server/mgmt/tree_connect.c | 5 | ||||
-rw-r--r-- | fs/smb/server/mgmt/user_config.c | 8 | ||||
-rw-r--r-- | fs/smb/server/mgmt/user_session.c | 84 | ||||
-rw-r--r-- | fs/smb/server/mgmt/user_session.h | 3 |
6 files changed, 82 insertions, 39 deletions
diff --git a/fs/smb/server/mgmt/ksmbd_ida.c b/fs/smb/server/mgmt/ksmbd_ida.c index a18e27e9e0cd..0e2ae994ab52 100644 --- a/fs/smb/server/mgmt/ksmbd_ida.c +++ b/fs/smb/server/mgmt/ksmbd_ida.c @@ -4,31 +4,32 @@ */ #include "ksmbd_ida.h" +#include "../glob.h" int ksmbd_acquire_smb2_tid(struct ida *ida) { - return ida_alloc_range(ida, 1, 0xFFFFFFFE, GFP_KERNEL); + return ida_alloc_range(ida, 1, 0xFFFFFFFE, KSMBD_DEFAULT_GFP); } int ksmbd_acquire_smb2_uid(struct ida *ida) { int id; - id = ida_alloc_min(ida, 1, GFP_KERNEL); + id = ida_alloc_min(ida, 1, KSMBD_DEFAULT_GFP); if (id == 0xFFFE) - id = ida_alloc_min(ida, 1, GFP_KERNEL); + id = ida_alloc_min(ida, 1, KSMBD_DEFAULT_GFP); return id; } int ksmbd_acquire_async_msg_id(struct ida *ida) { - return ida_alloc_min(ida, 1, GFP_KERNEL); + return ida_alloc_min(ida, 1, KSMBD_DEFAULT_GFP); } int ksmbd_acquire_id(struct ida *ida) { - return ida_alloc(ida, GFP_KERNEL); + return ida_alloc(ida, KSMBD_DEFAULT_GFP); } void ksmbd_release_id(struct ida *ida, int id) diff --git a/fs/smb/server/mgmt/share_config.c b/fs/smb/server/mgmt/share_config.c index d8d03070ae44..d3d5f99bdd34 100644 --- a/fs/smb/server/mgmt/share_config.c +++ b/fs/smb/server/mgmt/share_config.c @@ -102,11 +102,11 @@ static int parse_veto_list(struct ksmbd_share_config *share, if (!sz) break; - p = kzalloc(sizeof(struct ksmbd_veto_pattern), GFP_KERNEL); + p = kzalloc(sizeof(struct ksmbd_veto_pattern), KSMBD_DEFAULT_GFP); if (!p) return -ENOMEM; - p->pattern = kstrdup(veto_list, GFP_KERNEL); + p->pattern = kstrdup(veto_list, KSMBD_DEFAULT_GFP); if (!p->pattern) { kfree(p); return -ENOMEM; @@ -150,14 +150,14 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, goto out; } - share = kzalloc(sizeof(struct ksmbd_share_config), GFP_KERNEL); + share = kzalloc(sizeof(struct ksmbd_share_config), KSMBD_DEFAULT_GFP); if (!share) goto out; share->flags = resp->flags; atomic_set(&share->refcount, 1); INIT_LIST_HEAD(&share->veto_list); - share->name = kstrdup(name, GFP_KERNEL); + share->name = kstrdup(name, KSMBD_DEFAULT_GFP); if (!test_share_config_flag(share, KSMBD_SHARE_FLAG_PIPE)) { int path_len = PATH_MAX; @@ -166,7 +166,7 @@ static struct ksmbd_share_config *share_config_request(struct ksmbd_work *work, path_len = resp->payload_sz - resp->veto_list_sz; share->path = kstrndup(ksmbd_share_config_path(resp), path_len, - GFP_KERNEL); + KSMBD_DEFAULT_GFP); if (share->path) { share->path_sz = strlen(share->path); while (share->path_sz > 1 && diff --git a/fs/smb/server/mgmt/tree_connect.c b/fs/smb/server/mgmt/tree_connect.c index 94a52a75014a..ecfc57508671 100644 --- a/fs/smb/server/mgmt/tree_connect.c +++ b/fs/smb/server/mgmt/tree_connect.c @@ -31,7 +31,8 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name) if (!sc) return status; - tree_conn = kzalloc(sizeof(struct ksmbd_tree_connect), GFP_KERNEL); + tree_conn = kzalloc(sizeof(struct ksmbd_tree_connect), + KSMBD_DEFAULT_GFP); if (!tree_conn) { status.ret = -ENOMEM; goto out_error; @@ -80,7 +81,7 @@ ksmbd_tree_conn_connect(struct ksmbd_work *work, const char *share_name) init_waitqueue_head(&tree_conn->refcount_q); ret = xa_err(xa_store(&sess->tree_conns, tree_conn->id, tree_conn, - GFP_KERNEL)); + KSMBD_DEFAULT_GFP)); if (ret) { status.ret = -ENOMEM; goto out_error; diff --git a/fs/smb/server/mgmt/user_config.c b/fs/smb/server/mgmt/user_config.c index 421a4a95e216..56c9a38ca878 100644 --- a/fs/smb/server/mgmt/user_config.c +++ b/fs/smb/server/mgmt/user_config.c @@ -36,16 +36,16 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp, { struct ksmbd_user *user; - user = kmalloc(sizeof(struct ksmbd_user), GFP_KERNEL); + user = kmalloc(sizeof(struct ksmbd_user), KSMBD_DEFAULT_GFP); if (!user) return NULL; - user->name = kstrdup(resp->account, GFP_KERNEL); + user->name = kstrdup(resp->account, KSMBD_DEFAULT_GFP); user->flags = resp->status; user->gid = resp->gid; user->uid = resp->uid; user->passkey_sz = resp->hash_sz; - user->passkey = kmalloc(resp->hash_sz, GFP_KERNEL); + user->passkey = kmalloc(resp->hash_sz, KSMBD_DEFAULT_GFP); if (user->passkey) memcpy(user->passkey, resp->hash, resp->hash_sz); @@ -64,7 +64,7 @@ struct ksmbd_user *ksmbd_alloc_user(struct ksmbd_login_response *resp, user->sgid = kmemdup(resp_ext->____payload, resp_ext->ngroups * sizeof(gid_t), - GFP_KERNEL); + KSMBD_DEFAULT_GFP); if (!user->sgid) goto err_free; diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 1e4624e9d434..9dec4c2940bc 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -59,10 +59,12 @@ static void ksmbd_session_rpc_clear_list(struct ksmbd_session *sess) struct ksmbd_session_rpc *entry; long index; + down_write(&sess->rpc_lock); xa_for_each(&sess->rpc_handle_list, index, entry) { xa_erase(&sess->rpc_handle_list, index); __session_rpc_close(sess, entry); } + up_write(&sess->rpc_lock); xa_destroy(&sess->rpc_handle_list); } @@ -90,35 +92,41 @@ static int __rpc_method(char *rpc_name) int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name) { - struct ksmbd_session_rpc *entry; + struct ksmbd_session_rpc *entry, *old; struct ksmbd_rpc_command *resp; - int method; + int method, id; method = __rpc_method(rpc_name); if (!method) return -EINVAL; - entry = kzalloc(sizeof(struct ksmbd_session_rpc), GFP_KERNEL); + entry = kzalloc(sizeof(struct ksmbd_session_rpc), KSMBD_DEFAULT_GFP); if (!entry) return -ENOMEM; + down_read(&sess->rpc_lock); entry->method = method; - entry->id = ksmbd_ipc_id_alloc(); - if (entry->id < 0) + entry->id = id = ksmbd_ipc_id_alloc(); + if (id < 0) goto free_entry; - xa_store(&sess->rpc_handle_list, entry->id, entry, GFP_KERNEL); + old = xa_store(&sess->rpc_handle_list, id, entry, KSMBD_DEFAULT_GFP); + if (xa_is_err(old)) + goto free_id; - resp = ksmbd_rpc_open(sess, entry->id); + resp = ksmbd_rpc_open(sess, id); if (!resp) - goto free_id; + goto erase_xa; + up_read(&sess->rpc_lock); kvfree(resp); - return entry->id; -free_id: + return id; +erase_xa: xa_erase(&sess->rpc_handle_list, entry->id); +free_id: ksmbd_rpc_id_free(entry->id); free_entry: kfree(entry); + up_read(&sess->rpc_lock); return -EINVAL; } @@ -126,9 +134,11 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id) { struct ksmbd_session_rpc *entry; + down_write(&sess->rpc_lock); entry = xa_erase(&sess->rpc_handle_list, id); if (entry) __session_rpc_close(sess, entry); + up_write(&sess->rpc_lock); } int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id) @@ -175,9 +185,10 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn) unsigned long id; struct ksmbd_session *sess; + down_write(&sessions_table_lock); down_write(&conn->session_lock); xa_for_each(&conn->sessions, id, sess) { - if (atomic_read(&sess->refcnt) == 0 && + if (atomic_read(&sess->refcnt) <= 1 && (sess->state != SMB2_SESSION_VALID || time_after(jiffies, sess->last_active + SMB2_SESSION_TIMEOUT))) { @@ -188,6 +199,7 @@ static void ksmbd_expire_session(struct ksmbd_conn *conn) } } up_write(&conn->session_lock); + up_write(&sessions_table_lock); } int ksmbd_session_register(struct ksmbd_conn *conn, @@ -196,7 +208,7 @@ int ksmbd_session_register(struct ksmbd_conn *conn, sess->dialect = conn->dialect; memcpy(sess->ClientGUID, conn->ClientGUID, SMB2_CLIENT_GUID_SIZE); ksmbd_expire_session(conn); - return xa_err(xa_store(&conn->sessions, sess->id, sess, GFP_KERNEL)); + return xa_err(xa_store(&conn->sessions, sess->id, sess, KSMBD_DEFAULT_GFP)); } static int ksmbd_chann_del(struct ksmbd_conn *conn, struct ksmbd_session *sess) @@ -225,11 +237,14 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn) if (!ksmbd_chann_del(conn, sess) && xa_empty(&sess->ksmbd_chann_list)) { hash_del(&sess->hlist); - ksmbd_session_destroy(sess); + down_write(&conn->session_lock); + xa_erase(&conn->sessions, sess->id); + up_write(&conn->session_lock); + if (atomic_dec_and_test(&sess->refcnt)) + ksmbd_session_destroy(sess); } } } - up_write(&sessions_table_lock); down_write(&conn->session_lock); xa_for_each(&conn->sessions, id, sess) { @@ -245,10 +260,28 @@ void ksmbd_sessions_deregister(struct ksmbd_conn *conn) if (xa_empty(&sess->ksmbd_chann_list)) { xa_erase(&conn->sessions, sess->id); hash_del(&sess->hlist); - ksmbd_session_destroy(sess); + if (atomic_dec_and_test(&sess->refcnt)) + ksmbd_session_destroy(sess); } } up_write(&conn->session_lock); + up_write(&sessions_table_lock); +} + +bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn, + unsigned long long id) +{ + struct ksmbd_session *sess; + + down_read(&conn->session_lock); + sess = xa_load(&conn->sessions, id); + if (sess) { + up_read(&conn->session_lock); + return true; + } + up_read(&conn->session_lock); + + return false; } struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, @@ -258,8 +291,10 @@ struct ksmbd_session *ksmbd_session_lookup(struct ksmbd_conn *conn, down_read(&conn->session_lock); sess = xa_load(&conn->sessions, id); - if (sess) + if (sess) { sess->last_active = jiffies; + ksmbd_user_session_get(sess); + } up_read(&conn->session_lock); return sess; } @@ -270,6 +305,8 @@ struct ksmbd_session *ksmbd_session_lookup_slowpath(unsigned long long id) down_read(&sessions_table_lock); sess = __session_lookup(id); + if (sess) + ksmbd_user_session_get(sess); up_read(&sessions_table_lock); return sess; @@ -300,8 +337,8 @@ void ksmbd_user_session_put(struct ksmbd_session *sess) if (atomic_read(&sess->refcnt) <= 0) WARN_ON(1); - else - atomic_dec(&sess->refcnt); + else if (atomic_dec_and_test(&sess->refcnt)) + ksmbd_session_destroy(sess); } struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, @@ -309,7 +346,7 @@ struct preauth_session *ksmbd_preauth_session_alloc(struct ksmbd_conn *conn, { struct preauth_session *sess; - sess = kmalloc(sizeof(struct preauth_session), GFP_KERNEL); + sess = kmalloc(sizeof(struct preauth_session), KSMBD_DEFAULT_GFP); if (!sess) return NULL; @@ -344,13 +381,13 @@ void destroy_previous_session(struct ksmbd_conn *conn, ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_RECONNECT); err = ksmbd_conn_wait_idle_sess_id(conn, id); if (err) { - ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_NEGOTIATE); + ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP); goto out; } ksmbd_destroy_file_table(&prev_sess->file_table); prev_sess->state = SMB2_SESSION_EXPIRED; - ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_NEGOTIATE); + ksmbd_all_conn_set_status(id, KSMBD_SESS_NEED_SETUP); ksmbd_launch_ksmbd_durable_scavenger(); out: up_write(&conn->session_lock); @@ -393,7 +430,7 @@ static struct ksmbd_session *__session_create(int protocol) if (protocol != CIFDS_SESSION_FLAG_SMB2) return NULL; - sess = kzalloc(sizeof(struct ksmbd_session), GFP_KERNEL); + sess = kzalloc(sizeof(struct ksmbd_session), KSMBD_DEFAULT_GFP); if (!sess) return NULL; @@ -408,7 +445,8 @@ static struct ksmbd_session *__session_create(int protocol) xa_init(&sess->rpc_handle_list); sess->sequence_number = 1; rwlock_init(&sess->tree_conns_lock); - atomic_set(&sess->refcnt, 1); + atomic_set(&sess->refcnt, 2); + init_rwsem(&sess->rpc_lock); ret = __init_smb2_session(sess); if (ret) diff --git a/fs/smb/server/mgmt/user_session.h b/fs/smb/server/mgmt/user_session.h index c1c4b20bd5c6..c5749d6ec715 100644 --- a/fs/smb/server/mgmt/user_session.h +++ b/fs/smb/server/mgmt/user_session.h @@ -63,6 +63,7 @@ struct ksmbd_session { rwlock_t tree_conns_lock; atomic_t refcnt; + struct rw_semaphore rpc_lock; }; static inline int test_session_flag(struct ksmbd_session *sess, int bit) @@ -87,6 +88,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); +bool is_ksmbd_session_in_connection(struct ksmbd_conn *conn, + unsigned long long id); int ksmbd_session_register(struct ksmbd_conn *conn, struct ksmbd_session *sess); void ksmbd_sessions_deregister(struct ksmbd_conn *conn); |