From: Darrick J. Wong <djwong@xxxxxxxxxx> Add FUSE_IOMAP_CONFIG helpers to the low level fuse library. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- include/fuse_common.h | 31 ++++++++++++++++++++++++++ include/fuse_kernel.h | 30 ++++++++++++++++++++++++++ include/fuse_lowlevel.h | 25 +++++++++++++++++++++ lib/fuse_lowlevel.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++ lib/fuse_versionscript | 1 + 5 files changed, 142 insertions(+) diff --git a/include/fuse_common.h b/include/fuse_common.h index 8bc21677b6e5c7..98cb8f656efd13 100644 --- a/include/fuse_common.h +++ b/include/fuse_common.h @@ -1227,6 +1227,37 @@ struct fuse_iomap { /* use iomap for buffered io */ #define FUSE_IFLAG_IOMAP_FILEIO (1U << 2) +/* Which fields are set in fuse_iomap_config_out? */ +#define FUSE_IOMAP_CONFIG_SID (1 << 0ULL) +#define FUSE_IOMAP_CONFIG_UUID (1 << 1ULL) +#define FUSE_IOMAP_CONFIG_BLOCKSIZE (1 << 2ULL) +#define FUSE_IOMAP_CONFIG_MAX_LINKS (1 << 3ULL) +#define FUSE_IOMAP_CONFIG_TIME (1 << 4ULL) +#define FUSE_IOMAP_CONFIG_MAXBYTES (1 << 5ULL) + +struct fuse_iomap_config{ + uint64_t flags; /* FUSE_IOMAP_CONFIG_* */ + + char s_id[32]; /* Informational name */ + char s_uuid[16]; /* UUID */ + + uint8_t s_uuid_len; /* length of s_uuid */ + + uint8_t s_pad[3]; /* must be zeroes */ + + uint32_t s_blocksize; /* fs block size */ + uint32_t s_max_links; /* max hard links */ + + /* Granularity of c/m/atime in ns (cannot be worse than a second) */ + uint32_t s_time_gran; + + /* Time limits for c/m/atime in seconds */ + int64_t s_time_min; + int64_t s_time_max; + + int64_t s_maxbytes; /* max file size */ +}; + #endif /* FUSE_USE_VERSION >= 318 */ /* ----------------------------------------------------------- * diff --git a/include/fuse_kernel.h b/include/fuse_kernel.h index 7a1226d6bc2c0a..3c704f03434693 100644 --- a/include/fuse_kernel.h +++ b/include/fuse_kernel.h @@ -242,6 +242,7 @@ * - add FUSE_DEV_IOC_IOMAP_DEV_ADD to configure block devices for iomap * - add FUSE_IOMAP_DIRECTIO/FUSE_ATTR_IOMAP_DIRECTIO for direct I/O support * - add FUSE_IOMAP_FILEIO/FUSE_ATTR_IOMAP_FILEIO for buffered I/O support + * - add FUSE_IOMAP_CONFIG so the fuse server can configure more fs geometry */ #ifndef _LINUX_FUSE_H @@ -676,6 +677,7 @@ enum fuse_opcode { FUSE_TMPFILE = 51, FUSE_STATX = 52, + FUSE_IOMAP_CONFIG = 4092, FUSE_IOMAP_IOEND = 4093, FUSE_IOMAP_BEGIN = 4094, FUSE_IOMAP_END = 4095, @@ -1376,4 +1378,32 @@ struct fuse_iomap_ioend_in { uint32_t reserved1; /* zero */ }; +struct fuse_iomap_config_in { + uint64_t flags; /* zero for now */ + int64_t maxbytes; /* max supported file size */ +}; + +struct fuse_iomap_config_out { + uint64_t flags; /* FUSE_IOMAP_CONFIG_* */ + + char s_id[32]; /* Informational name */ + char s_uuid[16]; /* UUID */ + + uint8_t s_uuid_len; /* length of s_uuid */ + + uint8_t s_pad[3]; /* must be zeroes */ + + uint32_t s_blocksize; /* fs block size */ + uint32_t s_max_links; /* max hard links */ + + /* Granularity of c/m/atime in ns (cannot be worse than a second) */ + uint32_t s_time_gran; + + /* Time limits for c/m/atime in seconds */ + int64_t s_time_min; + int64_t s_time_max; + + int64_t s_maxbytes; /* max file size */ +}; + #endif /* _LINUX_FUSE_H */ diff --git a/include/fuse_lowlevel.h b/include/fuse_lowlevel.h index a529a112998d6e..fd7df5c2c11e16 100644 --- a/include/fuse_lowlevel.h +++ b/include/fuse_lowlevel.h @@ -1387,6 +1387,19 @@ struct fuse_lowlevel_ops { uint64_t attr_ino, off_t pos, size_t written, uint32_t ioendflags, int error, uint64_t new_addr); + + /** + * Configure the filesystem geometry for iomap mode + * + * Valid replies: + * fuse_reply_iomap_config + * fuse_reply_err + * + * @param req request handle + * @param flags currently zero + * @param maxbytes maximum supported file size + */ + void (*iomap_config) (fuse_req_t req, uint32_t flags, int64_t maxbytes); #endif /* FUSE_USE_VERSION >= 318 */ }; @@ -1856,6 +1869,18 @@ int fuse_reply_lseek(fuse_req_t req, off_t off); */ int fuse_reply_iomap_begin(fuse_req_t req, const struct fuse_iomap *read_iomap, const struct fuse_iomap *write_iomap); + +/** + * Reply with iomap configuration + * + * Possible requests: + * iomap_config + * + * @param req request handle + * @param cfg iomap configuration + * @return zero for success, -errno for failure to send reply + */ +int fuse_reply_iomap_config(fuse_req_t req, const struct fuse_iomap_config *cfg); #endif /* FUSE_USE_VERSION >= 318 */ /* ----------------------------------------------------------- * diff --git a/lib/fuse_lowlevel.c b/lib/fuse_lowlevel.c index 0c7d5cc99945ee..ed9464d592c8a1 100644 --- a/lib/fuse_lowlevel.c +++ b/lib/fuse_lowlevel.c @@ -2583,6 +2583,59 @@ static void do_iomap_ioend(fuse_req_t req, const fuse_ino_t nodeid, _do_iomap_ioend(req, nodeid, inarg, NULL); } +int fuse_reply_iomap_config(fuse_req_t req, const struct fuse_iomap_config *cfg) +{ + struct fuse_iomap_config_out arg = { + .flags = cfg->flags, + }; + + if (cfg->flags & FUSE_IOMAP_CONFIG_BLOCKSIZE) + arg.s_blocksize = cfg->s_blocksize; + + if (cfg->flags & FUSE_IOMAP_CONFIG_SID) + memcpy(arg.s_id, cfg->s_id, sizeof(arg.s_id)); + + if (cfg->flags & FUSE_IOMAP_CONFIG_UUID) { + arg.s_uuid_len = cfg->s_uuid_len; + if (arg.s_uuid_len > sizeof(arg.s_uuid)) + arg.s_uuid_len = sizeof(arg.s_uuid); + memcpy(arg.s_uuid, cfg->s_uuid, arg.s_uuid_len); + } + + if (cfg->flags & FUSE_IOMAP_CONFIG_MAX_LINKS) + arg.s_max_links = cfg->s_max_links; + + if (cfg->flags & FUSE_IOMAP_CONFIG_TIME) { + arg.s_time_gran = cfg->s_time_gran; + arg.s_time_min = cfg->s_time_min; + arg.s_time_max = cfg->s_time_max; + } + + if (cfg->flags & FUSE_IOMAP_CONFIG_MAXBYTES) + arg.s_maxbytes = cfg->s_maxbytes; + + return send_reply_ok(req, &arg, sizeof(arg)); +} + +static void _do_iomap_config(fuse_req_t req, const fuse_ino_t nodeid, + const void *op_in, const void *in_payload) +{ + (void)nodeid; + (void)in_payload; + const struct fuse_iomap_config_in *arg = op_in; + + if (req->se->op.iomap_config) + req->se->op.iomap_config(req, arg->flags, arg->maxbytes); + else + fuse_reply_err(req, ENOSYS); +} + +static void do_iomap_config(fuse_req_t req, const fuse_ino_t nodeid, + const void *inarg) +{ + _do_iomap_config(req, nodeid, inarg, NULL); +} + static bool want_flags_valid(uint64_t capable, uint64_t want) { uint64_t unknown_flags = want & (~capable); @@ -3474,6 +3527,7 @@ static struct { [FUSE_RENAME2] = { do_rename2, "RENAME2" }, [FUSE_COPY_FILE_RANGE] = { do_copy_file_range, "COPY_FILE_RANGE" }, [FUSE_LSEEK] = { do_lseek, "LSEEK" }, + [FUSE_IOMAP_CONFIG]= { do_iomap_config, "IOMAP_CONFIG" }, [FUSE_IOMAP_BEGIN] = { do_iomap_begin, "IOMAP_BEGIN" }, [FUSE_IOMAP_END] = { do_iomap_end, "IOMAP_END" }, [FUSE_IOMAP_IOEND] = { do_iomap_ioend, "IOMAP_IOEND" }, @@ -3531,6 +3585,7 @@ static struct { [FUSE_RENAME2] = { _do_rename2, "RENAME2" }, [FUSE_COPY_FILE_RANGE] = { _do_copy_file_range, "COPY_FILE_RANGE" }, [FUSE_LSEEK] = { _do_lseek, "LSEEK" }, + [FUSE_IOMAP_CONFIG] = { _do_iomap_config, "IOMAP_CONFIG" }, [FUSE_IOMAP_BEGIN] = { _do_iomap_begin, "IOMAP_BEGIN" }, [FUSE_IOMAP_END] = { _do_iomap_end, "IOMAP_END" }, [FUSE_IOMAP_IOEND] = { _do_iomap_ioend, "IOMAP_IOEND" }, diff --git a/lib/fuse_versionscript b/lib/fuse_versionscript index 606fdc6127462e..9cb46d8a7afdd2 100644 --- a/lib/fuse_versionscript +++ b/lib/fuse_versionscript @@ -220,6 +220,7 @@ FUSE_3.18 { fuse_reply_entry_iflags; fuse_add_direntry_plus_iflags; fuse_discover_iomap; + fuse_reply_iomap_config; } FUSE_3.17; # Local Variables: