[Devel] [PATCH RH7] virtio_net: fix hang on vhost backend setting

Denis V. Lunev den at virtuozzo.com
Tue May 17 19:43:55 MSK 2022


On 17.05.2022 18:29, Pavel Tikhomirov wrote:
> We can see a hang for 40 sec in (vz7.185.3) in vhost_net_set_backend:
>
> crash> ps -m | grep UN
> [0 00:00:40.157] [UN]  PID: 38937  TASK: ffff9b7f54ca8000  CPU: 2   COMMAND: "qemu-kvm"
>
> [<ffffffffc09c04a5>] vhost_net_ubuf_put_and_wait+0x65/0xb0 [vhost_net]
> [<ffffffffc09c2451>] vhost_net_ioctl+0x661/0x890 [vhost_net]
> [<ffffffff8fc89d80>] do_vfs_ioctl+0x3b0/0x5b0
> [<ffffffff8fc8a021>] SyS_ioctl+0xa1/0xc0
>
> while waiting for ubufs->refcount to get to zero.
>
> In crash we see an inprogress ubuf_info generated by handle_tx(), which
> is holding a refcount on ubufs, and should release it from
> vhost_zerocopy_callback() but yet didn't to it. We also see the
> skb_shared_info referencing this ubuf_info with zerocopy flag set. And
> finally we see an sk_buff referencing this skb_shared_info. This sk_buff
> had passed through validate_xmit_skb_list() as it has ->next == NULL and
> ->prev == skb. So it also passed dev_hard_start_xmit() already in
> sch_direct_xmit(), and by looking on sk_buff's dev's netdev_queue's
> trans_start we can see that it happened exactly 40 sec earlier. The
> netdev_queue has virtnet_netdev ops so everything happens in virtio_net.
>
> Considering all the above I believe that we have the same thing as in
> tun devices, seems that after virtio_net xmit the sk_buff can be held
> for long and thus we need to orphan frags to release ubufs earlier.
>
> See similar patches for tun:
> 868eefeb17d4 ("tun: orphan frags on xmit")
> 149d36f7187c ("tun: report orphan frags errors to zero copy callback")
>
> https://pmc.acronis.com/browse/VSTOR-52993
>
> Signed-off-by: Pavel Tikhomirov <ptikhomirov at virtuozzo.com>
> ---
>   drivers/net/virtio_net.c | 5 +++++
>   1 file changed, 5 insertions(+)
>
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index 652f5b1b218c..5d22e19ad161 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
> @@ -790,16 +790,21 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
>   	/* Free up any pending old buffers before queueing new ones. */
>   	free_old_xmit_skbs(sq);
>   
> +	if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC)))
> +		goto drop;
> +

This smells like the SKB data will be copied for EACH skb and thus
"zero copy" will not be zero copy anymore.

Am I correct?

>   	/* Try to transmit */
>   	err = xmit_skb(sq, skb);
>   
>   	/* This should not happen! */
>   	if (unlikely(err)) {
> +drop:
>   		dev->stats.tx_fifo_errors++;
>   		if (net_ratelimit())
>   			dev_warn(&dev->dev,
>   				 "Unexpected TXQ (%d) queue failure: %d\n", qnum, err);
>   		dev->stats.tx_dropped++;
> +		skb_tx_error(skb);
>   		kfree_skb(skb);
>   		return NETDEV_TX_OK;
>   	}



More information about the Devel mailing list