From nobody Sat Sep 5 05:48:24 2026 Received: from mta0.migadu.com (out-175.mta0.migadu.com [91.218.175.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EA92645DF48 for ; Fri, 4 Sep 2026 09:35:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.175 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514538; cv=none; b=UnJKCfFt8GVOw7iQYs6npPXzImzL0bWJDS2uAffjEP45W4Oj8ySXpVPRJvJRBVtzWb65YJ3knqVLBqpa5SXXvKet5oisyAE305bHeclMqS1xEoQs1ZZKqMEvhp3wAA+Q+IsL8FZhDViV5owS1+CBxczCQOmtuc7AjFZ6j1ZQWy8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514538; c=relaxed/simple; bh=tdcKdN6OzL4dbz6F127XZ+5NRuu50HW/RZoiUBdwkoo=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=McyJY9wLOQnS06ELyExtVhS7Vw6CRON30L/0FZyttI/2oIbQEHr3+WtcWe3UloUo01y3q29mPgSlaP1gfXh+BM0t1xuFQum9TKkRk+6ynwVhroZ9+vLQukqB1yEZuaOnal5Lgd95yjLeJhT/zFtbjXjtTjjyofRUlSr8CyqYs98= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=ATUa4hjy; arc=none smtp.client-ip=91.218.175.175 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="ATUa4hjy" X-Envelope-To: mptcp@lists.linux.dev DKIM-Signature: a=rsa-sha256; bh=tdcKdN6OzL4dbz6F127XZ+5NRuu50HW/RZoiUBdwkoo=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788514534; v=1; x=1789119334; b=ATUa4hjy7f1iq4NFGuBIyqg3nWzJhOXPmE0Mxftvu7zOjYp5lwNkeuUgM5yLbTr02r4bEVgF F/4rABTPmr5f5NtWp55v+XDRNOBJcP3Ou8JEGMxuig8cVqcXDgy1h0p7hszJpzHh23GuJtaW0Bn P0begOGODK6uHvycubqGAjCI= X-Envelope-To: mptcp@lists.linux.dev Received: by smtp.migadu.com with ESMTPS id 26a90282e7c8f3e1; Fri, 04 Sep 2026 09:35:34 +0000 X-Mizu-Trace-ID: 26a90282e7c8f3e1 X-Migadu-Flow: FLOW_OUT From: Gang Yan To: mptcp@lists.linux.dev Subject: [PATCH mptcp-next v6 1/6] mptcp: sched: change scheduler sysctl atomically Date: Fri, 4 Sep 2026 17:35:26 +0800 Message-ID: <20260904093531.20023-2-gang.yan@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260904093531.20023-1-gang.yan@linux.dev> References: <20260904093531.20023-1-gang.yan@linux.dev> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gang Yan 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. A pointer store is a single atomic word, so readers always observe a consistent value, and mptcp_get_scheduler() can now return the ops directly instead of going through mptcp_sched_find() again. Assisted-by: Claude:GLM5.2 Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/626 Co-developed-by: Tao Cui Signed-off-by: Tao Cui Signed-off-by: Gang Yan --- net/mptcp/ctrl.c | 63 +++++++++++++++++++++++++++++++++++--------- net/mptcp/protocol.c | 3 +-- net/mptcp/protocol.h | 3 ++- net/mptcp/sched.c | 2 +- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index 63c5747f0f63..7d0f3421bd04 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]; }; =20 @@ -90,9 +90,17 @@ const char *mptcp_get_path_manager(const struct net *net) return mptcp_get_pernet(net)->path_manager; } =20 -const char *mptcp_get_scheduler(const struct net *net) +static struct mptcp_sched_ops *mptcp_pernet_sched(struct mptcp_pernet *per= net) { - return mptcp_get_pernet(net)->scheduler; + struct mptcp_sched_ops *sched; + + sched =3D rcu_dereference(pernet->scheduler); + return sched ? sched : &mptcp_sched_default; +} + +struct mptcp_sched_ops *mptcp_get_scheduler(const struct net *net) +{ + return mptcp_pernet_sched(mptcp_get_pernet(net)); } =20 unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net) @@ -112,23 +120,33 @@ static void mptcp_pernet_set_defaults(struct mptcp_pe= rnet *pernet) pernet->allow_join_initial_addr_port =3D 1; pernet->stale_loss_cnt =3D 4; pernet->pm_type =3D MPTCP_PM_TYPE_KERNEL; - strscpy(pernet->scheduler, "default", sizeof(pernet->scheduler)); + + if (bpf_try_module_get(&mptcp_sched_default, mptcp_sched_default.owner)) + RCU_INIT_POINTER(pernet->scheduler, &mptcp_sched_default); + strscpy(pernet->path_manager, "kernel", sizeof(pernet->path_manager)); pernet->add_addr_v6_port_drop_ts =3D 1; } =20 #ifdef CONFIG_SYSCTL -static int mptcp_set_scheduler(char *scheduler, const char *name) +static int mptcp_set_scheduler(struct mptcp_pernet *pernet, const char *na= me) { - struct mptcp_sched_ops *sched; + struct mptcp_sched_ops *sched, *prev; int ret =3D 0; =20 rcu_read_lock(); sched =3D mptcp_sched_find(name); - if (sched) - strscpy(scheduler, name, MPTCP_SCHED_NAME_MAX); - else + if (sched) { + if (bpf_try_module_get(sched, sched->owner)) { + prev =3D xchg(&pernet->scheduler, sched); + if (prev) + bpf_module_put(prev, prev->owner); + } else { + ret =3D -EBUSY; + } + } else { ret =3D -ENOENT; + } rcu_read_unlock(); =20 return ret; @@ -137,7 +155,9 @@ static int mptcp_set_scheduler(char *scheduler, const c= har *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] =3D ctl->data; + struct mptcp_pernet *pernet =3D container_of(ctl->data, + struct mptcp_pernet, + scheduler); char val[MPTCP_SCHED_NAME_MAX]; struct ctl_table tbl =3D { .data =3D val, @@ -145,11 +165,13 @@ static int proc_scheduler(const struct ctl_table *ctl= , int write, }; int ret; =20 - strscpy(val, *scheduler, MPTCP_SCHED_NAME_MAX); + rcu_read_lock(); + strscpy(val, mptcp_pernet_sched(pernet)->name, MPTCP_SCHED_NAME_MAX); + rcu_read_unlock(); =20 ret =3D proc_dostring(&tbl, write, buffer, lenp, ppos); if (write && ret =3D=3D 0) - ret =3D mptcp_set_scheduler(*scheduler, val); + ret =3D mptcp_set_scheduler(pernet, val); =20 return ret; } @@ -563,18 +585,33 @@ void mptcp_active_detect_blackhole(struct sock *ssk, = bool expired) static int __net_init mptcp_net_init(struct net *net) { struct mptcp_pernet *pernet =3D mptcp_get_pernet(net); + int ret; =20 mptcp_pernet_set_defaults(pernet); =20 - return mptcp_pernet_new_table(net, pernet); + ret =3D mptcp_pernet_new_table(net, pernet); + if (ret) { + struct mptcp_sched_ops *sched; + + sched =3D rcu_dereference_protected(pernet->scheduler, true); + if (sched) + bpf_module_put(sched, sched->owner); + } + + return ret; } =20 /* Note: the callback will only be called per extra netns */ static void __net_exit mptcp_net_exit(struct net *net) { struct mptcp_pernet *pernet =3D mptcp_get_pernet(net); + struct mptcp_sched_ops *sched; =20 mptcp_pernet_del_table(pernet); + + sched =3D rcu_dereference_protected(pernet->scheduler, true); + if (sched) + bpf_module_put(sched, sched->owner); } =20 static struct pernet_operations mptcp_pernet_ops =3D { diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 0b24e0afedfb..179eb6bcebf8 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3272,8 +3272,7 @@ static int mptcp_init_sock(struct sock *sk) return -ENOMEM; =20 rcu_read_lock(); - ret =3D mptcp_init_sched(mptcp_sk(sk), - mptcp_sched_find(mptcp_get_scheduler(net))); + ret =3D mptcp_init_sched(mptcp_sk(sk), mptcp_get_scheduler(net)); rcu_read_unlock(); if (ret) return ret; diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index b3121c8c766b..5154c7ce3026 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); +struct mptcp_sched_ops *mptcp_get_scheduler(const struct net *net); unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net); =20 void mptcp_active_disable(struct sock *sk); @@ -1155,6 +1155,7 @@ int mptcp_pm_remove_addr(struct mptcp_sock *msk, cons= t struct mptcp_rm_list *rm_ =20 /* 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; =20 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_s= ock *msk) return 0; } =20 -static struct mptcp_sched_ops mptcp_sched_default =3D { +struct mptcp_sched_ops mptcp_sched_default =3D { .get_send =3D mptcp_sched_default_get_send, .get_retrans =3D mptcp_sched_default_get_retrans, .name =3D "default", --=20 2.43.0 From nobody Sat Sep 5 05:48:24 2026 Received: from mta0.migadu.com (out-176.mta0.migadu.com [91.218.175.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CF1B745FFB4 for ; Fri, 4 Sep 2026 09:35:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.176 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514539; cv=none; b=Jv+q8qlBklTWjNCruvNiuGnNHsuPt76KTRTKdcrQybK1QL+Gn7xmcLs8ZeR6V/cYEiu4nuzoIdgxFa+JBF4KW2uCXmgHxjv/qyfU7THxoijpK2y1RaIJmAVeH8Di7mxYo+F9auml7yMPkGVtylQlmDC0NeRSYDwj61Xsxl60dC4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514539; c=relaxed/simple; bh=rJZA++h0H6N8rFhPhJBJQ/h8b4tU7/zbmd43tpJ4tuI=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZPGXvrEw6Z0AGa3HBKGCnIsKvC/U9GALl1JBzRp/9LiHttsMji9vS/bly5i7VfV75vBdsQdHTHL13lNmIAosRh4UyxMB87Nj2l0dMfLatJ5nRZ3APyDyPyw0TQqqKRctjdx511JPHJqBlQfvxGICsDcBdD1UoBmIvLg5h4I+RtU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=woxa2vNm; arc=none smtp.client-ip=91.218.175.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="woxa2vNm" X-Envelope-To: mptcp@lists.linux.dev DKIM-Signature: a=rsa-sha256; bh=rJZA++h0H6N8rFhPhJBJQ/h8b4tU7/zbmd43tpJ4tuI=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788514535; v=1; x=1789119335; b=woxa2vNmuHE8bClboG3p1lxPjeWJmUoVASocfiaC5FGtZRNHtqtgwRwKMpbpdlAXlowGkfPL 1AJlzase9wkpf49Si+O8I94H0zOLpAcF3T1KmbVllTwa1AGVOyMPzssBkqFQ7ySuKunbHqirmb4 ISfwwWyFUtwK9oK7YAZpm+f0= X-Envelope-To: mptcp@lists.linux.dev Received: by smtp.migadu.com with ESMTPS id 526b0eadc573db47; Fri, 04 Sep 2026 09:35:35 +0000 X-Mizu-Trace-ID: 526b0eadc573db47 X-Migadu-Flow: FLOW_OUT From: Gang Yan To: mptcp@lists.linux.dev Subject: [PATCH mptcp-next v6 2/6] mptcp: pm: change path_manager sysctl atomically Date: Fri, 4 Sep 2026 17:35:27 +0800 Message-ID: <20260904093531.20023-3-gang.yan@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260904093531.20023-1-gang.yan@linux.dev> References: <20260904093531.20023-1-gang.yan@linux.dev> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gang Yan The per-netns path manager name is stored as an inline char[] buffer and updated via strscpy() from the sysctl handler. A concurrent reader can observe a half-written name (KCSAN), which READ_ONCE() cannot fix for a multi-byte string. Following the tcp_congestion_control() model (and the scheduler change in the previous patch), store a pointer to the immutable struct mptcp_pm_ops instead of the name string. No module reference is taken on the path manager ops for now, as they can only be registered from built-in code on one side, and on the other side the reference counting will be introduced by the last patch of this series, together with the BPF path manager support. Assisted-by: Claude:GLM5.2 Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/626 Co-developed-by: Tao Cui Signed-off-by: Tao Cui Signed-off-by: Gang Yan --- net/mptcp/ctrl.c | 33 +++++++++++++++++++++++---------- net/mptcp/pm.c | 3 ++- net/mptcp/protocol.h | 3 +-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index 7d0f3421bd04..76ff2a41ba38 100644 --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -40,7 +40,7 @@ struct mptcp_pernet { u8 pm_type; u8 add_addr_v6_port_drop_ts; struct mptcp_sched_ops __rcu *scheduler; - char path_manager[MPTCP_PM_NAME_MAX]; + struct mptcp_pm_ops __rcu *path_manager; }; =20 static struct mptcp_pernet *mptcp_get_pernet(const struct net *net) @@ -85,9 +85,20 @@ int mptcp_get_pm_type(const struct net *net) return mptcp_get_pernet(net)->pm_type; } =20 -const char *mptcp_get_path_manager(const struct net *net) +static struct mptcp_pm_ops *mptcp_pernet_pm(struct mptcp_pernet *pernet) { - return mptcp_get_pernet(net)->path_manager; + struct mptcp_pm_ops *pm_ops; + + pm_ops =3D rcu_dereference(pernet->path_manager); + return pm_ops ? pm_ops : &mptcp_pm_kernel; +} + +void mptcp_get_path_manager(const struct net *net, char *name) +{ + rcu_read_lock(); + strscpy(name, mptcp_pernet_pm(mptcp_get_pernet(net))->name, + MPTCP_PM_NAME_MAX); + rcu_read_unlock(); } =20 static struct mptcp_sched_ops *mptcp_pernet_sched(struct mptcp_pernet *per= net) @@ -124,7 +135,8 @@ static void mptcp_pernet_set_defaults(struct mptcp_pern= et *pernet) if (bpf_try_module_get(&mptcp_sched_default, mptcp_sched_default.owner)) RCU_INIT_POINTER(pernet->scheduler, &mptcp_sched_default); =20 - strscpy(pernet->path_manager, "kernel", sizeof(pernet->path_manager)); + RCU_INIT_POINTER(pernet->path_manager, &mptcp_pm_kernel); + pernet->add_addr_v6_port_drop_ts =3D 1; } =20 @@ -210,7 +222,7 @@ static int proc_blackhole_detect_timeout(const struct c= tl_table *table, return ret; } =20 -static int mptcp_set_path_manager(char *path_manager, const char *name) +static int mptcp_set_path_manager(struct mptcp_pernet *pernet, const char = *name) { struct mptcp_pm_ops *pm_ops; int ret =3D 0; @@ -218,7 +230,7 @@ static int mptcp_set_path_manager(char *path_manager, c= onst char *name) rcu_read_lock(); pm_ops =3D mptcp_pm_find(name); if (pm_ops) - strscpy(path_manager, name, MPTCP_PM_NAME_MAX); + xchg(&pernet->path_manager, pm_ops); else ret =3D -ENOENT; rcu_read_unlock(); @@ -232,7 +244,6 @@ static int proc_path_manager(const struct ctl_table *ct= l, int write, struct mptcp_pernet *pernet =3D container_of(ctl->data, struct mptcp_pernet, path_manager); - char (*path_manager)[MPTCP_PM_NAME_MAX] =3D ctl->data; char pm_name[MPTCP_PM_NAME_MAX]; const struct ctl_table tbl =3D { .data =3D pm_name, @@ -240,11 +251,13 @@ static int proc_path_manager(const struct ctl_table *= ctl, int write, }; int ret; =20 - strscpy(pm_name, *path_manager, MPTCP_PM_NAME_MAX); + rcu_read_lock(); + strscpy(pm_name, mptcp_pernet_pm(pernet)->name, MPTCP_PM_NAME_MAX); + rcu_read_unlock(); =20 ret =3D proc_dostring(&tbl, write, buffer, lenp, ppos); if (write && ret =3D=3D 0) { - ret =3D mptcp_set_path_manager(*path_manager, pm_name); + ret =3D mptcp_set_path_manager(pernet, pm_name); if (ret =3D=3D 0) { u8 pm_type =3D __MPTCP_PM_TYPE_NR; =20 @@ -276,7 +289,7 @@ static int proc_pm_type(const struct ctl_table *ctl, in= t write, pm_name =3D "kernel"; else if (pm_type =3D=3D MPTCP_PM_TYPE_USERSPACE) pm_name =3D "userspace"; - mptcp_set_path_manager(pernet->path_manager, pm_name); + mptcp_set_path_manager(pernet, pm_name); } =20 return ret; diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index d7c5b50b34cc..69a38cb48977 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -1204,7 +1204,7 @@ void mptcp_pm_destroy(struct mptcp_sock *msk) void mptcp_pm_data_reset(struct mptcp_sock *msk) { const struct net *net =3D sock_net((struct sock *)msk); - const char *pm_name =3D mptcp_get_path_manager(net); + char pm_name[MPTCP_PM_NAME_MAX]; u8 pm_type =3D mptcp_get_pm_type(net); struct mptcp_pm_data *pm =3D &msk->pm; =20 @@ -1213,6 +1213,7 @@ void mptcp_pm_data_reset(struct mptcp_sock *msk) pm->rm_list_rx.nr =3D 0; WRITE_ONCE(pm->pm_type, pm_type); =20 + mptcp_get_path_manager(net, pm_name); rcu_read_lock(); mptcp_pm_ops_init(msk, pm_name); rcu_read_unlock(); diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 5154c7ce3026..6f796d1c769a 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -802,7 +802,7 @@ int mptcp_allow_join_id0(const struct net *net); 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); +void mptcp_get_path_manager(const struct net *net, char *name); struct mptcp_sched_ops *mptcp_get_scheduler(const struct net *net); unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net); =20 @@ -1153,7 +1153,6 @@ int mptcp_pm_announce_addr(struct mptcp_sock *msk, bool echo); int mptcp_pm_remove_addr(struct mptcp_sock *msk, const struct mptcp_rm_lis= t *rm_list); =20 -/* 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; =20 --=20 2.43.0 From nobody Sat Sep 5 05:48:24 2026 Received: from mta1.migadu.com (out-187.mta1.migadu.com [95.215.58.187]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 125CC444706 for ; Fri, 4 Sep 2026 09:35:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.187 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514540; cv=none; b=TcDbh3z72f94km8axrz+jzqjPNgzwIepBehuGLhGi7c6Cvx3m/CGeNs8Fds0NXJvbWysOnJ1xpaBXNBfz+yL4ApWsGvQJ1BZNqW29+UdfIRQcHMNRG5/D6M+Mlwx3imXdvzHPqgVLaiCZXk+DmNMWFktEVOCq2SDrK1p5hgG4c0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514540; c=relaxed/simple; bh=f8tgCjT83aIcTUbhHk9sOl+jqy/sFiMJokips0njS/M=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=im0VhGaHavKMHFqRCzj5xRhC4kS1sOHFRf7gCTTlKF2/PJ0gg1tU2SKtEhP3uc9nF0HxmDVrc5Oy3zDP5JcwEYF37BMuSJ/ymNkrf6Vz+N7tzpb5coVlev8Rw8gb7CVTlIrgIa9IGZ1BKkC3uVs0Os5xCBYEOi25ldQqfAm3NoA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=NYPMUMMn; arc=none smtp.client-ip=95.215.58.187 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="NYPMUMMn" X-Envelope-To: mptcp@lists.linux.dev DKIM-Signature: a=rsa-sha256; bh=f8tgCjT83aIcTUbhHk9sOl+jqy/sFiMJokips0njS/M=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788514536; v=1; x=1789119336; b=NYPMUMMn6x7A4Lb912O8FfjSABVZBUf5dzSNPzPmTsq9xxH+ze3HjLAJ3HO0V+p2Qn3xF1SO GF5z/tkUFBat2jzT8IzCCCV/ak5GvND2gSytgGJBjIQAo6Hcdpg6ZZ+RPahJLYjEwG207Jyjq2T vpW7dHEtPPgdxIvyb20HEG+U= X-Envelope-To: mptcp@lists.linux.dev Received: by smtp.migadu.com with ESMTPS id 0d8275fe39731636; Fri, 04 Sep 2026 09:35:36 +0000 X-Mizu-Trace-ID: 0d8275fe39731636 X-Migadu-Flow: FLOW_OUT From: Gang Yan To: mptcp@lists.linux.dev Subject: [PATCH mptcp-next v6 3/6] mptcp: use READ_ONCE() over sysctls Date: Fri, 4 Sep 2026 17:35:28 +0800 Message-ID: <20260904093531.20023-4-gang.yan@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260904093531.20023-1-gang.yan@linux.dev> References: <20260904093531.20023-1-gang.yan@linux.dev> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: "Matthieu Baerts (NGI0)" To avoid KCSAN issues. This patch is in theory for -net, and will need to be split in multiple patches, with different Fixes tags. But I prefer to wait for Eric's patches, as I noticed he already started to modify mptcp_is_enabled: https://lore.kernel.org/CANn89iLdwhhwLyO6zRjWMEY3t9g60ZE8ZhOVx33ucg_uRETb= mQ@mail.gmail.com Still, keeping this patch in this series, not to forget about it. Reported-by: Eric Dumazet Closes: https://lore.kernel.org/CANn89iL=3Dos-60kDKqMDdyiXuPF5CG=3DeejS0vmt= hwpDGXz_Bp8A@mail.gmail.com Signed-off-by: Matthieu Baerts (NGI0) --- net/mptcp/ctrl.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index 76ff2a41ba38..5a75f9b76d15 100644 --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -50,39 +50,39 @@ static struct mptcp_pernet *mptcp_get_pernet(const stru= ct net *net) =20 int mptcp_is_enabled(const struct net *net) { - return mptcp_get_pernet(net)->mptcp_enabled; + return READ_ONCE(mptcp_get_pernet(net)->mptcp_enabled); } =20 unsigned int mptcp_get_add_addr_timeout(const struct net *net) { - return mptcp_get_pernet(net)->add_addr_timeout; + return READ_ONCE(mptcp_get_pernet(net)->add_addr_timeout); } =20 int mptcp_is_checksum_enabled(const struct net *net) { - return mptcp_get_pernet(net)->checksum_enabled; + return READ_ONCE(mptcp_get_pernet(net)->checksum_enabled); } =20 int mptcp_allow_join_id0(const struct net *net) { - return mptcp_get_pernet(net)->allow_join_initial_addr_port; + return READ_ONCE(mptcp_get_pernet(net)->allow_join_initial_addr_port); } =20 unsigned int mptcp_stale_loss_cnt(const struct net *net) { - return mptcp_get_pernet(net)->stale_loss_cnt; + return READ_ONCE(mptcp_get_pernet(net)->stale_loss_cnt); } =20 unsigned int mptcp_close_timeout(const struct sock *sk) { if (sock_flag(sk, SOCK_DEAD)) return TCP_TIMEWAIT_LEN; - return mptcp_get_pernet(sock_net(sk))->close_timeout; + return READ_ONCE(mptcp_get_pernet(sock_net(sk))->close_timeout); } =20 int mptcp_get_pm_type(const struct net *net) { - return mptcp_get_pernet(net)->pm_type; + return READ_ONCE(mptcp_get_pernet(net)->pm_type); } =20 static struct mptcp_pm_ops *mptcp_pernet_pm(struct mptcp_pernet *pernet) @@ -586,7 +586,7 @@ void mptcp_active_detect_blackhole(struct sock *ssk, bo= ol expired) =20 net =3D sock_net(ssk); timeouts =3D inet_csk(ssk)->icsk_retransmits; - to_max =3D mptcp_get_pernet(net)->syn_retrans_before_tcp_fallback; + to_max =3D READ_ONCE(mptcp_get_pernet(net)->syn_retrans_before_tcp_fallba= ck); =20 if (timeouts =3D=3D to_max || (timeouts < to_max && expired)) { subflow->mpc_drop =3D 1; --=20 2.43.0 From nobody Sat Sep 5 05:48:24 2026 Received: from mta1.migadu.com (out-188.mta1.migadu.com [95.215.58.188]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1742F449B03 for ; Fri, 4 Sep 2026 09:35:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.188 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514541; cv=none; b=nqi64bVv7w/Fr9mHdR9bJGoUf2WDbC5u+6ZF+QXi1TOmLSZoJTikQ5snG6NJWfSxbvKe16DqoL2ton8zuK1Q0MqAZoNHfDCp1EP6UT+GoTCi+zkoGEQQujzPLon5t4Iv/3ElMvS5hdnA48ryjo9HxEzWov1I9n+uZx3F2/TRdc4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514541; c=relaxed/simple; bh=rtw1YyrIvzIHYWYdRXpdAafdWLiYM50DLewJZDMU6SY=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=pEX84qVPMJJihWG2sspic0img6uFKs1H9Sezk4KkjYotjFv+0+163Xlxd5x9l5Wz23mmpoYyqKuDs/yoeNHR5PLHKJ6dAXx5NIJyYiuysfX+KkqyOtM6tthgcbNyFMRn1AKFVLW86ApMAsZxk6K0u6AXJySHcVatfPC5bv4FQEQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=qe/d62VF; arc=none smtp.client-ip=95.215.58.188 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="qe/d62VF" X-Envelope-To: mptcp@lists.linux.dev DKIM-Signature: a=rsa-sha256; bh=rtw1YyrIvzIHYWYdRXpdAafdWLiYM50DLewJZDMU6SY=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788514538; v=1; x=1789119338; b=qe/d62VFHVwSz8XYhBZJaKbeMReJr8LUUMigo2eOcuaH1lV7jH7pKeFbIVQ0Oy/mMVHuxCQp TPFMeZQhGIYWkcE3dpyuharVhbbjrGNtYu1ufUSoqworngGxHJNw2k7xH55ze9wRXEnLOl9G7ab JHeg1kkg4chkb6pq3oLh60UA= X-Envelope-To: mptcp@lists.linux.dev Received: by smtp.migadu.com with ESMTPS id e9368a71c461aff7; Fri, 04 Sep 2026 09:35:38 +0000 X-Mizu-Trace-ID: e9368a71c461aff7 X-Migadu-Flow: FLOW_OUT From: Gang Yan To: mptcp@lists.linux.dev Subject: [PATCH mptcp-next v6 4/6] mptcp: pm: use WRITE_ONCE() for the pm_type sysctl Date: Fri, 4 Sep 2026 17:35:29 +0800 Message-ID: <20260904093531.20023-5-gang.yan@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260904093531.20023-1-gang.yan@linux.dev> References: <20260904093531.20023-1-gang.yan@linux.dev> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gang Yan Write pernet->pm_type with WRITE_ONCE() in proc_path_manager(), pairing it with the READ_ONCE() readers introduced earlier in this series. Note that updating net.mptcp.path_manager swaps the ops pointer first, then writes the derived pm_type: a socket created in between may see the new ops with the old pm_type. As the net.mptcp.pm_type knob is deprecated since v6.15 and will be removed, the race is not fixed on purpose; document it above the assignment so it does not get reported again. Suggested-by: Matthieu Baerts Assisted-by: Claude:GLM5.2 Co-developed-by: Tao Cui Signed-off-by: Tao Cui Signed-off-by: Gang Yan --- net/mptcp/ctrl.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index 5a75f9b76d15..87491b961bf2 100644 --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -265,7 +265,13 @@ static int proc_path_manager(const struct ctl_table *c= tl, int write, pm_type =3D MPTCP_PM_TYPE_KERNEL; else if (strncmp(pm_name, "userspace", MPTCP_PM_NAME_MAX) =3D=3D 0) pm_type =3D MPTCP_PM_TYPE_USERSPACE; - pernet->pm_type =3D pm_type; + + /* Pre-existing race: two sequential writes, a socket + * created in between may see the new ops with the old + * pm_type. The knob is deprecated since v6.15 and will + * be removed: not fixed on purpose. + */ + WRITE_ONCE(pernet->pm_type, pm_type); } } =20 --=20 2.43.0 From nobody Sat Sep 5 05:48:24 2026 Received: from mta0.migadu.com (out-178.mta0.migadu.com [91.218.175.178]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 356DC444706 for ; Fri, 4 Sep 2026 09:35:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=91.218.175.178 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514543; cv=none; b=d0nuNR1gC8pijZF3r2gfUNZ7IxYes6mE4wqt33oqPDU3qd4HX1N26bPGpt5u0RsILzk8LLg6qdWLr/rbjn/fCkGi0bMoOeawRxLbzxNEA5r/bOZd3omFiHrgBJQI4MIlNoA5NtKKAIAeZjmN4XmMcTh2xMqWFbNpARhPCqvHtzc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514543; c=relaxed/simple; bh=4EpqRgte29+QoYQLFbN2XKOmNO3p33pxsxQ0m18n0gQ=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ICa0Xv3JNmM4afj/Ity4Hs8kGDUdSwM6OV/Zng/g43E3ASJPaoL2kf7yI8hMAoPfPoH2X4KAjFe+ZGTObO4yL1c4ubGwDCM+MEGIbV68xhaG85rRV4T2r2AGE/QwwD5xkV8EmgHFmyeKPuYY3dCwmP+jqYJtTJ76ONYCe/MUN0w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=CVVo6Um6; arc=none smtp.client-ip=91.218.175.178 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="CVVo6Um6" X-Envelope-To: mptcp@lists.linux.dev DKIM-Signature: a=rsa-sha256; bh=4EpqRgte29+QoYQLFbN2XKOmNO3p33pxsxQ0m18n0gQ=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788514539; v=1; x=1789119339; b=CVVo6Um6BM4XZrCVPDoaHV4X4FElbPgfgXDjhjjzKLWAEaTV2C/BF9pwT/liolRLDSR9nCjL ipiYdhmjjYqBdC7IrbczCZjVLz1YON9l1RNUa7wQEF8DcEIXzlEoGd1ls+PuAAjPP94IawP/LKF oRcVqNydKKpK2BfU1aPHSaSE= X-Envelope-To: mptcp@lists.linux.dev Received: by smtp.migadu.com with ESMTPS id f9afe5a6d9129784; Fri, 04 Sep 2026 09:35:39 +0000 X-Mizu-Trace-ID: f9afe5a6d9129784 X-Migadu-Flow: FLOW_OUT From: Gang Yan To: mptcp@lists.linux.dev Subject: [PATCH mptcp-next v6 5/6] Squash-to "mptcp: pm: init and release mptcp_pm_ops" Date: Fri, 4 Sep 2026 17:35:30 +0800 Message-ID: <20260904093531.20023-6-gang.yan@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260904093531.20023-1-gang.yan@linux.dev> References: <20260904093531.20023-1-gang.yan@linux.dev> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gang Yan This commit introduces the mptcp_pm_ops lifetime handling on sockets (mptcp_pm_ops_init/release taking a module reference), and would then be the first one whose per-net path managers can be unloaded while a pernet still stores them. mptcp_pm_ops_init() also takes the ops pointer directly instead of the name, and mptcp_get_path_manager() returns the ops: the redundant mptcp_pm_find() list walk from the name is avoided, as done for the scheduler side earlier in this series. Assisted-by: Claude:GLM5.2 Co-developed-by: Tao Cui Signed-off-by: Tao Cui Signed-off-by: Gang Yan --- net/mptcp/ctrl.c | 35 +++++++++++++++++++++++++---------- net/mptcp/pm.c | 12 ++++-------- net/mptcp/protocol.h | 2 +- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/net/mptcp/ctrl.c b/net/mptcp/ctrl.c index 87491b961bf2..6379a9f481ac 100644 --- a/net/mptcp/ctrl.c +++ b/net/mptcp/ctrl.c @@ -93,12 +93,9 @@ static struct mptcp_pm_ops *mptcp_pernet_pm(struct mptcp= _pernet *pernet) return pm_ops ? pm_ops : &mptcp_pm_kernel; } =20 -void mptcp_get_path_manager(const struct net *net, char *name) +struct mptcp_pm_ops *mptcp_get_path_manager(const struct net *net) { - rcu_read_lock(); - strscpy(name, mptcp_pernet_pm(mptcp_get_pernet(net))->name, - MPTCP_PM_NAME_MAX); - rcu_read_unlock(); + return mptcp_pernet_pm(mptcp_get_pernet(net)); } =20 static struct mptcp_sched_ops *mptcp_pernet_sched(struct mptcp_pernet *per= net) @@ -135,7 +132,8 @@ static void mptcp_pernet_set_defaults(struct mptcp_pern= et *pernet) if (bpf_try_module_get(&mptcp_sched_default, mptcp_sched_default.owner)) RCU_INIT_POINTER(pernet->scheduler, &mptcp_sched_default); =20 - RCU_INIT_POINTER(pernet->path_manager, &mptcp_pm_kernel); + if (bpf_try_module_get(&mptcp_pm_kernel, mptcp_pm_kernel.owner)) + RCU_INIT_POINTER(pernet->path_manager, &mptcp_pm_kernel); =20 pernet->add_addr_v6_port_drop_ts =3D 1; } @@ -224,15 +222,22 @@ static int proc_blackhole_detect_timeout(const struct= ctl_table *table, =20 static int mptcp_set_path_manager(struct mptcp_pernet *pernet, const char = *name) { - struct mptcp_pm_ops *pm_ops; + struct mptcp_pm_ops *pm_ops, *prev; int ret =3D 0; =20 rcu_read_lock(); pm_ops =3D mptcp_pm_find(name); - if (pm_ops) - xchg(&pernet->path_manager, pm_ops); - else + if (pm_ops) { + if (bpf_try_module_get(pm_ops, pm_ops->owner)) { + prev =3D xchg(&pernet->path_manager, pm_ops); + if (prev) + bpf_module_put(prev, prev->owner); + } else { + ret =3D -EBUSY; + } + } else { ret =3D -ENOENT; + } rcu_read_unlock(); =20 return ret; @@ -611,10 +616,15 @@ static int __net_init mptcp_net_init(struct net *net) ret =3D mptcp_pernet_new_table(net, pernet); if (ret) { struct mptcp_sched_ops *sched; + struct mptcp_pm_ops *pm; =20 sched =3D rcu_dereference_protected(pernet->scheduler, true); if (sched) bpf_module_put(sched, sched->owner); + + pm =3D rcu_dereference_protected(pernet->path_manager, true); + if (pm) + bpf_module_put(pm, pm->owner); } =20 return ret; @@ -625,12 +635,17 @@ static void __net_exit mptcp_net_exit(struct net *net) { struct mptcp_pernet *pernet =3D mptcp_get_pernet(net); struct mptcp_sched_ops *sched; + struct mptcp_pm_ops *pm; =20 mptcp_pernet_del_table(pernet); =20 sched =3D rcu_dereference_protected(pernet->scheduler, true); if (sched) bpf_module_put(sched, sched->owner); + + pm =3D rcu_dereference_protected(pernet->path_manager, true); + if (pm) + bpf_module_put(pm, pm->owner); } =20 static struct pernet_operations mptcp_pernet_ops =3D { diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 69a38cb48977..64244a1a01bc 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -1155,13 +1155,11 @@ void mptcp_pm_worker(struct mptcp_sock *msk) spin_unlock_bh(&msk->pm.lock); } =20 -static void mptcp_pm_ops_init(struct mptcp_sock *msk, const char *pm_name) +static void mptcp_pm_ops_init(struct mptcp_sock *msk, + struct mptcp_pm_ops *pm_ops) { - struct mptcp_pm_ops *pm_ops; - - pm_ops =3D mptcp_pm_find(pm_name); if (!pm_ops || !bpf_try_module_get(pm_ops, pm_ops->owner)) { - pr_warn_once("pm %s fails, fallback to default pm", pm_name); + pr_warn_once("pm %s fails, fallback to default pm", pm_ops->name); pm_ops =3D &mptcp_pm_kernel; } =20 @@ -1204,7 +1202,6 @@ void mptcp_pm_destroy(struct mptcp_sock *msk) void mptcp_pm_data_reset(struct mptcp_sock *msk) { const struct net *net =3D sock_net((struct sock *)msk); - char pm_name[MPTCP_PM_NAME_MAX]; u8 pm_type =3D mptcp_get_pm_type(net); struct mptcp_pm_data *pm =3D &msk->pm; =20 @@ -1213,9 +1210,8 @@ void mptcp_pm_data_reset(struct mptcp_sock *msk) pm->rm_list_rx.nr =3D 0; WRITE_ONCE(pm->pm_type, pm_type); =20 - mptcp_get_path_manager(net, pm_name); rcu_read_lock(); - mptcp_pm_ops_init(msk, pm_name); + mptcp_pm_ops_init(msk, mptcp_get_path_manager(net)); rcu_read_unlock(); } =20 diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 6f796d1c769a..4a7d7f1ab82e 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -802,7 +802,7 @@ int mptcp_allow_join_id0(const struct net *net); 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); -void mptcp_get_path_manager(const struct net *net, char *name); +struct mptcp_pm_ops *mptcp_get_path_manager(const struct net *net); struct mptcp_sched_ops *mptcp_get_scheduler(const struct net *net); unsigned int mptcp_add_addr_v6_port_drop_ts(const struct net *net); =20 --=20 2.43.0 From nobody Sat Sep 5 05:48:24 2026 Received: from mta1.migadu.com (out-191.mta1.migadu.com [95.215.58.191]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 491BF449B03 for ; Fri, 4 Sep 2026 09:35:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.191 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514544; cv=none; b=Icwx/fvl0el7fWv0RncnS4eQKqVuazeW+0rMYDhC5v3r6TlIx2w1asVdg+QVSM26cWRezfwh6J9BOMFSTqeiSjdx/HJw1F3mmhzAURwjZMD4idA1e64uRuDZxQqW+X/f1sRowS2izQoKqOqXIooIWGlvCZ9CJkRUkcOuXB5stHE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788514544; c=relaxed/simple; bh=Ck0r59kU/9TNMiQGFjyAoNMFTXTkRnMo5EiZ8VpFhtY=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=g2IjwUmlytzdTPewL8dYL//ftTg5ZzLDkF925r4gaxSVTMkQR/Shzfg8vJBimkyIjUOTDpZXI0PzCJeW+8OqVUutMF29DaJ4NQ9SFOz6NkosSbz1gk3B4uXIogUrwK0MJtLt7Mxcnwn9OFUcpBPkC7jyVHVtGI+Cjma7jGbOld8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=KJxNfYwF; arc=none smtp.client-ip=95.215.58.191 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="KJxNfYwF" X-Envelope-To: mptcp@lists.linux.dev DKIM-Signature: a=rsa-sha256; bh=Ck0r59kU/9TNMiQGFjyAoNMFTXTkRnMo5EiZ8VpFhtY=; c=simple/simple; d=linux.dev; h=from:to:subject:date:message-id:mime-version:content-type; s=key1; t=1788514540; v=1; x=1789119340; b=KJxNfYwFFsADA+7BqRwxAG0MtqkqcMuczeg7urhFoP+sO9+qRdsl3BcZvRHPFlzDC1Bz3zGQ WvvBiXxL/QbcKSawMSIytOFhywkpLSwO5bGl/vOg/2ir7FU1S1itNybKCSb22AgjHumplLmwp0+ iguoPgz73P2mSjMOx5Q/WKFE= X-Envelope-To: mptcp@lists.linux.dev Received: by smtp.migadu.com with ESMTPS id d38c5ec8a180e2f9; Fri, 04 Sep 2026 09:35:40 +0000 X-Mizu-Trace-ID: d38c5ec8a180e2f9 X-Migadu-Flow: FLOW_OUT From: Gang Yan To: mptcp@lists.linux.dev Subject: [PATCH mptcp-next v6 6/6] Squash to previous one Date: Fri, 4 Sep 2026 17:35:31 +0800 Message-ID: <20260904093531.20023-7-gang.yan@linux.dev> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260904093531.20023-1-gang.yan@linux.dev> References: <20260904093531.20023-1-gang.yan@linux.dev> Precedence: bulk X-Mailing-List: mptcp@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Gang Yan Fix the issue sashiko mentioned in [1]. This patch applies the usual RCU discipline to the pointer: mark it __rcu, read it via rcu_dereference() inside RCU read sections, assign it via rcu_assign_pointer(), wait for a grace period before dropping the reference on the ops being replaced, and do the final release from mptcp_destroy() -- after the last msk reference -- instead of mptcp_destroy_common(), which is also reached on mptcp_disconnect(). Also, we need to hold the pm.lock before modify the pm.ops, and using the status of lock to tell rcu it's safe. The previous ops is released (old->release() and the module reference, after the grace period) not only when it is replaced, but also when it is kept across a reset: this way a PM defining both init() and release() callbacks stays balanced over repeated disconnect/reuse cycles, instead of having release() deferred to the final destruction. Note that rcu_assign_pointer() before pm_ops->init(msk) does not publish a partially initialised object: pm_ops->init() prepares the per-socket state, the ops themselves are registered immutable, and the msk is not reachable by readers until its token is registered. For the current in-tree path managers, none of this changes behaviour: neither defines release(), the per-socket state (announced list, userspace local address list) is freed unconditionally by mptcp_pm_destroy() on every disconnect, and mptcp_pm_kernel_init() only re-sets flags from the current sysctl, it does not allocate. Keep it as a separate patch to ease the review, but to be squashed into the previous one, which is itself a squash-to for "mptcp: pm: init and release mptcp_pm_ops". [1] https://sashiko.dev/#/patchset/20260819125629.49823-1-gang.yan@linux.de= v?part=3D5 Assisted-by: Claude:GLM5.2 Co-developed-by: Tao Cui Signed-off-by: Tao Cui Signed-off-by: Gang Yan --- net/mptcp/pm.c | 63 ++++++++++++++++++++++++++++++++++---------- net/mptcp/protocol.c | 4 +++ net/mptcp/protocol.h | 3 ++- net/mptcp/subflow.c | 9 ++++++- 4 files changed, 63 insertions(+), 16 deletions(-) diff --git a/net/mptcp/pm.c b/net/mptcp/pm.c index 64244a1a01bc..d581d11b350f 100644 --- a/net/mptcp/pm.c +++ b/net/mptcp/pm.c @@ -27,6 +27,14 @@ static LIST_HEAD(mptcp_pm_list); =20 /* path manager helpers */ =20 +static struct mptcp_pm_ops *mptcp_pm_rcu_deref(struct mptcp_sock *msk) +{ + struct mptcp_pm_ops *pm_ops; + + pm_ops =3D rcu_dereference(msk->pm.ops); + return pm_ops ? pm_ops : &mptcp_pm_kernel; +} + /* if sk is ipv4 or ipv6_only allows only same-family local and remote add= resses, * otherwise allow any matching local/remote pair */ @@ -1049,7 +1057,7 @@ int mptcp_pm_get_local_id(struct mptcp_sock *msk, str= uct sock_common *skc) skc_local.addr.id =3D 0; skc_local.flags =3D MPTCP_PM_ADDR_FLAG_IMPLICIT; =20 - return msk->pm.ops->get_local_id(msk, &skc_local); + return mptcp_pm_rcu_deref(msk)->get_local_id(msk, &skc_local); } =20 bool mptcp_pm_is_backup(struct mptcp_sock *msk, struct sock_common *skc) @@ -1058,7 +1066,7 @@ bool mptcp_pm_is_backup(struct mptcp_sock *msk, struc= t sock_common *skc) =20 mptcp_local_address((struct sock_common *)skc, &skc_local); =20 - return msk->pm.ops->get_priority(msk, &skc_local); + return mptcp_pm_rcu_deref(msk)->get_priority(msk, &skc_local); } =20 static void @@ -1158,23 +1166,44 @@ void mptcp_pm_worker(struct mptcp_sock *msk) static void mptcp_pm_ops_init(struct mptcp_sock *msk, struct mptcp_pm_ops *pm_ops) { - if (!pm_ops || !bpf_try_module_get(pm_ops, pm_ops->owner)) { - pr_warn_once("pm %s fails, fallback to default pm", pm_ops->name); - pm_ops =3D &mptcp_pm_kernel; + struct mptcp_pm_ops *old; + bool need_sync =3D false; + + spin_lock_bh(&msk->pm.lock); + old =3D rcu_dereference_protected(msk->pm.ops, + lockdep_is_held(&msk->pm.lock)); + if (old =3D=3D pm_ops) { + need_sync =3D false; + } else { + rcu_assign_pointer(msk->pm.ops, pm_ops); + need_sync =3D !!old; } + spin_unlock_bh(&msk->pm.lock); =20 - msk->pm.ops =3D pm_ops; - if (msk->pm.ops->init) - msk->pm.ops->init(msk); + if (need_sync) + synchronize_rcu(); + if (old) { + if (old->release) + old->release(msk); + bpf_module_put(old, old->owner); + } + + if (pm_ops->init) + pm_ops->init(msk); =20 pr_debug("pm %s initialized\n", pm_ops->name); } =20 -static void mptcp_pm_ops_release(struct mptcp_sock *msk) +void mptcp_pm_ops_release(struct mptcp_sock *msk) { - struct mptcp_pm_ops *pm_ops =3D msk->pm.ops; + struct mptcp_pm_ops *pm_ops; + + spin_lock_bh(&msk->pm.lock); + pm_ops =3D rcu_dereference_protected(msk->pm.ops, + lockdep_is_held(&msk->pm.lock)); + rcu_assign_pointer(msk->pm.ops, NULL); + spin_unlock_bh(&msk->pm.lock); =20 - msk->pm.ops =3D NULL; if (pm_ops->release) pm_ops->release(msk); =20 @@ -1195,8 +1224,6 @@ void mptcp_pm_destroy(struct mptcp_sock *msk) * can be reused (mptcp_disconnect()) and re-selected to a different PM */ mptcp_userspace_pm_free_local_addr_list(msk); - - mptcp_pm_ops_release(msk); } =20 void mptcp_pm_data_reset(struct mptcp_sock *msk) @@ -1204,6 +1231,7 @@ void mptcp_pm_data_reset(struct mptcp_sock *msk) const struct net *net =3D sock_net((struct sock *)msk); u8 pm_type =3D mptcp_get_pm_type(net); struct mptcp_pm_data *pm =3D &msk->pm; + struct mptcp_pm_ops *pm_ops; =20 memset(&pm->reset, 0, sizeof(pm->reset)); pm->rm_list_tx.nr =3D 0; @@ -1211,8 +1239,15 @@ void mptcp_pm_data_reset(struct mptcp_sock *msk) WRITE_ONCE(pm->pm_type, pm_type); =20 rcu_read_lock(); - mptcp_pm_ops_init(msk, mptcp_get_path_manager(net)); + pm_ops =3D mptcp_get_path_manager(net); + if (!pm_ops || !bpf_try_module_get(pm_ops, pm_ops->owner)) { + pr_warn_once("pm %s fails, fallback to default pm", + pm_ops ? pm_ops->name : NULL); + pm_ops =3D &mptcp_pm_kernel; + } rcu_read_unlock(); + + mptcp_pm_ops_init(msk, pm_ops); } =20 void mptcp_pm_data_init(struct mptcp_sock *msk) diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c index 179eb6bcebf8..6dbd9a085025 100644 --- a/net/mptcp/protocol.c +++ b/net/mptcp/protocol.c @@ -3756,6 +3756,9 @@ struct sock *mptcp_sk_clone_init(const struct sock *s= k, inet_sk(nsk)->pinet6 =3D mptcp_inet6_sk(nsk); #endif =20 + msk =3D mptcp_sk(nsk); + RCU_INIT_POINTER(msk->pm.ops, NULL); + __mptcp_init_sock(nsk); =20 #if IS_ENABLED(CONFIG_MPTCP_IPV6) @@ -3825,6 +3828,7 @@ static void mptcp_destroy(struct sock *sk) /* allow the following to close even the initial subflow */ msk->free_first =3D 1; mptcp_destroy_common(msk); + mptcp_pm_ops_release(msk); sk_sockets_allocated_dec(sk); } =20 diff --git a/net/mptcp/protocol.h b/net/mptcp/protocol.h index 4a7d7f1ab82e..c5f581acd13d 100644 --- a/net/mptcp/protocol.h +++ b/net/mptcp/protocol.h @@ -222,7 +222,7 @@ struct mptcp_pm_data { struct mptcp_addr_info remote; struct list_head anno_list; struct list_head userspace_pm_local_addr_list; - struct mptcp_pm_ops *ops; + struct mptcp_pm_ops __rcu *ops; /* RCU: read via mptcp_pm_rcu_deref() */ =20 spinlock_t lock; /*protects the whole PM data */ =20 @@ -1101,6 +1101,7 @@ void __init mptcp_pm_init(void); void mptcp_pm_data_init(struct mptcp_sock *msk); void mptcp_pm_data_reset(struct mptcp_sock *msk); void mptcp_pm_destroy(struct mptcp_sock *msk); +void mptcp_pm_ops_release(struct mptcp_sock *msk); int mptcp_pm_parse_addr(struct nlattr *attr, struct genl_info *info, struct mptcp_addr_info *addr); int mptcp_pm_parse_entry(struct nlattr *attr, struct genl_info *info, diff --git a/net/mptcp/subflow.c b/net/mptcp/subflow.c index 2d7ccb01d234..6cb0ab1fbb0f 100644 --- a/net/mptcp/subflow.c +++ b/net/mptcp/subflow.c @@ -94,14 +94,17 @@ static struct mptcp_sock *subflow_token_join_request(st= ruct request_sock *req) return NULL; } =20 + rcu_read_lock(); local_id =3D mptcp_pm_get_local_id(msk, (struct sock_common *)req); if (local_id < 0) { SUBFLOW_REQ_INC_STATS(req, MPTCP_MIB_MPJOINNOIDFOUND); + rcu_read_unlock(); sock_put((struct sock *)msk); return NULL; } subflow_req->local_id =3D local_id; subflow_req->request_bkup =3D mptcp_pm_is_backup(msk, (struct sock_common= *)req); + rcu_read_unlock(); =20 return msk; } @@ -634,12 +637,16 @@ static int subflow_chk_local_id(struct sock *sk) if (likely(subflow->local_id >=3D 0)) return 0; =20 + rcu_read_lock(); err =3D mptcp_pm_get_local_id(msk, (struct sock_common *)sk); - if (err < 0) + if (err < 0) { + rcu_read_unlock(); return err; + } =20 subflow_set_local_id(subflow, err); subflow->request_bkup =3D mptcp_pm_is_backup(msk, (struct sock_common *)s= k); + rcu_read_unlock(); =20 return 0; } --=20 2.43.0