Skip to content

[drivers][virtio] Fix RX buffer leak on pbuf allocation failure - #11726

Open
Zepp-Hanzj wants to merge 1 commit into
RT-Thread:masterfrom
Zepp-Hanzj:agent/fix-virtio-net-rx-pbuf-leak
Open

[drivers][virtio] Fix RX buffer leak on pbuf allocation failure#11726
Zepp-Hanzj wants to merge 1 commit into
RT-Thread:masterfrom
Zepp-Hanzj:agent/fix-virtio-net-rx-pbuf-leak

Conversation

@Zepp-Hanzj

Copy link
Copy Markdown
Contributor

Description / 描述

Fix a receive buffer leak in virtio_net_rx(): when pbuf_alloc() fails, the buffer already read from the virtqueue used ring is not returned to the available ring, permanently losing that RX slot.

修复 virtio_net_rx() 中的接收缓冲泄漏:当 pbuf_alloc() 失败时,已从 virtqueue used ring 读出的 buffer 未归还到 available ring,导致该接收槽位永久丢失。

Why / 为什么需要

In virtio_net_rx(), after rt_virtqueue_read_buf() consumes a buffer (vq->num_free++ but the buffer is not yet re-queued), the code unlocks and calls pbuf_alloc(). On failure the original code simply return RT_NULL without calling rt_virtqueue_add_inbuf() to return the buffer. Repeated OOM eventually exhausts the RX queue.

The success path re-acquires the lock and returns the buffer via rt_virtqueue_add_inbuf() + rt_virtqueue_kick(); the failure path was missing this symmetric cleanup.

virtio_net_rx() 中,rt_virtqueue_read_buf() 消费 buffer 后(vq->num_free++ 但 buffer 尚未重新入队),代码解锁并调用 pbuf_alloc()。失败时原代码直接 return RT_NULL,未调用 rt_virtqueue_add_inbuf() 归还 buffer。反复 OOM 会逐步耗尽接收队列。成功路径会重新加锁并通过 rt_virtqueue_add_inbuf() + rt_virtqueue_kick() 归还 buffer,失败路径缺失了这个对称清理。

How / 修改了哪些文件

  • components/drivers/virtio/virtio-net.c: in the pbuf_alloc() failure branch, re-acquire rx_lock, mirror the success path's rt_virtqueue_poll / rt_list_remove / rt_virtqueue_add_inbuf / rt_virtqueue_kick sequence before returning RT_NULL.

@github-actions

Copy link
Copy Markdown

👋 感谢您对 RT-Thread 的贡献!Thank you for your contribution to RT-Thread!

为确保代码符合 RT-Thread 的编码规范,请在你的仓库中执行以下步骤运行代码格式化工作流(如果格式化CI运行失败)。
To ensure your code complies with RT-Thread's coding style, please run the code formatting workflow by following the steps below (If the formatting of CI fails to run).


🛠 操作步骤 | Steps

  1. 前往 Actions 页面 | Go to the Actions page
    点击进入工作流 → | Click to open workflow →

  2. 点击 Run workflow | Click Run workflow

  • Use workflow from 保持默认分支(通常为 master
    Keep the default branch (usually master) in Use workflow from
  • branch 输入框填写 PR 分支 agent/fix-virtio-net-rx-pbuf-leak
    Enter PR branch agent/fix-virtio-net-rx-pbuf-leak in the branch field
  • 设置需排除的文件/目录(目录请以"/"结尾)
    Set files/directories to exclude (directories should end with "/")
  1. 等待工作流完成 | Wait for the workflow to complete
    格式化后的代码将作为独立提交推送至你的分支。
    The formatting changes will be pushed to your branch as a separate commit.

完成后,提交将自动更新至 agent/fix-virtio-net-rx-pbuf-leak 分支,关联的 Pull Request 也会同步更新。
Once completed, commits will be pushed to the agent/fix-virtio-net-rx-pbuf-leak branch automatically, and the related Pull Request will be updated.

如有问题欢迎联系我们,再次感谢您的贡献!💐
If you have any questions, feel free to reach out. Thanks again for your contribution!

@github-actions

Copy link
Copy Markdown

📌 Code Review Assignment

🏷️ Tag: components

Reviewers: @Maihuanyi

Changed Files (Click to expand)
  • components/drivers/virtio/virtio-net.c

📊 Current Review Status (Last Updated: 2026-08-20 22:50 CST)


📝 Review Instructions

  1. 维护者可以通过单击此处来刷新审查状态: 🔄 刷新状态
    Maintainers can refresh the review status by clicking here: 🔄 Refresh Status

  2. 确认审核通过后评论 LGTM/lgtm
    Comment LGTM/lgtm after confirming approval

  3. PR合并前需至少一位维护者确认
    PR must be confirmed by at least one maintainer before merging

ℹ️ 刷新CI状态操作需要具备仓库写入权限。
ℹ️ Refresh CI status operation requires repository Write permission.

@GuEe-GUI

Copy link
Copy Markdown
Contributor

也就是放弃这个包的接收是吧?

@Zepp-Hanzj

Copy link
Copy Markdown
Contributor Author

是的,理解正确。

pbuf_alloc() 失败(OOM)时系统没有内存容纳该数据包,只能丢弃(返回 RT_NULL)——这是 OOM 下唯一的选择。

但本修复的关键在于:把已经通过 rt_virtqueue_read_buf() 从 used ring 读出的 buffer,通过 rt_virtqueue_add_inbuf() 归还到 available ring。原代码在失败路径直接 return RT_NULL,缺失了这段归还逻辑,反复 OOM 会逐步耗尽 RX 队列——这才是泄漏的根源。成功路径的清理逻辑保持不变,本改动只是补齐了失败路径的对称清理。


Yes, that's correct.

When pbuf_alloc() fails (OOM), there is no memory to hold the packet, so dropping it (returning RT_NULL) is the only option.

The key point of this fix is returning the buffer already consumed from the used ring back to the available ring via rt_virtqueue_add_inbuf(). The original code simply return RT_NULL on the failure path, missing this re-queue, so repeated OOM would gradually exhaust the RX queue — that is the actual leak. The success path's cleanup logic is unchanged; this change only adds the symmetric cleanup on the failure path.

@GuEe-GUI

Copy link
Copy Markdown
Contributor

是的,感谢修复

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants