diff options
| author | Enzo Matsumiya <ematsumiya@suse.de> | 2025-05-08 18:01:46 -0300 |
|---|---|---|
| committer | Enzo Matsumiya <ematsumiya@suse.de> | 2025-05-16 17:22:57 -0300 |
| commit | 67d48508a057757bb54f375b4a8f356ec3f5f8fa (patch) | |
| tree | 233a5df51e24291df59a352a53fa342d3e02316c | |
| parent | c94ef99937ec2add5e524f77bf777aef21acc201 (diff) | |
| download | linux-67d48508a057757bb54f375b4a8f356ec3f5f8fa.tar.gz linux-67d48508a057757bb54f375b4a8f356ec3f5f8fa.tar.bz2 linux-67d48508a057757bb54f375b4a8f356ec3f5f8fa.zip | |
smb: client: spread cifsd threads through available CPUs
Spawn cifsd thread on each available CPU.
Iterate in a round-robin fashion, but prefer the next one without a
cifsd instance running.
~10% performance improvement is observed on heavy workloads with
multichannel enabled.
Signed-off-by: Enzo Matsumiya <ematsumiya@suse.de>
| -rw-r--r-- | fs/smb/client/cifsglob.h | 1 | ||||
| -rw-r--r-- | fs/smb/client/connect.c | 80 |
2 files changed, 66 insertions, 15 deletions
diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 3b32116b0b49..d50466930c13 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -744,6 +744,7 @@ struct TCP_Server_Info { struct mutex _srv_mutex; unsigned int nofs_flag; struct task_struct *tsk; + unsigned int tsk_cpu; char server_GUID[16]; __u16 sec_mode; bool sign; /* is signing enabled on this connection? */ diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 6bf04d9a5491..af728cfccf54 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -65,6 +65,17 @@ static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); static void cifs_prune_tlinks(struct work_struct *work); /* + * Stores current CPU being used by cifsd. + * Updated after succesfully spawning a new cifsd thread. + */ +static int cifsd_cur_cpu; +/* + * Stores which CPUs have a cifsd thread running on it. + * Set/clear follows server->tsk lifetime. + */ +static struct cpumask cifsd_cpu_load; + +/* * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that may * get their ip addresses changed at some point. * @@ -1123,6 +1134,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server) */ } + cpumask_clear_cpu(server->tsk_cpu, &cifsd_cpu_load); put_net(cifs_net_ns(server)); kfree(server->leaf_fullpath); kfree(server->hostname); @@ -1722,8 +1734,57 @@ cifs_put_tcp_session(struct TCP_Server_Info *server, int from_reconnect) server->session_key.len = 0; task = xchg(&server->tsk, NULL); - if (task) + if (task) { + cpumask_clear_cpu(server->tsk_cpu, &cifsd_cpu_load); send_sig(SIGKILL, task, 1); + } +} + +static inline int cifsd_get_next_cpu(void) +{ + struct cpumask avail = {}; + int cpu; + + /* Try to get the next CPU without a cifsd instance. */ + cpumask_andnot(&avail, cpu_online_mask, &cifsd_cpu_load); + if (cpumask_empty(&avail)) + goto next_rr; + + cpu = cpumask_next(cifsd_cur_cpu, &cifsd_cpu_load); + if (likely(cpu < nr_cpu_ids)) + return cpu; +next_rr: + /* All CPUs are running cifsd, just get the next round-robin. */ + cpu = cpumask_next_wrap(cifsd_cur_cpu, cpu_online_mask); + if (likely(cpu < nr_cpu_ids)) + return cpu; + + /* Shouldn't reach as wrap above took care of returning something valid, but... */ + return 0; +} + +static int cifsd_start(struct TCP_Server_Info *server) +{ + int cpu, ret = 0; + + /* + * Since we're in a cifs function already, we know that this will succeed. + * No need for try_module_get(). + */ + __module_get(THIS_MODULE); + cpu = cifsd_get_next_cpu(); + server->tsk = kthread_run_on_cpu(cifs_demultiplex_thread, server, cpu, "cifsd"); + if (!IS_ERR(server->tsk)) { + cpumask_set_cpu(cifsd_cur_cpu, &cifsd_cpu_load); + server->tsk_cpu = cifsd_cur_cpu = cpu; + } else { + ret = PTR_ERR(server->tsk); + server->tsk = NULL; + cifs_dbg(VFS, "error %d create cifsd thread\n", ret); + module_put(THIS_MODULE); + } + + return ret; } struct TCP_Server_Info * @@ -1851,19 +1912,10 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, goto out_err_crypto_release; } smbd_connected: - /* - * since we're in a cifs function already, we know that - * this will succeed. No need for try_module_get(). - */ - __module_get(THIS_MODULE); - tcp_ses->tsk = kthread_run(cifs_demultiplex_thread, - tcp_ses, "cifsd"); - if (IS_ERR(tcp_ses->tsk)) { - rc = PTR_ERR(tcp_ses->tsk); - cifs_dbg(VFS, "error %d create cifsd thread\n", rc); - module_put(THIS_MODULE); + rc = cifsd_start(tcp_ses); + if (rc) goto out_err_crypto_release; - } + tcp_ses->min_offload = ctx->min_offload; tcp_ses->retrans = ctx->retrans; /* @@ -1894,9 +1946,7 @@ smbd_connected: out_err_crypto_release: cifs_crypto_secmech_release(tcp_ses); - put_net(cifs_net_ns(tcp_ses)); - out_err: if (tcp_ses) { if (SERVER_IS_CHAN(tcp_ses)) |
