diff mbox series

[02/17] ext4: Add fs parameter description

Message ID 20191106101457.11237-3-lczerner@redhat.com
State Superseded
Headers show
Series [01/17] vfs: Handle fs_param_neg_with_empty | expand

Commit Message

Lukas Czerner Nov. 6, 2019, 10:14 a.m. UTC
Signed-off-by: Lukas Czerner <lczerner@redhat.com>
---
 fs/ext4/super.c           | 109 ++++++++++++++++++++++++++++++++++++++
 include/linux/fs_parser.h |   6 +++
 2 files changed, 115 insertions(+)

Comments

Al Viro Dec. 17, 2019, 12:44 a.m. UTC | #1
On Wed, Nov 06, 2019 at 11:14:42AM +0100, Lukas Czerner wrote:
> +	fsparam_string_empty
> +			("usrjquota",		Opt_usrjquota),
> +	fsparam_string_empty
> +			("grpjquota",		Opt_grpjquota),

Umm...  That makes ...,usrjquota,... equivalent to ...,usrjquota=,...
unless I'm misreading the series.  Different from mainline, right?

> +	fsparam_bool	("barrier",		Opt_barrier),
> +	fsparam_flag	("nobarrier",		Opt_nobarrier),

That's even more interesting.  Current mainline:
		barrier		OK, sets EXT4_MOUNT_BARRIER
		barrier=0	OK, sets EXT4_MOUNT_BARRIER
		barrier=42	OK, sets EXT4_MOUNT_BARRIER
		barrier=yes	error
		barrier=no	error
		nobarrier	OK, clears EXT4_MOUNT_BARRIER
Unless I'm misreading your series, you get
		barrier		error
		barrier=0	OK, sets EXT4_MOUNT_BARRIER
		barrier=42	error
		barrier=yes	OK, sets EXT4_MOUNT_BARRIER
		barrier=no	OK, sets EXT4_MOUNT_BARRIER
		nobarrier	OK, clears EXT4_MOUNT_BARRIER

Granted, mainline behaviour is... unintuitive, to put it mildly,
but the replacement is just as strange _and_ incompatible with the
existing one.

Am I missing something subtle there?
Lukas Czerner Dec. 17, 2019, 12:19 p.m. UTC | #2
On Tue, Dec 17, 2019 at 12:44:19AM +0000, Al Viro wrote:
> On Wed, Nov 06, 2019 at 11:14:42AM +0100, Lukas Czerner wrote:
> > +	fsparam_string_empty
> > +			("usrjquota",		Opt_usrjquota),
> > +	fsparam_string_empty
> > +			("grpjquota",		Opt_grpjquota),
> 
> Umm...  That makes ...,usrjquota,... equivalent to ...,usrjquota=,...
> unless I'm misreading the series.  Different from mainline, right?

Unfortunatelly yes, I do not think this is a problem, but if you have a
solution within the new mount api framework I am happy to use it.

> 
> > +	fsparam_bool	("barrier",		Opt_barrier),
> > +	fsparam_flag	("nobarrier",		Opt_nobarrier),
> 
> That's even more interesting.  Current mainline:
> 		barrier		OK, sets EXT4_MOUNT_BARRIER
> 		barrier=0	OK, sets EXT4_MOUNT_BARRIER
> 		barrier=42	OK, sets EXT4_MOUNT_BARRIER
> 		barrier=yes	error
> 		barrier=no	error
> 		nobarrier	OK, clears EXT4_MOUNT_BARRIER
> Unless I'm misreading your series, you get
> 		barrier		error

Not really, this seems to be working as expected. Assuming that this
didn't change since 5.4.0-rc6. I does make sense to me that specifying
bool type parameter without any options would express "true".


> 		barrier=0	OK, sets EXT4_MOUNT_BARRIER


> 		barrier=42	error
> 		barrier=yes	OK, sets EXT4_MOUNT_BARRIER
> 		barrier=no	OK, sets EXT4_MOUNT_BARRIER

Those three are different, just because of how param_book() work. I do
not really see a problem with it, but if we want to keep it exactly the
same as current mainline it would be difficult with how the current api
works. Any suggestions ?

Thanks!
-Lukas

> 		nobarrier	OK, clears EXT4_MOUNT_BARRIER
> 
> Granted, mainline behaviour is... unintuitive, to put it mildly,
> but the replacement is just as strange _and_ incompatible with the
> existing one.
> 
> Am I missing something subtle there?
>
Al Viro Dec. 17, 2019, 3:20 p.m. UTC | #3
On Tue, Dec 17, 2019 at 01:19:56PM +0100, Lukas Czerner wrote:
> On Tue, Dec 17, 2019 at 12:44:19AM +0000, Al Viro wrote:
> > On Wed, Nov 06, 2019 at 11:14:42AM +0100, Lukas Czerner wrote:
> > > +	fsparam_string_empty
> > > +			("usrjquota",		Opt_usrjquota),
> > > +	fsparam_string_empty
> > > +			("grpjquota",		Opt_grpjquota),
> > 
> > Umm...  That makes ...,usrjquota,... equivalent to ...,usrjquota=,...
> > unless I'm misreading the series.  Different from mainline, right?
> 
> Unfortunatelly yes, I do not think this is a problem, but if you have a
> solution within the new mount api framework I am happy to use it.

Er...  Dump the fsparam_string_empty() use and instead of your
+       if (token == Opt_usrjquota) {
+               if (result.negated)
+                       return clear_qf_name(sb, USRQUOTA);
+               else
+                       return set_qf_name(sb, USRQUOTA, param);
do
+       if (token == Opt_usrjquota) {
+               if (!param->string[0])
+                       return clear_qf_name(sb, USRQUOTA);
+               else
+                       return set_qf_name(sb, USRQUOTA, param);
with the same for grpjquota?

> > > +	fsparam_bool	("barrier",		Opt_barrier),
> > > +	fsparam_flag	("nobarrier",		Opt_nobarrier),
> > 
> > That's even more interesting.  Current mainline:
> > 		barrier		OK, sets EXT4_MOUNT_BARRIER
> > 		barrier=0	OK, sets EXT4_MOUNT_BARRIER
> > 		barrier=42	OK, sets EXT4_MOUNT_BARRIER
> > 		barrier=yes	error
> > 		barrier=no	error
> > 		nobarrier	OK, clears EXT4_MOUNT_BARRIER
> > Unless I'm misreading your series, you get
> > 		barrier		error
> 
> Not really, this seems to be working as expected. Assuming that this
> didn't change since 5.4.0-rc6. I does make sense to me that specifying
> bool type parameter without any options would express "true".
> 
> 
> > 		barrier=0	OK, sets EXT4_MOUNT_BARRIER
> 
> 
> > 		barrier=42	error
> > 		barrier=yes	OK, sets EXT4_MOUNT_BARRIER
> > 		barrier=no	OK, sets EXT4_MOUNT_BARRIER
> 
> Those three are different, just because of how param_book() work. I do
> not really see a problem with it, but if we want to keep it exactly the
> same as current mainline it would be difficult with how the current api
> works. Any suggestions ?

If fsparam_bool() doesn't do the right thing, perhaps it shouldn't be
used in the first place?  Or changed, for that matter - it's not as if
we had many users of that thing and the only in-tree one is definitely
breaking userland ABI.

In case of ext4, after rereading that code (and getting some sleep) the
current behaviour is, AFAICS to accept barrier | nobarrier | barrier=<number>
with the last case being equialent to nobarrier when number is 0 and barrier
in all other cases.  Is that an accurate description?

If so, I would prefer
	fsparam_flag_no("barrier", Opt_barrier),	// barrier | nobarrier
	fsparam_u32("barrier", Opt_barrier),		// barrier=<number>
as the solution, with fs_parse() having been taught to allow argument-bearing
and argument-less options with the same name, picking the right one.  That
way Opt_nobarrier gets removed as well...

I'll push a branch with that stuff later today; will post when it's out...
Lukas Czerner Dec. 17, 2019, 4:34 p.m. UTC | #4
On Tue, Dec 17, 2019 at 03:20:12PM +0000, Al Viro wrote:
> On Tue, Dec 17, 2019 at 01:19:56PM +0100, Lukas Czerner wrote:
> > On Tue, Dec 17, 2019 at 12:44:19AM +0000, Al Viro wrote:
> > > On Wed, Nov 06, 2019 at 11:14:42AM +0100, Lukas Czerner wrote:
> > > > +	fsparam_string_empty
> > > > +			("usrjquota",		Opt_usrjquota),
> > > > +	fsparam_string_empty
> > > > +			("grpjquota",		Opt_grpjquota),
> > > 
> > > Umm...  That makes ...,usrjquota,... equivalent to ...,usrjquota=,...
> > > unless I'm misreading the series.  Different from mainline, right?
> > 
> > Unfortunatelly yes, I do not think this is a problem, but if you have a
> > solution within the new mount api framework I am happy to use it.
> 
> Er...  Dump the fsparam_string_empty() use and instead of your
> +       if (token == Opt_usrjquota) {
> +               if (result.negated)
> +                       return clear_qf_name(sb, USRQUOTA);
> +               else
> +                       return set_qf_name(sb, USRQUOTA, param);
> do
> +       if (token == Opt_usrjquota) {
> +               if (!param->string[0])
> +                       return clear_qf_name(sb, USRQUOTA);
> +               else
> +                       return set_qf_name(sb, USRQUOTA, param);
> with the same for grpjquota?

Ah right, it's been a while I guess I didn't realize that it will accept
usrjquota as well as usrjquota=

It makes sense to check the string directly, thanks.

> 
> > > > +	fsparam_bool	("barrier",		Opt_barrier),
> > > > +	fsparam_flag	("nobarrier",		Opt_nobarrier),
> > > 
> > > That's even more interesting.  Current mainline:
> > > 		barrier		OK, sets EXT4_MOUNT_BARRIER
> > > 		barrier=0	OK, sets EXT4_MOUNT_BARRIER
> > > 		barrier=42	OK, sets EXT4_MOUNT_BARRIER
> > > 		barrier=yes	error
> > > 		barrier=no	error
> > > 		nobarrier	OK, clears EXT4_MOUNT_BARRIER
> > > Unless I'm misreading your series, you get
> > > 		barrier		error
> > 
> > Not really, this seems to be working as expected. Assuming that this
> > didn't change since 5.4.0-rc6. I does make sense to me that specifying
> > bool type parameter without any options would express "true".
> > 
> > 
> > > 		barrier=0	OK, sets EXT4_MOUNT_BARRIER
> > 
> > 
> > > 		barrier=42	error
> > > 		barrier=yes	OK, sets EXT4_MOUNT_BARRIER
> > > 		barrier=no	OK, sets EXT4_MOUNT_BARRIER
> > 
> > Those three are different, just because of how param_book() work. I do
> > not really see a problem with it, but if we want to keep it exactly the
> > same as current mainline it would be difficult with how the current api
> > works. Any suggestions ?
> 
> If fsparam_bool() doesn't do the right thing, perhaps it shouldn't be
> used in the first place?  Or changed, for that matter - it's not as if
> we had many users of that thing and the only in-tree one is definitely
> breaking userland ABI.
> 
> In case of ext4, after rereading that code (and getting some sleep) the
> current behaviour is, AFAICS to accept barrier | nobarrier | barrier=<number>
> with the last case being equialent to nobarrier when number is 0 and barrier
> in all other cases.  Is that an accurate description?

Yeah, the documentation says
barrier=0 / barrier=1 / barrier / nobarrier

but we do accept any number from 0 to 2147483647

> 
> If so, I would prefer
> 	fsparam_flag_no("barrier", Opt_barrier),	// barrier | nobarrier
> 	fsparam_u32("barrier", Opt_barrier),		// barrier=<number>
> as the solution, with fs_parse() having been taught to allow argument-bearing
> and argument-less options with the same name, picking the right one.  That
> way Opt_nobarrier gets removed as well...
> 
> I'll push a branch with that stuff later today; will post when it's out...

That would be great, thanks.

-Lukas
Al Viro Dec. 24, 2019, 5:18 p.m. UTC | #5
On Tue, Dec 17, 2019 at 05:34:32PM +0100, Lukas Czerner wrote:

> > If so, I would prefer
> > 	fsparam_flag_no("barrier", Opt_barrier),	// barrier | nobarrier
> > 	fsparam_u32("barrier", Opt_barrier),		// barrier=<number>
> > as the solution, with fs_parse() having been taught to allow argument-bearing
> > and argument-less options with the same name, picking the right one.  That
> > way Opt_nobarrier gets removed as well...
> > 
> > I'll push a branch with that stuff later today; will post when it's out...
> 
> That would be great, thanks.

It took longer than I hoped, sorry ;-/  The current patchset is in
#untested.fs_parse; the really interesting part is up to
"turn fs_param_is_... into functions".

One surprising source of PITA around your patchset is ext4_show_options().
It pretty much forces you into keeping "no..." forms separate, even though
normally you could just say
	fsparam_flag_no("quota",               Opt_quota),
and get rid of Opt_noquota, etc.

If you keep that dependency, it'll need to be documented - right in
fs/ext4/super.c, to make sure we don't get "optimizing" followups breaking
the hell out of things.

Said that, I really doubt that token2str() is a good idea.  It might make
more sense to start with separating _ext4_show_options() from that
machinery.

Another thing is that all fsparam_bool() users are modifying user-visible
ABI; use fparam_flag_no() + fsparam_u32() with the same name and same
opt - that'll give you the existing behaviour.
diff mbox series

Patch

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index dd654e53ba3d..44254179bd4f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -47,6 +47,9 @@ 
 #include <linux/kthread.h>
 #include <linux/freezer.h>
 
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
+
 #include "ext4.h"
 #include "ext4_extents.h"	/* Needed for trace points definition */
 #include "ext4_jbd2.h"
@@ -1459,6 +1462,112 @@  enum {
 	Opt_dioread_nolock, Opt_dioread_lock,
 	Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
 	Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
+	Opt_errors, Opt_data, Opt_data_err, Opt_jqfmt,
+};
+
+static const struct fs_parameter_enum ext4_param_enums[] = {
+	{Opt_errors,	"continue",	Opt_err_cont},
+	{Opt_errors,	"panic",	Opt_err_panic},
+	{Opt_errors,	"remount-ro",	Opt_err_ro},
+	{Opt_data,	"journal",	Opt_data_journal},
+	{Opt_data,	"ordered",	Opt_data_ordered},
+	{Opt_data,	"writeback",	Opt_data_writeback},
+	{Opt_data_err,	"abort",	Opt_data_err_abort},
+	{Opt_data_err,	"ignore",	Opt_data_err_ignore},
+	{Opt_jqfmt,	"vfsold",	Opt_jqfmt_vfsold},
+	{Opt_jqfmt,	"vfsv0",	Opt_jqfmt_vfsv0},
+	{Opt_jqfmt,	"vfsv1",	Opt_jqfmt_vfsv1},
+};
+
+static const struct fs_parameter_spec ext4_param_specs[] = {
+	fsparam_flag	("bsddf",		Opt_bsd_df),
+	fsparam_flag	("minixdf",		Opt_minix_df),
+	fsparam_flag	("grpid",		Opt_grpid),
+	fsparam_flag	("bsdgroups",		Opt_grpid),
+	fsparam_flag	("nogrpid",		Opt_nogrpid),
+	fsparam_flag	("sysvgroups",		Opt_nogrpid),
+	fsparam_u32	("resgid",		Opt_resgid),
+	fsparam_u32	("resuid",		Opt_resuid),
+	fsparam_u32	("sb",			Opt_sb),
+	fsparam_enum	("errors",		Opt_errors),
+	fsparam_flag	("nouid32",		Opt_nouid32),
+	fsparam_flag	("debug",		Opt_debug),
+	fsparam_flag	("oldalloc",		Opt_removed),
+	fsparam_flag	("orlov",		Opt_removed),
+	fsparam_flag	("user_xattr",		Opt_user_xattr),
+	fsparam_flag	("nouser_xattr",	Opt_nouser_xattr),
+	fsparam_flag	("acl",			Opt_acl),
+	fsparam_flag	("noacl",		Opt_noacl),
+	fsparam_flag	("norecovery",		Opt_noload),
+	fsparam_flag	("noload",		Opt_noload),
+	fsparam_flag	("bh",			Opt_removed),
+	fsparam_flag	("nobh",		Opt_removed),
+	fsparam_u32	("commit",		Opt_commit),
+	fsparam_u32	("min_batch_time",	Opt_min_batch_time),
+	fsparam_u32	("max_batch_time",	Opt_max_batch_time),
+	fsparam_u32	("journal_dev",		Opt_journal_dev),
+	fsparam_bdev	("journal_path",	Opt_journal_path),
+	fsparam_flag	("journal_checksum",	Opt_journal_checksum),
+	fsparam_flag	("nojournal_checksum",	Opt_nojournal_checksum),
+	fsparam_flag	("journal_async_commit",Opt_journal_async_commit),
+	fsparam_flag	("abort",		Opt_abort),
+	fsparam_enum	("data",		Opt_data),
+	fsparam_enum	("data_err",		Opt_data_err),
+	fsparam_string_empty
+			("usrjquota",		Opt_usrjquota),
+	fsparam_string_empty
+			("grpjquota",		Opt_grpjquota),
+	fsparam_enum	("jqfmt",		Opt_jqfmt),
+	fsparam_flag	("grpquota",		Opt_grpquota),
+	fsparam_flag	("quota",		Opt_quota),
+	fsparam_flag	("noquota",		Opt_noquota),
+	fsparam_flag	("usrquota",		Opt_usrquota),
+	fsparam_flag	("prjquota",		Opt_prjquota),
+	fsparam_bool	("barrier",		Opt_barrier),
+	fsparam_flag	("nobarrier",		Opt_nobarrier),
+	fsparam_flag	("i_version",		Opt_i_version),
+	fsparam_flag	("dax",			Opt_dax),
+	fsparam_u32	("stripe",		Opt_stripe),
+	fsparam_flag	("delalloc",		Opt_delalloc),
+	fsparam_flag	("nodelalloc",		Opt_nodelalloc),
+	fsparam_flag	("warn_on_error",	Opt_warn_on_error),
+	fsparam_flag	("nowarn_on_error",	Opt_nowarn_on_error),
+	fsparam_flag	("lazytime",		Opt_lazytime),
+	fsparam_flag	("nolazytime",		Opt_nolazytime),
+	fsparam_u32	("debug_want_extra_isize",
+						Opt_debug_want_extra_isize),
+	fsparam_flag	("mblk_io_submit",	Opt_removed),
+	fsparam_flag	("nomblk_io_submit",	Opt_removed),
+	fsparam_flag	("block_validity",	Opt_block_validity),
+	fsparam_flag	("noblock_validity",	Opt_noblock_validity),
+	fsparam_u32	("inode_readahead_blks",
+						Opt_inode_readahead_blks),
+	fsparam_u32	("journal_ioprio",	Opt_journal_ioprio),
+	fsparam_bool	("auto_da_alloc",	Opt_auto_da_alloc),
+	fsparam_flag	("noauto_da_alloc",	Opt_noauto_da_alloc),
+	fsparam_flag	("dioread_nolock",	Opt_dioread_nolock),
+	fsparam_flag	("dioread_lock",	Opt_dioread_lock),
+	fsparam_flag	("discard",		Opt_discard),
+	fsparam_flag	("nodiscard",		Opt_nodiscard),
+	fsparam_u32_opt	("init_itable",		Opt_init_itable),
+	fsparam_flag	("noinit_itable",	Opt_noinit_itable),
+	fsparam_u32	("max_dir_size_kb",	Opt_max_dir_size_kb),
+	fsparam_flag	("test_dummy_encryption",
+						Opt_test_dummy_encryption),
+	fsparam_flag	("nombcache",		Opt_nombcache),
+	fsparam_flag	("no_mbcache",		Opt_nombcache),	/* for backward compatibility */
+	fsparam_string	("check",		Opt_removed),	/* mount option from ext2/3 */
+	fsparam_flag	("nocheck",		Opt_removed),	/* mount option from ext2/3 */
+	fsparam_flag	("reservation",		Opt_removed),	/* mount option from ext2/3 */
+	fsparam_flag	("noreservation",	Opt_removed),	/* mount option from ext2/3 */
+	fsparam_u32	("journal",		Opt_removed),	/* mount option from ext2/3 */
+	{}
+};
+
+static const struct fs_parameter_description ext4_fs_parameters = {
+	.name		= "ext4",
+	.specs		= ext4_param_specs,
+	.enums		= ext4_param_enums,
 };
 
 static const match_table_t tokens = {
diff --git a/include/linux/fs_parser.h b/include/linux/fs_parser.h
index dee140db6240..f704eb465cbd 100644
--- a/include/linux/fs_parser.h
+++ b/include/linux/fs_parser.h
@@ -133,11 +133,17 @@  static inline bool fs_validate_description(const struct fs_parameter_description
 				__fsparam(fs_param_is_u32_octal, NAME, OPT, 0)
 #define fsparam_u32hex(NAME, OPT) \
 				__fsparam(fs_param_is_u32_hex, NAME, OPT, 0)
+#define fsparam_u32_opt(NAME, OPT) \
+				__fsparam(fs_param_is_u32, NAME, OPT, \
+					  fs_param_v_optional)
 #define fsparam_s32(NAME, OPT)	__fsparam(fs_param_is_s32, NAME, OPT, 0)
 #define fsparam_u64(NAME, OPT)	__fsparam(fs_param_is_u64, NAME, OPT, 0)
 #define fsparam_enum(NAME, OPT)	__fsparam(fs_param_is_enum, NAME, OPT, 0)
 #define fsparam_string(NAME, OPT) \
 				__fsparam(fs_param_is_string, NAME, OPT, 0)
+#define fsparam_string_empty(NAME, OPT) \
+				__fsparam(fs_param_is_string, NAME, OPT, \
+					  fs_param_neg_with_empty)
 #define fsparam_blob(NAME, OPT)	__fsparam(fs_param_is_blob, NAME, OPT, 0)
 #define fsparam_bdev(NAME, OPT)	__fsparam(fs_param_is_blockdev, NAME, OPT, 0)
 #define fsparam_path(NAME, OPT)	__fsparam(fs_param_is_path, NAME, OPT, 0)