* [PATCH] fuse: virtiofs: fix illegal inode address access in fuse_release_end
@ 2026-05-14 12:41 Zhihao Cheng
2026-05-15 21:07 ` Darrick J. Wong
0 siblings, 1 reply; 3+ messages in thread
From: Zhihao Cheng @ 2026-05-14 12:41 UTC (permalink / raw)
To: miklos, djwong
Cc: linux-fsdevel, linux-kernel, chengzhihao1, yangerkun, yi.zhang
When a submount (e.g. virtiofs with fc->auto_submounts=true) is umounted
while an async RELEASE request is still pending, an illegal inode address
accessing occurs in fuse_release_end()->iput().
Trigger process:
1. virtiofs has a submount; user opens and closes a file under it
2. Close calls fuse_file_put() with sync=false, sending RELEASE
asynchronously
3. fuse_release_end() is scheduled to run later via igrab() holding
inode ref
4. File is freed, mount/dentry refcounts are released
5. User umounts the submount; fuse connection detects remaining
superblock and does NOT flush the connection's requests
6. generic_shutdown_super() destroys the superblock and poisons busy
inodes' inode->i_sb = VFS_PTR_POISON
7. Later, fuse_request_end() calls fuse_release_end() which does
iput(inode)
8. iput() accesses inode->i_sb->s_op at the poisoned address, crash!
There are two solutions to fix it:
Solution A: Hold path reference in fuse_file_put, and put path
synchronously, which could reintroduce the issue fixed by commit
5a18ec176c934 ("fuse: fix hang of single threaded fuseblk filesystem").
Solution B (chosen): Use synchronous RELEASE for auto_submounts (which
is only supported by virtiofs). The virtiofsd(fuse daemon) and virtiofs
won't work together under one same kernel instance, so the problem fixed
by commit 26e5c67deb2e ("fuse: fix livelock in synchronous file put from
fuseblk workers") won't be brought back in virtiofs.
Fetch a reproducer in https://bugzilla.kernel.org/show_bug.cgi?id=221519.
Fixes: 26e5c67deb2e ("fuse: fix livelock in synchronous file put from fuseblk workers")
Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
---
fs/fuse/file.c | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index c59452d60b8d..a6192b96d861 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -375,13 +375,20 @@ void fuse_file_release(struct inode *inode, struct fuse_file *ff,
* synchronous RELEASE is allowed (and desirable) in this case
* because the server can be trusted not to screw up.
*
- * Always use the asynchronous file put because the current thread
- * might be the fuse server. This can happen if a process starts some
- * aio and closes the fd before the aio completes. Since aio takes its
- * own ref to the file, the IO completion has to drop the ref, which is
- * how the fuse server can end up closing its clients' files.
+ * For auto_submounts (e.g. virtiofs), always use synchronous
+ * release to avoid illegal inode address access when umount
+ * happens before async release completes. The async release
+ * holds inode reference via igrab(), but umount can shutdown
+ * superblock and poison inode->i_sb before release ends,
+ * causing crash in fuse_release_end()->iput(). Otherwise,
+ * always use the asynchronous file put because the current
+ * thread might be the fuse server. This can happen if a
+ * process starts some aio and closes the fd before the aio
+ * completes. Since aio takes its own ref to the file, the IO
+ * completion has to drop the ref, which is how the fuse server
+ * can end up closing its clients' files.
*/
- fuse_file_put(ff, false);
+ fuse_file_put(ff, ff->fm->fc->auto_submounts);
}
void fuse_release_common(struct file *file, bool isdir)
--
2.52.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] fuse: virtiofs: fix illegal inode address access in fuse_release_end 2026-05-14 12:41 [PATCH] fuse: virtiofs: fix illegal inode address access in fuse_release_end Zhihao Cheng @ 2026-05-15 21:07 ` Darrick J. Wong 2026-05-16 3:20 ` Zhihao Cheng 0 siblings, 1 reply; 3+ messages in thread From: Darrick J. Wong @ 2026-05-15 21:07 UTC (permalink / raw) To: Zhihao Cheng Cc: miklos, linux-fsdevel, linux-kernel, yangerkun, yi.zhang, fuse-devel [add fuse-devel] On Thu, May 14, 2026 at 08:41:02PM +0800, Zhihao Cheng wrote: > When a submount (e.g. virtiofs with fc->auto_submounts=true) is umounted > while an async RELEASE request is still pending, an illegal inode address > accessing occurs in fuse_release_end()->iput(). > > Trigger process: > 1. virtiofs has a submount; user opens and closes a file under it > 2. Close calls fuse_file_put() with sync=false, sending RELEASE > asynchronously > 3. fuse_release_end() is scheduled to run later via igrab() holding > inode ref > 4. File is freed, mount/dentry refcounts are released > 5. User umounts the submount; fuse connection detects remaining > superblock and does NOT flush the connection's requests > 6. generic_shutdown_super() destroys the superblock and poisons busy > inodes' inode->i_sb = VFS_PTR_POISON > 7. Later, fuse_request_end() calls fuse_release_end() which does > iput(inode) > 8. iput() accesses inode->i_sb->s_op at the poisoned address, crash! > > There are two solutions to fix it: > Solution A: Hold path reference in fuse_file_put, and put path > synchronously, which could reintroduce the issue fixed by commit > 5a18ec176c934 ("fuse: fix hang of single threaded fuseblk filesystem"). > > Solution B (chosen): Use synchronous RELEASE for auto_submounts (which > is only supported by virtiofs). The virtiofsd(fuse daemon) and virtiofs > won't work together under one same kernel instance, so the problem fixed > by commit 26e5c67deb2e ("fuse: fix livelock in synchronous file put from > fuseblk workers") won't be brought back in virtiofs. Does the weird AIO "kernel breaks if you close the fd before all the IOs complete" behavior happen on virtiofsd? --D > > Fetch a reproducer in https://bugzilla.kernel.org/show_bug.cgi?id=221519. > > Fixes: 26e5c67deb2e ("fuse: fix livelock in synchronous file put from fuseblk workers") > Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> > --- > fs/fuse/file.c | 19 +++++++++++++------ > 1 file changed, 13 insertions(+), 6 deletions(-) > > diff --git a/fs/fuse/file.c b/fs/fuse/file.c > index c59452d60b8d..a6192b96d861 100644 > --- a/fs/fuse/file.c > +++ b/fs/fuse/file.c > @@ -375,13 +375,20 @@ void fuse_file_release(struct inode *inode, struct fuse_file *ff, > * synchronous RELEASE is allowed (and desirable) in this case > * because the server can be trusted not to screw up. > * > - * Always use the asynchronous file put because the current thread > - * might be the fuse server. This can happen if a process starts some > - * aio and closes the fd before the aio completes. Since aio takes its > - * own ref to the file, the IO completion has to drop the ref, which is > - * how the fuse server can end up closing its clients' files. > + * For auto_submounts (e.g. virtiofs), always use synchronous > + * release to avoid illegal inode address access when umount > + * happens before async release completes. The async release > + * holds inode reference via igrab(), but umount can shutdown > + * superblock and poison inode->i_sb before release ends, > + * causing crash in fuse_release_end()->iput(). Otherwise, > + * always use the asynchronous file put because the current > + * thread might be the fuse server. This can happen if a > + * process starts some aio and closes the fd before the aio > + * completes. Since aio takes its own ref to the file, the IO > + * completion has to drop the ref, which is how the fuse server > + * can end up closing its clients' files. > */ > - fuse_file_put(ff, false); > + fuse_file_put(ff, ff->fm->fc->auto_submounts); > } > > void fuse_release_common(struct file *file, bool isdir) > -- > 2.52.0 > ^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] fuse: virtiofs: fix illegal inode address access in fuse_release_end 2026-05-15 21:07 ` Darrick J. Wong @ 2026-05-16 3:20 ` Zhihao Cheng 0 siblings, 0 replies; 3+ messages in thread From: Zhihao Cheng @ 2026-05-16 3:20 UTC (permalink / raw) To: Darrick J. Wong Cc: miklos, linux-fsdevel, linux-kernel, yangerkun, yi.zhang, fuse-devel 在 2026/5/16 5:07, Darrick J. Wong 写道: > [add fuse-devel] > > On Thu, May 14, 2026 at 08:41:02PM +0800, Zhihao Cheng wrote: >> When a submount (e.g. virtiofs with fc->auto_submounts=true) is umounted >> while an async RELEASE request is still pending, an illegal inode address >> accessing occurs in fuse_release_end()->iput(). >> >> Trigger process: >> 1. virtiofs has a submount; user opens and closes a file under it >> 2. Close calls fuse_file_put() with sync=false, sending RELEASE >> asynchronously >> 3. fuse_release_end() is scheduled to run later via igrab() holding >> inode ref >> 4. File is freed, mount/dentry refcounts are released >> 5. User umounts the submount; fuse connection detects remaining >> superblock and does NOT flush the connection's requests >> 6. generic_shutdown_super() destroys the superblock and poisons busy >> inodes' inode->i_sb = VFS_PTR_POISON >> 7. Later, fuse_request_end() calls fuse_release_end() which does >> iput(inode) >> 8. iput() accesses inode->i_sb->s_op at the poisoned address, crash! >> >> There are two solutions to fix it: >> Solution A: Hold path reference in fuse_file_put, and put path >> synchronously, which could reintroduce the issue fixed by commit >> 5a18ec176c934 ("fuse: fix hang of single threaded fuseblk filesystem"). >> >> Solution B (chosen): Use synchronous RELEASE for auto_submounts (which >> is only supported by virtiofs). The virtiofsd(fuse daemon) and virtiofs >> won't work together under one same kernel instance, so the problem fixed >> by commit 26e5c67deb2e ("fuse: fix livelock in synchronous file put from >> fuseblk workers") won't be brought back in virtiofs. > > Does the weird AIO "kernel breaks if you close the fd before all the IOs > complete" behavior happen on virtiofsd? > Hi Darrick, IMHO, the problem fixed by commit 26e5c67deb2e1f42a9("fuse: fix livelock in synchronous file put from fuseblk workers") happens as following process: fuse user fuse daemon fd = open(file) io_submit_one req->ki_filp = fget(iocb->aio_fildes) close(fd) // file->f_ref = 1, file won't be released process FUSE_WRITE req write(/dev/fuse, reply) fuse_request_end fuse_aio_complete_req aio_complete_rw fput(iocb->ki_filp) task_work_add task_work_run __fput fuse_release __fuse_simple_request request_wait_answer For viriofs, the user(virtiofs) runs in kernel A(guest), the daemon(virtiofsd) runs kernel B(host), and the fuse_request_end is called by virtio_fs_requests_done_work -> virtio_fs_complete_req_work -> virtio_fs_request_complete, which is under the kworker context(kernel A, guest), so it won't block the daemon thread(kernel B, host). > --D > >> >> Fetch a reproducer in https://bugzilla.kernel.org/show_bug.cgi?id=221519. >> >> Fixes: 26e5c67deb2e ("fuse: fix livelock in synchronous file put from fuseblk workers") >> Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com> >> --- >> fs/fuse/file.c | 19 +++++++++++++------ >> 1 file changed, 13 insertions(+), 6 deletions(-) >> >> diff --git a/fs/fuse/file.c b/fs/fuse/file.c >> index c59452d60b8d..a6192b96d861 100644 >> --- a/fs/fuse/file.c >> +++ b/fs/fuse/file.c >> @@ -375,13 +375,20 @@ void fuse_file_release(struct inode *inode, struct fuse_file *ff, >> * synchronous RELEASE is allowed (and desirable) in this case >> * because the server can be trusted not to screw up. >> * >> - * Always use the asynchronous file put because the current thread >> - * might be the fuse server. This can happen if a process starts some >> - * aio and closes the fd before the aio completes. Since aio takes its >> - * own ref to the file, the IO completion has to drop the ref, which is >> - * how the fuse server can end up closing its clients' files. >> + * For auto_submounts (e.g. virtiofs), always use synchronous >> + * release to avoid illegal inode address access when umount >> + * happens before async release completes. The async release >> + * holds inode reference via igrab(), but umount can shutdown >> + * superblock and poison inode->i_sb before release ends, >> + * causing crash in fuse_release_end()->iput(). Otherwise, >> + * always use the asynchronous file put because the current >> + * thread might be the fuse server. This can happen if a >> + * process starts some aio and closes the fd before the aio >> + * completes. Since aio takes its own ref to the file, the IO >> + * completion has to drop the ref, which is how the fuse server >> + * can end up closing its clients' files. >> */ >> - fuse_file_put(ff, false); >> + fuse_file_put(ff, ff->fm->fc->auto_submounts); >> } >> >> void fuse_release_common(struct file *file, bool isdir) >> -- >> 2.52.0 >> > > . > ^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-05-16 3:20 UTC | newest] Thread overview: 3+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-05-14 12:41 [PATCH] fuse: virtiofs: fix illegal inode address access in fuse_release_end Zhihao Cheng 2026-05-15 21:07 ` Darrick J. Wong 2026-05-16 3:20 ` Zhihao Cheng
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.