Commit a0f8faea authored by Kent Overstreet's avatar Kent Overstreet

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: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 9f343e24
...@@ -1808,7 +1808,7 @@ int bch2_gc(struct bch_fs *c, bool initial, bool metadata_only) ...@@ -1808,7 +1808,7 @@ int bch2_gc(struct bch_fs *c, bool initial, bool metadata_only)
if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG) || if (IS_ENABLED(CONFIG_BCACHEFS_DEBUG) ||
(BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb) && (BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb) &&
c->curr_recovery_pass <= BCH_RECOVERY_PASS_check_allocations && 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"); bch_info(c, "Starting topology repair pass");
ret = bch2_repair_topology(c); ret = bch2_repair_topology(c);
if (ret) if (ret)
......
...@@ -204,7 +204,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) ...@@ -204,7 +204,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
prt_str(out, ", continuing"); prt_str(out, ", continuing");
ret = -BCH_ERR_fsck_ignore; 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"); prt_str(out, ", exiting");
ret = -BCH_ERR_fsck_errors_not_fixed; ret = -BCH_ERR_fsck_errors_not_fixed;
} else if (flags & FSCK_CAN_FIX) { } else if (flags & FSCK_CAN_FIX) {
...@@ -212,7 +212,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) ...@@ -212,7 +212,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
? s->fix ? s->fix
: c->opts.fix_errors; : c->opts.fix_errors;
if (fix == FSCK_OPT_ASK) { if (fix == FSCK_FIX_ask) {
int ask; int ask;
prt_str(out, ": fix?"); prt_str(out, ": fix?");
...@@ -223,13 +223,13 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) ...@@ -223,13 +223,13 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
if (ask >= YN_ALLNO && s) if (ask >= YN_ALLNO && s)
s->fix = ask == YN_ALLNO s->fix = ask == YN_ALLNO
? FSCK_OPT_NO ? FSCK_FIX_no
: FSCK_OPT_YES; : FSCK_FIX_yes;
ret = ask & 1 ret = ask & 1
? -BCH_ERR_fsck_fix ? -BCH_ERR_fsck_fix
: -BCH_ERR_fsck_ignore; : -BCH_ERR_fsck_ignore;
} else if (fix == FSCK_OPT_YES || } else if (fix == FSCK_FIX_yes ||
(c->opts.nochanges && (c->opts.nochanges &&
!(flags & FSCK_CAN_IGNORE))) { !(flags & FSCK_CAN_IGNORE))) {
prt_str(out, ", fixing"); prt_str(out, ", fixing");
...@@ -244,7 +244,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...) ...@@ -244,7 +244,7 @@ int bch2_fsck_err(struct bch_fs *c, unsigned flags, const char *fmt, ...)
} }
if (ret == -BCH_ERR_fsck_ignore && if (ret == -BCH_ERR_fsck_ignore &&
(c->opts.fix_errors == FSCK_OPT_EXIT || (c->opts.fix_errors == FSCK_FIX_exit ||
!(flags & FSCK_CAN_IGNORE))) !(flags & FSCK_CAN_IGNORE)))
ret = -BCH_ERR_fsck_errors_not_fixed; ret = -BCH_ERR_fsck_errors_not_fixed;
......
...@@ -91,13 +91,6 @@ do { \ ...@@ -91,13 +91,6 @@ do { \
* be able to repair: * 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 fsck_err_state {
struct list_head list; struct list_head list;
const char *fmt; const char *fmt;
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "bcachefs.h" #include "bcachefs.h"
#include "compress.h" #include "compress.h"
#include "disk_groups.h" #include "disk_groups.h"
#include "error.h"
#include "opts.h" #include "opts.h"
#include "super-io.h" #include "super-io.h"
#include "util.h" #include "util.h"
...@@ -16,6 +17,11 @@ const char * const bch2_error_actions[] = { ...@@ -16,6 +17,11 @@ const char * const bch2_error_actions[] = {
NULL NULL
}; };
const char * const bch2_fsck_fix_opts[] = {
BCH_FIX_ERRORS_OPTS()
NULL
};
const char * const bch2_version_upgrade_opts[] = { const char * const bch2_version_upgrade_opts[] = {
BCH_VERSION_UPGRADE_OPTS() BCH_VERSION_UPGRADE_OPTS()
NULL NULL
...@@ -89,6 +95,37 @@ const char * const bch2_fs_usage_types[] = { ...@@ -89,6 +95,37 @@ const char * const bch2_fs_usage_types[] = {
#undef x #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] = { const char * const bch2_d_types[BCH_DT_MAX] = {
[DT_UNKNOWN] = "unknown", [DT_UNKNOWN] = "unknown",
[DT_FIFO] = "fifo", [DT_FIFO] = "fifo",
...@@ -265,15 +302,26 @@ int bch2_opt_parse(struct bch_fs *c, ...@@ -265,15 +302,26 @@ int bch2_opt_parse(struct bch_fs *c,
switch (opt->type) { switch (opt->type) {
case BCH_OPT_BOOL: 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 (ret < 0 || (*res != 0 && *res != 1)) {
if (err) if (err)
prt_printf(err, "%s: must be bool", prt_printf(err, "%s: must be bool", opt->attr.name);
opt->attr.name);
return ret; return ret;
} }
break; break;
case BCH_OPT_UINT: case BCH_OPT_UINT:
if (!val) {
prt_printf(err, "%s: required value",
opt->attr.name);
return -EINVAL;
}
ret = opt->flags & OPT_HUMAN_READABLE ret = opt->flags & OPT_HUMAN_READABLE
? bch2_strtou64_h(val, res) ? bch2_strtou64_h(val, res)
: kstrtou64(val, 10, res); : kstrtou64(val, 10, res);
...@@ -285,6 +333,12 @@ int bch2_opt_parse(struct bch_fs *c, ...@@ -285,6 +333,12 @@ int bch2_opt_parse(struct bch_fs *c,
} }
break; break;
case BCH_OPT_STR: case BCH_OPT_STR:
if (!val) {
prt_printf(err, "%s: required value",
opt->attr.name);
return -EINVAL;
}
ret = match_string(opt->choices, -1, val); ret = match_string(opt->choices, -1, val);
if (ret < 0) { if (ret < 0) {
if (err) if (err)
...@@ -336,7 +390,7 @@ void bch2_opt_to_text(struct printbuf *out, ...@@ -336,7 +390,7 @@ void bch2_opt_to_text(struct printbuf *out,
if (flags & OPT_SHOW_FULL_LIST) if (flags & OPT_SHOW_FULL_LIST)
prt_string_option(out, opt->choices, v); prt_string_option(out, opt->choices, v);
else else
prt_printf(out, "%s", opt->choices[v]); prt_str(out, opt->choices[v]);
break; break;
case BCH_OPT_FN: case BCH_OPT_FN:
opt->fn.to_text(out, c, sb, v); 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, ...@@ -400,31 +454,19 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
name = strsep(&opt, "="); name = strsep(&opt, "=");
val = opt; val = opt;
if (val) { id = bch2_mount_opt_lookup(name);
id = bch2_mount_opt_lookup(name);
if (id < 0)
goto bad_opt;
ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err); /* Check for the form "noopt", negation of a boolean opt: */
if (ret < 0) if (id < 0 &&
goto bad_val; !val &&
} else { !strncmp("no", name, 2)) {
id = bch2_mount_opt_lookup(name); id = bch2_mount_opt_lookup(name + 2);
v = 1; val = "0";
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;
} }
if (id < 0)
goto bad_opt;
if (!(bch2_opt_table[id].flags & OPT_MOUNT)) if (!(bch2_opt_table[id].flags & OPT_MOUNT))
goto bad_opt; goto bad_opt;
...@@ -437,6 +479,10 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts, ...@@ -437,6 +479,10 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
!IS_ENABLED(CONFIG_BCACHEFS_QUOTA)) !IS_ENABLED(CONFIG_BCACHEFS_QUOTA))
goto bad_opt; 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); bch2_opt_set_by_id(opts, id, v);
} }
...@@ -451,10 +497,6 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts, ...@@ -451,10 +497,6 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
pr_err("Invalid mount option %s", err.buf); pr_err("Invalid mount option %s", err.buf);
ret = -1; ret = -1;
goto out; goto out;
no_val:
pr_err("Mount option %s requires a value", name);
ret = -1;
goto out;
out: out:
kfree(copied_opts_start); kfree(copied_opts_start);
printbuf_exit(&err); printbuf_exit(&err);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
struct bch_fs; struct bch_fs;
extern const char * const bch2_error_actions[]; 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_version_upgrade_opts[];
extern const char * const bch2_sb_features[]; extern const char * const bch2_sb_features[];
extern const char * const bch2_sb_compat[]; extern const char * const bch2_sb_compat[];
...@@ -105,6 +106,18 @@ struct bch_opt_fn { ...@@ -105,6 +106,18 @@ struct bch_opt_fn {
#define BCACHEFS_VERBOSE_DEFAULT false #define BCACHEFS_VERBOSE_DEFAULT false
#endif #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() \ #define BCH_OPTS() \
x(block_size, u16, \ x(block_size, u16, \
OPT_FS|OPT_FORMAT| \ OPT_FS|OPT_FORMAT| \
...@@ -325,8 +338,8 @@ struct bch_opt_fn { ...@@ -325,8 +338,8 @@ struct bch_opt_fn {
NULL, "Run fsck on mount") \ NULL, "Run fsck on mount") \
x(fix_errors, u8, \ x(fix_errors, u8, \
OPT_FS|OPT_MOUNT, \ OPT_FS|OPT_MOUNT, \
OPT_BOOL(), \ OPT_FN(bch2_opt_fix_errors), \
BCH2_NO_SB_OPT, false, \ BCH2_NO_SB_OPT, FSCK_FIX_exit, \
NULL, "Fix errors during fsck without asking") \ NULL, "Fix errors during fsck without asking") \
x(ratelimit_errors, u8, \ x(ratelimit_errors, u8, \
OPT_FS|OPT_MOUNT, \ OPT_FS|OPT_MOUNT, \
......
...@@ -1175,7 +1175,7 @@ static void check_version_upgrade(struct bch_fs *c) ...@@ -1175,7 +1175,7 @@ static void check_version_upgrade(struct bch_fs *c)
prt_str(&buf, "fsck required"); prt_str(&buf, "fsck required");
c->recovery_passes_explicit |= recovery_passes; 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); bch_info(c, "%s", buf.buf);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment