* [PATCH v2 0/3] virtiofs: hiprio FORGET robustness and no-reply request completion
@ 2026-04-02 10:44 Li Wang
2026-04-02 10:44 ` [PATCH v2 1/3] virtiofs: Complete no-reply virtio requests without parsing the out header Li Wang
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Li Wang @ 2026-04-02 10:44 UTC (permalink / raw)
To: German Maglione, Vivek Goyal, Stefan Hajnoczi, Miklos Szeredi
Cc: Eugenio Pérez, virtualization, linux-fsdevel, linux-kernel,
Li Wang
This series fixes virtiofs completion for FUSE requests that do not use a
reply descriptor, tightens hiprio FORGET handling when virtqueue submission
fails transiently, and prevents the hiprio worker from stalling when one
FORGET must be dropped after an unrecoverable error.
The first patch addresses correctness: completing a no-reply request must
not interpret the reply header fields, otherwise it will cause underflow,
and the bounce buffer allocated for the absent out header must be freed.
The host may complete virtio requests without an out descriptor (e.g.
FUSE_FORGET). The completion path must not run copy_args_from_argbuf(),
which expects a valid fuse_out_header from the reply path. This series also
ensures virtio_fs_verify_response() runs only for real replies (FR_ISREPLY),
and frees req->argbuf on the no-reply path to avoid a per-request leak.
Changes since v1
------------------------------
Patch 1: v1 only guarded copy_args_from_argbuf() with FR_ISREPLY. v2 also
kfree(req->argbuf) when !FR_ISREPLY (the buffer was allocated in
copy_args_to_argbuf for an out header that never arrives), and gates
virtio_fs_verify_response() in virtio_fs_requests_done_work() on FR_ISREPLY
so uninitialized fuse_out_header is never verified.
Patch 2: behavior matches v1. The commit message is expanded to explain
transient GFP_ATOMIC exhaustion and why dropping the FORGET would skew
nlookup and leak kernel state.
Patch 3: behavior matches v1. The commit message documents the
return-value contract with virtio_fs_hiprio_dispatch_work() and the stall
risk on the nonzero path.
Commit messages were rewritten for clearer rationale.
Li Wang (3):
virtiofs: Complete no-reply virtio requests without parsing the out
header
virtiofs: Retry hiprio FORGET when virtqueue_add_outbuf() returns
-ENOMEM
virtiofs: Do not stall hiprio FORGET dispatch after dropping one
request
fs/fuse/virtio_fs.c | 37 +++++++++++++++++++++++++++++--------
1 file changed, 29 insertions(+), 8 deletions(-)
--
2.34.1
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/3] virtiofs: Complete no-reply virtio requests without parsing the out header
2026-04-02 10:44 [PATCH v2 0/3] virtiofs: hiprio FORGET robustness and no-reply request completion Li Wang
@ 2026-04-02 10:44 ` Li Wang
2026-04-02 10:44 ` [PATCH v2 2/3] virtiofs: Retry hiprio FORGET when virtqueue_add_outbuf() returns -ENOMEM Li Wang
2026-04-02 10:44 ` [PATCH v2 3/3] virtiofs: Do not stall hiprio FORGET dispatch after dropping one request Li Wang
2 siblings, 0 replies; 4+ messages in thread
From: Li Wang @ 2026-04-02 10:44 UTC (permalink / raw)
To: German Maglione, Vivek Goyal, Stefan Hajnoczi, Miklos Szeredi
Cc: Eugenio Pérez, virtualization, linux-fsdevel, linux-kernel,
Li Wang
FUSE requests that do not set FR_ISREPLY never map fuse_out_header or reply
payload into the virtqueue in virtio_fs_enqueue_req(). For example,
for the FORGET requests sent in fuse_force_forget(), req->out.h.len is
initialized to 0 in fuse_request_alloc(). On completion, copy_args_from_argbuf()
must not run: it subtracts sizeof(fuse_out_header) from req->out.h.len,
which will cause an underflow.
Always free the bounce buffer allocated by copy_args_to_argbuf() on the
no-reply path so virtio_fs_enqueue_req() does not leak argbuf.
In virtio_fs_requests_done_work(), only call virtio_fs_verify_response()
when FR_ISREPLY is set.
Signed-off-by: Li Wang <liwang@kylinos.cn>
---
fs/fuse/virtio_fs.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c
index 2f7485ffac52..670dd413873b 100644
--- a/fs/fuse/virtio_fs.c
+++ b/fs/fuse/virtio_fs.c
@@ -789,7 +789,13 @@ static void virtio_fs_request_complete(struct fuse_req *req,
struct folio *folio;
args = req->args;
- copy_args_from_argbuf(args, req);
+ if (test_bit(FR_ISREPLY, &req->flags))
+ copy_args_from_argbuf(args, req);
+ else if (req->argbuf) {
+ /* Bounce buffer from virtio_fs_enqueue_req(); no reply payload to copy */
+ kfree(req->argbuf);
+ req->argbuf = NULL;
+ }
if (args->out_pages && args->page_zeroing) {
len = args->out_args[args->out_numargs - 1].size;
@@ -841,9 +847,11 @@ static void virtio_fs_requests_done_work(struct work_struct *work)
virtqueue_disable_cb(vq);
while ((req = virtqueue_get_buf(vq, &len)) != NULL) {
- if (!virtio_fs_verify_response(req, len)) {
- req->out.h.error = -EIO;
- req->out.h.len = sizeof(struct fuse_out_header);
+ if (test_bit(FR_ISREPLY, &req->flags)) {
+ if (!virtio_fs_verify_response(req, len)) {
+ req->out.h.error = -EIO;
+ req->out.h.len = sizeof(struct fuse_out_header);
+ }
}
spin_lock(&fpq->lock);
list_move_tail(&req->list, &reqs);
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 2/3] virtiofs: Retry hiprio FORGET when virtqueue_add_outbuf() returns -ENOMEM
2026-04-02 10:44 [PATCH v2 0/3] virtiofs: hiprio FORGET robustness and no-reply request completion Li Wang
2026-04-02 10:44 ` [PATCH v2 1/3] virtiofs: Complete no-reply virtio requests without parsing the out header Li Wang
@ 2026-04-02 10:44 ` Li Wang
2026-04-02 10:44 ` [PATCH v2 3/3] virtiofs: Do not stall hiprio FORGET dispatch after dropping one request Li Wang
2 siblings, 0 replies; 4+ messages in thread
From: Li Wang @ 2026-04-02 10:44 UTC (permalink / raw)
To: German Maglione, Vivek Goyal, Stefan Hajnoczi, Miklos Szeredi
Cc: Eugenio Pérez, virtualization, linux-fsdevel, linux-kernel,
Li Wang
The -ENOMEM from virtqueue_add_outbuf() under GFP_ATOMIC is typically transient.
Queue the FORGET on queued_reqs and return 1 so the hiprio worker backs off and
retries instead of dropping the forget.
This matches the existing -ENOSPC handling and avoids silent loss of
nlookup decrements under memory pressure.
Signed-off-by: Li Wang <liwang@kylinos.cn>
---
fs/fuse/virtio_fs.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c
index bcba1210c797..7e4c3fa6ab57 100644
--- a/fs/fuse/virtio_fs.c
+++ b/fs/fuse/virtio_fs.c
@@ -611,8 +611,8 @@ static void virtio_fs_request_dispatch_work(struct work_struct *work)
}
/*
- * Returns 1 if queue is full and sender should wait a bit before sending
- * next request, 0 otherwise.
+ * Returns 1 if the hiprio queue is full or transient allocation failed and
+ * the caller should wait before submitting the next FORGET, 0 otherwise.
*/
static int send_forget_request(struct virtio_fs_vq *fsvq,
struct virtio_fs_forget *forget,
@@ -638,13 +638,13 @@ static int send_forget_request(struct virtio_fs_vq *fsvq,
ret = virtqueue_add_outbuf(vq, &sg, 1, forget, GFP_ATOMIC);
if (ret < 0) {
- if (ret == -ENOSPC) {
+ if (ret == -ENOSPC || ret == -ENOMEM) {
pr_debug("virtio-fs: Could not queue FORGET: err=%d. Will try later\n",
ret);
list_add_tail(&forget->list, &fsvq->queued_reqs);
if (!in_flight)
inc_in_flight_req(fsvq);
- /* Queue is full */
+ /* Queue full or GFP_ATOMIC allocation failure; retry later */
ret = 1;
} else {
pr_debug("virtio-fs: Could not queue FORGET: err=%d. Dropping it.\n",
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] virtiofs: Do not stall hiprio FORGET dispatch after dropping one request
2026-04-02 10:44 [PATCH v2 0/3] virtiofs: hiprio FORGET robustness and no-reply request completion Li Wang
2026-04-02 10:44 ` [PATCH v2 1/3] virtiofs: Complete no-reply virtio requests without parsing the out header Li Wang
2026-04-02 10:44 ` [PATCH v2 2/3] virtiofs: Retry hiprio FORGET when virtqueue_add_outbuf() returns -ENOMEM Li Wang
@ 2026-04-02 10:44 ` Li Wang
2 siblings, 0 replies; 4+ messages in thread
From: Li Wang @ 2026-04-02 10:44 UTC (permalink / raw)
To: German Maglione, Vivek Goyal, Stefan Hajnoczi, Miklos Szeredi
Cc: Eugenio Pérez, virtualization, linux-fsdevel, linux-kernel,
Li Wang
send_forget_request() documents return value 1 as caller should wait;
virtio_fs_hiprio_dispatch_work() treats any non-zero return as a signal to
stop processing the rest of queued_reqs.
When virtqueue_add_outbuf() fails with a non-recoverable error we kfree the
forget but left ret negative, so the worker returned early and stranded
subsequent queued FORGETs. Return 0 after dropping so the queue keeps
draining.
Signed-off-by: Li Wang <liwang@kylinos.cn>
---
fs/fuse/virtio_fs.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/fs/fuse/virtio_fs.c b/fs/fuse/virtio_fs.c
index 7e4c3fa6ab57..e5d3d58a760c 100644
--- a/fs/fuse/virtio_fs.c
+++ b/fs/fuse/virtio_fs.c
@@ -652,6 +652,12 @@ static int send_forget_request(struct virtio_fs_vq *fsvq,
kfree(forget);
if (in_flight)
dec_in_flight_req(fsvq);
+ /*
+ * send_forget_request() returns 1 to mean "stop draining
+ * queued_reqs for now". A negative value is also non-zero
+ * and would stall the worker after one dropped forget.
+ */
+ ret = 0;
}
goto out;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-04-02 10:44 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-02 10:44 [PATCH v2 0/3] virtiofs: hiprio FORGET robustness and no-reply request completion Li Wang
2026-04-02 10:44 ` [PATCH v2 1/3] virtiofs: Complete no-reply virtio requests without parsing the out header Li Wang
2026-04-02 10:44 ` [PATCH v2 2/3] virtiofs: Retry hiprio FORGET when virtqueue_add_outbuf() returns -ENOMEM Li Wang
2026-04-02 10:44 ` [PATCH v2 3/3] virtiofs: Do not stall hiprio FORGET dispatch after dropping one request Li Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox