From 305853cce379407090a73b38c5de5ba748893aee Mon Sep 17 00:00:00 2001 From: Yunseong Kim Date: Mon, 15 Sep 2025 22:44:09 +0000 Subject: ksmbd: Fix race condition in RPC handle list access The 'sess->rpc_handle_list' XArray manages RPC handles within a ksmbd session. Access to this list is intended to be protected by 'sess->rpc_lock' (an rw_semaphore). However, the locking implementation was flawed, leading to potential race conditions. In ksmbd_session_rpc_open(), the code incorrectly acquired only a read lock before calling xa_store() and xa_erase(). Since these operations modify the XArray structure, a write lock is required to ensure exclusive access and prevent data corruption from concurrent modifications. Furthermore, ksmbd_session_rpc_method() accessed the list using xa_load() without holding any lock at all. This could lead to reading inconsistent data or a potential use-after-free if an entry is concurrently removed and the pointer is dereferenced. Fix these issues by: 1. Using down_write() and up_write() in ksmbd_session_rpc_open() to ensure exclusive access during XArray modification, and ensuring the lock is correctly released on error paths. 2. Adding down_read() and up_read() in ksmbd_session_rpc_method() to safely protect the lookup. Fixes: a1f46c99d9ea ("ksmbd: fix use-after-free in ksmbd_session_rpc_open") Fixes: b685757c7b08 ("ksmbd: Implements sess->rpc_handle_list as xarray") Cc: stable@vger.kernel.org Signed-off-by: Yunseong Kim Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/mgmt/user_session.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index 9dec4c2940bc..b36d0676dbe5 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -104,29 +104,32 @@ int ksmbd_session_rpc_open(struct ksmbd_session *sess, char *rpc_name) if (!entry) return -ENOMEM; - down_read(&sess->rpc_lock); entry->method = method; entry->id = id = ksmbd_ipc_id_alloc(); if (id < 0) goto free_entry; + + down_write(&sess->rpc_lock); old = xa_store(&sess->rpc_handle_list, id, entry, KSMBD_DEFAULT_GFP); - if (xa_is_err(old)) + if (xa_is_err(old)) { + up_write(&sess->rpc_lock); goto free_id; + } resp = ksmbd_rpc_open(sess, id); - if (!resp) - goto erase_xa; + if (!resp) { + xa_erase(&sess->rpc_handle_list, entry->id); + up_write(&sess->rpc_lock); + goto free_id; + } - up_read(&sess->rpc_lock); + up_write(&sess->rpc_lock); kvfree(resp); 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; } @@ -144,9 +147,14 @@ void ksmbd_session_rpc_close(struct ksmbd_session *sess, int id) int ksmbd_session_rpc_method(struct ksmbd_session *sess, int id) { struct ksmbd_session_rpc *entry; + int method; + down_read(&sess->rpc_lock); entry = xa_load(&sess->rpc_handle_list, id); - return entry ? entry->method : 0; + method = entry ? entry->method : 0; + up_read(&sess->rpc_lock); + + return method; } void ksmbd_session_destroy(struct ksmbd_session *sess) -- cgit v1.2.3 From 5da92a251e41f824d7e6b4d54d65dcdcfd69fda3 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Sun, 28 Sep 2025 09:26:48 +0900 Subject: ksmbd: make ksmbd thread names distinct by client IP This patch makes ksmbd thread names distinct by client IP address. 100943 ? S 0:00 [ksmbd:::ffff:10.177.110.57] or 101752 ? S 0:00 [ksmbd:10.177.110.57] Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_tcp.c | 39 +++++++++++++-------------------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c index 4337df97987d..6c6821971cf9 100644 --- a/fs/smb/server/transport_tcp.c +++ b/fs/smb/server/transport_tcp.c @@ -170,17 +170,6 @@ static struct kvec *get_conn_iovec(struct tcp_transport *t, unsigned int nr_segs return new_iov; } -static unsigned short ksmbd_tcp_get_port(const struct sockaddr *sa) -{ - switch (sa->sa_family) { - case AF_INET: - return ntohs(((struct sockaddr_in *)sa)->sin_port); - case AF_INET6: - return ntohs(((struct sockaddr_in6 *)sa)->sin6_port); - } - return 0; -} - /** * ksmbd_tcp_new_connection() - create a new tcp session on mount * @client_sk: socket associated with new connection @@ -192,7 +181,6 @@ static unsigned short ksmbd_tcp_get_port(const struct sockaddr *sa) */ static int ksmbd_tcp_new_connection(struct socket *client_sk) { - struct sockaddr *csin; int rc = 0; struct tcp_transport *t; struct task_struct *handler; @@ -203,27 +191,26 @@ static int ksmbd_tcp_new_connection(struct socket *client_sk) return -ENOMEM; } - csin = KSMBD_TCP_PEER_SOCKADDR(KSMBD_TRANS(t)->conn); - if (kernel_getpeername(client_sk, csin) < 0) { - pr_err("client ip resolution failed\n"); - rc = -EINVAL; - goto out_error; - } - +#if IS_ENABLED(CONFIG_IPV6) + if (client_sk->sk->sk_family == AF_INET6) + handler = kthread_run(ksmbd_conn_handler_loop, + KSMBD_TRANS(t)->conn, "ksmbd:%pI6c", + &KSMBD_TRANS(t)->conn->inet6_addr); + else + handler = kthread_run(ksmbd_conn_handler_loop, + KSMBD_TRANS(t)->conn, "ksmbd:%pI4", + &KSMBD_TRANS(t)->conn->inet_addr); +#else handler = kthread_run(ksmbd_conn_handler_loop, - KSMBD_TRANS(t)->conn, - "ksmbd:%u", - ksmbd_tcp_get_port(csin)); + KSMBD_TRANS(t)->conn, "ksmbd:%pI4", + &KSMBD_TRANS(t)->conn->inet_addr); +#endif if (IS_ERR(handler)) { pr_err("cannot start conn thread\n"); rc = PTR_ERR(handler); free_transport(t); } return rc; - -out_error: - free_transport(t); - return rc; } /** -- cgit v1.2.3 From 3677ca67b9791481af16d86e47c3c7d1f2442f95 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 25 Sep 2025 21:12:05 +0900 Subject: ksmbd: use sock_create_kern interface to create kernel socket we should use sock_create_kern() if the socket resides in kernel space. Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_tcp.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c index 6c6821971cf9..7440a2fd1126 100644 --- a/fs/smb/server/transport_tcp.c +++ b/fs/smb/server/transport_tcp.c @@ -455,12 +455,13 @@ static int create_socket(struct interface *iface) struct socket *ksmbd_socket; bool ipv4 = false; - ret = sock_create(PF_INET6, SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket); + ret = sock_create_kern(current->nsproxy->net_ns, PF_INET6, SOCK_STREAM, + IPPROTO_TCP, &ksmbd_socket); if (ret) { if (ret != -EAFNOSUPPORT) pr_err("Can't create socket for ipv6, fallback to ipv4: %d\n", ret); - ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, - &ksmbd_socket); + ret = sock_create_kern(current->nsproxy->net_ns, PF_INET, + SOCK_STREAM, IPPROTO_TCP, &ksmbd_socket); if (ret) { pr_err("Can't create socket for ipv4: %d\n", ret); goto out_clear; -- cgit v1.2.3 From c20988c21751ef67df4191e262675e231610e9ab Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Thu, 25 Sep 2025 21:15:20 +0900 Subject: ksmbd: copy overlapped range within the same file cifs.ko request to copy overlapped range within the same file. ksmbd is using vfs_copy_file_range for this, vfs_copy_file_range() does not allow overlapped copying within the same file. This patch use do_splice_direct() if offset and length are overlapped. Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/vfs.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/vfs.c b/fs/smb/server/vfs.c index 1cfa688904b2..c96e5d934ba9 100644 --- a/fs/smb/server/vfs.c +++ b/fs/smb/server/vfs.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "glob.h" #include "oplock.h" @@ -1829,8 +1830,19 @@ int ksmbd_vfs_copy_file_ranges(struct ksmbd_work *work, if (src_off + len > src_file_size) return -E2BIG; - ret = vfs_copy_file_range(src_fp->filp, src_off, - dst_fp->filp, dst_off, len, 0); + /* + * vfs_copy_file_range does not allow overlapped copying + * within the same file. + */ + if (file_inode(src_fp->filp) == file_inode(dst_fp->filp) && + dst_off + len > src_off && + dst_off < src_off + len) + ret = do_splice_direct(src_fp->filp, &src_off, + dst_fp->filp, &dst_off, + min_t(size_t, len, MAX_RW_COUNT), 0); + else + ret = vfs_copy_file_range(src_fp->filp, src_off, + dst_fp->filp, dst_off, len, 0); if (ret == -EOPNOTSUPP || ret == -EXDEV) ret = vfs_copy_file_range(src_fp->filp, src_off, dst_fp->filp, dst_off, len, -- cgit v1.2.3 From 88daf2f448aad05a2e6df738d66fe8b0cf85cee0 Mon Sep 17 00:00:00 2001 From: Matvey Kovalev Date: Thu, 25 Sep 2025 15:12:34 +0300 Subject: ksmbd: fix error code overwriting in smb2_get_info_filesystem() If client doesn't negotiate with SMB3.1.1 POSIX Extensions, then proper error code won't be returned due to overwriting. Return error immediately. Found by Linux Verification Center (linuxtesting.org) with SVACE. Fixes: e2f34481b24db ("cifsd: add server-side procedures for SMB3") Cc: stable@vger.kernel.org Signed-off-by: Matvey Kovalev Acked-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/smb2pdu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 0c069eff80b7..133ca5beb7cf 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -5629,7 +5629,8 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work, if (!work->tcon->posix_extensions) { pr_err("client doesn't negotiate with SMB3.1.1 POSIX Extensions\n"); - rc = -EOPNOTSUPP; + path_put(&path); + return -EOPNOTSUPP; } else { info = (struct filesystem_posix_info *)(rsp->Buffer); info->OptimalTransferSize = cpu_to_le32(stfs.f_bsize); -- cgit v1.2.3 From d8b6dc9256762293048bf122fc11c4e612d0ef5d Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 1 Oct 2025 09:25:35 +0900 Subject: ksmbd: add max ip connections parameter This parameter set the maximum number of connections per ip address. The default is 8. Cc: stable@vger.kernel.org Fixes: c0d41112f1a5 ("ksmbd: extend the connection limiting mechanism to support IPv6") Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/ksmbd_netlink.h | 5 +++-- fs/smb/server/server.h | 1 + fs/smb/server/transport_ipc.c | 3 +++ fs/smb/server/transport_tcp.c | 27 ++++++++++++++++----------- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/fs/smb/server/ksmbd_netlink.h b/fs/smb/server/ksmbd_netlink.h index 3f07a612c05b..8ccd57fd904b 100644 --- a/fs/smb/server/ksmbd_netlink.h +++ b/fs/smb/server/ksmbd_netlink.h @@ -112,10 +112,11 @@ struct ksmbd_startup_request { __u32 smbd_max_io_size; /* smbd read write size */ __u32 max_connections; /* Number of maximum simultaneous connections */ __s8 bind_interfaces_only; - __s8 reserved[503]; /* Reserved room */ + __u32 max_ip_connections; /* Number of maximum connection per ip address */ + __s8 reserved[499]; /* Reserved room */ __u32 ifc_list_sz; /* interfaces list size */ __s8 ____payload[]; -}; +} __packed; #define KSMBD_STARTUP_CONFIG_INTERFACES(s) ((s)->____payload) diff --git a/fs/smb/server/server.h b/fs/smb/server/server.h index 995555febe7d..b8a7317be86b 100644 --- a/fs/smb/server/server.h +++ b/fs/smb/server/server.h @@ -43,6 +43,7 @@ struct ksmbd_server_config { unsigned int auth_mechs; unsigned int max_connections; unsigned int max_inflight_req; + unsigned int max_ip_connections; char *conf[SERVER_CONF_WORK_GROUP + 1]; struct task_struct *dh_task; diff --git a/fs/smb/server/transport_ipc.c b/fs/smb/server/transport_ipc.c index 2a3e2b0ce557..2aa1b29bea08 100644 --- a/fs/smb/server/transport_ipc.c +++ b/fs/smb/server/transport_ipc.c @@ -335,6 +335,9 @@ static int ipc_server_config_on_startup(struct ksmbd_startup_request *req) if (req->max_connections) server_conf.max_connections = req->max_connections; + if (req->max_ip_connections) + server_conf.max_ip_connections = req->max_ip_connections; + ret = ksmbd_set_netbios_name(req->netbios_name); ret |= ksmbd_set_server_string(req->server_string); ret |= ksmbd_set_work_group(req->work_group); diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c index 7440a2fd1126..e9ecb43db9d9 100644 --- a/fs/smb/server/transport_tcp.c +++ b/fs/smb/server/transport_tcp.c @@ -225,6 +225,7 @@ static int ksmbd_kthread_fn(void *p) struct interface *iface = (struct interface *)p; struct ksmbd_conn *conn; int ret; + unsigned int max_ip_conns; while (!kthread_should_stop()) { mutex_lock(&iface->sock_release_lock); @@ -242,34 +243,38 @@ static int ksmbd_kthread_fn(void *p) continue; } + if (!server_conf.max_ip_connections) + goto skip_max_ip_conns_limit; + /* * Limits repeated connections from clients with the same IP. */ + max_ip_conns = 0; down_read(&conn_list_lock); - list_for_each_entry(conn, &conn_list, conns_list) + list_for_each_entry(conn, &conn_list, conns_list) { #if IS_ENABLED(CONFIG_IPV6) if (client_sk->sk->sk_family == AF_INET6) { if (memcmp(&client_sk->sk->sk_v6_daddr, - &conn->inet6_addr, 16) == 0) { - ret = -EAGAIN; - break; - } + &conn->inet6_addr, 16) == 0) + max_ip_conns++; } else if (inet_sk(client_sk->sk)->inet_daddr == - conn->inet_addr) { - ret = -EAGAIN; - break; - } + conn->inet_addr) + max_ip_conns++; #else if (inet_sk(client_sk->sk)->inet_daddr == - conn->inet_addr) { + conn->inet_addr) + max_ip_conns++; +#endif + if (server_conf.max_ip_connections <= max_ip_conns) { ret = -EAGAIN; break; } -#endif + } up_read(&conn_list_lock); if (ret == -EAGAIN) continue; +skip_max_ip_conns_limit: if (server_conf.max_connections && atomic_inc_return(&active_num_conn) >= server_conf.max_connections) { pr_info_ratelimited("Limit the maximum number of connections(%u)\n", -- cgit v1.2.3 From 67478857817be1585900ec49662e5b8f6ab6e3ef Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 29 Sep 2025 09:08:36 +0900 Subject: ksmbd: add an error print when maximum IP connections limit is reached This change introduces an error print using pr_info_ratelimited() to prevent excessive logging. This message will inform the user that the limit for maximum IP connections has been hit and what that current count is, which can be useful for debugging and monitoring connection limits. Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/transport_tcp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c index e9ecb43db9d9..f42acb544a0c 100644 --- a/fs/smb/server/transport_tcp.c +++ b/fs/smb/server/transport_tcp.c @@ -266,6 +266,8 @@ static int ksmbd_kthread_fn(void *p) max_ip_conns++; #endif if (server_conf.max_ip_connections <= max_ip_conns) { + pr_info_ratelimited("Maximum IP connections exceeded (%u/%u)\n", + max_ip_conns, server_conf.max_ip_connections); ret = -EAGAIN; break; } -- cgit v1.2.3 From 0bcc831be535269556f59cb70396f7e34f03a276 Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Wed, 1 Oct 2025 09:55:56 +0900 Subject: ksmbd: replace connection list with hash table Replace connection list with hash table to improve lookup performance. Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/connection.c | 23 +++++++++++------------ fs/smb/server/connection.h | 6 ++++-- fs/smb/server/smb2pdu.c | 4 ++-- fs/smb/server/transport_rdma.c | 5 +++++ fs/smb/server/transport_tcp.c | 25 +++++++++++++++++++++---- 5 files changed, 43 insertions(+), 20 deletions(-) diff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c index 91a934411134..b6b4f1286b9c 100644 --- a/fs/smb/server/connection.c +++ b/fs/smb/server/connection.c @@ -19,7 +19,7 @@ static DEFINE_MUTEX(init_lock); static struct ksmbd_conn_ops default_conn_ops; -LIST_HEAD(conn_list); +DEFINE_HASHTABLE(conn_list, CONN_HASH_BITS); DECLARE_RWSEM(conn_list_lock); /** @@ -33,7 +33,7 @@ DECLARE_RWSEM(conn_list_lock); void ksmbd_conn_free(struct ksmbd_conn *conn) { down_write(&conn_list_lock); - list_del(&conn->conns_list); + hash_del(&conn->hlist); up_write(&conn_list_lock); xa_destroy(&conn->sessions); @@ -77,7 +77,6 @@ struct ksmbd_conn *ksmbd_conn_alloc(void) init_waitqueue_head(&conn->req_running_q); init_waitqueue_head(&conn->r_count_q); - INIT_LIST_HEAD(&conn->conns_list); INIT_LIST_HEAD(&conn->requests); INIT_LIST_HEAD(&conn->async_requests); spin_lock_init(&conn->request_lock); @@ -90,19 +89,17 @@ struct ksmbd_conn *ksmbd_conn_alloc(void) init_rwsem(&conn->session_lock); - down_write(&conn_list_lock); - list_add(&conn->conns_list, &conn_list); - up_write(&conn_list_lock); return conn; } bool ksmbd_conn_lookup_dialect(struct ksmbd_conn *c) { struct ksmbd_conn *t; + int bkt; bool ret = false; down_read(&conn_list_lock); - list_for_each_entry(t, &conn_list, conns_list) { + hash_for_each(conn_list, bkt, t, hlist) { if (memcmp(t->ClientGUID, c->ClientGUID, SMB2_CLIENT_GUID_SIZE)) continue; @@ -163,9 +160,10 @@ void ksmbd_conn_unlock(struct ksmbd_conn *conn) void ksmbd_all_conn_set_status(u64 sess_id, u32 status) { struct ksmbd_conn *conn; + int bkt; down_read(&conn_list_lock); - list_for_each_entry(conn, &conn_list, conns_list) { + hash_for_each(conn_list, bkt, conn, hlist) { if (conn->binding || xa_load(&conn->sessions, sess_id)) WRITE_ONCE(conn->status, status); } @@ -181,14 +179,14 @@ int ksmbd_conn_wait_idle_sess_id(struct ksmbd_conn *curr_conn, u64 sess_id) { struct ksmbd_conn *conn; int rc, retry_count = 0, max_timeout = 120; - int rcount = 1; + int rcount = 1, bkt; retry_idle: if (retry_count >= max_timeout) return -EIO; down_read(&conn_list_lock); - list_for_each_entry(conn, &conn_list, conns_list) { + hash_for_each(conn_list, bkt, conn, hlist) { if (conn->binding || xa_load(&conn->sessions, sess_id)) { if (conn == curr_conn) rcount = 2; @@ -480,10 +478,11 @@ static void stop_sessions(void) { struct ksmbd_conn *conn; struct ksmbd_transport *t; + int bkt; again: down_read(&conn_list_lock); - list_for_each_entry(conn, &conn_list, conns_list) { + hash_for_each(conn_list, bkt, conn, hlist) { t = conn->transport; ksmbd_conn_set_exiting(conn); if (t->ops->shutdown) { @@ -494,7 +493,7 @@ again: } up_read(&conn_list_lock); - if (!list_empty(&conn_list)) { + if (!hash_empty(conn_list)) { msleep(100); goto again; } diff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h index 07b43634262a..7f9bcd9817b5 100644 --- a/fs/smb/server/connection.h +++ b/fs/smb/server/connection.h @@ -54,11 +54,12 @@ struct ksmbd_conn { u8 inet6_addr[16]; #endif }; + unsigned int inet_hash; char *request_buf; struct ksmbd_transport *transport; struct nls_table *local_nls; struct unicode_map *um; - struct list_head conns_list; + struct hlist_node hlist; struct rw_semaphore session_lock; /* smb session 1 per user */ struct xarray sessions; @@ -153,7 +154,8 @@ struct ksmbd_transport { #define KSMBD_TCP_SEND_TIMEOUT (5 * HZ) #define KSMBD_TCP_PEER_SOCKADDR(c) ((struct sockaddr *)&((c)->peer_addr)) -extern struct list_head conn_list; +#define CONN_HASH_BITS 12 +extern DECLARE_HASHTABLE(conn_list, CONN_HASH_BITS); extern struct rw_semaphore conn_list_lock; bool ksmbd_conn_alive(struct ksmbd_conn *conn); diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 133ca5beb7cf..ab1d45fcebde 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -7362,7 +7362,7 @@ int smb2_lock(struct ksmbd_work *work) int nolock = 0; LIST_HEAD(lock_list); LIST_HEAD(rollback_list); - int prior_lock = 0; + int prior_lock = 0, bkt; WORK_BUFFERS(work, req, rsp); @@ -7472,7 +7472,7 @@ int smb2_lock(struct ksmbd_work *work) nolock = 1; /* check locks in connection list */ down_read(&conn_list_lock); - list_for_each_entry(conn, &conn_list, conns_list) { + hash_for_each(conn_list, bkt, conn, hlist) { spin_lock(&conn->llist_lock); list_for_each_entry_safe(cmp_lock, tmp2, &conn->lock_list, clist) { if (file_inode(cmp_lock->fl->c.flc_file) != diff --git a/fs/smb/server/transport_rdma.c b/fs/smb/server/transport_rdma.c index 9e644a0daf1c..b3077766d6ec 100644 --- a/fs/smb/server/transport_rdma.c +++ b/fs/smb/server/transport_rdma.c @@ -425,6 +425,11 @@ static struct smb_direct_transport *alloc_transport(struct rdma_cm_id *cm_id) conn = ksmbd_conn_alloc(); if (!conn) goto err; + + down_write(&conn_list_lock); + hash_add(conn_list, &conn->hlist, 0); + up_write(&conn_list_lock); + conn->transport = KSMBD_TRANS(t); KSMBD_TRANS(t)->conn = conn; KSMBD_TRANS(t)->ops = &ksmbd_smb_direct_transport_ops; diff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c index f42acb544a0c..7a1e3dcc2cde 100644 --- a/fs/smb/server/transport_tcp.c +++ b/fs/smb/server/transport_tcp.c @@ -86,13 +86,21 @@ static struct tcp_transport *alloc_transport(struct socket *client_sk) } #if IS_ENABLED(CONFIG_IPV6) - if (client_sk->sk->sk_family == AF_INET6) + if (client_sk->sk->sk_family == AF_INET6) { memcpy(&conn->inet6_addr, &client_sk->sk->sk_v6_daddr, 16); - else + conn->inet_hash = ipv6_addr_hash(&client_sk->sk->sk_v6_daddr); + } else { conn->inet_addr = inet_sk(client_sk->sk)->inet_daddr; + conn->inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr); + } #else conn->inet_addr = inet_sk(client_sk->sk)->inet_daddr; + conn->inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr); #endif + down_write(&conn_list_lock); + hash_add(conn_list, &conn->hlist, conn->inet_hash); + up_write(&conn_list_lock); + conn->transport = KSMBD_TRANS(t); KSMBD_TRANS(t)->conn = conn; KSMBD_TRANS(t)->ops = &ksmbd_tcp_transport_ops; @@ -224,7 +232,7 @@ static int ksmbd_kthread_fn(void *p) struct socket *client_sk = NULL; struct interface *iface = (struct interface *)p; struct ksmbd_conn *conn; - int ret; + int ret, inet_hash; unsigned int max_ip_conns; while (!kthread_should_stop()) { @@ -249,9 +257,18 @@ static int ksmbd_kthread_fn(void *p) /* * Limits repeated connections from clients with the same IP. */ +#if IS_ENABLED(CONFIG_IPV6) + if (client_sk->sk->sk_family == AF_INET6) + inet_hash = ipv6_addr_hash(&client_sk->sk->sk_v6_daddr); + else + inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr); +#else + inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr); +#endif + max_ip_conns = 0; down_read(&conn_list_lock); - list_for_each_entry(conn, &conn_list, conns_list) { + hash_for_each_possible(conn_list, conn, hlist, inet_hash) { #if IS_ENABLED(CONFIG_IPV6) if (client_sk->sk->sk_family == AF_INET6) { if (memcmp(&client_sk->sk->sk_v6_daddr, -- cgit v1.2.3 From e28c5bc45640bc851e8f7f0b8d5431fdaa420c8e Mon Sep 17 00:00:00 2001 From: Namjae Jeon Date: Mon, 25 Aug 2025 08:27:12 +0900 Subject: ksmbd: increase session and share hash table bits Increases the number of bits for the hash table from 3 to 12. The thousands of sessions and shares can be connected. So the current 3-bit size can lead to frequent hash collisions. Signed-off-by: Namjae Jeon Signed-off-by: Steve French --- fs/smb/server/mgmt/share_config.c | 2 +- fs/smb/server/mgmt/user_session.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/smb/server/mgmt/share_config.c b/fs/smb/server/mgmt/share_config.c index d3d5f99bdd34..c9b1108d6e96 100644 --- a/fs/smb/server/mgmt/share_config.c +++ b/fs/smb/server/mgmt/share_config.c @@ -19,7 +19,7 @@ #include "../transport_ipc.h" #include "../misc.h" -#define SHARE_HASH_BITS 3 +#define SHARE_HASH_BITS 12 static DEFINE_HASHTABLE(shares_table, SHARE_HASH_BITS); static DECLARE_RWSEM(shares_table_lock); diff --git a/fs/smb/server/mgmt/user_session.c b/fs/smb/server/mgmt/user_session.c index b36d0676dbe5..6fa025374f2f 100644 --- a/fs/smb/server/mgmt/user_session.c +++ b/fs/smb/server/mgmt/user_session.c @@ -18,7 +18,7 @@ static DEFINE_IDA(session_ida); -#define SESSION_HASH_BITS 3 +#define SESSION_HASH_BITS 12 static DEFINE_HASHTABLE(sessions_table, SESSION_HASH_BITS); static DECLARE_RWSEM(sessions_table_lock); -- cgit v1.2.3