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:
@ -1808,7 +1808,7 @@ again:
|
|||||||
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, ...)
|
|||||||
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, ...)
|
|||||||
? 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, ...)
|
|||||||
|
|
||||||
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, ...)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 { \
|
|||||||
* 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 @@
|
|||||||
#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[] = {
|
|||||||
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[] = {
|
|||||||
|
|
||||||
#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,
|
|||||||
|
|
||||||
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,
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
!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 @@ bad_val:
|
|||||||
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 @@
|
|||||||
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 {
|
|||||||
#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 {
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user