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 45025e2d2119d0273e6aac475ec6bdb094a7bec7
Author: dengwenqi <[email protected]>
AuthorDate: Thu Aug 27 19:17:03 2026 +0800

    drivers/virtio-net: free RX buffers on ifdown
    
    virtio_net_ifdown() only disabled the callbacks and left the RX buffers
    filled by virtio_net_rxfill() queued in the virtqueue, so they stayed
    allocated while the interface was down.  Drain the RX and TX virtqueues
    on ifdown.
    
    Also free the netpkt when virtio_net_rxfill() fails to add it to the
    virtqueue; it was lost before.
    
    Signed-off-by: dengwenqi <[email protected]>
---
 drivers/virtio/virtio-net.c | 29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/drivers/virtio/virtio-net.c b/drivers/virtio/virtio-net.c
index d40a0932dfd..be2225ce42c 100644
--- a/drivers/virtio/virtio-net.c
+++ b/drivers/virtio/virtio-net.c
@@ -313,7 +313,12 @@ static void virtio_net_rxfill(FAR struct 
netdev_lowerhalf_s *dev)
 
       /* Add buffer to RX virtqueue */
 
-      virtio_net_addbuffer(dev, vq, pkt, VIRTIO_NET_RX);
+      if (virtio_net_addbuffer(dev, vq, pkt, VIRTIO_NET_RX) < 0)
+        {
+          vrterr("Failed to add buffer to RX virtqueue, i=%d\n", i);
+          netpkt_free(dev, pkt, NETPKT_RX);
+          break;
+        }
     }
 
   if (i > 0)
@@ -392,6 +397,8 @@ static int virtio_net_ifup(FAR struct netdev_lowerhalf_s 
*dev)
 static int virtio_net_ifdown(FAR struct netdev_lowerhalf_s *dev)
 {
   FAR struct virtio_net_priv_s *priv = (FAR struct virtio_net_priv_s *)dev;
+  FAR struct virtqueue *vq = priv->vdev->vrings_info[VIRTIO_NET_RX].vq;
+  FAR struct virtio_net_llhdr_s *hdr;
   int i;
 
   /* Disable the Ethernet interrupt */
@@ -402,6 +409,26 @@ static int virtio_net_ifdown(FAR struct netdev_lowerhalf_s 
*dev)
                                 &priv->lock[i]);
     }
 
+  /* Drain RX virtqueue to free netpkt buffers that are still queued
+   * but not yet consumed.
+   */
+
+  while (1)
+    {
+      hdr = virtqueue_get_buffer_lock(vq, NULL, NULL,
+                                      &priv->lock[VIRTIO_NET_RX]);
+      if (hdr == NULL)
+        {
+          break;
+        }
+
+      netpkt_free(dev, hdr->pkt, NETPKT_RX);
+    }
+
+  /* Drain TX virtqueue as well */
+
+  virtio_net_txfree(dev);
+
 #ifdef CONFIG_DRIVERS_WIFI_SIM
   if (priv->lower.wifi)
     {

Reply via email to