>From b3ad517ba41f8dc2129564ecfefcac45062076d5 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 10 Sep 2025 10:56:37 -0400 Subject: [PATCH 2/2] DO NOT SUBMIT: tune2fs: initial support for EXT4_IOC_GET_TUNE_SB_PARAM Not-Signed-off-by: Theodore Ts'o --- misc/tune2fs.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 188 insertions(+), 10 deletions(-) diff --git a/misc/tune2fs.c b/misc/tune2fs.c index b4c63da4..b76fba8c 100644 --- a/misc/tune2fs.c +++ b/misc/tune2fs.c @@ -101,6 +101,59 @@ struct fsuuid { #define EXT4_IOC_SETFSUUID _IOW('f', 44, struct fsuuid) #endif +#if (!defined(EXT4_IOC_GET_TUNE_SB_PARAM) && defined(__linux__)) + +struct ext4_tune_sb_params { + __u32 set_flags; + __u32 checkinterval; + __u16 errors_behavior; + __u16 mnt_count; + __u16 max_mnt_count; + __u16 raid_stride; + __u64 last_check_time; + __u64 reserved_blocks; + __u64 blocks_count; + __u32 default_mnt_opts; + __u32 reserved_uid; + __u32 reserved_gid; + __u32 raid_stripe_width; + __u8 def_hash_alg; + __u8 pad_1; + __u16 pad_2; + __u32 feature_compat; + __u32 feature_incompat; + __u32 feature_ro_compat; + __u32 set_feature_compat_mask; + __u32 set_feature_incompat_mask; + __u32 set_feature_ro_compat_mask; + __u32 clear_feature_compat_mask; + __u32 clear_feature_incompat_mask; + __u32 clear_feature_ro_compat_mask; + __u8 mount_opts[64]; + __u8 pad[64]; +}; + +#define EXT4_TUNE_FL_ERRORS_BEHAVIOR 0x00000001 +#define EXT4_TUNE_FL_MNT_COUNT 0x00000002 +#define EXT4_TUNE_FL_MAX_MNT_COUNT 0x00000004 +#define EXT4_TUNE_FL_CHECKINTRVAL 0x00000008 +#define EXT4_TUNE_FL_LAST_CHECK_TIME 0x00000010 +#define EXT4_TUNE_FL_RESERVED_BLOCKS 0x00000020 +#define EXT4_TUNE_FL_RESERVED_UID 0x00000040 +#define EXT4_TUNE_FL_RESERVED_GID 0x00000080 +#define EXT4_TUNE_FL_DEFAULT_MNT_OPTS 0x00000100 +#define EXT4_TUNE_FL_DEF_HASH_ALG 0x00000200 +#define EXT4_TUNE_FL_RAID_STRIDE 0x00000400 +#define EXT4_TUNE_FL_RAID_STRIPE_WIDTH 0x00000800 +#define EXT4_TUNE_FL_MOUNT_OPTS 0x00001000 +#define EXT4_TUNE_FL_FEATURES 0x00002000 +#define EXT4_TUNE_FL_EDIT_FEATURES 0x00002000 + +#define EXT4_IOC_GET_TUNE_SB_PARAM _IOR('f', 45, struct ext4_tune_sb_params) +#define EXT4_IOC_SET_TUNE_SB_PARAM _IOW('f', 46, struct ext4_tune_sb_params) + +#endif + extern int ask_yn(const char *string, int def); #define OPT_MAX_MOUNTCOUNT 1 @@ -160,6 +213,10 @@ char *journal_device; static blk64_t journal_location = ~0LL; static e2_blkcnt_t orphan_file_blocks; +static int fs_fd = -1; +static int fs_mnt_flags = 0; +static int fs_set_ops = 0; + static struct list_head blk_move_list; struct blk_move { @@ -2039,6 +2096,10 @@ static void parse_tune2fs_options(int argc, char **argv) } if (max_mount_count == 0) max_mount_count = -1; + else if (max_mount_count == 65536) { + max_mount_count = EXT2_DFL_MAX_MNT_COUNT + + (random() % EXT2_DFL_MAX_MNT_COUNT); + } break; case 'C': opts[OPT_MOUNTCOUNT] = true; @@ -2121,6 +2182,12 @@ static void parse_tune2fs_options(int argc, char **argv) _("bad interval - %s"), optarg); usage(); } + if ((unsigned long long)interval >= (1ULL << 32)) { + com_err(program_name, 0, + _("interval between checks is too big (%lu)"), + interval); + exit(1); + } break; case 'j': opts[OPT_JOURNAL_SIZE] = true; @@ -3124,6 +3191,121 @@ fs_update_journal_user(struct ext2_super_block *sb, __u8 old_uuid[UUID_SIZE]) return 0; } +static void try_mounted_access() +{ +#ifdef __linux__ + errcode_t ret; + char mntpt[PATH_MAX + 1]; + struct ext4_tune_sb_params params; + __u64 fs_blocks_count; + __u32 fs_feature_array[3]; + int opts_success = 0; + + fs_fd = -1; + fs_mnt_flags = 0; + ret = ext2fs_check_mount_point(device_name, &fs_mnt_flags, + mntpt, sizeof( + mntpt)); + if (ret) + return; + + if (!(fs_mnt_flags & EXT2_MF_MOUNTED)) + return; + + if (!mntpt[0]) + return; + + fs_fd = open(mntpt, O_RDONLY); + if (fs_fd < 0) + return; + + if (ioctl(fs_fd, EXT4_IOC_GET_TUNE_SB_PARAM, ¶ms)) + return; + + fs_set_ops = params.set_flags; + fs_blocks_count = params.blocks_count; + fs_feature_array[0] = params.feature_compat; + fs_feature_array[1] = params.feature_incompat; + fs_feature_array[2] = params.feature_ro_compat; + + memset(¶ms, 0, sizeof(params)); + + if (opts[OPT_ERROR_BEHAVIOR] && + (fs_set_ops & EXT4_TUNE_FL_ERRORS_BEHAVIOR)) { + params.set_flags |= EXT4_TUNE_FL_ERRORS_BEHAVIOR; + params.errors_behavior = errors; + } + if (opts[OPT_MOUNTCOUNT] && + (fs_set_ops & EXT4_TUNE_FL_MNT_COUNT)) { + params.set_flags |= EXT4_TUNE_FL_MNT_COUNT; + params.mnt_count = mount_count; + } + if (opts[OPT_MAX_MOUNTCOUNT] && + (fs_set_ops & EXT4_TUNE_FL_MAX_MNT_COUNT)) { + params.set_flags |= EXT4_TUNE_FL_MAX_MNT_COUNT; + params.max_mnt_count = max_mount_count; + } + if (opts[OPT_CHECKINTERVAL] && + (fs_set_ops & EXT4_TUNE_FL_CHECKINTRVAL)) { + params.set_flags |= EXT4_TUNE_FL_CHECKINTRVAL; + params.checkinterval = interval; + } + if (opts[OPT_CHECKTIME] && + (fs_set_ops & EXT4_TUNE_FL_LAST_CHECK_TIME)) { + params.set_flags |= EXT4_TUNE_FL_LAST_CHECK_TIME; + params.last_check_time = last_check_time; + } + if (opts[OPT_RESUID] && + (fs_set_ops & EXT4_TUNE_FL_RESERVED_UID)) { + params.set_flags |= EXT4_TUNE_FL_RESERVED_UID; + params.reserved_uid = resuid; + } + if (opts[OPT_RESGID] && + (fs_set_ops & EXT4_TUNE_FL_RESERVED_GID)) { + params.set_flags |= EXT4_TUNE_FL_RESERVED_GID; + params.reserved_uid = resgid; + } + if (opts[OPT_RESERVED_RATIO) && !opts[OPT_RESERVED_BLOCKS]) { + reserved_blocks = reserved_ratio * fs_blocks_count / 100.0; + opts[OPT_RESERVED_BLOCKS] = true; + } + if (opts[OPT_RESERVED_BLOCKS] && + (fs_set_ops & EXT4_TUNE_FL_RESERVED_BLOCKS)) { + params.set_flags |= EXT4_TUNE_FL_RESERVED_BLOCKS; + params.reserved_blocks = reserved_blocks; + } + +/* TODO: + * EXT4_TUNE_FL_DEFAULT_MNT_OPTS + * EXT4_TUNE_FL_DEF_HASH_ALG + * EXT4_TUNE_FL_RAID_STRIDE + * EXT4_TUNE_FL_RAID_STRIPE_WIDTH + * EXT4_TUNE_FL_MOUNT_OPTS + * EXT4_TUNE_FL_FEATURES + */ + + if (ioctl(fs_fd, EXT4_IOC_SET_TUNE_SB_PARAM, ¶ms) == 0) { + opts[OPT_ERROR_BEHAVIOR] = opts[OPT_MOUNTCOUNT] = + opts[OPT_MAX_MOUNTCOUNT] = opts[OPT_CHECKINTERVAL] = + opts[OPT_CHECKTIME] = opts[OPT_RESUID] = + opts[OPT_RESGID] = opts[OPT_RESERVED_RATIO] = + opts[OPT_RESERVED_BLOCKS] = false; + printf("ioctl EXT4_IOC_SET_TUNE_SB_PARAM succeeded\n"); + } else { + perror("ioctl EXT4_IOC_SET_TUNE_SB_PARAM"); + exit(1); + } + close(fs_fd); + +#else + fs_fd = -1; + fs_mnt_flags = 0; +#endif + printf("fs_fd %d, mnt_flags %08x, set_ops %08x\n", fs_fd, + fs_mnt_flags, fs_set_ops); +} + + /* * Use FS_IOC_SETFSLABEL or FS_IOC_GETFSLABEL to set/get file system label * Return: 0 on success @@ -3239,6 +3421,12 @@ int tune2fs_main(int argc, char **argv) #endif io_ptr = unix_io_manager; + try_mounted_access(); + if (!tune_opts_requested()) { + printf("No further tune opts left\n"); + exit(0); + } + /* * Try the get/set fs label using ioctls before we even attempt * to open the file system. @@ -3401,9 +3589,6 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" fs->flags |= EXT2_FLAG_SUPER_ONLY; if (opts[OPT_MAX_MOUNTCOUNT]) { - if (max_mount_count == 65536) - max_mount_count = EXT2_DFL_MAX_MNT_COUNT + - (random() % EXT2_DFL_MAX_MNT_COUNT); sb->s_max_mnt_count = max_mount_count; ext2fs_mark_super_dirty(fs); printf(_("Setting maximal mount count to %d\n"), @@ -3429,13 +3614,6 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n" } } if (opts[OPT_CHECKINTERVAL]) { - if ((unsigned long long)interval >= (1ULL << 32)) { - com_err(program_name, 0, - _("interval between checks is too big (%lu)"), - interval); - rc = 1; - goto closefs; - } sb->s_checkinterval = interval; ext2fs_mark_super_dirty(fs); printf(_("Setting interval between checks to %lu seconds\n"), -- 2.51.0