This is an automated email from the ASF dual-hosted git repository. acassis pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit a2524b8f4bd4ffc747d91402b3fe41e91acdb964 Author: dengwenqi <[email protected]> AuthorDate: Mon Sep 21 15:07:36 2026 +0800 drivers/virtio-net: free in-flight buffers on remove virtio_net_remove() reset the device and deleted the virtqueues without freeing the netpkts still queued in them, so unbinding the driver leaked the pre-filled RX ring and any pending TX buffers. After virtio_reset_device() and before virtio_delete_virtqueues(), drain both the used and the avail ring of each virtqueue and free every netpkt found there. Signed-off-by: dengwenqi <[email protected]> --- drivers/virtio/virtio-net.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/drivers/virtio/virtio-net.c b/drivers/virtio/virtio-net.c index be2225ce42c..633e6e27598 100644 --- a/drivers/virtio/virtio-net.c +++ b/drivers/virtio/virtio-net.c @@ -31,6 +31,7 @@ #include <stdlib.h> #include <nuttx/compiler.h> +#include <nuttx/nuttx.h> #include <nuttx/kmalloc.h> #include <nuttx/net/ip.h> #include <nuttx/net/netdev_lowerhalf.h> @@ -353,6 +354,70 @@ static void virtio_net_txfree(FAR struct netdev_lowerhalf_s *dev) } } +/**************************************************************************** + * Name: virtio_net_free_vq_buffers + * + * Description: + * Reclaim and free all in-flight RX/TX netpkt buffers still queued in the + * virtqueues. Called after virtio_reset_device() so the device no longer + * accesses the buffers, and before virtio_delete_virtqueues() so the ring + * and virtqueue structures are still valid. + * + * Input Parameters: + * vdev - The virtio device + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void virtio_net_free_vq_buffers(FAR struct virtio_device *vdev) +{ + FAR struct virtio_net_priv_s *priv = vdev->priv; + FAR struct netdev_lowerhalf_s *dev = (FAR struct netdev_lowerhalf_s *)priv; + FAR struct virtio_net_llhdr_s *hdr; + FAR struct virtqueue *vq; + FAR void *buf; + enum netpkt_type_e type; + uint16_t idx; + int i; + + for (i = 0; i < VIRTIO_NET_NUM; i++) + { + vq = vdev->vrings_info[i].vq; + type = (i == VIRTIO_NET_RX) ? NETPKT_RX : NETPKT_TX; + + while (1) + { + hdr = virtqueue_get_buffer_lock(vq, NULL, NULL, + &priv->lock[i]); + if (hdr == NULL) + { + break; + } + + netpkt_free(dev, hdr->pkt, type); + } + + /* virtio_reset_device does not return driver-submitted buffers, so + * reclaim those still queued in the avail ring. + */ + + while (1) + { + buf = virtqueue_get_available_buffer_lock(vq, &idx, NULL, + &priv->lock[i]); + if (buf == NULL) + { + break; + } + + hdr = container_of(buf, struct virtio_net_llhdr_s, vhdr); + netpkt_free(dev, hdr->pkt, type); + } + } +} + /**************************************************************************** * Name: virtio_net_ifup ****************************************************************************/ @@ -754,6 +819,7 @@ static void virtio_net_remove(FAR struct virtio_device *vdev) netdev_lower_unregister((FAR struct netdev_lowerhalf_s *)priv); virtio_reset_device(vdev); + virtio_net_free_vq_buffers(vdev); virtio_delete_virtqueues(vdev); #ifdef CONFIG_DRIVERS_WIFI_SIM g_netdev_num--;
