From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
To: netdev-bot+sashiko@kernel.org, willemdebruijn.kernel@gmail.com
Cc: netdev@vger.kernel.org, davem@davemloft.net, kuba@kernel.org,
edumazet@google.com, pabeni@redhat.com, horms@kernel.org,
andrew+netdev@lunn.ch, willemb@google.com,
kleaver@janestreet.com, doebel@amazon.de,
stable@vger.kernel.org
Subject: Re: [PATCH net v2 2/2] packet: use ubuf_info completion for TX_RING packets
Date: Tue, 22 Sep 2026 11:07:10 -0400 [thread overview]
Message-ID: <willemdebruijn.kernel.3ad8224b38583@gmail.com> (raw)
In-Reply-To: <179004896529.2160803.14644876688990648036@kernel.org>
netdev-bot+sashiko@ wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential
> issue(s) to consider.
>
> Critical: 0 · High: 0 · Medium: 2 · Low: 1
>
> [Severity: Medium]
> Should Documentation/networking/packet_mmap.rst be updated along with this
> change? The "Transmission process" section still says:
>
> The kernel updates each status of sent frames with TP_STATUS_SENDING
> until the end of transfer.
>
> At the end of each transfer, buffer status returns to
> TP_STATUS_AVAILABLE.
>
> With slot release moved into tpacket_ubuf_complete(), TP_STATUS_AVAILABLE
> now means "the kernel no longer references the payload", which the commit
> message says can happen before transmission:
>
> net/core/dev.c:deliver_skb()
> skb_orphan_frags_rx()
> skb_copy_ubufs()
> skb_zcopy_clear()
> tpacket_ubuf_complete()
[Medium] This is a pre-existing issue.
The slot can be returned prior to the end of transfer after this
change. But the same was true before this change with skb_orphan().
I can improve this documentation in a follow-up to net-next. But I
don't think it belongs in a stable patch.
>
> The timestamp section also documents a specific recipe:
>
> Getting timestamps for the TX_RING works as follows: i) fill the ring
> frames, ii) call sendto() e.g. in blocking mode, iii) wait for status of
> relevant frames to be updated resp. the frame handed over to the
> application, iv) walk through the frames to pick up the individual hw/sw
> timestamps.
>
> When the copy happens before skb_tx_timestamp(),
> __packet_set_timestamp() returns 0, so the frame is handed back as
> TP_STATUS_AVAILABLE with no TP_STATUS_TS_* bit and stale tp_sec/tp_nsec,
> even though timestamping was requested. Can that documented procedure
> still be followed, or should the text describe the new semantics?
>
> > +
> > + packet_dec_pending(&po->tx_ring);
> > + complete(&po->skb_completion);
> > +
> > + kfree(tu);
> > + sk_free(&po->sk);
> > +}
>
> [Severity: Medium]
> Does releasing the wmem charge through sk_free() here miss a write space
> notification?
>
> sk_free() only does the decrement:
>
> net/core/sock.c:sk_free() {
> if (refcount_dec_and_test(&sk->sk_wmem_alloc))
> __sk_free(sk);
> }
>
> whereas the skb charge release path notifies first:
>
> net/core/sock.c:sock_wfree() {
> ...
> WARN_ON(refcount_sub_and_test(len - 1, &sk->sk_wmem_alloc));
> sk_write_space(sk);
> len = 1;
> ...
> }
[Medium] False positive.
This sk_free only releases a 1 byte hold for the slot.
The actual release of the truesize attributed to the data (to_write)
is released in the normal sock_wfree path.
It is admittedly odd to have two wmem operations per slot. And perhaps
even questionable to have truesize and wmem count userspace TX_RING
data. But the second is pre-existing and for net-next.
The first is new, but alternatives like sock_hold were found to be
less preferable than an extra 1B hold on wmem.
>
> A blocking TX_RING sender reaches sock_wait_for_wmem() via
> tpacket_snd()->sock_alloc_send_skb()->sock_alloc_send_pskb(), and its only
> wake condition for send space is sk->sk_write_space():
>
> net/core/sock.c:sock_wait_for_wmem() {
> ...
> if (refcount_read(&sk->sk_wmem_alloc) < READ_ONCE(sk->sk_sndbuf))
> break;
> ...
> timeo = schedule_timeout(timeo);
> ...
> }
>
> With the default sk_sndtimeo that schedule_timeout() is
> MAX_SCHEDULE_TIMEOUT. If the drop below sk_sndbuf is performed by the new
> uarg charges only, is anything left to wake the sleeper? A path where the
> skb charge is gone while the uarg charge is still outstanding is
> loopback_xmit(), which calls skb_orphan(skb) (running sock_wfree) without
> skb_orphan_frags(), so the ubuf_info survives in the backlog.
>
> [ ... ]
>
> > @@ -2908,7 +2918,24 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
> > virtio_net_hdr_set_proto(skb, &vnet_hdr);
> > }
> >
> > - skb->destructor = tpacket_destruct_skb;
> > + uarg = kmalloc(sizeof(*uarg), GFP_KERNEL);
> > + if (unlikely(!uarg)) {
> > + if (likely(len_sum > 0))
> > + err = len_sum;
> > + else
> > + err = -ENOMEM;
> > + goto out_status;
> > + }
> > + uarg->po = po;
> > + uarg->ph = ph;
> > + uarg->ubuf.ops = &tpacket_ubuf_ops;
> > + uarg->ubuf.flags = SKBFL_ZEROCOPY_FRAG;
> > + refcount_set(&uarg->ubuf.refcnt, 1);
> > +
> > + /* Hold a sk_wmem_alloc reference until completion */
> > + refcount_inc(&po->sk.sk_wmem_alloc);
> > + skb_zcopy_init(skb, &uarg->ubuf);
> > +
> > __packet_set_status(po, ph, TP_STATUS_SENDING);
> > packet_inc_pending(&po->tx_ring);
> >
>
> [Severity: Low]
> Just below this, the packet_xmit() error handling in tpacket_snd() still
> refers to the destructor that this patch removes:
>
> net/packet/af_packet.c:tpacket_snd() {
> ...
> if (err && __packet_get_status(po, ph) ==
> TP_STATUS_AVAILABLE) {
> /* skb was destructed already */
> skb = NULL;
> goto out_status;
> }
> /*
> * skb was dropped but not destructed yet;
> * let's treat it like congestion or err < 0
> */
> ...
> }
>
> With skb->destructor back to sock_wfree and slot release moved to
> tpacket_ubuf_complete(), does the slot status still imply anything about
> the skb? TP_STATUS_AVAILABLE can now be observed while the skb is alive
> (the uarg completed early through skb_copy_ubufs()), and the slot can
> still read TP_STATUS_SENDING after the skb was freed if a clone or segment
> holds an extra uarg reference. Should these comments be reworded for the
> new completion scheme?
>
> --
> Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260919004748.1463985-1-willemdebruijn.kernel%40gmail.com
next prev parent reply other threads:[~2026-09-22 15:07 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-19 0:47 [PATCH net v2 0/2] packet: fix PACKET_TX_RING data corruption on skb_orphan Willem de Bruijn
2026-09-19 0:47 ` [PATCH net v2 1/2] virtio_net: copy zerocopy frags in start_xmit without NAPI Willem de Bruijn
2026-09-22 3:49 ` netdev-bot+sashiko
2026-09-22 15:01 ` Willem de Bruijn
2026-09-19 0:47 ` [PATCH net v2 2/2] packet: use ubuf_info completion for TX_RING packets Willem de Bruijn
2026-09-22 3:49 ` netdev-bot+sashiko
2026-09-22 15:07 ` Willem de Bruijn [this message]
2026-09-23 2:00 ` [PATCH net v2 0/2] packet: fix PACKET_TX_RING data corruption on skb_orphan patchwork-bot+netdevbpf
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=willemdebruijn.kernel.3ad8224b38583@gmail.com \
--to=willemdebruijn.kernel@gmail.com \
--cc=andrew+netdev@lunn.ch \
--cc=davem@davemloft.net \
--cc=doebel@amazon.de \
--cc=edumazet@google.com \
--cc=horms@kernel.org \
--cc=kleaver@janestreet.com \
--cc=kuba@kernel.org \
--cc=netdev-bot+sashiko@kernel.org \
--cc=netdev@vger.kernel.org \
--cc=pabeni@redhat.com \
--cc=stable@vger.kernel.org \
--cc=willemb@google.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.