diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-07-11 23:47:29 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:10:07 -0400 |
commit | a0f8faea5f47d6e18253225e8f2f88cdc49d27d8 (patch) | |
tree | cf2b0b930c403173fc70e39313fd4d1348cf428c | |
parent | 9f343e24f541bef3d5f081925eae5734c2c39c28 (diff) |
bcachefs: fix_errors option is now a proper enum
Before, it was parsed as a bool but internally it was really an enum:
this lets us pass in all the possible values.
But we special case the option parsing: no supplied value is parsed as
FSCK_FIX_yes, to match the previous behaviour.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r-- | fs/bcachefs/btree_gc.c | 2 | ||||
-rw-r--r-- | fs/bcachefs/error.c | 12 | ||||
-rw-r--r-- | fs/bcachefs/error.h | 7 | ||||
-rw-r--r-- | fs/bcachefs/opts.c | 102 | ||||
-rw-r--r-- | fs/bcachefs/opts.h | 17 | ||||
-rw-r--r-- | fs/bcachefs/recovery.c | 2 |
6 files changed, 95 insertions, 47 deletions
diff --git a/fs/bcachefs/btree_gc.c b/fs/bcachefs/btree_gc.c index 6000b09dec26..edea6bb66253 100644 --- a/fs/bcachefs/btree_gc.c +++ b/fs/bcachefs/btree_gc.c @@ -1808,7 +1808,7 @@ again: if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG) || (BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb) && c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_allocations && - c->opts.fix_errors != FSCK_OPT_NO)) { + c->opts.fix_errors != FSCK_FIX_no)) { bch_info(c, "Starting topology repair pass"); ret = bch2_repair_topology(c); if (ret) diff --git a/fs/bcachefs/error.c b/fs/bcachefs/error.c index b08cd23dee00..685464b8cce3 100644 --- a/fs/bcachefs/error.c +++ b/fs/bcachefs/error.c @@ -204,7 +204,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) prt_str(out, ", continuing"); ret = -BCH_ERR_fsck_ignore; } - } else if (c->opts.fix_errors == FSCK_OPT_EXIT) { + } else if (c->opts.fix_errors == FSCK_FIX_exit) { prt_str(out, ", exiting"); ret = -BCH_ERR_fsck_errors_not_fixed; } else if (flags & FSCK_CAN_FIX) { @@ -212,7 +212,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) ? s->fix : c->opts.fix_errors; - if (fix == FSCK_OPT_ASK) { + if (fix == FSCK_FIX_ask) { int ask; prt_str(out, ": fix?"); @@ -223,13 +223,13 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) if (ask >= YN_ALLNO && s) s->fix = ask == YN_ALLNO - ? FSCK_OPT_NO - : FSCK_OPT_YES; + ? FSCK_FIX_no + : FSCK_FIX_yes; ret = ask & 1 ? -BCH_ERR_fsck_fix : -BCH_ERR_fsck_ignore; - } else if (fix == FSCK_OPT_YES || + } else if (fix == FSCK_FIX_yes || (c->opts.nochanges && !(flags & FSCK_CAN_IGNORE))) { prt_str(out, ", fixing"); @@ -244,7 +244,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) } if (ret == -BCH_ERR_fsck_ignore && - (c->opts.fix_errors == FSCK_OPT_EXIT || + (c->opts.fix_errors == FSCK_FIX_exit || !(flags & FSCK_CAN_IGNORE))) ret = -BCH_ERR_fsck_errors_not_fixed; diff --git a/fs/bcachefs/error.h b/fs/bcachefs/error.h index edf12443822c..7ce9540052e5 100644 --- a/fs/bcachefs/error.h +++ b/fs/bcachefs/error.h @@ -91,13 +91,6 @@ do { \ * be able to repair: */ -enum fsck_err_opts { - FSCK_OPT_EXIT, - FSCK_OPT_YES, - FSCK_OPT_NO, - FSCK_OPT_ASK, -}; - struct fsck_err_state { struct list_head list; const char *fmt; diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c index 96c2f3c2fbce..56f586f8d25b 100644 --- a/fs/bcachefs/opts.c +++ b/fs/bcachefs/opts.c @@ -5,6 +5,7 @@ #include "bcachefs.h" #include "compress.h" #include "disk_groups.h" +#include "error.h" #include "opts.h" #include "super-io.h" #include "util.h" @@ -16,6 +17,11 @@ const char * const bch2_error_actions[] = { NULL }; +const char * const bch2_fsck_fix_opts[] = { + BCH_FIX_ERRORS_OPTS() + NULL +}; + const char * const bch2_version_upgrade_opts[] = { BCH_VERSION_UPGRADE_OPTS() NULL @@ -89,6 +95,37 @@ const char * const bch2_fs_usage_types[] = { #undef x +static int bch2_opt_fix_errors_parse(struct bch_fs *c, const char *val, u64 *res, + struct printbuf *err) +{ + if (!val) { + *res = FSCK_FIX_yes; + } else { + int ret = match_string(bch2_fsck_fix_opts, -1, val); + + if (ret < 0 && err) + prt_str(err, "fix_errors: invalid selection"); + if (ret < 0) + return ret; + *res = ret; + } + + return 0; +} + +static void bch2_opt_fix_errors_to_text(struct printbuf *out, + struct bch_fs *c, + struct bch_sb *sb, + u64 v) +{ + prt_str(out, bch2_fsck_fix_opts[v]); +} + +static const struct bch_opt_fn bch2_opt_fix_errors = { + .parse = bch2_opt_fix_errors_parse, + .to_text = bch2_opt_fix_errors_to_text, +}; + const char * const bch2_d_types[BCH_DT_MAX] = { [DT_UNKNOWN] = "unknown", [DT_FIFO] = "fifo", @@ -265,15 +302,26 @@ int bch2_opt_parse(struct bch_fs *c, switch (opt->type) { case BCH_OPT_BOOL: - ret = kstrtou64(val, 10, res); + if (val) { + ret = kstrtou64(val, 10, res); + } else { + ret = 0; + *res = 1; + } + if (ret < 0 || (*res != 0 && *res != 1)) { if (err) - prt_printf(err, "%s: must be bool", - opt->attr.name); + prt_printf(err, "%s: must be bool", opt->attr.name); return ret; } break; case BCH_OPT_UINT: + if (!val) { + prt_printf(err, "%s: required value", + opt->attr.name); + return -EINVAL; + } + ret = opt->flags & OPT_HUMAN_READABLE ? bch2_strtou64_h(val, res) : kstrtou64(val, 10, res); @@ -285,6 +333,12 @@ int bch2_opt_parse(struct bch_fs *c, } break; case BCH_OPT_STR: + if (!val) { + prt_printf(err, "%s: required value", + opt->attr.name); + return -EINVAL; + } + ret = match_string(opt->choices, -1, val); if (ret < 0) { if (err) @@ -336,7 +390,7 @@ void bch2_opt_to_text(struct printbuf *out, if (flags & OPT_SHOW_FULL_LIST) prt_string_option(out, opt->choices, v); else - prt_printf(out, "%s", opt->choices[v]); + prt_str(out, opt->choices[v]); break; case BCH_OPT_FN: opt->fn.to_text(out, c, sb, v); @@ -400,31 +454,19 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts, name = strsep(&opt, "="); val = opt; - if (val) { - id = bch2_mount_opt_lookup(name); - if (id < 0) - goto bad_opt; + id = bch2_mount_opt_lookup(name); - ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err); - if (ret < 0) - goto bad_val; - } else { - id = bch2_mount_opt_lookup(name); - v = 1; - - if (id < 0 && - !strncmp("no", name, 2)) { - id = bch2_mount_opt_lookup(name + 2); - v = 0; - } - - if (id < 0) - goto bad_opt; - - if (bch2_opt_table[id].type != BCH_OPT_BOOL) - goto no_val; + /* Check for the form "noopt", negation of a boolean opt: */ + if (id < 0 && + !val && + !strncmp("no", name, 2)) { + id = bch2_mount_opt_lookup(name + 2); + val = "0"; } + if (id < 0) + goto bad_opt; + if (!(bch2_opt_table[id].flags & OPT_MOUNT)) goto bad_opt; @@ -437,6 +479,10 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts, !IS_ENABLED(CONFIG_BCACHEFS_QUOTA)) goto bad_opt; + ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err); + if (ret < 0) + goto bad_val; + bch2_opt_set_by_id(opts, id, v); } @@ -451,10 +497,6 @@ bad_val: pr_err("Invalid mount option %s", err.buf); ret = -1; goto out; -no_val: - pr_err("Mount option %s requires a value", name); - ret = -1; - goto out; out: kfree(copied_opts_start); printbuf_exit(&err); diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h index 3be5095aa472..92e2e5e759d9 100644 --- a/fs/bcachefs/opts.h +++ b/fs/bcachefs/opts.h @@ -11,6 +11,7 @@ struct bch_fs; extern const char * const bch2_error_actions[]; +extern const char * const bch2_fsck_fix_opts[]; extern const char * const bch2_version_upgrade_opts[]; extern const char * const bch2_sb_features[]; extern const char * const bch2_sb_compat[]; @@ -105,6 +106,18 @@ struct bch_opt_fn { #define BCACHEFS_VERBOSE_DEFAULT false #endif +#define BCH_FIX_ERRORS_OPTS() \ + x(exit, 0) \ + x(yes, 1) \ + x(no, 2) \ + x(ask, 3) + +enum fsck_err_opts { +#define x(t, n) FSCK_FIX_##t, + BCH_FIX_ERRORS_OPTS() +#undef x +}; + #define BCH_OPTS() \ x(block_size, u16, \ OPT_FS|OPT_FORMAT| \ @@ -325,8 +338,8 @@ struct bch_opt_fn { NULL, "Run fsck on mount") \ x(fix_errors, u8, \ OPT_FS|OPT_MOUNT, \ - OPT_BOOL(), \ - BCH2_NO_SB_OPT, false, \ + OPT_FN(bch2_opt_fix_errors), \ + BCH2_NO_SB_OPT, FSCK_FIX_exit, \ NULL, "Fix errors during fsck without asking") \ x(ratelimit_errors, u8, \ OPT_FS|OPT_MOUNT, \ diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index c46297bd1cf9..63b385d8886a 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -1175,7 +1175,7 @@ static void check_version_upgrade(struct bch_fs *c) prt_str(&buf, "fsck required"); c->recovery_passes_explicit |= recovery_passes; - c->opts.fix_errors = FSCK_OPT_YES; + c->opts.fix_errors = FSCK_FIX_yes; } bch_info(c, "%s", buf.buf); |