From: Darrick J. Wong <djwong@xxxxxxxxxx> Plumb in the pieces needed to attach block devices to a fuse+iomap mount for use with iomap operations. This enables us to have filesystems where the metadata could live somewhere else, but the actual file IO goes to locally attached storage. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- include/fuse_kernel.h | 8 ++++++++ include/fuse_lowlevel.h | 16 ++++++++++++++++ lib/fuse_lowlevel.c | 21 +++++++++++++++++++++ lib/fuse_versionscript | 1 + 4 files changed, 46 insertions(+) diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h index 1b3f6046128bde..94efb90279579c 100644 --- a/include/fuse_kernel.h +++ b/include/fuse_kernel.h @@ -233,6 +233,7 @@ * 7.44 * - add FUSE_IOMAP and iomap_{begin,end,ioend} handlers for FIEMAP and * SEEK_{DATA,HOLE} support + * - add FUSE_NOTIFY_ADD_IOMAP_DEVICE for multi-device filesystems */ #ifndef _LINUX_FUSE_H @@ -676,6 +677,7 @@ enum fuse_notify_code { FUSE_NOTIFY_RETRIEVE = 5, FUSE_NOTIFY_DELETE = 6, FUSE_NOTIFY_RESEND = 7, + FUSE_NOTIFY_ADD_IOMAP_DEVICE = 8, FUSE_NOTIFY_CODE_MAX, }; @@ -1328,4 +1330,10 @@ struct fuse_iomap_end_in { uint32_t map_dev; /* device cookie */ }; +struct fuse_iomap_add_device_out { + int32_t fd; /* fd of the open device to add */ + uint32_t reserved; /* must be zero */ + uint32_t *map_dev; /* location to receive device cookie */ +}; + #endif /* _LINUX_FUSE_H */ diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index 4950aae4f82e0d..c9975f1862a074 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -1948,6 +1948,22 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, int fuse_lowlevel_notify_retrieve(struct fuse_session *se, fuse_ino_t ino, size_t size, off_t offset, void *cookie); +/** + * Attach an open file descriptor to a fuse+iomap mount. Currently must be + * a block device. + * + * Added in FUSE protocol version 7.44. If the kernel does not support + * this (or a newer) version, the function will return -ENOSYS and do + * nothing. + * + * @param se the session object + * @param fd file descriptor of an open block device + * @param map_dev pointer to iomap device number + * @return zero for success, -errno for failure + */ +int fuse_lowlevel_notify_iomap_add_device(struct fuse_session *se, int fd, + uint32_t *map_dev); + /* ----------------------------------------------------------- * * Utility functions * diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 56f4789ddb2d0a..ef92ab8c062cbf 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -3110,6 +3110,27 @@ int fuse_lowlevel_notify_store(struct fuse_session *se, fuse_ino_t ino, return res; } +int fuse_lowlevel_notify_iomap_add_device(struct fuse_session *se, int fd, + uint32_t *map_dev) +{ + struct fuse_iomap_add_device_out outarg = { + .fd = fd, + .map_dev = map_dev, + }; + struct iovec iov[2]; + + if (!se) + return -EINVAL; + + if (se->conn.proto_minor < 44) + return -ENOSYS; + + iov[1].iov_base = &outarg; + iov[1].iov_len = sizeof(outarg); + + return send_notify_iov(se, FUSE_NOTIFY_ADD_IOMAP_DEVICE, iov, 2); +} + struct fuse_retrieve_req { struct fuse_notify_req nreq; void *cookie; diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index 22c59e1af66c95..5c04e204adba33 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -205,6 +205,7 @@ FUSE_3.17 { FUSE_3.18 { global: fuse_req_is_uring; + fuse_lowlevel_notify_iomap_add_device; } FUSE_3.17; # Local Variables: