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--;

Reply via email to