linux-ext4.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH RFC 0/3] mke2fs: small doc and features
@ 2025-09-09 15:40 Ralph Siemsen
  2025-09-09 15:40 ` [PATCH RFC 1/3] mke2fs: document the hash_seed option Ralph Siemsen
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Ralph Siemsen @ 2025-09-09 15:40 UTC (permalink / raw)
  To: linux-ext4; +Cc: Ralph Siemsen

Three independent fixes for mke2fs:

1) document the hash_seed option
2) prohibit multiple '-E' arguments 
3) add extended option for setting root inode security context

The first fix is straightforward.

For the second one, some alternatives would be:
- only print a warning, not a fatal error (but that is easy to miss)
- allow multiple '-E' options, and join them automatically

For the third one, the main use case is when generating empty
filesystems for use when SELinux is enabled.

Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
Ralph Siemsen (3):
      mke2fs: document the hash_seed option
      mke2fs.c: fail on multiple '-E' options
      mke2fs: add root_selinux option for root inode label

 misc/mke2fs.8.in              | 14 +++++++++++
 misc/mke2fs.c                 | 53 ++++++++++++++++++++++++++++++++++++++++
 tests/m_root_selinux/expect.1 | 57 +++++++++++++++++++++++++++++++++++++++++++
 tests/m_root_selinux/script   |  4 +++
 4 files changed, 128 insertions(+)
---
base-commit: 4b02eb164221c079b428566499343af2766c2ec3
change-id: 20250909-mke2fs-small-fixes-6d4a0c3a8781

Best regards,
--  
Ralph Siemsen <ralph.siemsen@linaro.org>


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH RFC 1/3] mke2fs: document the hash_seed option
  2025-09-09 15:40 [PATCH RFC 0/3] mke2fs: small doc and features Ralph Siemsen
@ 2025-09-09 15:40 ` Ralph Siemsen
  2025-09-09 15:40 ` [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options Ralph Siemsen
  2025-09-09 15:40 ` [PATCH RFC 3/3] mke2fs: add root_selinux option for root inode label Ralph Siemsen
  2 siblings, 0 replies; 12+ messages in thread
From: Ralph Siemsen @ 2025-09-09 15:40 UTC (permalink / raw)
  To: linux-ext4; +Cc: Ralph Siemsen

For reproducible builds, it is necessary to control the random seed used
for hashing. Document the extended option for this feature.

Fixes: e1f71006 ("AOSP: mke2fs, libext2fs: make filesystem image reproducible")
Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
 misc/mke2fs.8.in | 4 ++++
 misc/mke2fs.c    | 1 +
 2 files changed, 5 insertions(+)

diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
index 13ddef47..14bae326 100644
--- a/misc/mke2fs.8.in
+++ b/misc/mke2fs.8.in
@@ -320,6 +320,10 @@ In the default configuration, the
 .I strict
 flag is disabled.
 .TP
+.BI hash_seed= UUID
+Use the specified UUID as the seed for hashing, rather than generating a
+random seed each time. Intended for use with reproducible builds.
+.TP
 .B lazy_itable_init\fR[\fB= \fI<0 to disable, 1 to enable>\fR]
 If enabled and the uninit_bg feature is enabled, the inode table will
 not be fully initialized by
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 7f81a513..3a8ff5b1 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -1180,6 +1180,7 @@ static void parse_extended_opts(struct ext2_super_block *param,
 			"\trevision=<revision>\n"
 			"\tencoding=<encoding>\n"
 			"\tencoding_flags=<flags>\n"
+			"\thash_seed=<UUID for hash seed>\n"
 			"\tquotatype=<quota type(s) to be enabled>\n"
 			"\tassume_storage_prezeroed=<0 to disable, 1 to enable>\n\n"),
 			badopt ? badopt : "");

-- 
2.45.2.121.gc2b3f2b3cd


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options
  2025-09-09 15:40 [PATCH RFC 0/3] mke2fs: small doc and features Ralph Siemsen
  2025-09-09 15:40 ` [PATCH RFC 1/3] mke2fs: document the hash_seed option Ralph Siemsen
@ 2025-09-09 15:40 ` Ralph Siemsen
  2025-09-10  0:32   ` Andreas Dilger
  2025-09-09 15:40 ` [PATCH RFC 3/3] mke2fs: add root_selinux option for root inode label Ralph Siemsen
  2 siblings, 1 reply; 12+ messages in thread
From: Ralph Siemsen @ 2025-09-09 15:40 UTC (permalink / raw)
  To: linux-ext4; +Cc: Ralph Siemsen

Make it an error to pass multiple -E options. As per the man page,
multiple extended options must be specified as a comma-separated list,
instead of multiple -E options.

This helps avoid surprises, as the existing behaviour is to process
only the last -E option, and to silently ignore any earlier ones.

Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
 misc/mke2fs.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 3a8ff5b1..59c7be17 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -1796,6 +1796,12 @@ profile_error:
 				_("'-R' is deprecated, use '-E' instead"));
 			/* fallthrough */
 		case 'E':
+			if (extended_opts) {
+				com_err(program_name, 0, "%s",
+					_("Multiple '-E' options are not supported, "
+					  "use one comma-separated value instead"));
+				exit(1);
+			}
 			extended_opts = optarg;
 			break;
 		case 'e':

-- 
2.45.2.121.gc2b3f2b3cd


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH RFC 3/3] mke2fs: add root_selinux option for root inode label
  2025-09-09 15:40 [PATCH RFC 0/3] mke2fs: small doc and features Ralph Siemsen
  2025-09-09 15:40 ` [PATCH RFC 1/3] mke2fs: document the hash_seed option Ralph Siemsen
  2025-09-09 15:40 ` [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options Ralph Siemsen
@ 2025-09-09 15:40 ` Ralph Siemsen
  2 siblings, 0 replies; 12+ messages in thread
From: Ralph Siemsen @ 2025-09-09 15:40 UTC (permalink / raw)
  To: linux-ext4; +Cc: Ralph Siemsen

This option allows setting the SELinux security context (label) for the
root directory. A common value would be system_u:object_r:root_t
possibly with a level/range such as :s0 suffix (for MCS/MLS policy).

Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
---
 misc/mke2fs.8.in              | 10 ++++++++
 misc/mke2fs.c                 | 46 ++++++++++++++++++++++++++++++++++
 tests/m_root_selinux/expect.1 | 57 +++++++++++++++++++++++++++++++++++++++++++
 tests/m_root_selinux/script   |  4 +++
 4 files changed, 117 insertions(+)

diff --git a/misc/mke2fs.8.in b/misc/mke2fs.8.in
index 14bae326..6af71fd5 100644
--- a/misc/mke2fs.8.in
+++ b/misc/mke2fs.8.in
@@ -426,6 +426,16 @@ Specify the root directory permissions in octal format. If no permissions
 are specified then the root directory permissions would be set in accordance with
 the default filesystem umask.
 .TP
+.BI root_selinux= label
+Specify the root directory SELinux security context as
+.IR label ,
+typically
+.nh
+.B system_u:object_r:root_t
+with an optional level/range suffix such as
+.B :s0
+for MCS/MLS policy types.
+.TP
 .BI stride= stride-size
 Configure the file system for a RAID array with
 .I stride-size
diff --git a/misc/mke2fs.c b/misc/mke2fs.c
index 59c7be17..a16a808a 100644
--- a/misc/mke2fs.c
+++ b/misc/mke2fs.c
@@ -95,6 +95,7 @@ static int	num_backups = 2; /* number of backup bg's for sparse_super2 */
 static uid_t	root_uid;
 static mode_t 	root_perms = (mode_t)-1;
 static gid_t	root_gid;
+static char	*root_selinux = NULL;
 int	journal_size;
 int	journal_flags;
 int	journal_fc_size;
@@ -515,6 +516,35 @@ static void create_root_dir(ext2_filsys fs)
 			exit(1);
 		}
 	}
+
+	if (root_selinux) {
+		struct ext2_xattr_handle *handle;
+		retval = ext2fs_xattrs_open(fs, EXT2_ROOT_INO, &handle);
+		if (retval) {
+			com_err("ext2fs_xattrs_open", retval,
+				_("while setting root inode label"));
+			exit(1);
+		}
+		retval = ext2fs_xattrs_read(handle);
+		if (retval) {
+			com_err("ext2fs_xattrs_read", retval,
+				_("while setting root inode label"));
+			exit(1);
+		}
+		retval = ext2fs_xattr_set(handle, "security.selinux",
+					  root_selinux, strlen(root_selinux));
+		if (retval) {
+			com_err("ext2fs_xattr_set", retval,
+				_("while setting root inode label"));
+			exit(1);
+		}
+		retval = ext2fs_xattrs_close(&handle);
+		if (retval) {
+			com_err("ext2fs_xattrs_close", retval,
+				_("while setting root inode label"));
+			exit(1);
+		}
+	}
 }
 
 static void create_lost_and_found(ext2_filsys fs)
@@ -1089,6 +1119,21 @@ static void parse_extended_opts(struct ext2_super_block *param,
 			if (arg) {
 				root_perms = strtoul(arg, &p, 8);
 			}
+		} else if (!strcmp(token, "root_selinux")) {
+			if (arg) {
+				root_selinux = realloc(root_selinux,
+						       strlen(arg) + 1);
+				if (!root_selinux) {
+					com_err(program_name, ENOMEM, "%s",
+						_("in malloc for root_selinux"));
+					exit(1);
+				}
+				strcpy(root_selinux, arg);
+			} else {
+				r_usage++;
+				badopt = token;
+				continue;
+			}
 		} else if (!strcmp(token, "discard")) {
 			discard = 1;
 		} else if (!strcmp(token, "nodiscard")) {
@@ -1174,6 +1219,7 @@ static void parse_extended_opts(struct ext2_super_block *param,
 			"\tlazy_journal_init=<0 to disable, 1 to enable>\n"
 			"\troot_owner=<uid of root dir>:<gid of root dir>\n"
 			"\troot_perms=<octal root directory permissions>\n"
+			"\troot_selinux=<selinux root directory label>\n"
 			"\ttest_fs\n"
 			"\tdiscard\n"
 			"\tnodiscard\n"
diff --git a/tests/m_root_selinux/expect.1 b/tests/m_root_selinux/expect.1
new file mode 100644
index 00000000..19a3d6ee
--- /dev/null
+++ b/tests/m_root_selinux/expect.1
@@ -0,0 +1,57 @@
+Creating filesystem with 1024 1k blocks and 128 inodes
+
+Allocating group tables:    \b\b\bdone                            
+Writing inode tables:    \b\b\bdone                            
+Writing superblocks and filesystem accounting information:    \b\b\bdone
+
+Filesystem features: ext_attr resize_inode dir_index filetype sparse_super
+Pass 1: Checking inodes, blocks, and sizes
+Pass 2: Checking directory structure
+Pass 3: Checking directory connectivity
+Pass 4: Checking reference counts
+Pass 5: Checking group summary information
+test_filesys: 11/128 files (0.0% non-contiguous), 54/1024 blocks
+Exit status is 0
+Filesystem volume name:   <none>
+Last mounted on:          <not available>
+Filesystem magic number:  0xEF53
+Filesystem revision #:    1 (dynamic)
+Filesystem features:      ext_attr resize_inode dir_index filetype sparse_super
+Default mount options:    (none)
+Filesystem state:         clean
+Errors behavior:          Continue
+Filesystem OS type:       Linux
+Inode count:              128
+Block count:              1024
+Reserved block count:     51
+Overhead clusters:        40
+Free blocks:              970
+Free inodes:              117
+First block:              1
+Block size:               1024
+Fragment size:            1024
+Reserved GDT blocks:      3
+Blocks per group:         8192
+Fragments per group:      8192
+Inodes per group:         128
+Inode blocks per group:   32
+Mount count:              0
+Check interval:           15552000 (6 months)
+Reserved blocks uid:      0
+Reserved blocks gid:      0
+First inode:              11
+Inode size:               256
+Required extra isize:     32
+Desired extra isize:      32
+Default directory hash:   half_md4
+
+
+Group 0: (Blocks 1-1023)
+  Primary superblock at 1, Group descriptors at 2-2
+  Reserved GDT blocks at 3-5
+  Block bitmap at 6 (+5)
+  Inode bitmap at 7 (+6)
+  Inode table at 8-39 (+7)
+  970 free blocks, 117 free inodes, 2 directories
+  Free blocks: 54-1023
+  Free inodes: 12-128
diff --git a/tests/m_root_selinux/script b/tests/m_root_selinux/script
new file mode 100644
index 00000000..4ac82918
--- /dev/null
+++ b/tests/m_root_selinux/script
@@ -0,0 +1,4 @@
+DESCRIPTION="root directory SELinux security context"
+FS_SIZE=1024
+MKE2FS_OPTS="-E root_selinux=system_u:object_r:root_t"
+. $cmd_dir/run_mke2fs

-- 
2.45.2.121.gc2b3f2b3cd


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options
  2025-09-09 15:40 ` [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options Ralph Siemsen
@ 2025-09-10  0:32   ` Andreas Dilger
  2025-09-10  0:49     ` Ralph Siemsen
  0 siblings, 1 reply; 12+ messages in thread
From: Andreas Dilger @ 2025-09-10  0:32 UTC (permalink / raw)
  To: Ralph Siemsen; +Cc: linux-ext4, Ralph Siemsen

Ralph,
I think it would be much better to allow and merge multiple "-E" options.

Cheers, Andreas

> On Sep 9, 2025, at 09:43, Ralph Siemsen <ralph.siemsen@linaro.org> wrote:
> 
> Make it an error to pass multiple -E options. As per the man page,
> multiple extended options must be specified as a comma-separated list,
> instead of multiple -E options.
> 
> This helps avoid surprises, as the existing behaviour is to process
> only the last -E option, and to silently ignore any earlier ones.
> 
> Signed-off-by: Ralph Siemsen <ralph.siemsen@linaro.org>
> ---
> misc/mke2fs.c | 6 ++++++
> 1 file changed, 6 insertions(+)
> 
> diff --git a/misc/mke2fs.c b/misc/mke2fs.c
> index 3a8ff5b1..59c7be17 100644
> --- a/misc/mke2fs.c
> +++ b/misc/mke2fs.c
> @@ -1796,6 +1796,12 @@ profile_error:
>                _("'-R' is deprecated, use '-E' instead"));
>            /* fallthrough */
>        case 'E':
> +            if (extended_opts) {
> +                com_err(program_name, 0, "%s",
> +                    _("Multiple '-E' options are not supported, "
> +                      "use one comma-separated value instead"));
> +                exit(1);
> +            }
>            extended_opts = optarg;
>            break;
>        case 'e':
> 
> --
> 2.45.2.121.gc2b3f2b3cd
> 
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options
  2025-09-10  0:32   ` Andreas Dilger
@ 2025-09-10  0:49     ` Ralph Siemsen
  2025-09-10 14:52       ` Theodore Ts'o
  0 siblings, 1 reply; 12+ messages in thread
From: Ralph Siemsen @ 2025-09-10  0:49 UTC (permalink / raw)
  To: Andreas Dilger; +Cc: linux-ext4

Hi Andreas,

On Tue, Sep 9, 2025 at 8:32 PM Andreas Dilger <adilger@dilger.ca> wrote:
>
> I think it would be much better to allow and merge multiple "-E" options.

Agreed. I'll work on it and post a v2 patch.

Thanks for your feedback,
Ralph

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options
  2025-09-10  0:49     ` Ralph Siemsen
@ 2025-09-10 14:52       ` Theodore Ts'o
  2025-09-10 15:00         ` Theodore Ts'o
  2025-09-10 16:29         ` Ralph Siemsen
  0 siblings, 2 replies; 12+ messages in thread
From: Theodore Ts'o @ 2025-09-10 14:52 UTC (permalink / raw)
  To: Ralph Siemsen; +Cc: Andreas Dilger, linux-ext4

On Tue, Sep 09, 2025 at 08:49:37PM -0400, Ralph Siemsen wrote:
> Hi Andreas,
> 
> On Tue, Sep 9, 2025 at 8:32 PM Andreas Dilger <adilger@dilger.ca> wrote:
> >
> > I think it would be much better to allow and merge multiple "-E" options.
> 
> Agreed. I'll work on it and post a v2 patch.

What I would suggest that you do is to move code which mutates the
file system from parse_extended_opts() so it is only interpreting the
options, and move that code to tuine2fs_main().

That way we can call parse_extended_opts() multiple times.  In fact,
that had been on my todo list, since I need to do this to support
changing the superblock using ioctl's while it is mounted, so we can
deny read/write access to the block device while the file system is
mounted.  See [1].

[1] https://lore.kernel.org/all/20250908-tune2fs-v1-0-e3a6929f3355@mit.edu/

Cheers,

						- Ted

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options
  2025-09-10 14:52       ` Theodore Ts'o
@ 2025-09-10 15:00         ` Theodore Ts'o
  2025-09-10 16:29         ` Ralph Siemsen
  1 sibling, 0 replies; 12+ messages in thread
From: Theodore Ts'o @ 2025-09-10 15:00 UTC (permalink / raw)
  To: Ralph Siemsen; +Cc: Andreas Dilger, linux-ext4

[-- Attachment #1: Type: text/plain, Size: 1096 bytes --]

On Wed, Sep 10, 2025 at 10:52:41AM -0400, Theodore Ts'o wrote:
> What I would suggest that you do is to move code which mutates the
> file system from parse_extended_opts() so it is only interpreting the
> options, and move that code to tuine2fs_main().
> 
> That way we can call parse_extended_opts() multiple times.  In fact,
> that had been on my todo list, since I need to do this to support
> changing the superblock using ioctl's while it is mounted, so we can
> deny read/write access to the block device while the file system is
> mounted.  See [1].
> 
> [1] https://lore.kernel.org/all/20250908-tune2fs-v1-0-e3a6929f3355@mit.edu/

In fact, if you want to see the direction which I'm headed, here is a
purely in-progress patch set for tune2fs.  The first patch is
incomplete because it doesn't handle parse_extended_opts() yet.

Since I want to have two code paths for setting the file system
parameters (one when the file system is mounted, one when it is
unmounted), it's why I want to separate out the functionality in
parse_extended_opts().

      	      	       	       		     - Ted

[-- Attachment #2: 0001-tune2fs-reorganize-command-line-flag-handling.patch --]
[-- Type: text/x-diff, Size: 16794 bytes --]

From 198cba8bec884bbd51901ceae45fc4384acb113c Mon Sep 17 00:00:00 2001
From: Theodore Ts'o <tytso@mit.edu>
Date: Mon, 8 Sep 2025 14:16:32 -0400
Subject: [PATCH 1/2] tune2fs: reorganize command-line flag handling

Instead of using individual ad-hoc variables indicating whether a
particular superblock value has been requested to be changed (e.g.,
c_flag, C_flag, et.al) use an array of booleans with indexes that are
defined with more human-readable #define's (e.g., OPT_MAX_MOUNTCOUNT).

There should be no behavioral changes from this code restructuring.

Signed-off-by: Theodore Ts'o <tytso@mit.edu>
---
 misc/tune2fs.c | 206 +++++++++++++++++++++++++++----------------------
 1 file changed, 114 insertions(+), 92 deletions(-)

diff --git a/misc/tune2fs.c b/misc/tune2fs.c
index 3db57632..b4c63da4 100644
--- a/misc/tune2fs.c
+++ b/misc/tune2fs.c
@@ -103,13 +103,34 @@ struct fsuuid {
 
 extern int ask_yn(const char *string, int def);
 
+#define OPT_MAX_MOUNTCOUNT	 1
+#define OPT_MOUNTCOUNT		 2
+#define OPT_CHECKINTERVAL	 3
+#define OPT_CHECKTIME		 4
+#define OPT_ERROR_BEHAVIOR	 5
+#define OPT_RESUID		 6
+#define OPT_RESGID		 7
+#define OPT_RESERVED_BLOCKS	 8
+#define OPT_RESERVED_RATIO	 9
+#define OPT_INODE_SIZE	 	10
+#define OPT_LABEL		11
+#define OPT_UUID		12
+#define OPT_LAST_MOUNTED	13
+#define OPT_SPARSE_SUPER	14
+#define OPT_QUOTA		15
+#define OPT_JOURNAL_SIZE	16
+#define OPT_JOURNAL_OPTS	17
+#define OPT_MNTOPTS		18
+#define OPT_FEATURES		19
+#define OPT_EXTENDED_CMD	20
+#define MAX_OPTS		21
+static bool opts[MAX_OPTS];
+
 const char *program_name = "tune2fs";
 char *device_name;
 char *new_label, *new_last_mounted, *requested_uuid;
 char *io_options;
-static int c_flag, C_flag, e_flag, f_flag, g_flag, i_flag, l_flag, L_flag;
-static int m_flag, M_flag, Q_flag, r_flag, s_flag = -1, u_flag, U_flag, T_flag;
-static int I_flag;
+static int force, do_list_super, sparse_value = -1;
 static int clear_mmp;
 static time_t last_check_time;
 static int print_label;
@@ -237,6 +258,19 @@ static __u32 clear_ok_features[3] = {
 		EXT4_FEATURE_RO_COMPAT_READONLY
 };
 
+/**
+ * Return true if there is at least one superblock change requested
+ */
+static bool tune_opts_requested()
+{
+	int	i;
+
+	for (i = 0; i < MAX_OPTS; i++)
+		if (opts[i])
+			return true;
+	return false;
+}
+
 /**
  * Try to get journal super block if any
  */
@@ -293,7 +327,7 @@ static int remove_journal_device(ext2_filsys fs)
 	int		commit_remove_journal = 0;
 	io_manager	io_ptr;
 
-	if (f_flag)
+	if (force)
 		commit_remove_journal = 1; /* force removal even if error */
 
 	uuid_unparse(fs->super->s_journal_uuid, buf);
@@ -1204,7 +1238,7 @@ static int update_feature_set(ext2_filsys fs, char *features)
 			return 1;
 		}
 		if (ext2fs_has_feature_journal_needs_recovery(sb) &&
-		    f_flag < 2) {
+		    force < 2) {
 			fputs(_("The needs_recovery flag is set.  "
 				"Please run e2fsck before clearing\n"
 				"the has_journal flag.\n"), stderr);
@@ -1228,7 +1262,7 @@ static int update_feature_set(ext2_filsys fs, char *features)
 				"when the filesystem is unmounted.\n"), stderr);
 			return 1;
 		}
-		if (ext2fs_has_feature_orphan_present(sb) && f_flag < 2) {
+		if (ext2fs_has_feature_orphan_present(sb) && force < 2) {
 			fputs(_("The orphan_present feature is set. Please "
 				"run e2fsck before clearing orphan_file "
 				"feature.\n"),
@@ -1551,8 +1585,8 @@ mmp_error:
 		 * Set the Q_flag here and handle the quota options in the code
 		 * below.
 		 */
-		if (!Q_flag) {
-			Q_flag = 1;
+		if (!opts[OPT_QUOTA]) {
+			opts[OPT_QUOTA] = 1;
 			/* Enable usr/grp quota by default */
 			for (qtype = 0; qtype < MAXQUOTAS; qtype++) {
 				if (qtype != PRJQUOTA)
@@ -1571,26 +1605,26 @@ mmp_error:
 					  "inode size too small.\n"));
 			return 1;
 		}
-		Q_flag = 1;
+		opts[OPT_QUOTA] = true;
 		quota_enable[PRJQUOTA] = QOPT_ENABLE;
 	}
 
 	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
 			EXT4_FEATURE_RO_COMPAT_PROJECT)) {
-		Q_flag = 1;
+		opts[OPT_QUOTA] = true;
 		quota_enable[PRJQUOTA] = QOPT_DISABLE;
 	}
 
 	if (FEATURE_OFF(E2P_FEATURE_RO_INCOMPAT,
 				EXT4_FEATURE_RO_COMPAT_QUOTA)) {
 		/*
-		 * Set the Q_flag here and handle the quota options in the code
-		 * below.
+		 * Set the quota flag here and handle the quota
+		 * options in the code below.
 		 */
-		if (Q_flag)
+		if (opts[OPT_QUOTA])
 			fputs(_("\nWarning: '^quota' option overrides '-Q'"
 				"arguments.\n"), stderr);
-		Q_flag = 1;
+	        opts[OPT_QUOTA] = true;
 		/* Disable all quota by default */
 		for (qtype = 0; qtype < MAXQUOTAS; qtype++)
 			quota_enable[qtype] = QOPT_DISABLE;
@@ -1940,7 +1974,7 @@ static void parse_e2label_options(int argc, char ** argv)
 	open_flag = EXT2_FLAG_JOURNAL_DEV_OK | EXT2_FLAG_SUPER_ONLY;
 	if (argc == 3) {
 		open_flag |= EXT2_FLAG_RW;
-		L_flag = 1;
+		opts[OPT_LABEL] = true;
 		new_label = argv[2];
 	} else
 		print_label++;
@@ -1990,8 +2024,7 @@ static void parse_tune2fs_options(int argc, char **argv)
 	while ((c = getopt(argc, argv, optstring)) != EOF)
 		switch (c) {
 		case 'c':
-			open_flag = EXT2_FLAG_RW;
-			c_flag = 1;
+			opts[OPT_MAX_MOUNTCOUNT] = true;
 			if (strcmp(optarg, "random") == 0) {
 				max_mount_count = 65536;
 				break;
@@ -2008,6 +2041,7 @@ static void parse_tune2fs_options(int argc, char **argv)
 				max_mount_count = -1;
 			break;
 		case 'C':
+			opts[OPT_MOUNTCOUNT] = true;
 			mount_count = strtoul(optarg, &tmp, 0);
 			if (*tmp || mount_count > 16000) {
 				com_err(program_name, 0,
@@ -2015,10 +2049,9 @@ static void parse_tune2fs_options(int argc, char **argv)
 					optarg);
 				usage();
 			}
-			C_flag = 1;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'e':
+			opts[OPT_ERROR_BEHAVIOR] = true;
 			if (strcmp(optarg, "continue") == 0)
 				errors = EXT2_ERRORS_CONTINUE;
 			else if (strcmp(optarg, "remount-ro") == 0)
@@ -2031,17 +2064,16 @@ static void parse_tune2fs_options(int argc, char **argv)
 					optarg);
 				usage();
 			}
-			e_flag = 1;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'E':
+			opts[OPT_EXTENDED_CMD] = true;
 			extended_cmd = optarg;
-			open_flag |= EXT2_FLAG_RW;
 			break;
 		case 'f': /* Force */
-			f_flag++;
+			force++;
 			break;
 		case 'g':
+			opts[OPT_RESGID] = true;
 			resgid = strtoul(optarg, &tmp, 0);
 			if (*tmp) {
 				gr = getgrnam(optarg);
@@ -2058,10 +2090,9 @@ static void parse_tune2fs_options(int argc, char **argv)
 					optarg);
 				usage();
 			}
-			g_flag = 1;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'i':
+			opts[OPT_CHECKINTERVAL] = 1;
 			interval = strtoul(optarg, &tmp, 0);
 			switch (*tmp) {
 			case 's':
@@ -2090,28 +2121,25 @@ static void parse_tune2fs_options(int argc, char **argv)
 					_("bad interval - %s"), optarg);
 				usage();
 			}
-			i_flag = 1;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'j':
+			opts[OPT_JOURNAL_SIZE] = true;
 			if (!journal_size)
 				journal_size = -1;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'J':
+			opts[OPT_JOURNAL_OPTS] = true;
 			parse_journal_opts(optarg);
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'l':
-			l_flag = 1;
+			do_list_super = 1;
 			break;
 		case 'L':
+			opts[OPT_LABEL] = true;
 			new_label = optarg;
-			L_flag = 1;
-			open_flag |= EXT2_FLAG_RW |
-				EXT2_FLAG_JOURNAL_DEV_OK;
 			break;
 		case 'm':
+			opts[OPT_RESERVED_RATIO] = true;
 			reserved_ratio = strtod(optarg, &tmp);
 			if (*tmp || reserved_ratio > 50 ||
 			    reserved_ratio < 0) {
@@ -2120,40 +2148,37 @@ static void parse_tune2fs_options(int argc, char **argv)
 					optarg);
 				usage();
 			}
-			m_flag = 1;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'M':
+			opts[OPT_LAST_MOUNTED] = true;
 			new_last_mounted = optarg;
-			M_flag = 1;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'o':
+			opts[OPT_MNTOPTS] = true;
 			if (mntopts_cmd) {
 				com_err(program_name, 0, "%s",
 					_("-o may only be specified once"));
 				usage();
 			}
 			mntopts_cmd = optarg;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'O':
+			opts[OPT_FEATURES] = true;
 			if (features_cmd) {
 				com_err(program_name, 0, "%s",
 					_("-O may only be specified once"));
 				usage();
 			}
 			features_cmd = optarg;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'Q':
-			Q_flag = 1;
+			opts[OPT_QUOTA] = true;
 			ret = parse_quota_opts(optarg, option_handle_function);
 			if (ret)
 				exit(1);
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'r':
+			opts[OPT_RESERVED_BLOCKS] = true;
 			reserved_blocks = strtoul(optarg, &tmp, 0);
 			if (*tmp) {
 				com_err(program_name, 0,
@@ -2161,45 +2186,39 @@ static void parse_tune2fs_options(int argc, char **argv)
 					optarg);
 				usage();
 			}
-			r_flag = 1;
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 's': /* Deprecated */
-			s_flag = atoi(optarg);
-			open_flag = EXT2_FLAG_RW;
+			opts[OPT_SPARSE_SUPER] = true;
+			sparse_value = atoi(optarg);
 			break;
 		case 'T':
-			T_flag = 1;
+			opts[OPT_CHECKTIME] = true;
 			last_check_time = parse_time(optarg);
-			open_flag = EXT2_FLAG_RW;
 			break;
 		case 'u':
-				resuid = strtoul(optarg, &tmp, 0);
-				if (*tmp) {
-					pw = getpwnam(optarg);
-					if (pw == NULL)
-						tmp = optarg;
-					else {
-						resuid = pw->pw_uid;
-						*tmp = 0;
-					}
+			opts[OPT_RESUID] = true;
+			resuid = strtoul(optarg, &tmp, 0);
+			if (*tmp) {
+				pw = getpwnam(optarg);
+				if (pw == NULL)
+					tmp = optarg;
+				else {
+					resuid = pw->pw_uid;
+					*tmp = 0;
 				}
-				if (*tmp) {
-					com_err(program_name, 0,
-						_("bad uid/user name - %s"),
-						optarg);
+			}
+			if (*tmp) {
+				com_err(program_name, 0,
+					_("bad uid/user name - %s"), optarg);
 					usage();
-				}
-				u_flag = 1;
-				open_flag = EXT2_FLAG_RW;
-				break;
+			}
+			break;
 		case 'U':
+			opts[OPT_UUID] = true;
 			requested_uuid = optarg;
-			U_flag = 1;
-			open_flag = EXT2_FLAG_RW |
-				EXT2_FLAG_JOURNAL_DEV_OK;
 			break;
 		case 'I':
+			opts[OPT_INODE_SIZE] = true;
 			new_inode_size = strtoul(optarg, &tmp, 0);
 			if (*tmp) {
 				com_err(program_name, 0,
@@ -2215,8 +2234,6 @@ static void parse_tune2fs_options(int argc, char **argv)
 					optarg);
 				usage();
 			}
-			open_flag = EXT2_FLAG_RW;
-			I_flag = 1;
 			break;
 		case 'z':
 			undo_file = optarg;
@@ -2226,8 +2243,13 @@ static void parse_tune2fs_options(int argc, char **argv)
 		}
 	if (optind < argc - 1 || optind == argc)
 		usage();
-	if (!open_flag && !l_flag)
+	if (tune_opts_requested()) {
+		open_flag = EXT2_FLAG_RW;
+		if (opts[OPT_LABEL] || opts[OPT_UUID])
+			open_flag |= EXT2_FLAG_JOURNAL_DEV_OK;
+	} else {
 		usage();
+	}
 	io_options = strchr(argv[optind], '?');
 	if (io_options)
 		*io_options++ = 0;
@@ -3221,8 +3243,8 @@ int tune2fs_main(int argc, char **argv)
 	 * Try the get/set fs label using ioctls before we even attempt
 	 * to open the file system.
 	 */
-	if (L_flag || print_label) {
-		rc = handle_fslabel(L_flag);
+	if (opts[OPT_LABEL] || print_label) {
+		rc = handle_fslabel(opts[OPT_LABEL]);
 		if (rc != -1) {
 #ifndef BUILD_AS_LIB
 			exit(rc);
@@ -3233,7 +3255,7 @@ int tune2fs_main(int argc, char **argv)
 	}
 
 retry_open:
-	if ((open_flag & EXT2_FLAG_RW) == 0 || f_flag)
+	if ((open_flag & EXT2_FLAG_RW) == 0 || force)
 		open_flag |= EXT2_FLAG_SKIP_MMP;
 
 	open_flag |= EXT2_FLAG_64BITS | EXT2_FLAG_THREADS |
@@ -3276,7 +3298,7 @@ retry_open:
 	}
 	fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
 
-	if (I_flag) {
+	if (opts[OPT_INODE_SIZE]) {
 		/*
 		 * Check the inode size is right so we can issue an
 		 * error message and bail before setting up the tdb
@@ -3378,7 +3400,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 	/* Normally we only need to write out the superblock */
 	fs->flags |= EXT2_FLAG_SUPER_ONLY;
 
-	if (c_flag) {
+	if (opts[OPT_MAX_MOUNTCOUNT]) {
 		if (max_mount_count == 65536)
 			max_mount_count = EXT2_DFL_MAX_MNT_COUNT +
 				(random() % EXT2_DFL_MAX_MNT_COUNT);
@@ -3387,17 +3409,17 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 		printf(_("Setting maximal mount count to %d\n"),
 		       max_mount_count);
 	}
-	if (C_flag) {
+	if (opts[OPT_MOUNTCOUNT]) {
 		sb->s_mnt_count = mount_count;
 		ext2fs_mark_super_dirty(fs);
 		printf(_("Setting current mount count to %d\n"), mount_count);
 	}
-	if (e_flag) {
+	if (opts[OPT_ERROR_BEHAVIOR]) {
 		sb->s_errors = errors;
 		ext2fs_mark_super_dirty(fs);
 		printf(_("Setting error behavior to %d\n"), errors);
 	}
-	if (g_flag) {
+	if (opts[OPT_RESGID]) {
 		if (sb->s_def_resgid != resgid) {
 			sb->s_def_resgid = resgid;
 			ext2fs_mark_super_dirty(fs);
@@ -3406,7 +3428,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 			printf(_("Reserved blocks gid already set to %lu\n"), resgid);
 		}
 	}
-	if (i_flag) {
+	if (opts[OPT_CHECKINTERVAL]) {
 		if ((unsigned long long)interval >= (1ULL << 32)) {
 			com_err(program_name, 0,
 				_("interval between checks is too big (%lu)"),
@@ -3419,7 +3441,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 		printf(_("Setting interval between checks to %lu seconds\n"),
 		       interval);
 	}
-	if (m_flag) {
+	if (opts[OPT_RESERVED_RATIO]) {
 		ext2fs_r_blocks_count_set(sb, reserved_ratio *
 					  ext2fs_blocks_count(sb) / 100.0);
 		ext2fs_mark_super_dirty(fs);
@@ -3427,7 +3449,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 			reserved_ratio,
 			(unsigned long long) ext2fs_r_blocks_count(sb));
 	}
-	if (r_flag) {
+	if (opts[OPT_RESERVED_BLOCKS]) {
 		if (reserved_blocks > ext2fs_blocks_count(sb)/2) {
 			com_err(program_name, 0,
 				_("reserved blocks count is too big (%llu)"),
@@ -3440,7 +3462,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 		printf(_("Setting reserved blocks count to %llu\n"),
 		       (unsigned long long) reserved_blocks);
 	}
-	if (s_flag == 1) {
+	if (sparse_value == 1) {
 		if (ext2fs_has_feature_sparse_super(sb)) {
 			fputs(_("\nThe filesystem already has sparse "
 				"superblocks.\n"), stderr);
@@ -3459,24 +3481,24 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 			       _(please_fsck));
 		}
 	}
-	if (s_flag == 0) {
+	if (sparse_value == 0) {
 		fputs(_("\nClearing the sparse superblock flag not supported.\n"),
 		      stderr);
 		rc = 1;
 		goto closefs;
 	}
-	if (T_flag) {
+	if (opts[OPT_CHECKTIME]) {
 		ext2fs_set_tstamp(sb, s_lastcheck, last_check_time);
 		ext2fs_mark_super_dirty(fs);
 		printf(_("Setting time filesystem last checked to %s\n"),
 		       ctime(&last_check_time));
 	}
-	if (u_flag) {
+	if (opts[OPT_RESUID]) {
 		sb->s_def_resuid = resuid;
 		ext2fs_mark_super_dirty(fs);
 		printf(_("Setting reserved blocks uid to %lu\n"), resuid);
 	}
-	if (L_flag) {
+	if (opts[OPT_LABEL]) {
 		if (strlen(new_label) > sizeof(sb->s_volume_name))
 			fputs(_("Warning: label too long, truncating.\n"),
 			      stderr);
@@ -3485,7 +3507,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 			sizeof(sb->s_volume_name));
 		ext2fs_mark_super_dirty(fs);
 	}
-	if (M_flag) {
+	if (opts[OPT_LAST_MOUNTED]) {
 		memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
 		strncpy((char *)sb->s_last_mounted, new_last_mounted,
 			sizeof(sb->s_last_mounted));
@@ -3505,7 +3527,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 		rc = parse_extended_opts(fs, extended_cmd);
 		if (rc)
 			goto closefs;
-		if (clear_mmp && !f_flag) {
+		if (clear_mmp && !force) {
 			fputs(_("Error in using clear_mmp. "
 				"It must be used with -f\n"),
 			      stderr);
@@ -3541,7 +3563,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 		}
 	}
 
-	if (Q_flag) {
+	if (opts[OPT_QUOTA]) {
 		if (mount_flags & (EXT2_MF_BUSY | EXT2_MF_MOUNTED)) {
 			fputs(_("The quota feature may only be changed when "
 				"the filesystem is unmounted and not in use.\n"), stderr);
@@ -3553,7 +3575,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 			goto closefs;
 	}
 
-	if (U_flag) {
+	if (opts[OPT_UUID]) {
 		int set_csum = 0;
 		dgrp_t i;
 		char buf[SUPERBLOCK_SIZE] __attribute__ ((aligned(8)));
@@ -3694,7 +3716,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 		}
 	}
 
-	if (I_flag) {
+	if (opts[OPT_INODE_SIZE]) {
 		if (mount_flags & (EXT2_MF_BUSY | EXT2_MF_MOUNTED)) {
 			fputs(_("The inode size may only be "
 				"changed when the filesystem is "
@@ -3740,7 +3762,7 @@ _("Warning: The journal is dirty. You may wish to replay the journal like:\n\n"
 		}
 	}
 
-	if (l_flag)
+	if (do_list_super)
 		list_super(sb);
 	if (stride_set) {
 		sb->s_raid_stride = stride;
-- 
2.51.0


[-- Attachment #3: 0002-DO-NOT-SUBMIT-tune2fs-initial-support-for-EXT4_IOC_G.patch --]
[-- Type: text/x-diff, Size: 8042 bytes --]

From b3ad517ba41f8dc2129564ecfefcac45062076d5 Mon Sep 17 00:00:00 2001
From: Theodore Ts'o <tytso@mit.edu>
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 <tytso@mit.edu>
---
 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, &params))
+		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(&params, 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, &params) == 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


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options
  2025-09-10 14:52       ` Theodore Ts'o
  2025-09-10 15:00         ` Theodore Ts'o
@ 2025-09-10 16:29         ` Ralph Siemsen
  2025-09-10 20:45           ` Theodore Ts'o
  1 sibling, 1 reply; 12+ messages in thread
From: Ralph Siemsen @ 2025-09-10 16:29 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Andreas Dilger, linux-ext4

Hi Ted,

On Wed, Sep 10, 2025 at 10:52 AM Theodore Ts'o <tytso@mit.edu> wrote:
> What I would suggest that you do is to move code which mutates the
> file system from parse_extended_opts() so it is only interpreting the
> options, and move that code to tuine2fs_main().

Yes, I see where you are going. Being able to deny read/write to a
block device that is mounted is a good goal.

But I am talking about mke2fs rather than tune2fs. I can't really see
a need for two code paths when creating a filesystem?

It would still make sense to separate the option parsing from the
mutation logic of course.

> That way we can call parse_extended_opts() multiple times.

Note this is already occurs in mke2fs: one call to process options
from profile/config file, and another call for command-line args.

So in v2 patch, I just made further calls, one for each -E argument.
So far it seems to work without problems.

Regards
-Ralph

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options
  2025-09-10 16:29         ` Ralph Siemsen
@ 2025-09-10 20:45           ` Theodore Ts'o
  2025-09-10 21:31             ` Ralph Siemsen
  0 siblings, 1 reply; 12+ messages in thread
From: Theodore Ts'o @ 2025-09-10 20:45 UTC (permalink / raw)
  To: Ralph Siemsen; +Cc: Andreas Dilger, linux-ext4

On Wed, Sep 10, 2025 at 12:29:21PM -0400, Ralph Siemsen wrote:
> > That way we can call parse_extended_opts() multiple times.
> 
> Note this is already occurs in mke2fs: one call to process options
> from profile/config file, and another call for command-line args.

Sorry, I've had tune2fs on the brain.  Mke2fs is different from
tune2fs because there's only one path for configuring the newly create
file system --- and we have to process the command-line extended
options *after* processing the profile/config file options.

So in PRS, we need to save each of the -E arguments --- or concatenate
them together into a single set of extended options, and keep the call
site for parse_extended_options() them where it currently is located

						- Ted
						

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options
  2025-09-10 20:45           ` Theodore Ts'o
@ 2025-09-10 21:31             ` Ralph Siemsen
  2025-09-19 15:44               ` Ralph Siemsen
  0 siblings, 1 reply; 12+ messages in thread
From: Ralph Siemsen @ 2025-09-10 21:31 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Andreas Dilger, linux-ext4

On Wed, Sep 10, 2025 at 4:45 PM Theodore Ts'o <tytso@mit.edu> wrote:

> So in PRS, we need to save each of the -E arguments --- or concatenate
> them together into a single set of extended options, and keep the call
> site for parse_extended_options() them where it currently is located

That what I am doing in patch v2:
https://lore.kernel.org/linux-ext4/20250910-mke2fs-small-fixes-v2-2-55c9842494e0@linaro.org/T/#u
It makes use of the already existing push_string() helper, to make
copies of each argument.

-Ralph

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options
  2025-09-10 21:31             ` Ralph Siemsen
@ 2025-09-19 15:44               ` Ralph Siemsen
  0 siblings, 0 replies; 12+ messages in thread
From: Ralph Siemsen @ 2025-09-19 15:44 UTC (permalink / raw)
  To: Theodore Ts'o; +Cc: Andreas Dilger, linux-ext4

Hi Andreas and Ted,

On Wed, Sep 10, 2025 at 5:31 PM Ralph Siemsen <ralph.siemsen@linaro.org> wrote:
> On Wed, Sep 10, 2025 at 4:45 PM Theodore Ts'o <tytso@mit.edu> wrote:
>
> > So in PRS, we need to save each of the -E arguments --- or concatenate
> > them together into a single set of extended options, and keep the call
> > site for parse_extended_options() them where it currently is located
>
> That what I am doing in patch v2:
> https://lore.kernel.org/linux-ext4/20250910-mke2fs-small-fixes-v2-2-55c9842494e0@linaro.org/T/#u
> It makes use of the already existing push_string() helper, to make
> copies of each argument.

Any feedback on the v2 patch series [1]? If you prefer another
approach (such as concatenating extended options) please let me know.

Also any comments regarding the other changes, particularly the
addition of root_selinux extended option?

[1] https://lore.kernel.org/linux-ext4/20250910-mke2fs-small-fixes-v2-0-55c9842494e0@linaro.org/

Thanks,
-Ralph

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2025-09-19 15:44 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-09 15:40 [PATCH RFC 0/3] mke2fs: small doc and features Ralph Siemsen
2025-09-09 15:40 ` [PATCH RFC 1/3] mke2fs: document the hash_seed option Ralph Siemsen
2025-09-09 15:40 ` [PATCH RFC 2/3] mke2fs.c: fail on multiple '-E' options Ralph Siemsen
2025-09-10  0:32   ` Andreas Dilger
2025-09-10  0:49     ` Ralph Siemsen
2025-09-10 14:52       ` Theodore Ts'o
2025-09-10 15:00         ` Theodore Ts'o
2025-09-10 16:29         ` Ralph Siemsen
2025-09-10 20:45           ` Theodore Ts'o
2025-09-10 21:31             ` Ralph Siemsen
2025-09-19 15:44               ` Ralph Siemsen
2025-09-09 15:40 ` [PATCH RFC 3/3] mke2fs: add root_selinux option for root inode label Ralph Siemsen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).