OpenVZ / Virtuozzo kernel development (devel@openvz.org)
 help / color / mirror / Atom feed
* [Devel] [PATCH hci-8.0 0/2] fs/fuse: unify dropping the fuse file reference of a writeback request
@ 2026-09-23 12:50 Liu Kui
  2026-09-23 12:50 ` [Devel] [PATCH hci-8.0 1/2] Revert "fs/fuse: fix fuse file refcount leak on close_wait writeback" Liu Kui
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Liu Kui @ 2026-09-23 12:50 UTC (permalink / raw)
  To: Konstantin Khorenko; +Cc: azaitsev, devel, Liu Kui

Rework the fix for the fuse file refcount leak on close_wait writeback
(VSTOR-145614): revert the previous fix, which moved the wpa's
reference acquisition back to submit time, and instead drop the
reference unconditionally in fuse_writepage_free(), which every wpa
death path passes exactly once. This keeps the allocation-time
ownership model of mainline commit 4046d3adcca4 ("fuse: move fuse file
initialization to wpa allocation time") unmodified.

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

---
Liu Kui (2):
      Revert "fs/fuse: fix fuse file refcount leak on close_wait writeback"
      fs/fuse: unify dropping the fuse file reference of a writeback request

 fs/fuse/file.c | 14 +++-----------
 1 file changed, 3 insertions(+), 11 deletions(-)
---
base-commit: f2a619dddfc50f37d3255d68a33b78bbae2d65ad
change-id: 20260923-vstor-145614-unify-d7c8392ff890

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

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Devel] [PATCH hci-8.0 1/2] Revert "fs/fuse: fix fuse file refcount leak on close_wait writeback"
  2026-09-23 12:50 [Devel] [PATCH hci-8.0 0/2] fs/fuse: unify dropping the fuse file reference of a writeback request Liu Kui
@ 2026-09-23 12:50 ` Liu Kui
  2026-09-23 12:50 ` [Devel] [PATCH hci-8.0 2/2] fs/fuse: unify dropping the fuse file reference of a writeback request Liu Kui
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Liu Kui @ 2026-09-23 12:50 UTC (permalink / raw)
  To: Konstantin Khorenko; +Cc: azaitsev, devel, Liu Kui

This reverts commit 4c648a077765fdb61aa1298ecb8205b629411fed.

The fix addressed the fuse file refcount leak on close_wait writeback
by moving the wpa's reference acquisition from allocation time back to
submit/promotion time, so that wpas freed without passing through
fuse_writepage_finish() own no reference. Revert it in favor of the
following patch, which fixes the leak while keeping the allocation-time
ownership model of mainline commit 4046d3adcca4 ("fuse: move fuse file
initialization to wpa allocation time") unmodified.

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

Signed-off-by: Liu Kui <kui.liu@virtuozzo.com>
---
 fs/fuse/file.c | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 50d3f8186d39..180f60fc539a 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 = get_fuse_conn(wpa->inode);
+	struct fuse_conn *fc = wpa->ia.ff->fm->fc;
 	int i;
 
 	if (wpa->bucket)
@@ -2374,7 +2374,6 @@ 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);
 
 		/*
@@ -2524,7 +2523,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 = NULL;
+	wpa->ia.ff = ff;
 
 	ap = &wpa->ia.ap;
 	ap->args.in_pages = true;
@@ -2562,7 +2561,6 @@ 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;
 
@@ -2630,7 +2628,6 @@ 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);
@@ -2794,6 +2791,7 @@ 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;
 

-- 
Git-155)

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Devel] [PATCH hci-8.0 2/2] fs/fuse: unify dropping the fuse file reference of a writeback request
  2026-09-23 12:50 [Devel] [PATCH hci-8.0 0/2] fs/fuse: unify dropping the fuse file reference of a writeback request Liu Kui
  2026-09-23 12:50 ` [Devel] [PATCH hci-8.0 1/2] Revert "fs/fuse: fix fuse file refcount leak on close_wait writeback" Liu Kui
@ 2026-09-23 12:50 ` Liu Kui
  2026-09-23 17:26   ` Konstantin Khorenko
  2026-09-23 17:01 ` [Devel] [PATCH hci-8.0 0/2] " Konstantin Khorenko
  2026-09-23 17:13 ` Konstantin Khorenko
  3 siblings, 1 reply; 6+ messages in thread
From: Liu Kui @ 2026-09-23 12:50 UTC (permalink / raw)
  To: Konstantin Khorenko; +Cc: azaitsev, devel, Liu Kui

The drop of the wpa's fuse file reference is split between two
functions: fuse_writepage_finish() puts it on close_wait mounts,
fuse_writepage_free() on !close_wait ones. The split requires that
every wpa owning a reference passes through fuse_writepage_finish()
before being freed on close_wait, an invariant silently broken by the
rebase to mainline commit 4046d3adcca4 ("fuse: move fuse file
initialization to wpa allocation time"), which makes every wpa own its
reference from allocation time. Then there are two cases where wpas
are freed without going through fuse_writepage_finish(): the temp page
swap case in fuse_writepage_add() and the killed aux request chain in
fuse_send_writepage(), leaking ff->count, so fuse_release() can hang
forever waiting for ff->count to drain.

Fix the leak by dropping the split: release the reference
unconditionally in fuse_writepage_free(), which every wpa death path
passes exactly once, via fuse_release_ff(), which already handles the
close_wait accounting. The allocation-time ownership model of the
mainline commit stays unmodified, which additionally keeps an aux
wpa's args->ff pinned between creation and promotion.

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

Signed-off-by: Liu Kui <kui.liu@virtuozzo.com>
---
 fs/fuse/file.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 180f60fc539a..0a7c6d03b13d 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2181,7 +2181,6 @@ 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;
 	int i;
 
 	if (wpa->bucket)
@@ -2190,8 +2189,7 @@ static void fuse_writepage_free(struct fuse_writepage_args *wpa)
 	for (i = 0; i < ap->num_pages; i++)
 		__free_page(ap->pages[i]);
 
-	if (wpa->ia.ff && !fc->close_wait)
-		fuse_file_put(wpa->ia.ff, false);
+	fuse_release_ff(wpa->inode, wpa->ia.ff);
 
 	kfree(ap->pages);
 	kfree(wpa);
@@ -2211,12 +2209,8 @@ static void fuse_writepage_finish(struct fuse_writepage_args *wpa)
 	struct fuse_args_pages *ap = &wpa->ia.ap;
 	struct inode *inode = wpa->inode;
 	struct fuse_inode *fi = get_fuse_inode(inode);
-	struct fuse_conn *fc = get_fuse_conn(inode);
 	int i;
 
-	if (wpa->ia.ff && fc->close_wait)
-		__fuse_file_put(wpa->ia.ff);
-
 	for (i = 0; i < ap->num_pages; i++)
 		fuse_writepage_finish_stat(inode, ap->pages[i]);
 

-- 
Git-155)

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Devel] [PATCH hci-8.0 0/2] fs/fuse: unify dropping the fuse file reference of a writeback request
  2026-09-23 12:50 [Devel] [PATCH hci-8.0 0/2] fs/fuse: unify dropping the fuse file reference of a writeback request Liu Kui
  2026-09-23 12:50 ` [Devel] [PATCH hci-8.0 1/2] Revert "fs/fuse: fix fuse file refcount leak on close_wait writeback" Liu Kui
  2026-09-23 12:50 ` [Devel] [PATCH hci-8.0 2/2] fs/fuse: unify dropping the fuse file reference of a writeback request Liu Kui
@ 2026-09-23 17:01 ` Konstantin Khorenko
  2026-09-23 17:13 ` Konstantin Khorenko
  3 siblings, 0 replies; 6+ messages in thread
From: Konstantin Khorenko @ 2026-09-23 17:01 UTC (permalink / raw)
  To: Liu Kui; +Cc: devel, azaitsev

On Wed, 23 Sep 2026 20:50:39 +0800, Liu Kui wrote:
> fs/fuse: unify dropping the fuse file reference of a writeback request
> 
> Rework the fix for the fuse file refcount leak on close_wait writeback
> (VSTOR-145614): revert the previous fix, which moved the wpa's
> reference acquisition back to submit time, and instead drop the
> reference unconditionally in fuse_writepage_free(), which every wpa
> death path passes exactly once. This keeps the allocation-time
> ownership model of mainline commit 4046d3adcca4 ("fuse: move fuse file
> initialization to wpa allocation time") unmodified.
> 
> [...]

Applied to branch-rh10-6.12.0-211.52.1.22.x.vz10-ovz, will be released in rh10-6.12.0-211.52.1.22.3.vz10, thanks!

[1/2] Revert "fs/fuse: fix fuse file refcount leak on close_wait writeback"
      https://bitbucket.org/virtuozzocore/vzkernel.vzs/commits/d377ba5110e8
[2/2] fs/fuse: unify dropping the fuse file reference of a writeback request
      https://bitbucket.org/virtuozzocore/vzkernel.vzs/commits/6a30a2b00fee

-- 
Konstantin Khorenko <khorenko@virtuozzo.com>

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Devel] [PATCH hci-8.0 0/2] fs/fuse: unify dropping the fuse file reference of a writeback request
  2026-09-23 12:50 [Devel] [PATCH hci-8.0 0/2] fs/fuse: unify dropping the fuse file reference of a writeback request Liu Kui
                   ` (2 preceding siblings ...)
  2026-09-23 17:01 ` [Devel] [PATCH hci-8.0 0/2] " Konstantin Khorenko
@ 2026-09-23 17:13 ` Konstantin Khorenko
  3 siblings, 0 replies; 6+ messages in thread
From: Konstantin Khorenko @ 2026-09-23 17:13 UTC (permalink / raw)
  To: Liu Kui; +Cc: devel, azaitsev

On Wed, 23 Sep 2026 20:50:39 +0800, Liu Kui wrote:
> fs/fuse: unify dropping the fuse file reference of a writeback request
> 
> Rework the fix for the fuse file refcount leak on close_wait writeback
> (VSTOR-145614): revert the previous fix, which moved the wpa's
> reference acquisition back to submit time, and instead drop the
> reference unconditionally in fuse_writepage_free(), which every wpa
> death path passes exactly once. This keeps the allocation-time
> ownership model of mainline commit 4046d3adcca4 ("fuse: move fuse file
> initialization to wpa allocation time") unmodified.
> 
> [...]

Applied to branch-rh10-6.12.0-211.52.1.20.x.vz10-ovz, will be released in rh10-6.12.0-211.52.1.20.12.vz10, thanks!

[1/2] Revert "fs/fuse: fix fuse file refcount leak on close_wait writeback"
      https://bitbucket.org/virtuozzocore/vzkernel.vzs/commits/85c1f54e4eb9
[2/2] fs/fuse: unify dropping the fuse file reference of a writeback request
      https://bitbucket.org/virtuozzocore/vzkernel.vzs/commits/f0bf0a35b307

-- 
Konstantin Khorenko <khorenko@virtuozzo.com>

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Devel] [PATCH hci-8.0 2/2] fs/fuse: unify dropping the fuse file reference of a writeback request
  2026-09-23 12:50 ` [Devel] [PATCH hci-8.0 2/2] fs/fuse: unify dropping the fuse file reference of a writeback request Liu Kui
@ 2026-09-23 17:26   ` Konstantin Khorenko
  0 siblings, 0 replies; 6+ messages in thread
From: Konstantin Khorenko @ 2026-09-23 17:26 UTC (permalink / raw)
  To: Liu Kui; +Cc: azaitsev, devel

  ▎ One more spot of the same class, outside this series: the error path of fuse_writepage_locked().
  ▎
  ▎ Since mainline commit 0acad9289be3 ("fuse: refactor out shared logic in fuse_writepages_fill() and
  ▎ fuse_writepage_locked()") the fuse file reference is taken by fuse_write_file_get() before the wpa is allocated, so the
  ▎ wpa allocation failure path now holds a reference and drops it with a plain fuse_file_put(ff, false). Before that commit
  ▎ the reference was taken last, after all allocations, and this path never owned one.
  ▎
  ▎ On a close_wait mount that put is only a decrement: it does not wake fi->page_waitq. fuse_release() removes ff from
  ▎ fi->write_files under fi->lock and then sleeps in wait_event(fi->page_waitq, ff->count == 1). If fuse_writepage_locked()
  ▎ grabbed ff via fuse_write_file_get() just before the list_del_init() and then fails the wpa allocation, its put brings
  ▎ ff->count to 1 without a wakeup, and fuse_release() stays asleep until some unrelated writeback on the same inode
  ▎ happens to wake the queue, which may never come for a file being closed. The same pattern, put plus wake, is what
  ▎ fuse_release_ff() encapsulates and what fuse_writepages() already uses for data.ff.
  ▎
  ▎ The window is narrow (a GFP_NOFS allocation of a few hundred bytes has to fail while a close races with writepage), but
  ▎ the consequence is a task stuck in close() forever. A one-line follow-up patch replacing fuse_file_put() with
  ▎ fuse_release_ff() in that error path is enough; proposed below.

  Patch:

  fs/fuse: wake close_wait waiters when fuse_writepage_locked() bails out

  fuse_writepage_locked() takes the fuse file reference before allocating
  the wpa and drops it with fuse_file_put() if the allocation fails. On a
  close_wait mount that put does not wake fi->page_waitq, while
  fuse_release() may already be sleeping there for ff->count to reach 1
  after removing ff from fi->write_files. If the writepage grabbed ff
  right before that removal and then failed the allocation, the last
  writeback reference goes away silently and close() hangs until some
  unrelated writeback on the inode wakes the queue.

  Use fuse_release_ff(), which does the put and the wakeup, as the other
  writeback paths already do.

  Fixes: 6b5ddd8253eb ("fuse: Wait for real writeback to finish on file")
  https://virtuozzo.atlassian.net/browse/VSTOR-145614
  Feature: vStorage

  ---
   fs/fuse/file.c | 2 +-
   1 file changed, 1 insertion(+), 1 deletion(-)

  diff --git a/fs/fuse/file.c b/fs/fuse/file.c
  --- a/fs/fuse/file.c
  +++ b/fs/fuse/file.c
  @@ -2572,7 +2572,7 @@ static int fuse_writepage_locked(struct folio *folio)
        return 0;

   err_writepage_args:
  -     fuse_file_put(ff, false);
  +     fuse_release_ff(inode, ff);
   err_nofile:
        folio_put(tmp_folio);
   err:

--
Best regards,

Konstantin Khorenko,
Virtuozzo Linux Kernel Team

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

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-09-23 17:27 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 12:50 [Devel] [PATCH hci-8.0 0/2] fs/fuse: unify dropping the fuse file reference of a writeback request Liu Kui
2026-09-23 12:50 ` [Devel] [PATCH hci-8.0 1/2] Revert "fs/fuse: fix fuse file refcount leak on close_wait writeback" Liu Kui
2026-09-23 12:50 ` [Devel] [PATCH hci-8.0 2/2] fs/fuse: unify dropping the fuse file reference of a writeback request Liu Kui
2026-09-23 17:26   ` Konstantin Khorenko
2026-09-23 17:01 ` [Devel] [PATCH hci-8.0 0/2] " Konstantin Khorenko
2026-09-23 17:13 ` Konstantin Khorenko

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox