[PATCH 21/28] fuse: implement fadvise for iomap files

Darrick J. Wong
2025-09-16T00:33:27Z

If userspace asks us to perform readahead on a file, take i_rwsem so
that it can't race with hole punching or writes.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
fs/fuse/fuse_i.h | 3 +++
fs/fuse/file.c | 1 +
fs/fuse/file_iomap.c | 20 ++++++++++++++++++++
3 files changed, 24 insertions(+)

diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index e45780f6fe9e39..d59c19f61d5337 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1789,6 +1789,8 @@ int fuse_iomap_flush_unmap_range(struct inode *inode, loff_t pos,

int fuse_dev_ioctl_iomap_support(struct file *file,
struct fuse_iomap_support __user *argp);
+
+int fuse_iomap_fadvise(struct file *file, loff_t start, loff_t end, int advice);
#else
# define fuse_iomap_enabled(...) (false)
# define fuse_has_iomap(...) (false)
@@ -1813,6 +1815,7 @@ int fuse_dev_ioctl_iomap_support(struct file *file,
# define fuse_iomap_fallocate(...) (-ENOSYS)
# define fuse_iomap_flush_unmap_range(...) (-ENOSYS)
# define fuse_dev_ioctl_iomap_support(...) (-EOPNOTSUPP)
+# define fuse_iomap_fadvise NULL
#endif

#endif /* _FS_FUSE_I_H */
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index dd65485c9743bf..9476f14035bb7f 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3189,6 +3189,7 @@ static const struct file_operations fuse_file_operations = {
.poll = fuse_file_poll,
.fallocate = fuse_file_fallocate,
.copy_file_range = fuse_copy_file_range,
+ .fadvise = fuse_iomap_fadvise,
};

static const struct address_space_operations fuse_file_aops = {
diff --git a/fs/fuse/file_iomap.c b/fs/fuse/file_iomap.c
index 2d01828fc532b0..a484cd235d9da2 100644
--- a/fs/fuse/file_iomap.c
+++ b/fs/fuse/file_iomap.c
@@ -7,6 +7,7 @@
#include <linux/fiemap.h>
#include <linux/pagemap.h>
#include <linux/falloc.h>
+#include <linux/fadvise.h>
#include "fuse_i.h"
#include "fuse_trace.h"
#include "iomap_priv.h"
@@ -1856,3 +1857,22 @@ int fuse_dev_ioctl_iomap_support(struct file *file,
return -EFAULT;
return 0;
}
+
+int fuse_iomap_fadvise(struct file *file, loff_t start, loff_t end, int advice)
+{
+ struct inode *inode = file_inode(file);
+ bool needlock = advice == POSIX_FADV_WILLNEED &&
+ fuse_inode_has_iomap(inode);
+ int ret;
+
+ /*
+ * Operations creating pages in page cache need protection from hole
+ * punching and similar ops
+ */
+ if (needlock)
+ inode_lock_shared(inode);
+ ret = generic_fadvise(file, start, end, advice);
+ if (needlock)
+ inode_unlock_shared(inode);
+ return ret;
+}