Re: [PATCH v2] fuse: Forward vfs_fadvise to backing_file in passthrough mode
From: Amir Goldstein
Date: Thu Sep 10 2026 - 15:02:34 EST
On Thu, Sep 10, 2026 at 8:44 PM Shai Barack <shayba@xxxxxxxxxx> wrote:
>
> When an application invokes posix_fadvise(..., POSIX_FADV_DONTNEED) or
> other fadvise advice on a FUSE passthrough file descriptor, the VFS
> currently only executes generic_fadvise() on the upper FUSE inode
> mapping.
>
> Because FUSE passthrough does not forward fadvise operations to the
> underlying backing file, pages residing in the lower filesystem's
> pagecache remain resident in memory.
>
> During media-heavy workloads (such as image thumbnail generation or
> streaming), single-access file data accumulates in the inactive pagecache
> of the lower filesystem. Under memory pressure, the kernel retains these
> stale media pages and instead evicts active executable pages from
> running processes, leading to severe direct reclaim latency spikes.
>
> Architecturally, Linux VFS supports filesystem-specific fadvise
> delegation via the .fadvise hook in struct file_operations. Implement
> fuse_file_fadvise() in fs/fuse/file.c and register it in
> fuse_file_operations. When passthrough is active on a fuse_file,
> fuse_file_fadvise() forwards the vfs_fadvise() call to the lower
> backing_file under the opened credentials, allowing POSIX_FADV_DONTNEED
> to cleanly invalidate the physical backing filesystem pagecache.
>
> Signed-off-by: Shai Barack <shayba@xxxxxxxxxx>
> Cc: Miklos Szeredi <miklos@xxxxxxxxxx>
> Cc: Amir Goldstein <amir73il@xxxxxxxxx>
> Cc: Bernd Schubert <bschubert@xxxxxxx>
> Cc: Sandeep Dhavale <dhavale@xxxxxxxxxx>
> Cc: Akilesh Kailash <akailash@xxxxxxxxxx>
> Cc: Suren Baghdasaryan <surenb@xxxxxxxxxx>
> Cc: fuse-devel@xxxxxxxxxxxxxxx
> Cc: linux-fsdevel@xxxxxxxxxxxxxxx
> Cc: linux-kernel@xxxxxxxxxxxxxxx
Reviewed-by: Amir Goldstein <amir73il@xxxxxxxxx>
Thanks,
Amir.
> ---
> v2:
> - Remove redundant !backing_file check in fuse_passthrough_fadvise() (Amir Goldstein)
> - Remove unused fuse_passthrough_fadvise() stub under #ifndef CONFIG_FUSE_PASSTHROUGH (Amir Goldstein)
> - Reorder fuse_passthrough_fadvise() above fuse_passthrough_open() alongside other passthrough ops (Amir Goldstein)
> - Add fuse-devel@xxxxxxxxxxxxxxx to CC list (Amir Goldstein, TJ Mercier)
>
> fs/fuse/file.c | 11 +++++++++++
> fs/fuse/fuse_i.h | 1 +
> fs/fuse/passthrough.c | 13 +++++++++++++
> 3 files changed, 25 insertions(+)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index a4d736945..81709ab82 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -3537,6 +3537,16 @@ static ssize_t fuse_copy_file_range(struct file *src_file, loff_t src_off,
> return ret;
> }
>
> +static int fuse_file_fadvise(struct file *file, loff_t offset, loff_t len, int advice)
> +{
> + struct fuse_file *ff = file->private_data;
> +
> + if (fuse_file_passthrough(ff))
> + return fuse_passthrough_fadvise(ff, offset, len, advice);
> +
> + return generic_fadvise(file, offset, len, advice);
> +}
> +
> static const struct file_operations fuse_file_operations = {
> .llseek = fuse_file_llseek,
> .read_iter = fuse_file_read_iter,
> @@ -3557,6 +3567,7 @@ static const struct file_operations fuse_file_operations = {
> .fallocate = fuse_file_fallocate,
> .copy_file_range = fuse_copy_file_range,
> .fop_flags = FOP_DONTCACHE,
> + .fadvise = fuse_file_fadvise,
> };
>
> static const struct address_space_operations fuse_file_aops = {
> diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
> index 939553b34..6c60716e7 100644
> --- a/fs/fuse/fuse_i.h
> +++ b/fs/fuse/fuse_i.h
> @@ -1581,6 +1581,7 @@ ssize_t fuse_passthrough_splice_write(struct pipe_inode_info *pipe,
> struct file *out, loff_t *ppos,
> size_t len, unsigned int flags);
> ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma);
> +int fuse_passthrough_fadvise(struct fuse_file *ff, loff_t offset, loff_t len, int advice);
>
> /* backing.c */
>
> diff --git a/fs/fuse/passthrough.c b/fs/fuse/passthrough.c
> index 059e57969..8a8fa6b8c 100644
> --- a/fs/fuse/passthrough.c
> +++ b/fs/fuse/passthrough.c
> @@ -160,6 +160,19 @@ ssize_t fuse_passthrough_mmap(struct file *file, struct vm_area_struct *vma)
> return backing_file_mmap(backing_file, vma, &ctx);
> }
>
> +int fuse_passthrough_fadvise(struct fuse_file *ff, loff_t offset, loff_t len, int advice)
> +{
> + struct file *backing_file = fuse_file_passthrough(ff);
> + const struct cred *old_cred;
> + int ret;
> +
> + old_cred = override_creds(ff->cred);
> + ret = vfs_fadvise(backing_file, offset, len, advice);
> + revert_creds(old_cred);
> +
> + return ret;
> +}
> +
> struct fuse_backing *fuse_backing_get(struct fuse_backing *fb)
> {
> if (fb && refcount_inc_not_zero(&fb->count))
> --
> 2.43.0