[PATCH 13/19] fuse2fs: improve want_extra_isize handling

Darrick J. Wong
2025-11-06T22:34:32Z

System administrators can set the {min,want}_extra_isize fields in the
superblock to try to influence the allocation of extra space in an
inode. Currently fuse2fs ignores any such value and sets it to the
minimum possible size; let's actually follow it, like the kernel does.

Note: fuse2fs isn't quite as flexible as the kernel is about changing
extra_isize, so this isn't quite good enough to pass ext4/022.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
misc/fuse2fs.c | 29 +++++++++++++++++++++++++----
1 file changed, 25 insertions(+), 4 deletions(-)

diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
index 4af22ea9e0d3a3..f1fb7227f1d077 100644
--- a/misc/fuse2fs.c
+++ b/misc/fuse2fs.c
@@ -1403,6 +1403,27 @@ static inline int fuse2fs_dirsync_flush(struct fuse2fs *ff, ext2_ino_t ino,
return 0;
}

+static void fuse2fs_set_extra_isize(struct fuse2fs *ff, ext2_ino_t ino,
+ struct ext2_inode_large *inode)
+{
+ ext2_filsys fs = ff->fs;
+ size_t extra = sizeof(struct ext2_inode_large) -
+ EXT2_GOOD_OLD_INODE_SIZE;
+
+ if (ext2fs_has_feature_extra_isize(fs->super)) {
+ dbg_printf(ff, "%s: ino=%u extra=%zu want=%u min=%u\n",
+ __func__, ino, extra, fs->super->s_want_extra_isize,
+ fs->super->s_min_extra_isize);
+
+ if (fs->super->s_want_extra_isize > extra)
+ extra = fs->super->s_want_extra_isize;
+ if (fs->super->s_min_extra_isize > extra)
+ extra = fs->super->s_min_extra_isize;
+ }
+
+ inode->i_extra_isize = extra;
+}
+
static int op_mknod(const char *path, mode_t mode, dev_t dev)
{
struct fuse_context *ctxt = fuse_get_context();
@@ -1498,8 +1519,7 @@ static int op_mknod(const char *path, mode_t mode, dev_t dev)
else
inode.i_block[0] = dev;
inode.i_links_count = 1;
- inode.i_extra_isize = sizeof(struct ext2_inode_large) -
- EXT2_GOOD_OLD_INODE_SIZE;
+ fuse2fs_set_extra_isize(ff, child, &inode);
fuse2fs_set_uid(&inode, ctxt->uid);
fuse2fs_set_gid(&inode, gid);

@@ -1617,6 +1637,7 @@ static int op_mkdir(const char *path, mode_t mode)
goto out2;
}

+ fuse2fs_set_extra_isize(ff, child, &inode);
fuse2fs_set_uid(&inode, ctxt->uid);
fuse2fs_set_gid(&inode, gid);
inode.i_mode = LINUX_S_IFDIR | (mode & ~S_ISUID);
@@ -2079,6 +2100,7 @@ static int op_symlink(const char *src, const char *dest)
goto out2;
}

+ fuse2fs_set_extra_isize(ff, child, &inode);
fuse2fs_set_uid(&inode, ctxt->uid);
fuse2fs_set_gid(&inode, gid);
inode.i_generation = ff->next_generation++;
@@ -3760,8 +3782,7 @@ static int op_create(const char *path, mode_t mode, struct fuse_file_info *fp)
memset(&inode, 0, sizeof(inode));
inode.i_mode = mode;
inode.i_links_count = 1;
- inode.i_extra_isize = sizeof(struct ext2_inode_large) -
- EXT2_GOOD_OLD_INODE_SIZE;
+ fuse2fs_set_extra_isize(ff, child, &inode);
fuse2fs_set_uid(&inode, ctxt->uid);
fuse2fs_set_gid(&inode, gid);
if (ext2fs_has_feature_extents(fs->super)) {