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 <[email protected]>
> 
> 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 <[email protected]>
> ---
>  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);

_______________________________________________
Devel mailing list
[email protected]
https://lists.openvz.org/mailman/listinfo/devel

Reply via email to