From: Darrick J. Wong <djwong@xxxxxxxxxx> Advertise our new IO paths programmatically by creating an ioctl that can return the capabilities of the kernel. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- fs/fuse/fuse_i.h | 4 ++++ include/uapi/linux/fuse.h | 13 +++++++++++++ fs/fuse/dev.c | 3 +++ fs/fuse/file_iomap.c | 18 ++++++++++++++++++ 4 files changed, 38 insertions(+) diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 8481b1d0299df0..5b14e8b23f305f 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h @@ -1683,6 +1683,9 @@ int fuse_iomap_setsize(struct mnt_idmap *idmap, struct dentry *dentry, struct iattr *iattr); int fuse_iomap_fallocate(struct file *file, int mode, loff_t offset, loff_t length, loff_t new_size); + +int fuse_iomap_ioc_support(struct file *file, + struct fuse_iomap_support __user *argp); #else # define fuse_iomap_enabled(...) (false) # define fuse_has_iomap(...) (false) @@ -1706,6 +1709,7 @@ int fuse_iomap_fallocate(struct file *file, int mode, loff_t offset, # define fuse_iomap_buffered_write(...) (-ENOSYS) # define fuse_iomap_setsize(...) (-ENOSYS) # define fuse_iomap_fallocate(...) (-ENOSYS) +# define fuse_iomap_ioc_support(...) (-ENOTTY) #endif #endif /* _FS_FUSE_I_H */ diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h index c9402f2b2a335c..cbef70ae05c73b 100644 --- a/include/uapi/linux/fuse.h +++ b/include/uapi/linux/fuse.h @@ -1135,12 +1135,25 @@ struct fuse_backing_map { uint64_t padding; }; +/* basic reporting functionality */ +#define FUSE_IOMAP_SUPPORT_BASICS (1ULL << 0) +/* fuse driver can do direct io */ +#define FUSE_IOMAP_SUPPORT_DIRECTIO (1ULL << 1) +/* fuse driver can do buffered io */ +#define FUSE_IOMAP_SUPPORT_PAGECACHE (1ULL << 2) +struct fuse_iomap_support { + uint64_t flags; + uint64_t padding; +}; + /* Device ioctls: */ #define FUSE_DEV_IOC_MAGIC 229 #define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t) #define FUSE_DEV_IOC_BACKING_OPEN _IOW(FUSE_DEV_IOC_MAGIC, 1, \ struct fuse_backing_map) #define FUSE_DEV_IOC_BACKING_CLOSE _IOW(FUSE_DEV_IOC_MAGIC, 2, uint32_t) +#define FUSE_DEV_IOC_IOMAP_SUPPORT _IOR(FUSE_DEV_IOC_MAGIC, 3, \ + struct fuse_iomap_support) struct fuse_lseek_in { uint64_t fh; diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 9d7064ec170cf6..91beafbbcf7c02 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c @@ -2620,6 +2620,9 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd, case FUSE_DEV_IOC_BACKING_CLOSE: return fuse_dev_ioctl_backing_close(file, argp); + case FUSE_DEV_IOC_IOMAP_SUPPORT: + return fuse_iomap_ioc_support(file, argp); + default: return -ENOTTY; } diff --git a/fs/fuse/file_iomap.c b/fs/fuse/file_iomap.c index 746d9ae192dc55..60e1242b32fd7c 100644 --- a/fs/fuse/file_iomap.c +++ b/fs/fuse/file_iomap.c @@ -1425,3 +1425,21 @@ fuse_iomap_fallocate( return 0; } + +int fuse_iomap_ioc_support(struct file *file, + struct fuse_iomap_support __user *argp) +{ + struct fuse_iomap_support ios = { }; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (fuse_iomap_enabled()) + ios.flags = FUSE_IOMAP_SUPPORT_BASICS | + FUSE_IOMAP_SUPPORT_DIRECTIO | + FUSE_IOMAP_SUPPORT_PAGECACHE; + + if (copy_to_user(argp, &ios, sizeof(ios))) + return -EFAULT; + return 0; +}