public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
From: Xin Long <lucien.xin@gmail.com>
To: network dev <netdev@vger.kernel.org>, quic@lists.linux.dev
Cc: davem@davemloft.net, kuba@kernel.org,
	Eric Dumazet <edumazet@google.com>,
	 Paolo Abeni <pabeni@redhat.com>, Simon Horman <horms@kernel.org>,
	 Stefan Metzmacher <metze@samba.org>,
	Moritz Buhl <mbuhl@openbsd.org>,
	Tyler Fanelli <tfanelli@redhat.com>,
	 Pengtao He <hepengtao@xiaomi.com>,
	Thomas Dreibholz <dreibh@simula.no>,
	linux-cifs@vger.kernel.org,  Steve French <smfrench@gmail.com>,
	Namjae Jeon <linkinjeon@kernel.org>,
	 Paulo Alcantara <pc@manguebit.com>, Tom Talpey <tom@talpey.com>,
	kernel-tls-handshake@lists.linux.dev,
	 Chuck Lever <chuck.lever@oracle.com>,
	Jeff Layton <jlayton@kernel.org>,
	 Steve Dickson <steved@redhat.com>,
	Hannes Reinecke <hare@suse.de>,
	Alexander Aring <aahringo@redhat.com>,
	 David Howells <dhowells@redhat.com>,
	Matthieu Baerts <matttbe@kernel.org>,
	 John Ericson <mail@johnericson.me>,
	Cong Wang <xiyou.wangcong@gmail.com>,
	 "D . Wythe" <alibuda@linux.alibaba.com>,
	Jason Baron <jbaron@akamai.com>,
	 illiliti <illiliti@protonmail.com>,
	Sabrina Dubroca <sd@queasysnail.net>,
	 Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>,
	Daniel Stenberg <daniel@haxx.se>,
	 Andy Gospodarek <andrew.gospodarek@broadcom.com>,
	 "Marc E . Fiuczynski" <marc@fiuczynski.com>
Subject: Re: [PATCH net-next v11 06/15] quic: add stream management
Date: Thu, 26 Mar 2026 11:06:26 -0400	[thread overview]
Message-ID: <CADvbK_eXUfnGGQgGc_k-ecCW3-Co1MpGb7UvMgLonPy3HRhyFA@mail.gmail.com> (raw)
In-Reply-To: <91c6fd0a44eb15a98f945171ead8062badb89a60.1774410440.git.lucien.xin@gmail.com>

On Tue, Mar 24, 2026 at 11:49 PM Xin Long <lucien.xin@gmail.com> wrote:
>
> This patch introduces 'struct quic_stream_table' for managing QUIC streams,
> each represented by 'struct quic_stream'.
>
> It implements mechanisms for acquiring and releasing streams on both the
> send and receive paths, ensuring efficient lifecycle management during
> transmission and reception.
>
> - quic_stream_get(): Acquire a send-side stream by ID and flags during
>   TX path, or a receive-side stream by ID during RX path.
>
> - quic_stream_put(): Release a send-side stream when sending is done,
>   or a receive-side stream when receiving is done.
>
> It includes logic to detect when stream ID limits are reached and when
> control frames should be sent to update or request limits from the peer.
>
> - quic_stream_id_exceeds(): Check a stream ID would exceed local (recv)
>   or peer (send) limits.
>
> - quic_stream_max_streams_update(): Determines whether a
>   MAX_STREAMS_UNI/BIDI frame should be sent to the peer.
>
> Note stream hash table is per socket, the operations on it are always
> protected by the sock lock.
>
> Signed-off-by: Xin Long <lucien.xin@gmail.com>
> Acked-by: Paolo Abeni <pabeni@redhat.com>
> ---
> v3:
>   - Merge send/recv stream helpers into unified functions to reduce code:
>     * quic_stream_id_send/recv() → quic_stream_id_valid()
>     * quic_stream_id_send/recv_closed() → quic_stream_id_closed()
>     * quic_stream_id_send/recv_exceeds() → quic_stream_id_exceeds()
>     (pointed out by Paolo).
>   - Clarify in changelog that stream hash table is always protected by sock
>     lock (suggested by Paolo).
>   - quic_stream_init/free(): adjust for new hashtable type; call
>     quic_stream_delete() in quic_stream_free() to avoid open-coded logic.
>   - Receiving streams: delete stream only when fully read or reset, instead
>     of when no data was received. Prevents freeing a stream while a FIN
>     with no data is still queued.
> v4:
>   - Replace struct quic_shash_table with struct hlist_head for the
>     stream hashtable. Since they are protected by the socket lock,
>     no per-chain lock is needed.
>   - Initialize stream to NULL in stream creation functions to avoid
>     warnings from Smatch (reported by Simon).
>   - Allocate send streams with GFP_KERNEL_ACCOUNT and receive streams
>     with GFP_ATOMIC | __GFP_ACCOUNT for memory accounting (suggested
>     by Paolo).
> v5:
>   - Introduce struct quic_stream_limits to merge quic_stream_send_create()
>     and quic_stream_recv_create(), and to simplify quic_stream_get_param()
>     (suggested by Paolo).
>   - Annotate the sock-lock requirement for quic_stream_send/recv_get()
>     and quic_stream_send/recv_put() (notied by Paolo).
>   - Add quic_stream_bidi_put() to deduplicate the common logic between
>     quic_stream_send_put() and quic_stream_recv_put().
>   - Remove the unnecessary check when incrementing
>     streams->send.next_bidi/uni_stream_id in quic_stream_create().
>   - Remove the unused 'is_serv' parameter from quic_stream_get_param().
> v7:
>   - Free the allocated streams on error path in quic_stream_create() (noted
>     by Paolo).
>   - Merge quic_stream_send_get/put() and quic_stream_recv_get/put() helpers
>     to quic_stream_get/put() (suggested by Paolo).
>   - Add more comments in quic_stream_id_exceeds() and quic_stream_create().
> v8:
>   - Replace bitfields with plain u8 in struct quic_stream_limits and struct
>     quic_stream (suggested by Paolo).
> v9:
>   - Fix grammar in the comment for quic_stream::send.window.
> v10:
>   - Move quic_stream_init() to after sock_prot_inuse_add() ensure counters
>     are incremented before any early return paths in quic_init_sock(),
>     preventing underflow in quic_destroy_sock() (noted by AI review).
>   - Initialize the output parameters '*max_uni' and '*max_bidi' to 0 at the
>     start of quic_stream_max_streams_update()
>   - Use 'stream->recv.state > QUIC_STREAM_RECV_STATE_RECVD' instead of '!='
>     for clearer intent.
>   - Simplify some state checks in quic_stream_put() by using range
>     comparisons (> or <) instead of multiple != conditions.
>   - streams_uni/bidi are u16 type, and their overflow is already prevented
>     by QUIC_MAX_STREAMS indirectly. Update comment in quic_stream_create().
>   - Replace open-coded kzalloc(sizeof(*stream)) with kzalloc_obj(*stream)
>     in quic_stream_create().
> v11:
>   - Set maximum line length to 80 characters.
>   - Change is_serv parameter type to bool in quic_stream_id_local().
> ---
>  net/quic/Makefile |   2 +-
>  net/quic/socket.c |   5 +
>  net/quic/socket.h |   8 +
>  net/quic/stream.c | 444 ++++++++++++++++++++++++++++++++++++++++++++++
>  net/quic/stream.h | 133 ++++++++++++++
>  5 files changed, 591 insertions(+), 1 deletion(-)
>  create mode 100644 net/quic/stream.c
>  create mode 100644 net/quic/stream.h
>
> diff --git a/net/quic/Makefile b/net/quic/Makefile
> index 13bf4a4e5442..094e9da5d739 100644
> --- a/net/quic/Makefile
> +++ b/net/quic/Makefile
> @@ -5,4 +5,4 @@
>
>  obj-$(CONFIG_IP_QUIC) += quic.o
>
> -quic-y := common.o family.o protocol.o socket.o
> +quic-y := common.o family.o protocol.o socket.o stream.o
> diff --git a/net/quic/socket.c b/net/quic/socket.c
> index 8dc2cb7628db..0006668551f4 100644
> --- a/net/quic/socket.c
> +++ b/net/quic/socket.c
> @@ -45,11 +45,16 @@ static int quic_init_sock(struct sock *sk)
>         sk_sockets_allocated_inc(sk);
>         sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
>
> +       if (quic_stream_init(quic_streams(sk)))
> +               return -ENOMEM;
> +
>         return 0;
>  }
>
>  static void quic_destroy_sock(struct sock *sk)
>  {
> +       quic_stream_free(quic_streams(sk));
> +
>         quic_data_free(quic_ticket(sk));
>         quic_data_free(quic_token(sk));
>         quic_data_free(quic_alpn(sk));
> diff --git a/net/quic/socket.h b/net/quic/socket.h
> index 61df0c5867be..e76737b9b74b 100644
> --- a/net/quic/socket.h
> +++ b/net/quic/socket.h
> @@ -13,6 +13,7 @@
>
>  #include "common.h"
>  #include "family.h"
> +#include "stream.h"
>
>  #include "protocol.h"
>
> @@ -33,6 +34,8 @@ struct quic_sock {
>         struct quic_data                ticket;
>         struct quic_data                token;
>         struct quic_data                alpn;
> +
> +       struct quic_stream_table        streams;
>  };
>
>  struct quic6_sock {
> @@ -65,6 +68,11 @@ static inline struct quic_data *quic_alpn(const struct sock *sk)
>         return &quic_sk(sk)->alpn;
>  }
>
> +static inline struct quic_stream_table *quic_streams(const struct sock *sk)
> +{
> +       return &quic_sk(sk)->streams;
> +}
> +
>  static inline bool quic_is_serv(const struct sock *sk)
>  {
>         return !!sk->sk_max_ack_backlog;
> diff --git a/net/quic/stream.c b/net/quic/stream.c
> new file mode 100644
> index 000000000000..4d980f9b03ce
> --- /dev/null
> +++ b/net/quic/stream.c
> @@ -0,0 +1,444 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/* QUIC kernel implementation
> + * (C) Copyright Red Hat Corp. 2023
> + *
> + * This file is part of the QUIC kernel implementation
> + *
> + * Initialization/cleanup for QUIC protocol support.
> + *
> + * Written or modified by:
> + *    Xin Long <lucien.xin@gmail.com>
> + */
> +
> +#include <linux/quic.h>
> +
> +#include "common.h"
> +#include "stream.h"
> +
> +/* Check if a stream ID is valid for sending or receiving. */
> +static bool quic_stream_id_valid(s64 stream_id, bool is_serv, bool send)
> +{
> +       u8 type = (stream_id & QUIC_STREAM_TYPE_MASK);
> +
> +       if (send) {
> +               if (is_serv)
> +                       return type != QUIC_STREAM_TYPE_CLIENT_UNI;
> +               return type != QUIC_STREAM_TYPE_SERVER_UNI;
> +       }
> +       if (is_serv)
> +               return type != QUIC_STREAM_TYPE_SERVER_UNI;
> +       return type != QUIC_STREAM_TYPE_CLIENT_UNI;
> +}
> +
> +/* Check if a stream ID was initiated locally. */
> +static bool quic_stream_id_local(s64 stream_id, bool is_serv)
> +{
> +       return is_serv ^ !(stream_id & QUIC_STREAM_TYPE_SERVER_MASK);
> +}
> +
> +/* Check if a stream ID represents a unidirectional stream. */
> +static bool quic_stream_id_uni(s64 stream_id)
> +{
> +       return stream_id & QUIC_STREAM_TYPE_UNI_MASK;
> +}
> +
> +#define QUIC_STREAM_HT_SIZE    64
> +
> +static struct hlist_head *quic_stream_head(struct quic_stream_table *streams,
> +                                          s64 stream_id)
> +{
> +       return &streams->head[stream_id & (QUIC_STREAM_HT_SIZE - 1)];
> +}
> +
> +struct quic_stream *quic_stream_find(struct quic_stream_table *streams,
> +                                    s64 stream_id)
> +{
> +       struct hlist_head *head = quic_stream_head(streams, stream_id);
> +       struct quic_stream *stream;
> +
> +       hlist_for_each_entry(stream, head, node) {
> +               if (stream->id == stream_id)
> +                       break;
> +       }
> +       return stream;
> +}
> +
> +static void quic_stream_add(struct quic_stream_table *streams,
> +                           struct quic_stream *stream)
> +{
> +       struct hlist_head *head;
> +
> +       head = quic_stream_head(streams, stream->id);
> +       hlist_add_head(&stream->node, head);
> +}
> +
> +static void quic_stream_delete(struct quic_stream *stream)
> +{
> +       hlist_del_init(&stream->node);
> +       kfree(stream);
> +}
> +
> +/* Create and register new streams for sending or receiving. */
> +static struct quic_stream *quic_stream_create(struct quic_stream_table *streams,
> +                                             s64 max_stream_id, bool send,
> +                                             bool is_serv)
> +{
> +       struct quic_stream_limits *limits = &streams->send;
> +       struct quic_stream *pos, *stream = NULL;
> +       gfp_t gfp = GFP_KERNEL_ACCOUNT;
> +       struct hlist_node *tmp;
> +       HLIST_HEAD(head);
> +       s64 stream_id;
> +       u32 count = 0;
> +
> +       if (!send) {
> +               limits = &streams->recv;
> +               gfp = GFP_ATOMIC | __GFP_ACCOUNT;
> +       }
> +       stream_id = limits->next_bidi_stream_id;
> +       if (quic_stream_id_uni(max_stream_id))
> +               stream_id = limits->next_uni_stream_id;
> +
> +       /* rfc9000#section-2.1: A stream ID that is used out of order results in
> +        * all streams of that type with lower-numbered stream IDs also being
> +        * opened.
> +        */
> +       while (stream_id <= max_stream_id) {
> +               stream = kzalloc_obj(*stream, gfp);
> +               if (!stream)
> +                       goto free;
> +
> +               stream->id = stream_id;
> +               if (quic_stream_id_uni(stream_id)) {
> +                       if (send) {
> +                               stream->send.max_bytes =
> +                                       limits->max_stream_data_uni;
> +                       } else {
> +                               stream->recv.max_bytes =
> +                                       limits->max_stream_data_uni;
> +                               stream->recv.window = stream->recv.max_bytes;
> +                       }
> +                       hlist_add_head(&stream->node, &head);
> +                       stream_id += QUIC_STREAM_ID_STEP;
> +                       continue;
> +               }
> +
> +               if (quic_stream_id_local(stream_id, is_serv)) {
> +                       stream->send.max_bytes =
> +                               streams->send.max_stream_data_bidi_remote;
> +                       stream->recv.max_bytes =
> +                               streams->recv.max_stream_data_bidi_local;
> +               } else {
> +                       stream->send.max_bytes =
> +                               streams->send.max_stream_data_bidi_local;
> +                       stream->recv.max_bytes =
> +                               streams->recv.max_stream_data_bidi_remote;
> +               }
> +               stream->recv.window = stream->recv.max_bytes;
> +               hlist_add_head(&stream->node, &head);
> +               stream_id += QUIC_STREAM_ID_STEP;
> +       }
> +
> +       hlist_for_each_entry_safe(pos, tmp, &head, node) {
> +               hlist_del_init(&pos->node);
> +               quic_stream_add(streams, pos);
> +               count++;
> +       }
> +
> +       /* Streams must be opened sequentially. Update the next stream ID so the
> +        * correct starting point is known if an out-of-order open is requested.
> +        * Note overflow of next_uni/bidi_stream_id is impossible with s64.
> +        */
> +       if (quic_stream_id_uni(stream_id)) {
> +               limits->next_uni_stream_id = stream_id;
> +               limits->streams_uni += count;
> +               return stream;
> +       }
> +
> +       limits->next_bidi_stream_id = stream_id;
> +       limits->streams_bidi += count;
> +       return stream;
> +
> +free:
> +       hlist_for_each_entry_safe(pos, tmp, &head, node) {
> +               hlist_del_init(&pos->node);
> +               kfree(pos);
> +       }
> +       return NULL;
> +}
> +
> +/* Check if a send or receive stream ID is already closed. */
> +static bool quic_stream_id_closed(struct quic_stream_table *streams,
> +                                 s64 stream_id, bool send)
> +{
> +       struct quic_stream_limits *limits = send ? &streams->send :
> +                                                  &streams->recv;
> +
> +       if (quic_stream_id_uni(stream_id))
> +               return stream_id < limits->next_uni_stream_id;
> +       return stream_id < limits->next_bidi_stream_id;
> +}
> +
> +/* Check if a stream ID would exceed local (recv) or peer (send) limits. */
> +bool quic_stream_id_exceeds(struct quic_stream_table *streams, s64 stream_id,
> +                           bool send)
> +{
> +       u64 nstreams;
> +
> +       if (!send) {
> +               /* recv.max_uni_stream_id is updated in
> +                * quic_stream_max_streams_update() already based on
> +                * next_uni/bidi_stream_id, max_streams_uni/bidi, and
> +                * streams_uni/bidi, so only recv.max_uni_stream_id needs to be
> +                * checked.
> +                */
> +               if (quic_stream_id_uni(stream_id))
> +                       return stream_id > streams->recv.max_uni_stream_id;
> +
> +               return stream_id > streams->recv.max_bidi_stream_id;
> +       }
> +
> +       if (quic_stream_id_uni(stream_id)) {
> +               if (stream_id > streams->send.max_uni_stream_id)
> +                       return true;
> +               stream_id -= streams->send.next_uni_stream_id;
> +               nstreams = quic_stream_id_to_streams(stream_id);
> +
> +               return nstreams + streams->send.streams_uni >
> +                      streams->send.max_streams_uni;
> +       }
> +
> +       if (stream_id > streams->send.max_bidi_stream_id)
> +               return true;
> +       stream_id -= streams->send.next_bidi_stream_id;
> +       nstreams = quic_stream_id_to_streams(stream_id);
> +
> +       return nstreams + streams->send.streams_bidi >
> +              streams->send.max_streams_bidi;
> +}
> +
> +/* Get or create a send or recv stream by ID. Requires sock lock held. */
> +struct quic_stream *quic_stream_get(struct quic_stream_table *streams,
> +                                   s64 stream_id, u32 flags, bool is_serv,
> +                                   bool send)
> +{
> +       struct quic_stream *stream;
> +
> +       if (!quic_stream_id_valid(stream_id, is_serv, send))
> +               return ERR_PTR(-EINVAL);
> +
> +       stream = quic_stream_find(streams, stream_id);
> +       if (stream) {
> +               if (send && (flags & MSG_QUIC_STREAM_NEW) &&
> +                   stream->send.state != QUIC_STREAM_SEND_STATE_READY)
> +                       return ERR_PTR(-EINVAL);
> +               return stream;
> +       }
> +
> +       if (!send && quic_stream_id_local(stream_id, is_serv)) {
> +               if (quic_stream_id_closed(streams, stream_id, !send))
> +                       return ERR_PTR(-ENOSTR);
> +               return ERR_PTR(-EINVAL);
> +       }
> +
> +       if (quic_stream_id_closed(streams, stream_id, send))
> +               return ERR_PTR(-ENOSTR);
> +
> +       if (send && !(flags & MSG_QUIC_STREAM_NEW))
> +               return ERR_PTR(-EINVAL);
> +
> +       if (quic_stream_id_exceeds(streams, stream_id, send))
> +               return ERR_PTR(-EAGAIN);
> +
> +       stream = quic_stream_create(streams, stream_id, send, is_serv);
> +       if (!stream)
> +               return ERR_PTR(-ENOSTR);
> +
> +       if (send || quic_stream_id_valid(stream_id, is_serv, !send))
> +               streams->send.active_stream_id = stream_id;
> +
> +       return stream;
> +}
> +
> +/* Release or clean up a send or recv stream. This function updates stream
> + * counters and state when a send stream has either successfully sent all data
> + * or has been reset, or when a recv stream has either consumed all data or has
> + * been reset. Requires sock lock held.
> + */
> +void quic_stream_put(struct quic_stream_table *streams,
> +                    struct quic_stream *stream, bool is_serv, bool send)
> +{
> +       if (quic_stream_id_uni(stream->id)) {
> +               if (send) {
> +                       /* For uni streams, decrement uni count and delete
> +                        * immediately.
> +                        */
> +                       streams->send.streams_uni--;
> +                       quic_stream_delete(stream);
> +                       return;
> +               }
> +               /* For uni streams, decrement uni count and mark done. */
> +               if (!stream->recv.done) {
> +                       stream->recv.done = 1;
> +                       streams->recv.streams_uni--;
> +                       streams->recv.uni_pending = 1;
> +               }
> +               /* Delete stream if fully read or reset. */
> +               if (stream->recv.state > QUIC_STREAM_RECV_STATE_RECVD)
> +                       quic_stream_delete(stream);
> +               return;
> +       }
> +
> +       if (send) {
> +               /* For bidi streams, only proceed if receive side is in a final
> +                * state.
> +                */
> +               if (stream->recv.state < QUIC_STREAM_RECV_STATE_RECVD)
> +                       return;
> +       } else {
> +               /* For bidi streams, only proceed if send side is in a final
> +                * state.
> +                */
> +               if (stream->send.state != QUIC_STREAM_SEND_STATE_RECVD &&
> +                   stream->send.state != QUIC_STREAM_SEND_STATE_RESET_RECVD)
> +                       return;
> +       }
> +
> +       if (quic_stream_id_local(stream->id, is_serv)) {
> +               /* Local-initiated stream: mark send done and decrement
> +                * send.bidi count.
> +                */
> +               if (!stream->send.done) {
> +                       stream->send.done = 1;
> +                       streams->send.streams_bidi--;
> +               }
> +       } else {
> +               /* Remote-initiated stream: mark recv done and decrement recv
> +                * bidi count.
> +                */
> +               if (!stream->recv.done) {
> +                       stream->recv.done = 1;
> +                       streams->recv.streams_bidi--;
> +                       streams->recv.bidi_pending = 1;
> +               }
> +       }
> +
> +       /* Delete stream if fully read or reset. */
> +       if (stream->recv.state > QUIC_STREAM_RECV_STATE_RECVD)
> +               quic_stream_delete(stream);
> +}
> +
> +/* Updates the maximum allowed incoming stream IDs if any streams were recently
> + * closed.  Recalculates the max_uni and max_bidi stream ID limits based on the
> + * number of open streams and whether any were marked for deletion.
> + *
> + * Returns true if either max_uni or max_bidi was updated, indicating that a
> + * MAX_STREAMS_UNI or MAX_STREAMS_BIDI frame should be sent to the peer.
> + */
> +bool quic_stream_max_streams_update(struct quic_stream_table *streams,
> +                                   s64 *max_uni, s64 *max_bidi)
> +{
> +       s64 max, rem;
> +
> +       *max_uni = 0;
> +       *max_bidi = 0;
> +       if (streams->recv.uni_pending) {
> +               rem = streams->recv.max_streams_uni - streams->recv.streams_uni;
> +               max = streams->recv.next_uni_stream_id - QUIC_STREAM_ID_STEP +
> +                     (rem << QUIC_STREAM_TYPE_BITS);
> +
> +               streams->recv.max_uni_stream_id = max;
> +               *max_uni = quic_stream_id_to_streams(max);
> +               streams->recv.uni_pending = 0;
> +       }
> +       if (streams->recv.bidi_pending) {
> +               rem = streams->recv.max_streams_bidi -
> +                     streams->recv.streams_bidi;
> +               max = streams->recv.next_bidi_stream_id - QUIC_STREAM_ID_STEP +
> +                       (rem << QUIC_STREAM_TYPE_BITS);
> +
> +               streams->recv.max_bidi_stream_id = max;
> +               *max_bidi = quic_stream_id_to_streams(max);
> +               streams->recv.bidi_pending = 0;
> +       }
> +
> +       return *max_uni || *max_bidi;
> +}
> +
> +int quic_stream_init(struct quic_stream_table *streams)
> +{
> +       struct hlist_head *head;
> +       int i;
> +
> +       head = kmalloc_array(QUIC_STREAM_HT_SIZE, sizeof(*head), GFP_KERNEL);
> +       if (!head)
> +               return -ENOMEM;
> +       for (i = 0; i < QUIC_STREAM_HT_SIZE; i++)
> +               INIT_HLIST_HEAD(&head[i]);
> +       streams->head = head;
> +       return 0;
> +}
> +
> +void quic_stream_free(struct quic_stream_table *streams)
> +{
> +       struct quic_stream *stream;
> +       struct hlist_head *head;
> +       struct hlist_node *tmp;
> +       int i;
> +
> +       if (!streams->head)
> +               return;
> +
> +       for (i = 0; i < QUIC_STREAM_HT_SIZE; i++) {
> +               head = &streams->head[i];
> +               hlist_for_each_entry_safe(stream, tmp, head, node)
> +                       quic_stream_delete(stream);
> +       }
> +       kfree(streams->head);
The AI report on

  https://netdev-ai.bots.linux.dev/ai-review.html?id=1624d906-c0b6-4e12-a63f-5cbfc51b660e#patch-5

is false positive.

As the sk_alloc() calls sk_prot_alloc() with __GFP_ZERO, and the streams->head
is always initialized to NULL.

  reply	other threads:[~2026-03-26 15:06 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-25  3:47 [PATCH net-next v11 00/15] net: introduce QUIC infrastructure and core subcomponents Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 01/15] net: define IPPROTO_QUIC and SOL_QUIC constants Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 02/15] net: build socket infrastructure for QUIC protocol Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 03/15] quic: provide common utilities and data structures Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 04/15] quic: provide family ops for address and protocol Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 05/15] quic: provide quic.h header files for kernel and userspace Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 06/15] quic: add stream management Xin Long
2026-03-26 15:06   ` Xin Long [this message]
2026-03-26 20:07     ` Jakub Kicinski
2026-03-26 21:48       ` Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 07/15] quic: add connection id management Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 08/15] quic: add path management Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 09/15] quic: add congestion control Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 10/15] quic: add packet number space Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 11/15] quic: add crypto key derivation and installation Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 12/15] quic: add crypto packet encryption and decryption Xin Long
2026-03-26 15:10   ` Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 13/15] quic: add timer management Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 14/15] quic: add packet builder base Xin Long
2026-03-25  3:47 ` [PATCH net-next v11 15/15] quic: add packet parser base Xin Long

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CADvbK_eXUfnGGQgGc_k-ecCW3-Co1MpGb7UvMgLonPy3HRhyFA@mail.gmail.com \
    --to=lucien.xin@gmail.com \
    --cc=aahringo@redhat.com \
    --cc=alibuda@linux.alibaba.com \
    --cc=andrew.gospodarek@broadcom.com \
    --cc=chuck.lever@oracle.com \
    --cc=daniel@haxx.se \
    --cc=davem@davemloft.net \
    --cc=dhowells@redhat.com \
    --cc=dreibh@simula.no \
    --cc=edumazet@google.com \
    --cc=hare@suse.de \
    --cc=hepengtao@xiaomi.com \
    --cc=horms@kernel.org \
    --cc=illiliti@protonmail.com \
    --cc=jbaron@akamai.com \
    --cc=jlayton@kernel.org \
    --cc=kernel-tls-handshake@lists.linux.dev \
    --cc=kuba@kernel.org \
    --cc=linkinjeon@kernel.org \
    --cc=linux-cifs@vger.kernel.org \
    --cc=mail@johnericson.me \
    --cc=marc@fiuczynski.com \
    --cc=marcelo.leitner@gmail.com \
    --cc=matttbe@kernel.org \
    --cc=mbuhl@openbsd.org \
    --cc=metze@samba.org \
    --cc=netdev@vger.kernel.org \
    --cc=pabeni@redhat.com \
    --cc=pc@manguebit.com \
    --cc=quic@lists.linux.dev \
    --cc=sd@queasysnail.net \
    --cc=smfrench@gmail.com \
    --cc=steved@redhat.com \
    --cc=tfanelli@redhat.com \
    --cc=tom@talpey.com \
    --cc=xiyou.wangcong@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox