From: sashiko-bot@kernel.org
To: "Longjun Tang" <lange_tang@163.com>
Cc: virtualization@lists.linux.dev,
"Michael S. Tsirkin" <mst@redhat.com>,
"Eugenio Perez" <eperezma@redhat.com>
Subject: Re: [PATCH 3/3] virtio_net: add rx_timeouts per-queue statistic
Date: Tue, 10 Nov 2026 09:43:54 +0000 [thread overview]
Message-ID: <sashiko-outbox-206799@kernel.org> (raw)
In-Reply-To: <20261109094310.103979-4-lange_tang@163.com>
Thank you for your contribution! Sashiko AI review found 2 potential
issues to consider:
- [Medium] virtio_net: data race and lost rx_timeouts events via
rq->watchdog.stalled
- [Medium] virtio_net: race between virtnet_rx_watchdog() and RX queue
pause/reset
--
commit 4a62fe0fe638e28583b6ebe514a0626f687513ee
Author: Longjun Tang <tanglongjun@kylinos.cn>
virtio_net: add rx_timeouts per-queue statistic
This commit adds an rx_timeouts per-queue RX statistic exposed via ethtool
that is incremented in virtnet_receive() when rq->watchdog.stalled is set.
> diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
> index ec7c248080c57..feb6bfbb1c5a8 100644
> --- a/drivers/net/virtio_net.c
> +++ b/drivers/net/virtio_net.c
[ ... ]
> @@ -2983,6 +2985,12 @@ static int virtnet_receive(struct receive_queue *rq, int budget,
> u64_stats_add(item, u64_stats_read(src));
> }
>
> + /* Count a stall recovered by this poll. */
> + if (rq->watchdog.stalled) {
> + u64_stats_inc(&rq->stats.rx_timeouts);
> + rq->watchdog.stalled = false;
> + }
> +
> u64_stats_add(&rq->stats.packets, u64_stats_read(&stats.packets));
> u64_stats_add(&rq->stats.bytes, u64_stats_read(&stats.bytes));
> u64_stats_add(&rq->stats.alloc_fail, u64_stats_read(&stats.alloc_fail));
[Severity: Medium]
Does passing timeout events through the plain boolean rq->watchdog.stalled
race with virtnet_rx_watchdog() and lose rx_timeouts increments?
CPU0 (timer softirq) CPU1 (NAPI poll)
virtnet_rx_watchdog() virtnet_receive()
if (rq->watchdog.stalled)
u64_stats_inc(&rq->stats.rx_timeouts)
rq->watchdog.stalled = true;
rq->watchdog.stalled = false;
<-- data race / lost timeout
Because virtnet_rx_watchdog() writes rq->watchdog.stalled = true on each
timeout and virtnet_receive() reads and clears it without atomic operations,
concurrent execution triggers a KCSAN data race and can clobber a newly
detected stall. Counting in virtnet_receive() also leaves rx_timeouts at 0
while NAPI remains wedged, collapses multiple watchdog expirations before a
poll into a single increment, loses the count if the device is reopened via
virtnet_rx_watchdog_init_queue() before NAPI runs, and clears stalled even
when virtnet_poll() is called with budget == 0 (such as via netpoll) without
draining packets.
[Severity: Medium]
Can virtnet_rx_watchdog() also race with RX queue pause, resize, and reset?
CPU0 CPU1 (timer softirq)
virtnet_rx_resize() virtnet_rx_watchdog()
virtnet_rx_pause(vi, rq)
virtqueue_resize(rq->vq, ...)
virtqueue_resize_split()
vring_free(&vq->vq)
virtqueue_poll(rq->vq, last_used)
<-- use-after-free / OOB read
virtqueue_vring_attach_split()
commit "virtio_net: introduce an RX queue watchdog for stuck detection"
starts vi->rx_watchdog in virtnet_open() and only stops it in
virtnet_close(), while virtnet_rx_pause() only disables rq->napi and cancels
rq->dim:
drivers/net/virtio_net.c:virtnet_rx_pause() {
bool running = netif_running(vi->dev);
if (running) {
virtnet_napi_disable(rq);
virtnet_cancel_dim(vi, &rq->dim);
}
}
When virtnet_rx_resize() or virtnet_rq_bind_xsk_pool() pauses a queue to
resize or reset rq->vq, virtnet_rx_watchdog() continues polling rq->vq every
second and can read freed vring memory or index past a newly shrunk packed
descriptor ring, or call virtqueue_napi_schedule() while rq->vq is being
reset. Because neither path reinitializes rq->watchdog after resetting
vq->last_used_idx, any rq->watchdog.stalled state left from before the
reset is also consumed by virtnet_receive() on resume and falsely increments
rq->stats.rx_timeouts.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261109094310.103979-1-lange_tang@163.com?part=3
prev parent reply other threads:[~2026-11-10 9:43 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 9:43 [PATCH 0/3] virtio_net: introduce an RX queue watchdog for stuck detection Longjun Tang
2026-11-09 9:43 ` [PATCH 1/3] virtio: add virtqueue_get_last_used_idx() helper Longjun Tang
2026-11-10 9:43 ` sashiko-bot
2026-11-09 9:43 ` [PATCH 2/3] virtio_net: introduce an RX queue watchdog for stuck detection Longjun Tang
2026-11-10 9:43 ` sashiko-bot
2026-11-09 9:43 ` [PATCH 3/3] virtio_net: add rx_timeouts per-queue statistic Longjun Tang
2026-11-10 9:43 ` sashiko-bot [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-206799@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=eperezma@redhat.com \
--cc=lange_tang@163.com \
--cc=mst@redhat.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=virtualization@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox