From: Darrick J. Wong <djwong@xxxxxxxxxx> 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@xxxxxxxxxx> --- 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 136b9e5aabaf51..5fba84c75f4a64 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1714,6 +1714,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) @@ -1742,6 +1744,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 207836e2e09cc4..78e776878427e3 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -3236,6 +3236,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 5253f7ef88c110..3f6e0496c4744b 100644 --- a/fs/fuse/file_iomap.c +++ b/fs/fuse/file_iomap.c @@ -8,6 +8,7 @@ #include <linux/iomap.h> #include <linux/pagemap.h> #include <linux/falloc.h> +#include <linux/fadvise.h> static bool __read_mostly enable_iomap = #if IS_ENABLED(CONFIG_FUSE_IOMAP_BY_DEFAULT) @@ -1831,3 +1832,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_has_iomap_fileio(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; +}