mirror of
https://github.com/torvalds/linux.git
synced 2026-10-07 11:06:03 +02:00
virtio_net: copy zerocopy frags in start_xmit without NAPI
Virtio-net without NAPI frees completed skbs lazily on the next
start_xmit. Senders waiting for in-flight zerocopy buffers can
deadlock if they cannot transmit more packets, as then no
completed packets will be freed.
When !use_napi, virtio-net already calls skb_orphan to avoid waiting
up for transmitted skbs to be freed. For zerocopy packets that
require deep copying on orphan (i.e. those that do not set
SKBFL_DONT_ORPHAN, such as PACKET_TX_RING), call skb_orphan_frags
before orphaning to release the buffers.
This fixes the tpacket_snd slot reuse bug on skb_orphan for
virtio-net, and prevents PACKET_TX_RING from running out of slots.
This fix also touches vhost_net zerocopy packets, which also do not
set SKBFL_DONT_ORPHAN. This is fine: vhost_net packets only encounter
virtio-net in nested virtualization, and only if napi_tx is
explicitly disabled (it has been default-enabled since Linux 4.12).
In that rare case, copying the frags is desirable anyway to prevent
holding guest descriptors pinned across unbounded intervals.
This is a prerequisite for the next patch, which converts
PACKET_TX_RING to standard zerocopy completion. Without this patch
first, a bounded ring sender can stall indefinitely behind a
virtio-net virtqueue that cannot reclaim.
Fixes: 5cd8d46ea1 ("packet: copy user buffers before orphan or clone")
Cc: stable@vger.kernel.org
Cc: mst@redhat.com
Cc: jasowangio@gmail.com
Signed-off-by: Willem de Bruijn <willemb@google.com>
Link: https://patch.msgid.link/20260919004748.1463985-2-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
4498467a8a
commit
07e1a9408b
|
|
@ -3349,6 +3349,14 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
else
|
||||
virtqueue_disable_cb(sq->vq);
|
||||
|
||||
if (!use_napi &&
|
||||
unlikely(skb_orphan_frags(skb, GFP_ATOMIC))) {
|
||||
DEV_STATS_INC(dev, tx_dropped);
|
||||
dev_kfree_skb_any(skb);
|
||||
kick = !xmit_more || netif_xmit_stopped(txq);
|
||||
goto kick_vq;
|
||||
}
|
||||
|
||||
/* timestamp packet in software */
|
||||
skb_tx_timestamp(skb);
|
||||
|
||||
|
|
@ -3381,6 +3389,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||
|
||||
kick = use_napi ? __netdev_tx_sent_queue(txq, skb->len, xmit_more) :
|
||||
!xmit_more || netif_xmit_stopped(txq);
|
||||
kick_vq:
|
||||
if (kick) {
|
||||
if (virtqueue_kick_prepare(sq->vq) && virtqueue_notify(sq->vq)) {
|
||||
u64_stats_update_begin(&sq->stats.syncp);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user