* [PATCH mptcp-next 1/2] mptcp: give MPTCP sockets a distinct lockdep class
2026-10-15 10:42 [PATCH mptcp-next 0/2] add distinct lockdep class for MPTCP sockets Geliang Tang
@ 2026-10-15 10:42 ` Geliang Tang
2026-10-15 10:59 ` sashiko-bot
2026-10-15 17:30 ` Matthieu Baerts
2026-10-15 10:42 ` [PATCH mptcp-next 2/2] mptcp: kunit: add sockopt test for subflow socket locking Geliang Tang
2026-10-15 11:48 ` [PATCH mptcp-next 0/2] add distinct lockdep class for MPTCP sockets MPTCP CI
2 siblings, 2 replies; 6+ messages in thread
From: Geliang Tang @ 2026-10-15 10:42 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
MPTCP sockets and their subflows share the same k-sk_lock-AF_INET
lockdep class. When both are kernel sockets, lockdep flags every path
that holds the MPTCP socket lock and then locks a subflow (setsockopt,
connect, bind, worker send-ack) as "possible recursive locking".
Reclassify the MPTCP socket lock in mptcp_init_sock() to use a distinct
lock class (sk_lock-AF_INET-MPTCP for IPv4, sk_lock-AF_INET6-MPTCP for
IPv6). This approach is similar to nvme-tcp and avoids the need to
reclassify each subflow socket individually.
The implementation is based on nvme_tcp_reclassify_socket() from
drivers/nvme/host/tcp.c.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/protocol.c | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 60cbd91be632..e63896a60595 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -56,6 +56,41 @@ DEFINE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions) = {
};
static struct net_device *mptcp_napi_dev;
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+/* distinct lockdep class for MPTCP sockets */
+static struct lock_class_key mptcp_sk_key[2];
+static struct lock_class_key mptcp_slock_key[2];
+
+static void mptcp_reclassify_socket(struct socket *sock)
+{
+ struct sock *sk = sock->sk;
+
+ if (WARN_ON_ONCE(!sock_allow_reclassification(sk)))
+ return;
+
+ switch (sk->sk_family) {
+ case AF_INET:
+ sock_lock_init_class_and_name(sk, "slock-AF_INET-MPTCP",
+ &mptcp_slock_key[0],
+ "sk_lock-AF_INET-MPTCP",
+ &mptcp_sk_key[0]);
+ break;
+#if IS_ENABLED(CONFIG_MPTCP_IPV6)
+ case AF_INET6:
+ sock_lock_init_class_and_name(sk, "slock-AF_INET6-MPTCP",
+ &mptcp_slock_key[1],
+ "sk_lock-AF_INET6-MPTCP",
+ &mptcp_sk_key[1]);
+ break;
+#endif
+ default:
+ WARN_ON_ONCE(1);
+ }
+}
+#else
+static void mptcp_reclassify_socket(struct socket *sock) { }
+#endif
+
/* Returns end sequence number of the receiver's advertised window */
u64 mptcp_wnd_end(const struct mptcp_sock *msk)
{
@@ -3292,6 +3327,8 @@ static int mptcp_init_sock(struct sock *sk)
sk->sk_sndbuf = READ_ONCE(net->ipv4.sysctl_tcp_wmem[1]);
sk->sk_write_space = sk_stream_write_space;
+ mptcp_reclassify_socket(sk->sk_socket);
+
return 0;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH mptcp-next 1/2] mptcp: give MPTCP sockets a distinct lockdep class
2026-10-15 10:42 ` [PATCH mptcp-next 1/2] mptcp: give MPTCP sockets a distinct lockdep class Geliang Tang
@ 2026-10-15 10:59 ` sashiko-bot
2026-10-15 17:30 ` Matthieu Baerts
1 sibling, 0 replies; 6+ messages in thread
From: sashiko-bot @ 2026-10-15 10:59 UTC (permalink / raw)
To: Geliang Tang, mptcp
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] mptcp: passive sockets miss lockdep reclassification causing warnings
--
commit c0431dba7b7ab62b7e71ad2f4ff94fb4913cc837
Author: Geliang Tang <geliang@kernel.org>
mptcp: give MPTCP sockets a distinct lockdep class
MPTCP sockets and their subflows share the same k-sk_lock-AF_INET
lockdep class. When both are kernel sockets, lockdep flags every path
that holds the MPTCP socket lock and then locks a subflow (setsockopt,
connect, bind, worker send-ack) as "possible recursive locking".
Reclassify the MPTCP socket lock in mptcp_init_sock() to use a distinct
lock class (sk_lock-AF_INET-MPTCP for IPv4, sk_lock-AF_INET6-MPTCP for
IPv6). This approach is similar to nvme-tcp and avoids the need to
reclassify each subflow socket individually.
The implementation is based on nvme_tcp_reclassify_socket() from
drivers/nvme/host/tcp.c.
> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 60cbd91be6320..e63896a605953 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c
[ ... ]
> @@ -3292,6 +3327,8 @@ static int mptcp_init_sock(struct sock *sk)
> sk->sk_sndbuf = READ_ONCE(net->ipv4.sysctl_tcp_wmem[1]);
> sk->sk_write_space = sk_stream_write_space;
>
> + mptcp_reclassify_socket(sk->sk_socket);
> +
> return 0;
> }
[Severity: Medium]
Since mptcp_init_sock() is only used for active socket creation, are cloned
(passive) connections missing this lockdep reclassification?
When an incoming MPTCP connection is accepted, the socket is cloned:
net/mptcp/protocol.c:mptcp_sk_clone_init() {
...
struct sock *nsk = sk_clone_lock(sk, GFP_ATOMIC);
...
__mptcp_init_sock(nsk);
...
}
sk_clone_lock() initializes the lockdep class back to the generic AF_INET
default. Because mptcp_reclassify_socket() is never called for these cloned
sockets, will lockdep continue to falsely report recursive locking when an
accepted MPTCP socket and its subflow are locked simultaneously?
--
Sashiko AI review · https://sashiko.dev/#/patchset/cover.1792060837.git.tanggeliang@kylinos.cn?part=1
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: [PATCH mptcp-next 1/2] mptcp: give MPTCP sockets a distinct lockdep class
2026-10-15 10:42 ` [PATCH mptcp-next 1/2] mptcp: give MPTCP sockets a distinct lockdep class Geliang Tang
2026-10-15 10:59 ` sashiko-bot
@ 2026-10-15 17:30 ` Matthieu Baerts
1 sibling, 0 replies; 6+ messages in thread
From: Matthieu Baerts @ 2026-10-15 17:30 UTC (permalink / raw)
To: Geliang Tang, mptcp; +Cc: Geliang Tang
Hi Geliang,
Thank you for the patches!
On 15/10/2026 12:42, Geliang Tang wrote:
> From: Geliang Tang <tanggeliang@kylinos.cn>
>
> MPTCP sockets and their subflows share the same k-sk_lock-AF_INET
> lockdep class. When both are kernel sockets, lockdep flags every path
> that holds the MPTCP socket lock and then locks a subflow (setsockopt,
> connect, bind, worker send-ack) as "possible recursive locking".
>
> Reclassify the MPTCP socket lock in mptcp_init_sock() to use a distinct
> lock class (sk_lock-AF_INET-MPTCP for IPv4, sk_lock-AF_INET6-MPTCP for
> IPv6). This approach is similar to nvme-tcp and avoids the need to
> reclassify each subflow socket individually.
>
> The implementation is based on nvme_tcp_reclassify_socket() from
> drivers/nvme/host/tcp.c.
Note: we also do that in pm_kernel.c for the extra listening socket.
> Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
> ---
> net/mptcp/protocol.c | 37 +++++++++++++++++++++++++++++++++++++
> 1 file changed, 37 insertions(+)
>
> diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
> index 60cbd91be632..e63896a60595 100644
> --- a/net/mptcp/protocol.c
> +++ b/net/mptcp/protocol.c
> @@ -56,6 +56,41 @@ DEFINE_PER_CPU(struct mptcp_delegated_action, mptcp_delegated_actions) = {
> };
> static struct net_device *mptcp_napi_dev;
>
> +#ifdef CONFIG_DEBUG_LOCK_ALLOC
In pm_kernel.c we don't have that. Do we really need it? If all the
functions are nops, maybe not?
> +/* distinct lockdep class for MPTCP sockets */
> +static struct lock_class_key mptcp_sk_key[2];
> +static struct lock_class_key mptcp_slock_key[2];
> +
> +static void mptcp_reclassify_socket(struct socket *sock)
> +{
> + struct sock *sk = sock->sk;
> +
> + if (WARN_ON_ONCE(!sock_allow_reclassification(sk)))
> + return;
> +
> + switch (sk->sk_family) {
> + case AF_INET:
> + sock_lock_init_class_and_name(sk, "slock-AF_INET-MPTCP",
> + &mptcp_slock_key[0],
> + "sk_lock-AF_INET-MPTCP",
> + &mptcp_sk_key[0]);
> + break;
> +#if IS_ENABLED(CONFIG_MPTCP_IPV6)
> + case AF_INET6:
> + sock_lock_init_class_and_name(sk, "slock-AF_INET6-MPTCP",
> + &mptcp_slock_key[1],
> + "sk_lock-AF_INET6-MPTCP",
> + &mptcp_sk_key[1]);
In pm_kernel.c we only call sock_lock_init_class_and_name() once. Maybe
we should do the same here, then no need to have a special helper?
> + break;
> +#endif
> + default:
> + WARN_ON_ONCE(1);
> + }
> +}
> +#else
> +static void mptcp_reclassify_socket(struct socket *sock) { }
> +#endif
> +
> /* Returns end sequence number of the receiver's advertised window */
> u64 mptcp_wnd_end(const struct mptcp_sock *msk)
> {
> @@ -3292,6 +3327,8 @@ static int mptcp_init_sock(struct sock *sk)
> sk->sk_sndbuf = READ_ONCE(net->ipv4.sysctl_tcp_wmem[1]);
> sk->sk_write_space = sk_stream_write_space;
>
> + mptcp_reclassify_socket(sk->sk_socket);
Indeed, better in __mptcp_init_sock().
> +
> return 0;
> }
>
Cheers,
Matt
--
Sponsored by the NGI0 Core fund.
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH mptcp-next 2/2] mptcp: kunit: add sockopt test for subflow socket locking
2026-10-15 10:42 [PATCH mptcp-next 0/2] add distinct lockdep class for MPTCP sockets Geliang Tang
2026-10-15 10:42 ` [PATCH mptcp-next 1/2] mptcp: give MPTCP sockets a distinct lockdep class Geliang Tang
@ 2026-10-15 10:42 ` Geliang Tang
2026-10-15 11:48 ` [PATCH mptcp-next 0/2] add distinct lockdep class for MPTCP sockets MPTCP CI
2 siblings, 0 replies; 6+ messages in thread
From: Geliang Tang @ 2026-10-15 10:42 UTC (permalink / raw)
To: mptcp; +Cc: Geliang Tang
From: Geliang Tang <tanggeliang@kylinos.cn>
Add a KUnit test to verify that MPTCP sockets have a distinct lockdep
class from their subflows. The test creates a kernel MPTCP socket and
sets SO_REUSEADDR, which triggers the code path where
mptcp_setsockopt_sol_socket() locks the MPTCP socket and then calls
sk_setsockopt() on the subflow.
Without the lockdep fix (distinct MPTCP socket class), this triggers a
"possible recursive locking" warning:
'''
kunit_try_catch/355 is trying to acquire lock:
ffff888115c99c58 (k-sk_lock-AF_INET){+.+.}-{0:0}, at: \
sk_setsockopt+0x1132/0x3b30
but task is already holding lock:
ffff88811ac80e98 (k-sk_lock-AF_INET){+.+.}-{0:0}, at: \
mptcp_setsockopt_sol_socket+0xed/0x910
Possible unsafe locking scenario:
CPU0
----
lock(k-sk_lock-AF_INET);
lock(k-sk_lock-AF_INET);
*** DEADLOCK ***
'''
With the fix, the MPTCP socket has its own sk_lock-AF_INET-MPTCP class
and no warning appears.
Signed-off-by: Geliang Tang <tanggeliang@kylinos.cn>
---
net/mptcp/Makefile | 4 +++-
net/mptcp/sockopt_test.c | 37 +++++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+), 1 deletion(-)
create mode 100644 net/mptcp/sockopt_test.c
diff --git a/net/mptcp/Makefile b/net/mptcp/Makefile
index bd72b300a0f6..e9ae91cff940 100644
--- a/net/mptcp/Makefile
+++ b/net/mptcp/Makefile
@@ -10,7 +10,9 @@ obj-$(CONFIG_INET_MPTCP_DIAG) += mptcp_diag.o
mptcp_crypto_test-objs := crypto_test.o
mptcp_token_test-objs := token_test.o
-obj-$(CONFIG_MPTCP_KUNIT_TEST) += mptcp_crypto_test.o mptcp_token_test.o
+mptcp_sockopt_test-objs := sockopt_test.o
+obj-$(CONFIG_MPTCP_KUNIT_TEST) += mptcp_crypto_test.o mptcp_token_test.o \
+ mptcp_sockopt_test.o
obj-$(CONFIG_BPF_SYSCALL) += bpf.o
diff --git a/net/mptcp/sockopt_test.c b/net/mptcp/sockopt_test.c
new file mode 100644
index 000000000000..ebd43de02543
--- /dev/null
+++ b/net/mptcp/sockopt_test.c
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <kunit/test.h>
+
+#include "protocol.h"
+
+static void mptcp_sockopt_reuseaddr(struct kunit *test)
+{
+ struct socket *sock;
+ int err, reuse = 1;
+
+ err = sock_create_kern(&init_net, AF_INET, SOCK_STREAM, IPPROTO_MPTCP,
+ &sock);
+ KUNIT_ASSERT_EQ(test, err, 0);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sock);
+
+ err = sock_common_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
+ KERNEL_SOCKPTR(&reuse), sizeof(reuse));
+
+ KUNIT_EXPECT_EQ(test, err, 0);
+
+ sock_release(sock);
+}
+
+static struct kunit_case mptcp_sockopt_test_cases[] = {
+ KUNIT_CASE(mptcp_sockopt_reuseaddr),
+ {}
+};
+
+static struct kunit_suite mptcp_sockopt_suite = {
+ .name = "mptcp-sockopt",
+ .test_cases = mptcp_sockopt_test_cases,
+};
+
+kunit_test_suite(mptcp_sockopt_suite);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("KUnit tests for MPTCP sockopt");
--
2.55.0
^ permalink raw reply related [flat|nested] 6+ messages in thread* Re: [PATCH mptcp-next 0/2] add distinct lockdep class for MPTCP sockets
2026-10-15 10:42 [PATCH mptcp-next 0/2] add distinct lockdep class for MPTCP sockets Geliang Tang
2026-10-15 10:42 ` [PATCH mptcp-next 1/2] mptcp: give MPTCP sockets a distinct lockdep class Geliang Tang
2026-10-15 10:42 ` [PATCH mptcp-next 2/2] mptcp: kunit: add sockopt test for subflow socket locking Geliang Tang
@ 2026-10-15 11:48 ` MPTCP CI
2 siblings, 0 replies; 6+ messages in thread
From: MPTCP CI @ 2026-10-15 11:48 UTC (permalink / raw)
To: Geliang Tang; +Cc: mptcp
Hi Geliang,
Thank you for your modifications, that's great!
Our CI did some validations and here is its report:
- KVM Validation: normal (except selftest_mptcp_join): Success! ✅
- KVM Validation: normal (only selftest_mptcp_join): Success! ✅
- KVM Validation: debug (except selftest_mptcp_join): Success! ✅
- KVM Validation: debug (only selftest_mptcp_join): Success! ✅
- KVM Validation: btf-normal (only bpftest_all): Success! ✅
- KVM Validation: btf-debug (only bpftest_all): Success! ✅
- Perf: Success! ✅
- Task: https://github.com/multipath-tcp/mptcp_net-next/actions/runs/38724382972
Initiator: Patchew Applier
Commits: https://github.com/multipath-tcp/mptcp_net-next/commits/e7a2821a1eae
Patchwork: https://patchwork.kernel.org/project/mptcp/list/?series=1186364
If there are some issues, you can reproduce them using the same environment as
the one used by the CI thanks to a docker image, e.g.:
$ cd [kernel source code]
$ docker run -v "${PWD}:${PWD}:rw" -w "${PWD}" --privileged --rm -it \
--pull always mptcp/mptcp-upstream-virtme-docker:latest \
auto-normal
For more details:
https://github.com/multipath-tcp/mptcp-upstream-virtme-docker
Please note that despite all the efforts that have been already done to have a
stable tests suite when executed on a public CI like here, it is possible some
reported issues are not due to your modifications. Still, do not hesitate to
help us improve that ;-)
Cheers,
MPTCP GH Action bot
Bot operated by Matthieu Baerts (NGI0 Core)
^ permalink raw reply [flat|nested] 6+ messages in thread