[Devel] [PATCH hci-8.0 2/2] fs/fuse: unify dropping the fuse file reference of a writeback request
Liu Kui
kui.liu at virtuozzo.com
Wed Sep 23 15:50:41 MSK 2026
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 at 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)
More information about the Devel
mailing list