From: Gang Yan <gang.yan@linux.dev>
To: mptcp@lists.linux.dev
Subject: [PATCH mptcp-next v2 1/5] mptcp: sched: change scheduler sysctl atomically
Date: Tue, 18 Aug 2026 17:39:06 +0800 [thread overview]
Message-ID: <20260818093910.47559-2-gang.yan@linux.dev> (raw)
In-Reply-To: <20260818093910.47559-1-gang.yan@linux.dev>
From: Gang Yan <yangang@kylinos.cn>
The per-netns scheduler name is stored as an inline char[] buffer and
updated via strscpy() from the sysctl handler. A concurrent reader (e.g.
mptcp_init_sock() resolving the default scheduler) can observe a
half-written name, which is also flagged by KCSAN. READ_ONCE() does not
help here as it cannot read a multi-byte string atomically.
Following the tcp_congestion_control() model, store a pointer to the
immutable struct mptcp_sched_ops instead of the name string:
- mptcp_set_scheduler() now looks the ops up and atomically swaps the
pernet pointer with xchg();
- mptcp_get_scheduler() copies the ops name out under rcu_read_lock();
- the default ops is assigned in mptcp_pernet_set_defaults().
A pointer store is a single atomic word, so readers always observe a
consistent value.
Assisted-by: Claude:GLM5.2
Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/626
Co-developed-by: Tao Cui <cuitao@kylinos.cn>
Signed-off-by: Tao Cui <cuitao@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
---
net/mptcp/ctrl.c | 31 ++++++++++++++++++++++---------
net/mptcp/protocol.c | 5 +++--
net/mptcp/protocol.h | 3 ++-
net/mptcp/sched.c | 2 +-
4 files changed, 28 insertions(+), 13 deletions(-)
diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c
index 63c5747f0f63..479b31eb3007 100644
--- a/net/mptcp/ctrl.c
+++ b/net/mptcp/ctrl.c
@@ -39,7 +39,7 @@ struct mptcp_pernet {
u8 allow_join_initial_addr_port;
u8 pm_type;
u8 add_addr_v6_port_drop_ts;
- char scheduler[MPTCP_SCHED_NAME_MAX];
+ struct mptcp_sched_ops __rcu *scheduler;
char path_manager[MPTCP_PM_NAME_MAX];
};
@@ -90,9 +90,14 @@ const char *mptcp_get_path_manager(const struct net *net)
return mptcp_get_pernet(net)->path_manager;
}
-const char *mptcp_get_scheduler(const struct net *net)
+void mptcp_get_scheduler(const struct net *net, char *name)
{
- return mptcp_get_pernet(net)->scheduler;
+ struct mptcp_sched_ops *sched;
+
+ rcu_read_lock();
+ sched = rcu_dereference(mptcp_get_pernet(net)->scheduler);
+ strscpy(name, sched ? sched->name : "default", MPTCP_SCHED_NAME_MAX);
+ rcu_read_unlock();
}
unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net)
@@ -112,13 +117,15 @@ static void mptcp_pernet_set_defaults(struct mptcp_pernet *pernet)
pernet->allow_join_initial_addr_port = 1;
pernet->stale_loss_cnt = 4;
pernet->pm_type = MPTCP_PM_TYPE_KERNEL;
- strscpy(pernet->scheduler, "default", sizeof(pernet->scheduler));
+
+ RCU_INIT_POINTER(pernet->scheduler, &mptcp_sched_default);
+
strscpy(pernet->path_manager, "kernel", sizeof(pernet->path_manager));
pernet->add_addr_v6_port_drop_ts = 1;
}
#ifdef CONFIG_SYSCTL
-static int mptcp_set_scheduler(char *scheduler, const char *name)
+static int mptcp_set_scheduler(struct mptcp_pernet *pernet, const char *name)
{
struct mptcp_sched_ops *sched;
int ret = 0;
@@ -126,7 +133,7 @@ static int mptcp_set_scheduler(char *scheduler, const char *name)
rcu_read_lock();
sched = mptcp_sched_find(name);
if (sched)
- strscpy(scheduler, name, MPTCP_SCHED_NAME_MAX);
+ xchg(&pernet->scheduler, sched);
else
ret = -ENOENT;
rcu_read_unlock();
@@ -137,7 +144,10 @@ static int mptcp_set_scheduler(char *scheduler, const char *name)
static int proc_scheduler(const struct ctl_table *ctl, int write,
void *buffer, size_t *lenp, loff_t *ppos)
{
- char (*scheduler)[MPTCP_SCHED_NAME_MAX] = ctl->data;
+ struct mptcp_pernet *pernet = container_of(ctl->data,
+ struct mptcp_pernet,
+ scheduler);
+ struct mptcp_sched_ops *sched;
char val[MPTCP_SCHED_NAME_MAX];
struct ctl_table tbl = {
.data = val,
@@ -145,11 +155,14 @@ static int proc_scheduler(const struct ctl_table *ctl, int write,
};
int ret;
- strscpy(val, *scheduler, MPTCP_SCHED_NAME_MAX);
+ rcu_read_lock();
+ sched = rcu_dereference(pernet->scheduler);
+ strscpy(val, sched ? sched->name : "default", MPTCP_SCHED_NAME_MAX);
+ rcu_read_unlock();
ret = proc_dostring(&tbl, write, buffer, lenp, ppos);
if (write && ret == 0)
- ret = mptcp_set_scheduler(*scheduler, val);
+ ret = mptcp_set_scheduler(pernet, val);
return ret;
}
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index f879b1061f2d..9d84dd803802 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -3260,6 +3260,7 @@ static void mptcp_ca_reset(struct sock *sk)
static int mptcp_init_sock(struct sock *sk)
{
struct net *net = sock_net(sk);
+ char sched_name[MPTCP_SCHED_NAME_MAX];
int ret;
__mptcp_init_sock(sk);
@@ -3271,8 +3272,8 @@ static int mptcp_init_sock(struct sock *sk)
return -ENOMEM;
rcu_read_lock();
- ret = mptcp_init_sched(mptcp_sk(sk),
- mptcp_sched_find(mptcp_get_scheduler(net)));
+ mptcp_get_scheduler(net, sched_name);
+ ret = mptcp_init_sched(mptcp_sk(sk), mptcp_sched_find(sched_name));
rcu_read_unlock();
if (ret)
return ret;
diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h
index 7e168e450fb0..af79b3450ab7 100644
--- a/net/mptcp/protocol.h
+++ b/net/mptcp/protocol.h
@@ -803,7 +803,7 @@ unsigned int mptcp_stale_loss_cnt(const struct net *net);
unsigned int mptcp_close_timeout(const struct sock *sk);
int mptcp_get_pm_type(const struct net *net);
const char *mptcp_get_path_manager(const struct net *net);
-const char *mptcp_get_scheduler(const struct net *net);
+void mptcp_get_scheduler(const struct net *net, char *name);
unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net);
void mptcp_active_disable(struct sock *sk);
@@ -1155,6 +1155,7 @@ int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_list *rm_
/* the default path manager, used in mptcp_pm_unregister */
extern struct mptcp_pm_ops mptcp_pm_kernel;
+extern struct mptcp_sched_ops mptcp_sched_default;
struct mptcp_pm_ops *mptcp_pm_find(const char *name);
int mptcp_pm_register(struct mptcp_pm_ops *pm_ops);
diff --git a/net/mptcp/sched.c b/net/mptcp/sched.c
index 1e59072d478c..0d13ee46ffdf 100644
--- a/net/mptcp/sched.c
+++ b/net/mptcp/sched.c
@@ -40,7 +40,7 @@ static int mptcp_sched_default_get_retrans(struct mptcp_sock *msk)
return 0;
}
-static struct mptcp_sched_ops mptcp_sched_default = {
+struct mptcp_sched_ops mptcp_sched_default = {
.get_send = mptcp_sched_default_get_send,
.get_retrans = mptcp_sched_default_get_retrans,
.name = "default",
--
2.43.0
next prev parent reply other threads:[~2026-08-18 9:39 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-18 9:39 [PATCH mptcp-next v2 0/5] mptcp: avoid data-races around the sysctls Gang Yan
2026-08-18 9:39 ` Gang Yan [this message]
2026-08-18 9:39 ` [PATCH mptcp-next v2 2/5] mptcp: pm: change path_manager sysctl atomically Gang Yan
2026-08-18 9:48 ` gang.yan
-- strict thread matches above, loose matches on Subject: below --
2026-08-18 9:48 [PATCH mptcp-next v2 0/5] mptcp: avoid data-races around the sysctls Gang Yan
2026-08-18 9:48 ` [PATCH mptcp-next v2 1/5] mptcp: sched: change scheduler sysctl atomically Gang Yan
2026-08-18 9:59 ` sashiko-bot
2026-08-18 12:56 ` gang.yan
2026-08-18 15:50 ` Matthieu Baerts
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260818093910.47559-2-gang.yan@linux.dev \
--to=gang.yan@linux.dev \
--cc=mptcp@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.