Message ID | 20191106101457.11237-3-lczerner@redhat.com |
---|---|
State | Superseded |
Headers | show |
Series | [01/17] vfs: Handle fs_param_neg_with_empty | expand |
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?
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? >
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...
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
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 --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)
Signed-off-by: Lukas Czerner <lczerner@redhat.com> --- fs/ext4/super.c | 109 ++++++++++++++++++++++++++++++++++++++ include/linux/fs_parser.h | 6 +++ 2 files changed, 115 insertions(+)