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>
This commit is contained in:
Kent Overstreet 2023-07-11 23:47:29 -04:00
parent 9f343e24f5
commit a0f8faea5f
6 changed files with 95 additions and 47 deletions

View File

@ -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)

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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, \

View File

@ -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);