All Virtuozzo development lists (kernel + QEMU)
 help / color / mirror / Atom feed
From: Liu Kui <kui.liu@virtuozzo.com>
To: Konstantin Khorenko <khorenko@virtuozzo.com>
Cc: azaitsev@virtuozzo.com, devel@openvz.org,
	Liu Kui <kui.liu@virtuozzo.com>
Subject: [Devel] [PATCH hci-8.0] fs/fuse: fix fuse file refcount leak on close_wait writeback
Date: Tue, 22 Sep 2026 21:53:40 +0800	[thread overview]
Message-ID: <20260922-vstor-145614-v1-1-e14dd025e85a@virtuozzo.com> (raw)

Mainline commit 4046d3adcca4 ("fuse: move fuse file initialization to
wpa allocation time") moved acquisition of the wpa's fuse file
reference from submit time (fuse_writepages_send) to wpa allocation
time, and compensated by dropping the reference unconditionally in
fuse_writepage_free().

This breaks the close_wait accounting in the vz tree, which splits the
drop between two functions: fuse_writepage_finish() does
__fuse_file_put() for close_wait (allowing fuse_release() to pass
wait_event(ff->count == 1)), while fuse_writepage_free() puts the
reference only for !close_wait. This split requires that every wpa
owning a reference passes through fuse_writepage_finish() before being
freed. Two paths free a wpa without calling it:

  - fuse_writepage_add(): temp page swap case frees the new wpa
  - fuse_send_writepage(): out_free path frees the aux request chain

Before that commit these paths only ever saw wpas with ia.ff == NULL
(never submitted or promoted), so nothing leaked. After it, every wpa
owns a reference from birth, and on close_wait mounts both paths leak
it: ff->count never returns to 1, fuse_release() hangs forever in
wait_event(), and the fuse file and its FUSE_RELEASE are leaked.

Fix it by reverting to the old ownership model for the writeback path:
a wpa is allocated with ia.ff = NULL and acquires the reference at
submit time (fuse_writepages_send, fuse_writepage_locked) or at aux
promotion time (fuse_writepage_end). Also make fuse_writepage_free()
derive fuse_conn from wpa->inode since ia.ff may now legitimately be
NULL there.

Note: this is effectively a revert of the mainline change for the
writeback path. It can be restored later on a rework of the close_wait
accounting (e.g. dropping the finish/free split in favour of an
unconditional put).

https://virtuozzo.atlassian.net/browse/VSTOR-145614

Signed-off-by: Liu Kui <kui.liu@virtuozzo.com>
---
Fix a fuse file refcount leak on close_wait mounts introduced by the
rebase to mainline commit 4046d3adcca4 ("fuse: move fuse file
initialization to wpa allocation time"): wpas freed without going
through fuse_writepage_finish() (aux temp-page swap, killed aux chains)
now own a reference nobody drops, so fuse_release() hangs forever in
wait_event(ff->count == 1). Restore the old ownership model (reference
acquired at submit/promotion time) for the writeback path.

https://virtuozzo.atlassian.net/browse/VSTOR-145614
---
 fs/fuse/file.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 180f60fc539a..50d3f8186d39 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2181,7 +2181,7 @@ static ssize_t fuse_splice_write(struct pipe_inode_info *pipe, struct file *out,
 static void fuse_writepage_free(struct fuse_writepage_args *wpa)
 {
 	struct fuse_args_pages *ap = &wpa->ia.ap;
-	struct fuse_conn *fc = wpa->ia.ff->fm->fc;
+	struct fuse_conn *fc = get_fuse_conn(wpa->inode);
 	int i;
 
 	if (wpa->bucket)
@@ -2374,6 +2374,7 @@ static void fuse_writepage_end(struct fuse_mount *fm, struct fuse_args *args,
 
 		wpa->next = next->next;
 		next->next = NULL;
+		next->ia.ff = fuse_file_get(wpa->ia.ff);
 		tree_insert(&fi->writepages, next);
 
 		/*
@@ -2523,7 +2524,7 @@ static struct fuse_writepage_args *fuse_writepage_args_setup(struct folio *folio
 	fuse_write_args_fill(&wpa->ia, ff, inode, folio_pos(folio), 0);
 	wpa->ia.write.in.write_flags |= FUSE_WRITE_CACHE;
 	wpa->inode = inode;
-	wpa->ia.ff = ff;
+	wpa->ia.ff = NULL;
 
 	ap = &wpa->ia.ap;
 	ap->args.in_pages = true;
@@ -2561,6 +2562,7 @@ static int fuse_writepage_locked(struct folio *folio)
 	if (!wpa)
 		goto err_writepage_args;
 
+	wpa->ia.ff = ff;
 	ap = &wpa->ia.ap;
 	ap->num_pages = 1;
 
@@ -2628,6 +2630,7 @@ static void fuse_writepages_send(struct fuse_fill_wb_data *data)
 	int num_pages = wpa->ia.ap.num_pages;
 	int i;
 
+	wpa->ia.ff = fuse_file_get(data->ff);
 	spin_lock(&fi->lock);
 	list_add_tail(&wpa->queue_entry, &fi->queued_writes);
 	fuse_flush_writepages(inode);
@@ -2791,7 +2794,6 @@ static int fuse_writepages_fill(struct folio *folio,
 			folio_redirty_for_writepage(wbc, folio);
 			goto out_unlock;
 		}
-		fuse_file_get(wpa->ia.ff);
 		data->max_pages = 1;
 		ap = &wpa->ia.ap;
 

---
base-commit: 978369605ab89b48b86d12af9f8dda88689ed5ca
change-id: 20260922-vstor-145614-10a4ac579905

Best regards,
--  
Liu Kui <kui.liu@virtuozzo.com>

_______________________________________________
Devel mailing list
Devel@openvz.org
https://lists.openvz.org/mailman/listinfo/devel

             reply	other threads:[~2026-09-22 13:55 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-22 13:53 Liu Kui [this message]
2026-09-22 15:37 ` Konstantin Khorenko
2026-09-22 15:54 ` Konstantin Khorenko
2026-09-22 18:54 ` Konstantin Khorenko

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=20260922-vstor-145614-v1-1-e14dd025e85a@virtuozzo.com \
    --to=kui.liu@virtuozzo.com \
    --cc=azaitsev@virtuozzo.com \
    --cc=devel@openvz.org \
    --cc=khorenko@virtuozzo.com \
    /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.