[PATCH 2/2] fuse: set iomap backing device block size

Darrick J. Wong
2025-09-16T00:41:32Z

Add a new ioctl so that an unprivileged fuse server can set the block
size of a bdev that's opened for iomap usage.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
fs/fuse/fuse_i.h | 3 +++
include/uapi/linux/fuse.h | 7 +++++++
fs/fuse/dev.c | 2 ++
fs/fuse/file_iomap.c | 24 ++++++++++++++++++++++++
4 files changed, 36 insertions(+)

diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h
index 1a965d3dee6479..faef0efe6a9506 100644
--- a/fs/fuse/fuse_i.h
+++ b/fs/fuse/fuse_i.h
@@ -1853,6 +1853,8 @@ void fuse_iomap_copied_file_range(struct inode *inode, loff_t offset,
int fuse_dev_ioctl_add_iomap(struct file *file);
int fuse_dev_ioctl_iomap_support(struct file *file,
struct fuse_iomap_support __user *argp);
+int fuse_dev_ioctl_iomap_set_blocksize(struct file *file,
+ struct fuse_iomap_backing_info __user *argp);
int fuse_iomap_dev_inval(struct fuse_conn *fc,
const struct fuse_iomap_dev_inval_out *arg);

@@ -1902,6 +1904,7 @@ int fuse_iomap_inval(struct fuse_conn *fc,
# define fuse_iomap_copied_file_range(...) ((void)0)
# define fuse_dev_ioctl_add_iomap(...) (-EOPNOTSUPP)
# define fuse_dev_ioctl_iomap_support(...) (-EOPNOTSUPP)
+# define fuse_dev_ioctl_iomap_set_blocksize(...) (-EOPNOTSUPP)
# define fuse_iomap_dev_inval(...) (-ENOSYS)
# define fuse_iomap_fadvise NULL
# define fuse_inode_caches_iomaps(...) (false)
diff --git a/include/uapi/linux/fuse.h b/include/uapi/linux/fuse.h
index b59ce131513efd..d360c39be43104 100644
--- a/include/uapi/linux/fuse.h
+++ b/include/uapi/linux/fuse.h
@@ -1180,6 +1180,11 @@ struct fuse_iomap_support {
uint64_t padding;
};

+struct fuse_iomap_backing_info {
+ uint32_t backing_id;
+ uint32_t blocksize;
+};
+
/* Device ioctls: */
#define FUSE_DEV_IOC_MAGIC 229
#define FUSE_DEV_IOC_CLONE _IOR(FUSE_DEV_IOC_MAGIC, 0, uint32_t)
@@ -1190,6 +1195,8 @@ struct fuse_iomap_support {
#define FUSE_DEV_IOC_ADD_IOMAP _IO(FUSE_DEV_IOC_MAGIC, 99)
#define FUSE_DEV_IOC_IOMAP_SUPPORT _IOR(FUSE_DEV_IOC_MAGIC, 99, \
struct fuse_iomap_support)
+#define FUSE_DEV_IOC_IOMAP_SET_BLOCKSIZE _IOW(FUSE_DEV_IOC_MAGIC, 99, \
+ struct fuse_iomap_backing_info)

struct fuse_lseek_in {
uint64_t fh;
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 7a24fbcdb2f919..5003a862daf37a 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -2782,6 +2782,8 @@ static long fuse_dev_ioctl(struct file *file, unsigned int cmd,
return fuse_dev_ioctl_iomap_support(file, argp);
case FUSE_DEV_IOC_ADD_IOMAP:
return fuse_dev_ioctl_add_iomap(file);
+ case FUSE_DEV_IOC_IOMAP_SET_BLOCKSIZE:
+ return fuse_dev_ioctl_iomap_set_blocksize(file, argp);

default:
return -ENOTTY;
diff --git a/fs/fuse/file_iomap.c b/fs/fuse/file_iomap.c
index 70b01638006a2e..a915cc9520b532 100644
--- a/fs/fuse/file_iomap.c
+++ b/fs/fuse/file_iomap.c
@@ -2721,3 +2721,27 @@ int fuse_iomap_inval(struct fuse_conn *fc,
up_read(&fc->killsb);
return ret ? ret : ret2;
}
+
+int fuse_dev_ioctl_iomap_set_blocksize(struct file *file,
+ struct fuse_iomap_backing_info __user *argp)
+{
+ struct fuse_iomap_backing_info fbi;
+ struct fuse_dev *fud = fuse_get_dev(file);
+ struct fuse_backing *fb;
+ int ret;
+
+ if (IS_ERR(fud))
+ return PTR_ERR(fud);
+
+ if (copy_from_user(&fbi, argp, sizeof(fbi)))
+ return -EFAULT;
+
+ fb = fuse_backing_lookup(fud->fc, &fuse_iomap_backing_ops,
+ fbi.backing_id);
+ if (!fb)
+ return -ENOENT;
+
+ ret = set_blocksize(fb->file, fbi.blocksize);
+ fuse_backing_put(fb);
+ return ret;
+}