Commit a0f8faea authored by Kent Overstreet's avatar Kent Overstreet
Browse files

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
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1808,7 +1808,7 @@ int bch2_gc(struct bch_fs *c, bool initial, bool metadata_only)
	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)
+6 −6
Original line number Diff line number Diff line
@@ -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;

+0 −7
Original line number Diff line number Diff line
@@ -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;
+72 −30
Original line number Diff line number Diff line
@@ -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:
		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;

			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;

		/* 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);
				v = 0;
			val = "0";
		}

		if (id < 0)
			goto bad_opt;

			if (bch2_opt_table[id].type != BCH_OPT_BOOL)
				goto no_val;
		}

		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 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
	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);
+15 −2
Original line number Diff line number Diff line
@@ -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,						\
Loading