From: sashiko-bot@kernel.org
To: Qihang <q.h.hack.winter@gmail.com>
Cc: virtualization@lists.linux.dev,
"Michael S. Tsirkin" <mst@redhat.com>,
"Eugenio Perez" <eperezma@redhat.com>
Subject: Re: [PATCH v3] fuse: virtio-fs: stop new requests before draining queues
Date: Mon, 09 Nov 2026 03:16:33 +0000 [thread overview]
Message-ID: <sashiko-outbox-204365@kernel.org> (raw)
In-Reply-To: <20261109023957.34500-1-q.h.hack.winter@gmail.com>
Thank you for your contribution! Sashiko AI review found 1 potential
issue to consider:
- [Medium] fuse: virtio-fs: hang in virtio_fs_drain_queue() on stranded
queued_reqs
--
commit 01cb846c58c4f5ed59cf9d9ee391ec0c2e114c82
Author: Qihang <q.h.hack.winter@gmail.com>
fuse: virtio-fs: stop new requests before draining queues
This commit adds a per-virtqueue aborting flag to reject new requests
(other than FUSE_DESTROY) before draining queues during teardown, and
offloads blocking request end callbacks from the dispatch worker.
> diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c
> index ba8d79c4bcac6..a46536c9fdc8e 100644
> --- a/fs/fuse/virtio_fs.c
> +++ b/fs/fuse/virtio_fs.c
[ ... ]
> @@ -593,9 +633,17 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work)
> if (ret < 0) {
> if (ret == -ENOSPC) {
> spin_lock(&fsvq->lock);
> - list_add_tail(&req->list, &fsvq->queued_reqs);
> - spin_unlock(&fsvq->lock);
> - return;
> + if (!fsvq->connected ||
> + (fsvq->aborting &&
> + req->in.h.opcode != FUSE_DESTROY)) {
> + spin_unlock(&fsvq->lock);
> + ret = -ENOTCONN;
> + } else {
> + list_add_tail(&req->list,
> + &fsvq->queued_reqs);
> + spin_unlock(&fsvq->lock);
> + return;
> + }
> }
[ ... ]
> @@ -1226,6 +1274,28 @@ static void virtio_fs_stop_all_queues(struct virtio_fs *fs)
> }
> }
>
> +/*
> + * Stop admitting new requests before draining the queues. Admission and
> + * virtqueue submission are serialized by fsvq->lock, so a request is
> + * either rejected before reaching the device or accounted in in_flight
> + * and covered by the drain.
> + *
> + * FUSE_DESTROY is exempt because fuse_conn_destroy() sends it after the
> + * first drain and waits for its completion before aborting the channel.
> + */
> +static void virtio_fs_stop_new_requests(struct virtio_fs *fs)
> +{
> + struct virtio_fs_vq *fsvq;
> + int i;
> +
> + for (i = 0; i < fs->nvqs; i++) {
> + fsvq = &fs->vqs[i];
> + spin_lock(&fsvq->lock);
> + fsvq->aborting = true;
> + spin_unlock(&fsvq->lock);
> + }
> +}
[ ... ]
> @@ -1551,12 +1622,22 @@ static void virtio_fs_send_req(struct fuse_iqueue *fiq, struct fuse_req *req)
> /*
> * Virtqueue full. Retry submission from worker
> * context as we might be holding fc->chan->bg_lock.
> + * Re-check admission under the same lock that
> + * increments in_flight: teardown may have started
> + * between enqueue_req() dropping its lock and here.
> */
> spin_lock(&fsvq->lock);
> - list_add_tail(&req->list, &fsvq->queued_reqs);
> - inc_in_flight_req(fsvq);
> - spin_unlock(&fsvq->lock);
> - return;
> + if (!fsvq->connected ||
> + (fsvq->aborting &&
> + req->in.h.opcode != FUSE_DESTROY)) {
> + spin_unlock(&fsvq->lock);
> + ret = -ENOTCONN;
> + } else {
> + list_add_tail(&req->list, &fsvq->queued_reqs);
> + inc_in_flight_req(fsvq);
> + spin_unlock(&fsvq->lock);
> + return;
> + }
> }
[Severity: Medium]
Can a request added to fsvq->queued_reqs on -ENOSPC still be stranded with
fsvq->in_flight > 0 and hang virtio_fs_drain_queue()?
virtio_fs_enqueue_req() drops fsvq->lock before returning -ENOSPC, and
neither virtio_fs_send_req() nor virtio_fs_request_dispatch_work()
schedules fsvq->dispatch_work when placing req on fsvq->queued_reqs; they
rely on virtio_fs_requests_done_work() seeing a non-empty queued_reqs when
in-flight virtqueue requests complete.
If the virtqueue drains during the window where fsvq->lock is dropped,
and the caller then re-acquires fsvq->lock before teardown sets
fsvq->aborting, nothing kicks fsvq->dispatch_work:
CPU0 CPU1 (kworker)
virtio_fs_send_req()
virtio_fs_enqueue_req()
spin_lock(&fsvq->lock)
virtqueue_add_sgs() -> -ENOSPC
spin_unlock(&fsvq->lock)
virtio_fs_requests_done_work()
spin_lock(&fsvq->lock)
/* drains all vq buffers */
!list_empty(&fsvq->queued_reqs) -> false
spin_unlock(&fsvq->lock)
spin_lock(&fsvq->lock)
/* connected && !aborting */
list_add_tail(..., &fsvq->queued_reqs)
inc_in_flight_req(fsvq)
spin_unlock(&fsvq->lock)
When virtio_fs_conn_destroy() then runs virtio_fs_stop_new_requests() and
virtio_fs_drain_all_queues(), fsvq->vq is already empty so
virtio_fs_requests_done_work() never runs again, and virtio_fs_drain_queue()
waits forever in wait_for_completion(&fsvq->in_flight_zero) before
reaching flush_work(&fsvq->dispatch_work). (The same window exists in
virtio_fs_request_dispatch_work() after it removes req from queued_reqs,
and against virtio_fs_stop_all_queues() in virtio_fs_remove().)
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261109023957.34500-1-q.h.hack.winter@gmail.com?part=1
next prev parent reply other threads:[~2026-11-09 3:16 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-09 2:39 [PATCH v3] fuse: virtio-fs: stop new requests before draining queues Qihang
2026-11-09 3:16 ` sashiko-bot [this message]
2026-11-12 3:09 ` Li Wang
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-204365@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=eperezma@redhat.com \
--cc=mst@redhat.com \
--cc=q.h.hack.winter@gmail.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.