From: Darrick J. Wong <djwong@xxxxxxxxxx> Upload the filesystem geometry to the kernel when asked. Signed-off-by: "Darrick J. Wong" <djwong@xxxxxxxxxx> --- misc/fuse2fs.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 3 deletions(-) diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c index d4912dee08d43f..fb71886b58f215 100644 --- a/misc/fuse2fs.c +++ b/misc/fuse2fs.c @@ -194,6 +194,10 @@ static inline uint64_t round_down(uint64_t b, unsigned int align) # define FL_ZERO_RANGE_FLAG (0) #endif +#ifndef NSEC_PER_SEC +# define NSEC_PER_SEC (1000000000L) +#endif + errcode_t ext2fs_run_ext3_journal(ext2_filsys *fs); const char *err_shortdev; @@ -575,9 +579,9 @@ static int update_atime(ext2_filsys fs, ext2_ino_t ino) EXT4_INODE_GET_XTIME(i_mtime, &mtime, pinode); get_now(&now); - datime = atime.tv_sec + ((double)atime.tv_nsec / 1000000000); - dmtime = mtime.tv_sec + ((double)mtime.tv_nsec / 1000000000); - dnow = now.tv_sec + ((double)now.tv_nsec / 1000000000); + datime = atime.tv_sec + ((double)atime.tv_nsec / NSEC_PER_SEC); + dmtime = mtime.tv_sec + ((double)mtime.tv_nsec / NSEC_PER_SEC); + dnow = now.tv_sec + ((double)now.tv_nsec / NSEC_PER_SEC); /* * If atime is newer than mtime and atime hasn't been updated in thirty @@ -5228,6 +5232,91 @@ static int op_iomap_end(const char *path, uint64_t nodeid, uint64_t attr_ino, return 0; } + +/* + * Maximal extent format file size. + * Resulting logical blkno at s_maxbytes must fit in our on-disk + * extent format containers, within a sector_t, and within i_blocks + * in the vfs. ext4 inode has 48 bits of i_block in fsblock units, + * so that won't be a limiting factor. + * + * However there is other limiting factor. We do store extents in the form + * of starting block and length, hence the resulting length of the extent + * covering maximum file size must fit into on-disk format containers as + * well. Given that length is always by 1 unit bigger than max unit (because + * we count 0 as well) we have to lower the s_maxbytes by one fs block. + * + * Note, this does *not* consider any metadata overhead for vfs i_blocks. + */ +static off_t fuse2fs_max_size(struct fuse2fs *ff, off_t upper_limit) +{ + off_t res; + + if (!ext2fs_has_feature_huge_file(ff->fs->super)) { + upper_limit = (1LL << 32) - 1; + + /* total blocks in file system block size */ + upper_limit >>= (ff->blocklog - 9); + upper_limit <<= ff->blocklog; + } + + /* + * 32-bit extent-start container, ee_block. We lower the maxbytes + * by one fs block, so ee_len can cover the extent of maximum file + * size + */ + res = (1LL << 32) - 1; + res <<= ff->blocklog; + + /* Sanity check against vm- & vfs- imposed limits */ + if (res > upper_limit) + res = upper_limit; + + return res; +} + +static int op_iomap_config(uint32_t flags, off_t maxbytes, + struct fuse_iomap_config *cfg) +{ + struct fuse_context *ctxt = fuse_get_context(); + struct fuse2fs *ff = (struct fuse2fs *)ctxt->private_data; + ext2_filsys fs; + + FUSE2FS_CHECK_CONTEXT(ff); + + dbg_printf(ff, "%s: flags=0x%x maxbytes=0x%llx\n", __func__, flags, + (long long)maxbytes); + fs = fuse2fs_start(ff); + + cfg->flags |= FUSE_IOMAP_CONFIG_UUID; + memcpy(cfg->s_uuid, fs->super->s_uuid, sizeof(cfg->s_uuid)); + cfg->s_uuid_len = sizeof(fs->super->s_uuid); + + cfg->flags |= FUSE_IOMAP_CONFIG_BLOCKSIZE; + cfg->s_blocksize = FUSE2FS_FSB_TO_B(ff, 1); + + /* + * If there inode is large enough to house i_[acm]time_extra then we + * can turn on nanosecond timestamps; i_crtime was the next field added + * after i_atime_extra. + */ + cfg->flags |= FUSE_IOMAP_CONFIG_TIME; + if (fs->super->s_inode_size >= + offsetof(struct ext2_inode_large, i_crtime)) { + cfg->s_time_gran = 1; + cfg->s_time_max = EXT4_EXTRA_TIMESTAMP_MAX; + } else { + cfg->s_time_gran = NSEC_PER_SEC; + cfg->s_time_max = EXT4_NON_EXTRA_TIMESTAMP_MAX; + } + cfg->s_time_min = EXT4_TIMESTAMP_MIN; + + cfg->flags |= FUSE_IOMAP_CONFIG_MAXBYTES; + cfg->s_maxbytes = fuse2fs_max_size(ff, maxbytes); + + fuse2fs_finish(ff, 0); + return 0; +} #endif /* HAVE_FUSE_IOMAP */ static struct fuse_operations fs_ops = { @@ -5293,6 +5382,7 @@ static struct fuse_operations fs_ops = { #ifdef HAVE_FUSE_IOMAP .iomap_begin = op_iomap_begin, .iomap_end = op_iomap_end, + .iomap_config = op_iomap_config, #endif /* HAVE_FUSE_IOMAP */ };