[Devel] [PATCH vz10 2/5] fixup! fs/fuse: force offload of final fput in aio completion to workqueue

Konstantin Khorenko khorenko at virtuozzo.com
Mon Jun 29 17:33:30 MSK 2026


Already applied:

4dc73eb6adc3d fs/fuse: force offload of final fput in aio completion to workqueue

--
Best regards,

Konstantin Khorenko,
Virtuozzo Linux Kernel Team

On 6/25/26 20:16, Eva Kurchatova wrote:
> From: Alexey Kuznetsov <kuznet at virtuozzo.com>
> 
> The patch is known as "fuse: queue work for aio_complete (v3)",
> here is its simpler form.
> 
> aio completion is executed in context of userspace worker thread.
> Final fput might make lots of additional work like updating mtime,
> releasing file, which could be routed to the same thread.
> The problem is not specific to vstorage, all decent fuse fses
> suffer of this. The code as is works only with low performance
> fses based on libfuse. Also, current version of vstorage
> is not supposed suffer if this problem because aio completions
> are guaranteed to be done in threads different of threads
> working on metadata. Yet, it can be configured, deliberately
> or by mistake to route everything to one thread.
> 
> Use workqueue supplied by vfs, all kernels in use (rh7,9,10)
> offload final fput to workqueue when fput() is called from
> interrupt or kthread context. So, we grab reference to file
> before ki_complete() and release it afterwards surrounded
> with local_bh_disable/local_bh_enable pair. It looks like
> a good pragmatic solution with minimal impact on performance
> and maintanance cost.
> 
> Signed-off-by: Alexey Kuznetsov <kuznet at virtuozzo.com>
> ---
>  fs/fuse/file.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index 40cded85037f..c812420cc109 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -18,6 +18,7 @@
>  #include <linux/falloc.h>
>  #include <linux/uio.h>
>  #include <linux/fs.h>
> +#include <linux/file.h>
>  #include <linux/filelock.h>
>  #include <linux/splice.h>
>  #include <linux/task_io_accounting_ops.h>
> @@ -971,6 +972,7 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
>  
>  	if (!left && !io->blocking) {
>  		ssize_t res = fuse_get_res_by_io(io);
> +		struct file *file = io->iocb->ki_filp;
>  
>  		if (res >= 0) {
>  			struct inode *inode = file_inode(io->iocb->ki_filp);
> @@ -989,7 +991,20 @@ static void fuse_aio_complete(struct fuse_io_priv *io, int err, ssize_t pos)
>  			       io->iocb->ki_flags, io->iocb->ki_pos);
>  		}
>  
> +		/* We have to bump f_count here to avoid deadlock for
> +		 * single-threaded fuse daemon: if the process that generated
> +		 * AIO is already close(2) the file, fput() called from
> +		 * aio_complete will be the last fput(); hence, it will send
> +		 * flush_mtime (or release) request to userspace who is busy
> +		 * now writing ACK for given AIO to in-kernel fuse
> +		 */
> +		get_file(file);
>  		io->iocb->ki_complete(io->iocb, res);
> +
> +		/* local_bh_disable() forces fput() to offload final release to workqueue */
> +		local_bh_disable();
> +		fput(file);
> +		local_bh_enable();
>  	}
>  
>  	kref_put(&io->refcnt, fuse_io_release);



More information about the Devel mailing list