From nobody Sat Sep 5 05:49:05 2026 Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) (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 3263D3CF043 for ; Tue, 1 Sep 2026 12:54:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788267254; cv=none; b=ZtPiMDovSZ9eerMIN9ImlhM7wZ4xnIJUETPp77QgdHS5Wrd7rYzlsGwmjJhJLlFpBla0Bfjee0mDNH9DXGQp5ZfK0wpteLCrHzrs6zugeQk4RITA6J9WM6qmb1jPoWdbNhegALkiCka6rmQkaOWuFIEbZFIJMOB39Kq8RfJhMh4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788267254; c=relaxed/simple; bh=uxW5j4A6X52FZbh8lJl8gie5IiK5qhRUh36oA7KEFoU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=O0CHNW6pvmOc5gqEgopBN8In55+Tc0AG36ytkIGap4Ed2XxH9dR728yXmS70O82mpgd5WkVbVYtDla17rt5JWTOUDUEM/DTsIp2Ie532YHcTk1Q9C9hvz0tiQ8POkUTC1Y42WhymDLTZlMygYHgW4s3r7+DwD1tiHFnzgWAW6/8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=nebusec.ai; spf=pass smtp.mailfrom=nebusec.ai; dkim=pass (2048-bit key) header.d=nebusec.ai header.i=@nebusec.ai header.b=b8uXS/ij; arc=none smtp.client-ip=209.85.214.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=nebusec.ai Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nebusec.ai Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nebusec.ai header.i=@nebusec.ai header.b="b8uXS/ij" Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-2d5cad1a6baso45159065ad.3 for ; Tue, 01 Sep 2026 05:54:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nebusec.ai; s=google; t=1788267250; x=1788872050; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=7mMZ1zbpoXdqJJAf+iyw7TfdMbYoOVSHzzCFK3nTdQs=; b=b8uXS/ijxMQuKU3RE8c0ZcawxgDrfqVqLLUbor1/LhgtTDk/+k5l3RH0cAgkhFxHVZ 8b+WdFVxX6rX0E5/5uAx4EfUfHm+NGyxQdLfNl6G6rsgo65whdDqufsPMybzxt4hRMsi wbOVfPgPObDAzOv5cw6MA2rAYrZSx2ngaETn1L5q/JvJI9eYLgjIi4POXzHWMxZL+861 b+mZh6iVNrT5A06tx1esfYZA6ZiL3mwhY1Z603OI57ZsCpDu706wW/OHnMuNnIwxsXb/ skeU1BFSN6rZkYAu7H0F+iT72y0OgOo1Qe1kdspLJJuH6fVMve6OcZJeq1EI+PbIbblg 8EIQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788267250; x=1788872050; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=7mMZ1zbpoXdqJJAf+iyw7TfdMbYoOVSHzzCFK3nTdQs=; b=AH5P1haaSac81SNj+UQ3Ca1AlQVCV7Ck5WbNdeYphb9OqYBYHLc+LTA+ZrQ0UvOoIg h0bmd7jysgYV9u6l/UYDdOx0Lr8s3GJKzNBmtk9suPV03duwQQox+ZqwyTpnDrY5ztJL M7p5spOBUK6beMFv+Lan7dwKVXNMkSrsXp1dy0EIAAIPF/vWYBUFfAxLLN88PVNa/I8d fZYvQF3mwvfPp8NkKgw+N5K1M0whYuwyWOUudcGZrvzaXuLujHH/vSau79wb+Aqt9J0R mEZ/viP8fT/AXi4Aee17T8s897s0GENH7QHQhYs+XPutKn/uBkDF5kdizoAuLRVX8dJt wfVw== X-Forwarded-Encrypted: i=1; AKwUvBwOKm/qFI0aohMRAgVt5G3zE7giljo5dGdX8cgkPQO8SVvIz2SqK3rEhjECx4l/nYWBBKQqpQ==@lists.linux.dev X-Gm-Message-State: AFuF++lNs0XSwKRb8hAmu8eA/VL+3l7Q7qdNczAzjWDgc2gq/5dPvSGr jF4WOrn581YHADglGzqtZSeQsD+NT/xa0EoNXD8wbPkoi1bUsBgaU2OsKiPLnfl2SWIHUt8dfmA ifneTms+1qpY= X-Gm-Gg: AYBFou3V2i0V65d8ZlEuJSjwO/4dUv9FNi+AieBvmrl8Oz0HtTxB49OMX+XIuNYoa7U jMlNTXTKs/lEA4Q4+Rcm2FtU4BZQviDE++B4hRbk6vE46Gt+ZyjMHy67lbkWgd41Bbrg9nRXuKg gHJkia8JiGe5uqeE09DNE9r/skr278wFXuLeSxPyrQ+mntjO65GinY/OpCjt9BDjOIf2UESdY43 ZKyhm4ctSk4D3ZkcKXuwtThtGbyrQ9yHIdg3XrHZ8YFiOCGfCXe1h8jcWUTfMgPK6dBD78MIVsI sd5BjYilGSjo7jvbGD3KE/I1Eox8+L/UqOfiFr1yUsdnU4lwS3XclZArJFzYrMMl66IoCeeq2c0 l1j2io3M3SVljzB6xerIbRZdZrpscFT4zPY8iVJXgJTMDjqFhBK9GkONdS6YMeBj+4btnqUHxDk 7SywolTE1IAPgQ6sJwHI27SK0or4+Jmq/xYdEfcf6Tlr/0qXenMu9g9aJpf2zMOhvvP9Z7Mr5vB /WPTTbrMK0JEE+/+pQ= X-Received: by 2002:a17:902:d98c:b0:2d9:3083:a3ac with SMTP id d9443c01a7336-2d94a8fb674mr113217995ad.15.1788267250206; Tue, 01 Sep 2026 05:54:10 -0700 (PDT) Received: from b6ad5085b32f.. ([122.51.212.64]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d759869c96sm51184175ad.40.2026.09.01.05.54.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2026 05:54:09 -0700 (PDT) From: Zihan Xi To: netdev@vger.kernel.org Cc: Zihan Xi , linux-kernel@vger.kernel.org, mptcp@lists.linux.dev, "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Neal Cardwell , Kuniyuki Iwashima , Matthieu Baerts , Mat Martineau , Geliang Tang , Guillaume Nault , Florian Westphal , stable@vger.kernel.org, Vega Subject: [PATCH net v2 1/2] tcp: diag: bound bucket lock hold in tcp_diag_dump() Date: Tue, 1 Sep 2026 12:53:46 +0000 Message-ID: X-Mailer: git-send-email 2.47.3 In-Reply-To: References: 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" inet_diag dumps run request-supplied bytecode through inet_diag_bc_sk(). tcp_diag_dump() currently evaluates socket filters and fills replies while holding the listener, bind, and ehash bucket locks. The time spent under a bucket lock can therefore grow with the number of sockets visited and with per-socket dump work. This defeats the intended bounded nature of the bucket walk and can cause excessive lock hold times. Fix this by collecting only referenced sockets while holding each bucket lock. Move the filtering, bytecode evaluation, and fill work out of the critical section, and keep a referenced dump cursor so each subsequent batch resumes after the previous socket instead of rescanning the bucket head. Validate a cursor against the current listener, bind, or ehash bucket, and against the table implied by sk_state, before resuming from it. Bind collection counts TIME_WAIT nodes toward the batch limit and resumes them via tw_tb2. Fixes: 5caea4ea7088 ("net: listening_hash get a spinlock per bucket") Fixes: 91051f003948 ("tcp: Dump bound-only sockets in inet_diag.") Cc: stable@vger.kernel.org Reported-by: Vega Assisted-by: Codex:gpt-5.4 Signed-off-by: Zihan Xi --- changes in v2: - Rebased onto net commit e2a6641e3bfd (2026-08-27). - Added current-bucket cursor validation for listener, bind, and ehash paths, with safe restart on mismatch. - Reject listen/ehash cursors unless sk_state still matches the table being walked, so a reused sk_nulls_node cannot continue under the wrong bucket lock. - Count TIME_WAIT bind nodes toward SKARR_SZ and resume them via tw_tb2 instead of skipping them under the bind lock. - Kept listener and bound-only Fixes tags; dropped 7e3aab4a9cd7 because that commit only converted the existing ehash dump lock type. - Sorted new listen/bind/ehash local declarations reverse xmas tree. - Left INET_DIAG_DUMP_CURSOR_MPTCP_LISTEN to the MPTCP patch. - Moved SKARR_SZ comment off "bh disabled" and aligned the ehash cursor continuation indent. - Refreshed the reviewed PoC and decoded crash-log artifacts. - v1 Link: https://lore.kernel.org/all/cover.1785307984.git.zihanx@nebuse= c.ai/ include/linux/inet_diag.h | 14 ++ include/net/inet_hashtables.h | 18 ++ net/ipv4/inet_diag.c | 13 ++ net/ipv4/inet_hashtables.c | 18 -- net/ipv4/tcp_diag.c | 338 +++++++++++++++++++++++++--------- 5 files changed, 294 insertions(+), 107 deletions(-) diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 704fd415c2b4..6ccd32bc48f9 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -6,6 +6,7 @@ #include =20 struct inet_hashinfo; +struct sock; =20 struct inet_diag_handler { struct module *owner; @@ -32,12 +33,23 @@ struct inet_diag_handler { }; =20 struct bpf_sk_storage_diag; + +enum inet_diag_dump_cursor_type { + INET_DIAG_DUMP_CURSOR_NONE, + INET_DIAG_DUMP_CURSOR_TCP_LISTEN, + INET_DIAG_DUMP_CURSOR_TCP_BIND, + INET_DIAG_DUMP_CURSOR_TCP_EHASH, +}; + struct inet_diag_dump_data { struct nlattr *req_nlas[__INET_DIAG_REQ_MAX]; #define inet_diag_nla_bc req_nlas[INET_DIAG_REQ_BYTECODE] #define inet_diag_nla_bpf_stgs req_nlas[INET_DIAG_REQ_SK_BPF_STORAGES] =20 struct bpf_sk_storage_diag *bpf_stg_diag; + struct sock *dump_cursor; + unsigned int dump_cursor_slot; + u8 dump_cursor_type; bool mark_needed; /* INET_DIAG_BC_MARK_COND present. */ #ifdef CONFIG_SOCK_CGROUP_DATA bool cgroup_needed; /* INET_DIAG_BC_CGROUP_COND present. */ @@ -53,6 +65,8 @@ int inet_sk_diag_fill(struct sock *sk, struct inet_connec= tion_sock *icsk, =20 int inet_diag_bc_sk(const struct inet_diag_dump_data *cb_data, struct sock= *sk); =20 +void inet_diag_dump_clear_cursor(struct inet_diag_dump_data *cb_data); + void inet_diag_msg_common_fill(struct inet_diag_msg *r, struct sock *sk); =20 static inline size_t inet_diag_msg_attrs_size(void) diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 6e2fe186d0dc..d95639ac70c6 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -188,6 +188,24 @@ inet_lhash2_bucket(struct inet_hashinfo *h, u32 hash) return &h->lhash2[hash & h->lhash2_mask]; } =20 +static inline struct inet_listen_hashbucket * +inet_lhash2_bucket_sk(struct inet_hashinfo *h, struct sock *sk) +{ + u32 hash; + +#if IS_ENABLED(CONFIG_IPV6) + if (sk->sk_family =3D=3D AF_INET6) + hash =3D ipv6_portaddr_hash(sock_net(sk), + &sk->sk_v6_rcv_saddr, + inet_sk(sk)->inet_num); + else +#endif + hash =3D ipv4_portaddr_hash(sock_net(sk), + inet_sk(sk)->inet_rcv_saddr, + inet_sk(sk)->inet_num); + return inet_lhash2_bucket(h, hash); +} + static inline struct inet_ehash_bucket *inet_ehash_bucket( struct inet_hashinfo *hashinfo, unsigned int hash) diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 34b77aa87d0a..41148e880054 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -891,10 +891,23 @@ static int inet_diag_dump_start_compat(struct netlink= _callback *cb) return __inet_diag_dump_start(cb, sizeof(struct inet_diag_req)); } =20 +void inet_diag_dump_clear_cursor(struct inet_diag_dump_data *cb_data) +{ + if (!cb_data->dump_cursor) + return; + + sock_gen_put(cb_data->dump_cursor); + cb_data->dump_cursor =3D NULL; + cb_data->dump_cursor_slot =3D 0; + cb_data->dump_cursor_type =3D INET_DIAG_DUMP_CURSOR_NONE; +} +EXPORT_SYMBOL_GPL(inet_diag_dump_clear_cursor); + static int inet_diag_dump_done(struct netlink_callback *cb) { struct inet_diag_dump_data *cb_data =3D cb->data; =20 + inet_diag_dump_clear_cursor(cb_data); bpf_sk_storage_diag_free(cb_data->bpf_stg_diag); kfree(cb->data); =20 diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index ba0faa9ae2bb..1c839fe3d7e0 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -331,24 +331,6 @@ int __inet_inherit_port(const struct sock *sk, struct = sock *child) return -ENOMEM; } =20 -static struct inet_listen_hashbucket * -inet_lhash2_bucket_sk(struct inet_hashinfo *h, struct sock *sk) -{ - u32 hash; - -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family =3D=3D AF_INET6) - hash =3D ipv6_portaddr_hash(sock_net(sk), - &sk->sk_v6_rcv_saddr, - inet_sk(sk)->inet_num); - else -#endif - hash =3D ipv4_portaddr_hash(sock_net(sk), - inet_sk(sk)->inet_rcv_saddr, - inet_sk(sk)->inet_num); - return inet_lhash2_bucket(h, hash); -} - static inline int compute_score(struct sock *sk, const struct net *net, const unsigned short hnum, const __be32 daddr, const int dif, const int sdif) diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index ba1fdbe9807f..842e13ee79e5 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -285,6 +285,73 @@ static int sk_diag_fill(struct sock *sk, struct sk_buf= f *skb, net_admin); } =20 +/* Process a maximum of SKARR_SZ sockets at a time when walking hash bucke= ts + * while holding a bucket lock. + */ +#define SKARR_SZ 16 + +static void tcp_diag_save_cursor(struct inet_diag_dump_data *cb_data, int = type, + unsigned int slot, struct sock *sk) +{ + sock_hold(sk); + inet_diag_dump_clear_cursor(cb_data); + cb_data->dump_cursor =3D sk; + cb_data->dump_cursor_slot =3D slot; + cb_data->dump_cursor_type =3D type; +} + +static struct inet_bind2_bucket *tcp_diag_sk_bind2(const struct sock *sk) +{ + if (sk->sk_state =3D=3D TCP_TIME_WAIT) + return inet_twsk(sk)->tw_tb2; + + return inet_csk(sk)->icsk_bind2_hash; +} + +static bool tcp_diag_bind_collect_sock(struct sock *sk, struct sock **sk_a= rr, + int *num_arr, int *accum, int num) +{ + sock_hold(sk); + num_arr[*accum] =3D num; + sk_arr[*accum] =3D sk; + + return ++*accum =3D=3D SKARR_SZ; +} + +static bool tcp_diag_bind_collect_owners(struct hlist_head *owners, + struct sock **sk_arr, int *num_arr, + int *accum, int *num, int s_num) +{ + struct sock *sk; + + sk_for_each_bound(sk, owners) { + if (*num < s_num) { + (*num)++; + continue; + } + + if (tcp_diag_bind_collect_sock(sk, sk_arr, num_arr, accum, *num)) + return true; + (*num)++; + } + + return false; +} + +static bool tcp_diag_bind_collect_owners_continue(struct sock *sk, + struct sock **sk_arr, + int *num_arr, int *accum, + int *num) +{ + hlist_for_each_entry_continue(sk, sk_bind_node) { + if (tcp_diag_bind_collect_sock(sk, sk_arr, num_arr, accum, *num)) + return true; + (*num)++; + } + + return false; +} + static void twsk_build_assert(void) { BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_family) !=3D @@ -335,8 +402,15 @@ static void tcp_diag_dump(struct sk_buff *skb, struct = netlink_callback *cb, for (i =3D s_i; i <=3D hashinfo->lhash2_mask; i++) { struct inet_listen_hashbucket *ilb; struct hlist_nulls_node *node; + struct sock *sk_arr[SKARR_SZ]; + int num_arr[SKARR_SZ]; + struct sock *cursor; + int idx, accum, res; + bool use_cursor; =20 +resume_listen_walk: num =3D 0; + accum =3D 0; ilb =3D &hashinfo->lhash2[i]; =20 if (hlist_nulls_empty(&ilb->nulls_head)) { @@ -344,52 +418,81 @@ static void tcp_diag_dump(struct sk_buff *skb, struct= netlink_callback *cb, continue; } spin_lock(&ilb->lock); - sk_nulls_for_each(sk, node, &ilb->nulls_head) { - struct inet_sock *inet =3D inet_sk(sk); + cursor =3D cb_data->dump_cursor; + use_cursor =3D cursor && + cb_data->dump_cursor_type =3D=3D + INET_DIAG_DUMP_CURSOR_TCP_LISTEN && + cb_data->dump_cursor_slot =3D=3D i && + inet_sk_state_load(cursor) =3D=3D TCP_LISTEN && + !hlist_nulls_unhashed(&cursor->sk_nulls_node) && + cursor->sk_nulls_node.pprev !=3D LIST_POISON2 && + inet_lhash2_bucket_sk(hashinfo, cursor) =3D=3D ilb; + node =3D use_cursor ? cursor->sk_nulls_node.next : + ilb->nulls_head.first; + if (!use_cursor) + s_num =3D 0; + hlist_nulls_for_each_entry_from(sk, node, sk_nulls_node) { =20 - if (!net_eq(sock_net(sk), net)) - continue; + sock_hold(sk); + num_arr[accum] =3D num; + sk_arr[accum] =3D sk; + if (++accum =3D=3D SKARR_SZ) + break; =20 - if (num < s_num) { - num++; - continue; - } + ++num; + } + spin_unlock(&ilb->lock); + + res =3D 0; + for (idx =3D 0; idx < accum; idx++) { + struct inet_sock *inet; + + sk =3D sk_arr[idx]; + if (!net_eq(sock_net(sk), net)) + goto processed_listen_sk; =20 + inet =3D inet_sk(sk); if (r->sdiag_family !=3D AF_UNSPEC && sk->sk_family !=3D r->sdiag_family) - goto next_listen; + goto processed_listen_sk; =20 if (r->id.idiag_sport !=3D inet->inet_sport && r->id.idiag_sport) - goto next_listen; - - if (!inet_diag_bc_sk(cb_data, sk)) - goto next_listen; + goto processed_listen_sk; =20 - if (inet_sk_diag_fill(sk, inet_csk(sk), skb, - cb, r, NLM_F_MULTI, - net_admin) < 0) { - spin_unlock(&ilb->lock); - goto done; + if (res >=3D 0 && inet_diag_bc_sk(cb_data, sk)) { + res =3D inet_sk_diag_fill(sk, inet_csk(sk), + skb, cb, r, NLM_F_MULTI, + net_admin); + if (res < 0) + num =3D num_arr[idx]; } +processed_listen_sk: + if (res >=3D 0) + tcp_diag_save_cursor(cb_data, + INET_DIAG_DUMP_CURSOR_TCP_LISTEN, + i, sk); + sock_put(sk); + } + if (res < 0) + goto done; =20 -next_listen: - ++num; + cond_resched(); + + if (accum =3D=3D SKARR_SZ) { + s_num =3D 0; + goto resume_listen_walk; } - spin_unlock(&ilb->lock); =20 + inet_diag_dump_clear_cursor(cb_data); s_num =3D 0; } skip_listen_ht: + inet_diag_dump_clear_cursor(cb_data); cb->args[0] =3D 1; s_i =3D num =3D s_num =3D 0; } =20 -/* Process a maximum of SKARR_SZ sockets at a time when walking hash bucke= ts - * with bh disabled. - */ -#define SKARR_SZ 16 - /* Dump bound but inactive (not listening, connecting, etc.) sockets */ if (cb->args[0] =3D=3D 1) { if (!(idiag_states & TCPF_BOUND_INACTIVE)) @@ -400,7 +503,9 @@ static void tcp_diag_dump(struct sk_buff *skb, struct n= etlink_callback *cb, struct inet_bind2_bucket *tb2; struct sock *sk_arr[SKARR_SZ]; int num_arr[SKARR_SZ]; + struct sock *cursor; int idx, accum, res; + bool use_cursor; =20 resume_bind_walk: num =3D 0; @@ -412,34 +517,46 @@ static void tcp_diag_dump(struct sk_buff *skb, struct= netlink_callback *cb, continue; } spin_lock_bh(&ibb->lock); - inet_bind_bucket_for_each(tb2, &ibb->chain) { - if (!net_eq(ib2_net(tb2), net)) - continue; - - sk_for_each_bound(sk, &tb2->owners) { - struct inet_sock *inet =3D inet_sk(sk); - - if (num < s_num) - goto next_bind; - - if (sk->sk_state !=3D TCP_CLOSE || - !inet->inet_num) - goto next_bind; - - if (r->sdiag_family !=3D AF_UNSPEC && - r->sdiag_family !=3D sk->sk_family) - goto next_bind; - - if (!inet_diag_bc_sk(cb_data, sk)) - goto next_bind; - - sock_hold(sk); - num_arr[accum] =3D num; - sk_arr[accum] =3D sk; - if (++accum =3D=3D SKARR_SZ) + cursor =3D cb_data->dump_cursor; + use_cursor =3D cursor && + cb_data->dump_cursor_type =3D=3D + INET_DIAG_DUMP_CURSOR_TCP_BIND && + cb_data->dump_cursor_slot =3D=3D i && + !hlist_unhashed(&cursor->sk_bind_node) && + cursor->sk_bind_node.pprev !=3D LIST_POISON2; + if (use_cursor) { + tb2 =3D tcp_diag_sk_bind2(cursor); + use_cursor =3D tb2 && + inet_bhashfn_portaddr(hashinfo, cursor, + sock_net(cursor), + inet_sk(cursor)->inet_num) =3D=3D + ibb; + } + if (!use_cursor) + s_num =3D 0; + if (use_cursor) { + sk =3D cursor; + if (tcp_diag_bind_collect_owners_continue(sk, sk_arr, + num_arr, + &accum, + &num)) + goto pause_bind_walk; + hlist_for_each_entry_continue(tb2, node) { + if (tcp_diag_bind_collect_owners(&tb2->owners, + sk_arr, + num_arr, + &accum, + &num, 0)) + goto pause_bind_walk; + } + } else { + inet_bind_bucket_for_each(tb2, &ibb->chain) { + if (tcp_diag_bind_collect_owners(&tb2->owners, + sk_arr, + num_arr, + &accum, + &num, s_num)) goto pause_bind_walk; -next_bind: - num++; } } pause_bind_walk: @@ -447,15 +564,33 @@ static void tcp_diag_dump(struct sk_buff *skb, struct= netlink_callback *cb, =20 res =3D 0; for (idx =3D 0; idx < accum; idx++) { - if (res >=3D 0) { - res =3D inet_sk_diag_fill(sk_arr[idx], - NULL, skb, cb, + struct inet_sock *inet; + + sk =3D sk_arr[idx]; + if (!net_eq(sock_net(sk), net)) + goto put_bind_sk; + + inet =3D inet_sk(sk); + if (sk->sk_state !=3D TCP_CLOSE || !inet->inet_num) + goto put_bind_sk; + + if (r->sdiag_family !=3D AF_UNSPEC && + r->sdiag_family !=3D sk->sk_family) + goto put_bind_sk; + + if (res >=3D 0 && inet_diag_bc_sk(cb_data, sk)) { + res =3D inet_sk_diag_fill(sk, NULL, skb, cb, r, NLM_F_MULTI, net_admin); if (res < 0) num =3D num_arr[idx]; } - sock_put(sk_arr[idx]); +put_bind_sk: + if (res >=3D 0) + tcp_diag_save_cursor(cb_data, + INET_DIAG_DUMP_CURSOR_TCP_BIND, + i, sk); + sock_gen_put(sk); } if (res < 0) goto done; @@ -463,13 +598,15 @@ static void tcp_diag_dump(struct sk_buff *skb, struct= netlink_callback *cb, cond_resched(); =20 if (accum =3D=3D SKARR_SZ) { - s_num =3D num + 1; + s_num =3D 0; goto resume_bind_walk; } =20 + inet_diag_dump_clear_cursor(cb_data); s_num =3D 0; } skip_bind_ht: + inet_diag_dump_clear_cursor(cb_data); cb->args[0] =3D 2; s_i =3D num =3D s_num =3D 0; } @@ -483,43 +620,35 @@ static void tcp_diag_dump(struct sk_buff *skb, struct= netlink_callback *cb, struct hlist_nulls_node *node; struct sock *sk_arr[SKARR_SZ]; int num_arr[SKARR_SZ]; + struct sock *cursor; int idx, accum, res; + bool use_cursor; =20 if (hlist_nulls_empty(&head->chain)) continue; =20 - if (i > s_i) + if (i > s_i) { + inet_diag_dump_clear_cursor(cb_data); s_num =3D 0; + } =20 next_chunk: num =3D 0; accum =3D 0; spin_lock_bh(lock); - sk_nulls_for_each(sk, node, &head->chain) { - int state; - - if (!net_eq(sock_net(sk), net)) - continue; - if (num < s_num) - goto next_normal; - state =3D (sk->sk_state =3D=3D TCP_TIME_WAIT) ? - READ_ONCE(inet_twsk(sk)->tw_substate) : sk->sk_state; - if (!(idiag_states & (1 << state))) - goto next_normal; - if (r->sdiag_family !=3D AF_UNSPEC && - sk->sk_family !=3D r->sdiag_family) - goto next_normal; - if (r->id.idiag_sport !=3D htons(READ_ONCE(sk->sk_num)) && - r->id.idiag_sport) - goto next_normal; - if (r->id.idiag_dport !=3D sk->sk_dport && - r->id.idiag_dport) - goto next_normal; - twsk_build_assert(); - - if (!inet_diag_bc_sk(cb_data, sk)) - goto next_normal; - + cursor =3D cb_data->dump_cursor; + use_cursor =3D cursor && + cb_data->dump_cursor_type =3D=3D + INET_DIAG_DUMP_CURSOR_TCP_EHASH && + cb_data->dump_cursor_slot =3D=3D i && + inet_sk_state_load(cursor) !=3D TCP_LISTEN && + !hlist_nulls_unhashed(&cursor->sk_nulls_node) && + cursor->sk_nulls_node.pprev !=3D LIST_POISON2 && + inet_ehash_bucket(hashinfo, cursor->sk_hash) =3D=3D head; + node =3D use_cursor ? cursor->sk_nulls_node.next : head->chain.first; + if (!use_cursor) + s_num =3D 0; + hlist_nulls_for_each_entry_from(sk, node, sk_nulls_node) { if (!refcount_inc_not_zero(&sk->sk_refcnt)) goto next_normal; =20 @@ -534,13 +663,42 @@ static void tcp_diag_dump(struct sk_buff *skb, struct= netlink_callback *cb, =20 res =3D 0; for (idx =3D 0; idx < accum; idx++) { - if (res >=3D 0) { - res =3D sk_diag_fill(sk_arr[idx], skb, cb, r, - NLM_F_MULTI, net_admin); + int state; + + sk =3D sk_arr[idx]; + if (!net_eq(sock_net(sk), net)) + goto put_estab_sk; + + state =3D (sk->sk_state =3D=3D TCP_TIME_WAIT) ? + READ_ONCE(inet_twsk(sk)->tw_substate) : sk->sk_state; + if (!(idiag_states & (1 << state))) + goto put_estab_sk; + + if (r->sdiag_family !=3D AF_UNSPEC && + sk->sk_family !=3D r->sdiag_family) + goto put_estab_sk; + + if (r->id.idiag_sport !=3D htons(READ_ONCE(sk->sk_num)) && + r->id.idiag_sport) + goto put_estab_sk; + + if (r->id.idiag_dport !=3D sk->sk_dport && + r->id.idiag_dport) + goto put_estab_sk; + + twsk_build_assert(); + if (res >=3D 0 && inet_diag_bc_sk(cb_data, sk)) { + res =3D sk_diag_fill(sk, skb, cb, r, NLM_F_MULTI, + net_admin); if (res < 0) num =3D num_arr[idx]; } - sock_gen_put(sk_arr[idx]); +put_estab_sk: + if (res >=3D 0) + tcp_diag_save_cursor(cb_data, + INET_DIAG_DUMP_CURSOR_TCP_EHASH, + i, sk); + sock_gen_put(sk); } if (res < 0) break; @@ -548,9 +706,11 @@ static void tcp_diag_dump(struct sk_buff *skb, struct = netlink_callback *cb, cond_resched(); =20 if (accum =3D=3D SKARR_SZ) { - s_num =3D num + 1; + s_num =3D 0; goto next_chunk; } + + inet_diag_dump_clear_cursor(cb_data); } =20 done: --=20 2.43.0 From nobody Sat Sep 5 05:49:05 2026 Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) (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 1E2313A7F54 for ; Tue, 1 Sep 2026 12:54:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788267269; cv=none; b=cRdTdw0CPSjFjSDq4Fvm51uNusuZurDc0wfpkr9BXZ+Pepx2bvq1EAnaUuuGAor95S+cKuxHEgrIiVCQNZQHzpXjBxhRJCfg3Xp6Zj/G94ev7WwR345b31RhAKwwU3tECxG17UCLDs1qLMdj3mrEBhSqUP+waFKjRH5cZglZOYM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788267269; c=relaxed/simple; bh=zarcyGPirVKljwxNeGDx0sin76rbHeFW2Cd7O0/qZDQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=aqJOIrhIk3k2wTxyPjwMHZ7al6P3erbgzNiHgY8chY+vjZlJTprWOf7JZuwQ9Brt4ATrjuw0oICtwIP5nD3PKmNFpSSjmXOhydthk+5CA/UOPT8MNV+Qf34aN3AfixsCZdgR5CDvOGEOT3QNwEjm9h7Pt0WwSZqWdnRM7yKCNSk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=nebusec.ai; spf=pass smtp.mailfrom=nebusec.ai; dkim=pass (2048-bit key) header.d=nebusec.ai header.i=@nebusec.ai header.b=cvzDpjpG; arc=none smtp.client-ip=209.85.214.174 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=nebusec.ai Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=nebusec.ai Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=nebusec.ai header.i=@nebusec.ai header.b="cvzDpjpG" Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-2d715f4a587so12026155ad.2 for ; Tue, 01 Sep 2026 05:54:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nebusec.ai; s=google; t=1788267267; x=1788872067; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=nPBTnM4CiDrSs11VlMGUK8cKAPSAQrX+j7COGLEHoVw=; b=cvzDpjpG77x8Ar6J0vWudVI0IgTUkMZyTIRMZTfQLey5DnuUGhWlgew999ScibUIOJ QqtRlBWvtJEVp9dvvGg976Jk50ZaORFQ1lVpFtXXHSausq34z80afuGpRih5GSCPidYb 9kl5+AS7lnnIPjEwH/yVUKDkQVUGgaulV1VgC2qHJ02eEla/MTL4dB4K6enBZ7nqGvXu NkQn4kU4ifjD/JprXsktU4EXRYZP/6QFM6N9EgzdPyO6iA3RuoFbQ6L+MSFft6Fp6lHj qv93MIPVKB6gNK6xOzrvx4bRIqgbE8VpVVEmAJR9xeFhzlInChUqRrt+UwaDecjVoEOu jw5g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1788267267; x=1788872067; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=nPBTnM4CiDrSs11VlMGUK8cKAPSAQrX+j7COGLEHoVw=; b=X0rsRCshHRT+np2K9InygAR61cQsR9Uchq8FCEx6b3DvlFMYW8O9su8BFAOx7Df195 94AvA9NtyxTFgjzIFsLLWl6Va7gLsZP7kIUyr+lIT5jy0EEvpRe1vVCplQ/QHVFhCKK0 AXC9mBvPgyMZ5H3jGir1ytiJjKwRF7qIwtsq5rZ5dFEdnZkvp8MqEgT+hKZMuoH1lpfp 84WDDsV2nMiZmyUTQsQWDv2YPwqBRCukzmOunW36VI2DEWZ4xdnDHHUfRdwYGf6ETzrG 4BBBIkwWtnyUjxusCbFsFrHfu/NfFg7+d0tH4Mj9PPLNcl/mZIez0+Bl2BbVaxEr52OX /DEQ== X-Forwarded-Encrypted: i=1; AKwUvBzFtXx1w43YVPLG1RWfipoSpUC/7KyB1oussk3wBWlaU3OQF9/dTk277f9WsY7yVco0Xc1AJHcJl5wx9Ek=@vger.kernel.org X-Gm-Message-State: AFuF++kPrRcDYADRVPDRUFuHycLBczeoOiCPGOB7DR2dfz+ldKFUicdf 9I6aRd2UVnp9oyHoo6Ltw9aaw8uoflAKtsl5+wM7O461QMdVIDpZ4SOeBsVMeoRYATPv X-Gm-Gg: AYBFou16t7HEkK0BHl2iIUzQZnndHQzt+abeN+c8AEc9Hcu4yZA+znn1UFPy+Gb1ibA bI74yKtBfgInRkNX6nSKyxlJlGoz29Thm1toEa0ZI2+ygRuqIIQ1ZSfdMosZVCJxgeMVzIsALfd f1CBazOs8Lg+j9c2LOhK3l/u4OtOfyUB34PJePnXPzIVyEJ4aRQ8HtLuc40J3CltHTTPIHc/Jaj DwKBK68zi7iVzLLaymogYfbxF6xMb9AOqGmSR+RmYc3njApwKcgpytItiQi3lxn8KpAgDh9aNZn HcvaH/4U8MUpAv1DxT/DoTpR8hmI3n/zz6w7sNzLMzQD09QiXHSA+6TApUTOWyUhU+xIxLl1cZJ zbB8PR1gE4dYUKdQb8onFV617/9e13ngndT5aFwnjJjH4K45cc/VywzIl7+47I9xz/iGN7Gl9bJ fBEaZw2mUmeQg5nIIMd21y6RKlv/A13B3k/JONm9lmJdVSqzn2XVvzvuDUmXwVc84q1rSbEpMBt Dczn4HT1POski9U9z0= X-Received: by 2002:a17:902:f70a:b0:2d9:56d8:75f with SMTP id d9443c01a7336-2d956d80878mr80857275ad.9.1788267267455; Tue, 01 Sep 2026 05:54:27 -0700 (PDT) Received: from b6ad5085b32f.. ([122.51.212.64]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d759869c96sm51184175ad.40.2026.09.01.05.54.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Sep 2026 05:54:26 -0700 (PDT) From: Zihan Xi To: netdev@vger.kernel.org Cc: Zihan Xi , linux-kernel@vger.kernel.org, mptcp@lists.linux.dev, "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Neal Cardwell , Kuniyuki Iwashima , Matthieu Baerts , Mat Martineau , Geliang Tang , Guillaume Nault , Florian Westphal , stable@vger.kernel.org, Vega Subject: [PATCH net v2 2/2] mptcp: diag: bound listener bucket lock hold Date: Tue, 1 Sep 2026 12:53:47 +0000 Message-ID: X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" MPTCP listener diag dumping reuses sk_diag_dump(), which executes inet_diag_bc_sk() before filling the netlink reply. The listener walk in mptcp_diag_dump_listeners() currently performs that work while holding the listener bucket lock. The time spent under the listener bucket lock can therefore grow with the number of sockets visited and with per-socket dump work. The resume state also requires later batches to revisit the bucket prefix. Fix this by collecting only referenced listener sockets while holding the bucket lock. After dropping it, re-check the listener properties, obtain the parent MPTCP socket reference, and call sk_diag_dump(). Keep a referenced cursor so later batches resume after the previous listener instead of rescanning the bucket head. Validate a cursor against the current listener bucket and TCP_LISTEN state before resuming from it. After dropping the lock, read icsk_ulp_data with rcu_dereference(). Fixes: 4fa39b701ce9 ("mptcp: listen diag dump support") Cc: stable@vger.kernel.org Reported-by: Vega Assisted-by: Codex:gpt-5.4 Signed-off-by: Zihan Xi --- changes in v2: - Rebased onto net commit e2a6641e3bfd (2026-08-27). - Added current-bucket cursor validation and safe restart. - Reject MPTCP listener cursors unless the socket is still TCP_LISTEN. - Read icsk_ulp_data with rcu_dereference() after dropping the listener lock. - Moved INET_DIAG_DUMP_CURSOR_MPTCP_LISTEN into this patch. - Moved MPTCP_DIAG_BULK_SZ below the includes and sorted new local declarations reverse xmas tree. - Refreshed the reviewed PoC and decoded crash-log artifacts. - v1 Link: https://lore.kernel.org/all/cover.1785307984.git.zihanx@nebuse= c.ai/ include/linux/inet_diag.h | 1 + net/mptcp/mptcp_diag.c | 124 +++++++++++++++++++++++++++----------- 2 files changed, 89 insertions(+), 36 deletions(-) diff --git a/include/linux/inet_diag.h b/include/linux/inet_diag.h index 6ccd32bc48f9..4859e77a28c7 100644 --- a/include/linux/inet_diag.h +++ b/include/linux/inet_diag.h @@ -39,6 +39,7 @@ enum inet_diag_dump_cursor_type { INET_DIAG_DUMP_CURSOR_TCP_LISTEN, INET_DIAG_DUMP_CURSOR_TCP_BIND, INET_DIAG_DUMP_CURSOR_TCP_EHASH, + INET_DIAG_DUMP_CURSOR_MPTCP_LISTEN, }; =20 struct inet_diag_dump_data { diff --git a/net/mptcp/mptcp_diag.c b/net/mptcp/mptcp_diag.c index 136c2d05c0ee..37b33ea5d79d 100644 --- a/net/mptcp/mptcp_diag.c +++ b/net/mptcp/mptcp_diag.c @@ -12,6 +12,19 @@ #include #include "protocol.h" =20 +/* Process a bounded number of listeners per bucket lock hold. */ +#define MPTCP_DIAG_BULK_SZ 16 + +static void mptcp_diag_save_cursor(struct inet_diag_dump_data *cb_data, + unsigned int slot, struct sock *sk) +{ + sock_hold(sk); + inet_diag_dump_clear_cursor(cb_data); + cb_data->dump_cursor =3D sk; + cb_data->dump_cursor_slot =3D slot; + cb_data->dump_cursor_type =3D INET_DIAG_DUMP_CURSOR_MPTCP_LISTEN; +} + static int sk_diag_dump(struct sock *sk, struct sk_buff *skb, struct netlink_callback *cb, const struct inet_diag_req_v2 *req, @@ -77,6 +90,7 @@ static void mptcp_diag_dump_listeners(struct sk_buff *skb= , struct netlink_callba bool net_admin) { struct mptcp_diag_ctx *diag_ctx =3D (void *)cb->ctx; + struct inet_diag_dump_data *cb_data =3D cb->data; struct net *net =3D sock_net(skb->sk); struct inet_hashinfo *hinfo; int i; @@ -84,64 +98,102 @@ static void mptcp_diag_dump_listeners(struct sk_buff *= skb, struct netlink_callba hinfo =3D net->ipv4.tcp_death_row.hashinfo; =20 for (i =3D diag_ctx->l_slot; i <=3D hinfo->lhash2_mask; i++) { + struct sock *tmp, *sk, *sk_arr[MPTCP_DIAG_BULK_SZ]; struct inet_listen_hashbucket *ilb; + int num_arr[MPTCP_DIAG_BULK_SZ]; struct hlist_nulls_node *node; - struct sock *sk; - int num =3D 0; + int accum, idx, num, ret; + struct sock *cursor; + bool use_cursor; =20 +resume_listen_walk: + num =3D 0; + accum =3D 0; ilb =3D &hinfo->lhash2[i]; + ret =3D 0; =20 rcu_read_lock(); spin_lock(&ilb->lock); - sk_nulls_for_each(sk, node, &ilb->nulls_head) { - const struct mptcp_subflow_context *ctx =3D mptcp_subflow_ctx(sk); - struct inet_sock *inet =3D inet_sk(sk); - int ret; - - if (num < diag_ctx->l_num) - goto next_listen; - - if (!ctx || strcmp(inet_csk(sk)->icsk_ulp_ops->name, "mptcp")) - goto next_listen; - - sk =3D ctx->conn; - if (!sk || !net_eq(sock_net(sk), net)) - goto next_listen; - - if (r->sdiag_family !=3D AF_UNSPEC && - sk->sk_family !=3D r->sdiag_family) - goto next_listen; - - if (r->id.idiag_sport !=3D inet->inet_sport && - r->id.idiag_sport) + cursor =3D cb_data->dump_cursor; + use_cursor =3D cursor && + cb_data->dump_cursor_type =3D=3D + INET_DIAG_DUMP_CURSOR_MPTCP_LISTEN && + cb_data->dump_cursor_slot =3D=3D i && + inet_sk_state_load(cursor) =3D=3D TCP_LISTEN && + !hlist_nulls_unhashed(&cursor->sk_nulls_node) && + cursor->sk_nulls_node.pprev !=3D LIST_POISON2 && + inet_lhash2_bucket_sk(hinfo, cursor) =3D=3D ilb; + node =3D use_cursor ? cursor->sk_nulls_node.next : + ilb->nulls_head.first; + hlist_nulls_for_each_entry_from(sk, node, sk_nulls_node) { + if (!use_cursor && num < diag_ctx->l_num) goto next_listen; =20 if (!refcount_inc_not_zero(&sk->sk_refcnt)) goto next_listen; =20 - ret =3D sk_diag_dump(sk, skb, cb, r, net_admin); - - sock_put(sk); - - if (ret < 0) { - spin_unlock(&ilb->lock); - rcu_read_unlock(); - diag_ctx->l_slot =3D i; - diag_ctx->l_num =3D num; - return; - } - diag_ctx->l_num =3D num + 1; - num =3D 0; + num_arr[accum] =3D num; + sk_arr[accum] =3D sk; + if (++accum =3D=3D MPTCP_DIAG_BULK_SZ) + break; next_listen: ++num; } spin_unlock(&ilb->lock); rcu_read_unlock(); =20 + for (idx =3D 0; idx < accum; idx++) { + const struct mptcp_subflow_context *ctx; + const struct tcp_ulp_ops *ulp_ops; + struct inet_sock *inet; + + sk =3D sk_arr[idx]; + rcu_read_lock(); + ctx =3D rcu_dereference(inet_csk(sk)->icsk_ulp_data); + ulp_ops =3D READ_ONCE(inet_csk(sk)->icsk_ulp_ops); + inet =3D inet_sk(sk); + tmp =3D ctx ? ctx->conn : NULL; + if (!ctx || !ulp_ops || strcmp(ulp_ops->name, "mptcp") || + !tmp || !net_eq(sock_net(tmp), net) || + (r->sdiag_family !=3D AF_UNSPEC && + tmp->sk_family !=3D r->sdiag_family) || + (r->id.idiag_sport !=3D inet->inet_sport && + r->id.idiag_sport) || + !refcount_inc_not_zero(&tmp->sk_refcnt)) { + rcu_read_unlock(); + goto processed_listener_sk; + } + rcu_read_unlock(); + if (ret >=3D 0) { + ret =3D sk_diag_dump(tmp, skb, cb, r, net_admin); + if (ret < 0) + num =3D num_arr[idx]; + } + sock_put(tmp); +processed_listener_sk: + if (ret >=3D 0) + mptcp_diag_save_cursor(cb_data, i, sk); + sock_put(sk); + } + + if (ret < 0) { + diag_ctx->l_slot =3D i; + diag_ctx->l_num =3D num; + return; + } + cond_resched(); + + if (accum =3D=3D MPTCP_DIAG_BULK_SZ) { + diag_ctx->l_num =3D 0; + goto resume_listen_walk; + } + + inet_diag_dump_clear_cursor(cb_data); diag_ctx->l_num =3D 0; } =20 + inet_diag_dump_clear_cursor(cb_data); diag_ctx->l_num =3D 0; diag_ctx->l_slot =3D i; } --=20 2.43.0