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

bcachefs: Kill BCH_DEV_OPT_SETTERS()



Previously, device options had their superblock option field listed
separately, which was weird and easy to miss when defining options.

Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent dd7ae389
Loading
Loading
Loading
Loading
+50 −58
Original line number Diff line number Diff line
@@ -163,16 +163,6 @@ const char * const bch2_d_types[BCH_DT_MAX] = {
	[DT_SUBVOL]	= "subvol",
};

u64 BCH2_NO_SB_OPT(const struct bch_sb *sb)
{
	BUG();
}

void SET_BCH2_NO_SB_OPT(struct bch_sb *sb, u64 v)
{
	BUG();
}

void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
{
#define x(_name, ...)						\
@@ -223,6 +213,21 @@ void bch2_opt_set_by_id(struct bch_opts *opts, enum bch_opt_id id, u64 v)
	}
}

/* dummy option, for options that aren't stored in the superblock */
typedef u64 (*sb_opt_get_fn)(const struct bch_sb *);
typedef void (*sb_opt_set_fn)(struct bch_sb *, u64);
typedef u64 (*member_opt_get_fn)(const struct bch_member *);
typedef void (*member_opt_set_fn)(struct bch_member *, u64);

__maybe_unused static const sb_opt_get_fn	BCH2_NO_SB_OPT = NULL;
__maybe_unused static const sb_opt_set_fn	SET_BCH2_NO_SB_OPT = NULL;
__maybe_unused static const member_opt_get_fn	BCH2_NO_MEMBER_OPT = NULL;
__maybe_unused static const member_opt_set_fn	SET_BCH2_NO_MEMBER_OPT = NULL;

#define type_compatible_or_null(_p, _type)				\
	__builtin_choose_expr(						\
		__builtin_types_compatible_p(typeof(_p), typeof(_type)), _p, NULL)

const struct bch_option bch2_opt_table[] = {
#define OPT_BOOL()		.type = BCH_OPT_BOOL, .min = 0, .max = 2
#define OPT_UINT(_min, _max)	.type = BCH_OPT_UINT,			\
@@ -239,15 +244,15 @@ const struct bch_option bch2_opt_table[] = {

#define x(_name, _bits, _flags, _type, _sb_opt, _default, _hint, _help)	\
	[Opt_##_name] = {						\
		.attr	= {						\
			.name	= #_name,				\
			.mode = (_flags) & OPT_RUNTIME ? 0644 : 0444,	\
		},							\
		.attr.name	= #_name,				\
		.attr.mode	= (_flags) & OPT_RUNTIME ? 0644 : 0444,	\
		.flags		= _flags,				\
		.hint		= _hint,				\
		.help		= _help,				\
		.get_sb = _sb_opt,					\
		.set_sb	= SET_##_sb_opt,				\
		.get_sb		= type_compatible_or_null(_sb_opt,	*BCH2_NO_SB_OPT),	\
		.set_sb		= type_compatible_or_null(SET_##_sb_opt,*SET_BCH2_NO_SB_OPT),	\
		.get_member	= type_compatible_or_null(_sb_opt,	*BCH2_NO_MEMBER_OPT),	\
		.set_member	= type_compatible_or_null(SET_##_sb_opt,*SET_BCH2_NO_MEMBER_OPT),\
		_type							\
	},

@@ -495,12 +500,8 @@ int bch2_opt_check_may_set(struct bch_fs *c, int id, u64 v)

int bch2_opts_check_may_set(struct bch_fs *c)
{
	unsigned i;
	int ret;

	for (i = 0; i < bch2_opts_nr; i++) {
		ret = bch2_opt_check_may_set(c, i,
				bch2_opt_get_by_id(&c->opts, i));
	for (unsigned i = 0; i < bch2_opts_nr; i++) {
		int ret = bch2_opt_check_may_set(c, i, bch2_opt_get_by_id(&c->opts, i));
		if (ret)
			return ret;
	}
@@ -619,12 +620,25 @@ int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
	return ret;
}

u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id)
u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id, int dev_idx)
{
	const struct bch_option *opt = bch2_opt_table + id;
	u64 v;

	if (dev_idx < 0) {
		v = opt->get_sb(sb);
	} else {
		if (WARN(!bch2_member_exists(sb, dev_idx),
			 "tried to set device option %s on nonexistent device %i",
			 opt->attr.name, dev_idx))
			return 0;

		struct bch_member m = bch2_sb_member_get(sb, dev_idx);
		v = opt->get_member(&m);
	}

	if (opt->flags & OPT_SB_FIELD_ONE_BIAS)
		--v;

	if (opt->flags & OPT_SB_FIELD_ILOG2)
		v = 1ULL << v;
@@ -641,35 +655,19 @@ u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id)
 */
int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)
{
	unsigned id;

	for (id = 0; id < bch2_opts_nr; id++) {
	for (unsigned id = 0; id < bch2_opts_nr; id++) {
		const struct bch_option *opt = bch2_opt_table + id;

		if (opt->get_sb == BCH2_NO_SB_OPT)
			continue;

		bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id));
		if (opt->get_sb)
			bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id, -1));
	}

	return 0;
}

struct bch_dev_sb_opt_set {
	void			(*set_sb)(struct bch_member *, u64);
};

static const struct bch_dev_sb_opt_set bch2_dev_sb_opt_setters [] = {
#define x(n, set)	[Opt_##n] = { .set_sb = SET_##set },
	BCH_DEV_OPT_SETTERS()
#undef x
};

void __bch2_opt_set_sb(struct bch_sb *sb, int dev_idx,
		       const struct bch_option *opt, u64 v)
{
	enum bch_opt_id id = opt - bch2_opt_table;

	if (opt->flags & OPT_SB_FIELD_SECTORS)
		v >>= 9;

@@ -679,24 +677,18 @@ void __bch2_opt_set_sb(struct bch_sb *sb, int dev_idx,
	if (opt->flags & OPT_SB_FIELD_ONE_BIAS)
		v++;

	if (opt->flags & OPT_FS) {
		if (opt->set_sb != SET_BCH2_NO_SB_OPT)
	if ((opt->flags & OPT_FS) && opt->set_sb)
		opt->set_sb(sb, v);
	}

	if ((opt->flags & OPT_DEVICE) && dev_idx >= 0) {
	if ((opt->flags & OPT_DEVICE) &&
	    opt->set_member &&
	    dev_idx >= 0) {
		if (WARN(!bch2_member_exists(sb, dev_idx),
			 "tried to set device option %s on nonexistent device %i",
			 opt->attr.name, dev_idx))
			return;

		struct bch_member *m = bch2_members_v2_get_mut(sb, dev_idx);

		const struct bch_dev_sb_opt_set *set = bch2_dev_sb_opt_setters + id;
		if (set->set_sb)
			set->set_sb(m, v);
		else
			pr_err("option %s cannot be set via opt_set_sb()", opt->attr.name);
		opt->set_member(bch2_members_v2_get_mut(sb, dev_idx), v);
	}
}

+25 −25
Original line number Diff line number Diff line
@@ -50,10 +50,6 @@ static inline const char *bch2_d_type_str(unsigned d_type)
 * apply the options from that struct that are defined.
 */

/* dummy option, for options that aren't stored in the superblock */
u64 BCH2_NO_SB_OPT(const struct bch_sb *);
void SET_BCH2_NO_SB_OPT(struct bch_sb *, u64);

/* When can be set: */
enum opt_flags {
	OPT_FS			= BIT(0),	/* Filesystem option */
@@ -318,11 +314,6 @@ enum fsck_err_opts {
	  OPT_BOOL(),							\
	  BCH2_NO_SB_OPT,		false,				\
	  NULL,		"Don't kick drives out when splitbrain detected")\
	x(discard,			u8,				\
	  OPT_FS|OPT_MOUNT|OPT_DEVICE,					\
	  OPT_BOOL(),							\
	  BCH2_NO_SB_OPT,		true,				\
	  NULL,		"Enable discard/TRIM support")			\
	x(verbose,			u8,				\
	  OPT_FS|OPT_MOUNT|OPT_RUNTIME,					\
	  OPT_BOOL(),							\
@@ -503,27 +494,37 @@ enum fsck_err_opts {
	  BCH2_NO_SB_OPT,		false,				\
	  NULL,		"Skip submit_bio() for data reads and writes, "	\
			"for performance testing purposes")		\
	x(fs_size,			u64,				\
	x(state,			u64,				\
	  OPT_DEVICE,							\
	  OPT_STR(bch2_member_states),					\
	  BCH_MEMBER_STATE,		BCH_MEMBER_STATE_rw,		\
	  "state",	"rw,ro,failed,spare")				\
	x(fs_size,			u64,				\
	  OPT_DEVICE|OPT_HIDDEN,					\
	  OPT_UINT(0, S64_MAX),						\
	  BCH2_NO_SB_OPT,		0,				\
	  BCH2_NO_MEMBER_OPT,		0,				\
	  "size",	"Size of filesystem on device")			\
	x(bucket,			u32,				\
	  OPT_DEVICE,							\
	x(bucket_size,			u32,				\
	  OPT_DEVICE|OPT_HUMAN_READABLE|OPT_SB_FIELD_SECTORS,		\
	  OPT_UINT(0, S64_MAX),						\
	  BCH2_NO_SB_OPT,		0,				\
	  BCH_MEMBER_BUCKET_SIZE,	0,				\
	  "size",	"Specifies the bucket size; must be greater than the btree node size")\
	x(durability,			u8,				\
	  OPT_DEVICE|OPT_SB_FIELD_ONE_BIAS,				\
	  OPT_DEVICE|OPT_RUNTIME|OPT_SB_FIELD_ONE_BIAS,			\
	  OPT_UINT(0, BCH_REPLICAS_MAX),				\
	  BCH2_NO_SB_OPT,		1,				\
	  BCH_MEMBER_DURABILITY,	1,				\
	  "n",		"Data written to this device will be considered\n"\
			"to have already been replicated n times")	\
	x(data_allowed,			u8,				\
	  OPT_DEVICE,							\
	  OPT_BITFIELD(__bch2_data_types),				\
	  BCH2_NO_SB_OPT,		BIT(BCH_DATA_journal)|BIT(BCH_DATA_btree)|BIT(BCH_DATA_user),\
	  BCH_MEMBER_DATA_ALLOWED,	BIT(BCH_DATA_journal)|BIT(BCH_DATA_btree)|BIT(BCH_DATA_user),\
	  "types",	"Allowed data types for this device: journal, btree, and/or user")\
	x(discard,			u8,				\
	  OPT_MOUNT|OPT_DEVICE|OPT_RUNTIME,				\
	  OPT_BOOL(),							\
	  BCH_MEMBER_DISCARD,		true,				\
	  NULL,		"Enable discard/TRIM support")			\
	x(btree_node_prefetch,		u8,				\
	  OPT_FS|OPT_MOUNT|OPT_RUNTIME,					\
	  OPT_BOOL(),							\
@@ -531,11 +532,6 @@ enum fsck_err_opts {
	  NULL,		"BTREE_ITER_prefetch casuse btree nodes to be\n"\
	  " prefetched sequentially")

#define BCH_DEV_OPT_SETTERS()						\
	x(discard,		BCH_MEMBER_DISCARD)			\
	x(durability,		BCH_MEMBER_DURABILITY)			\
	x(data_allowed,		BCH_MEMBER_DATA_ALLOWED)

struct bch_opts {
#define x(_name, _bits, ...)	unsigned _name##_defined:1;
	BCH_OPTS()
@@ -592,8 +588,6 @@ struct printbuf;

struct bch_option {
	struct attribute	attr;
	u64			(*get_sb)(const struct bch_sb *);
	void			(*set_sb)(struct bch_sb *, u64);
	enum opt_type		type;
	enum opt_flags		flags;
	u64			min, max;
@@ -605,6 +599,12 @@ struct bch_option {
	const char		*hint;
	const char		*help;

	u64			(*get_sb)(const struct bch_sb *);
	void			(*set_sb)(struct bch_sb *, u64);

	u64			(*get_member)(const struct bch_member *);
	void			(*set_member)(struct bch_member *, u64);

};

extern const struct bch_option bch2_opt_table[];
@@ -613,7 +613,7 @@ bool bch2_opt_defined_by_id(const struct bch_opts *, enum bch_opt_id);
u64 bch2_opt_get_by_id(const struct bch_opts *, enum bch_opt_id);
void bch2_opt_set_by_id(struct bch_opts *, enum bch_opt_id, u64);

u64 bch2_opt_from_sb(struct bch_sb *, enum bch_opt_id);
u64 bch2_opt_from_sb(struct bch_sb *, enum bch_opt_id, int);
int bch2_opts_from_sb(struct bch_opts *, struct bch_sb *);
void __bch2_opt_set_sb(struct bch_sb *, int, const struct bch_option *, u64);

+1 −0
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ struct bch_member {

#define BCH_MEMBER_V1_BYTES	56

LE16_BITMASK(BCH_MEMBER_BUCKET_SIZE,	struct bch_member, bucket_size,  0, 16)
LE64_BITMASK(BCH_MEMBER_STATE,		struct bch_member, flags,  0,  4)
/* 4-14 unused, was TIER, HAS_(META)DATA, REPLACEMENT */
LE64_BITMASK(BCH_MEMBER_DISCARD,	struct bch_member, flags, 14, 15)
+4 −4
Original line number Diff line number Diff line
@@ -489,8 +489,8 @@ int bch2_sb_validate(struct bch_sb *sb, u64 read_offset,
	for (opt_id = 0; opt_id < bch2_opts_nr; opt_id++) {
		const struct bch_option *opt = bch2_opt_table + opt_id;

		if (opt->get_sb != BCH2_NO_SB_OPT) {
			u64 v = bch2_opt_from_sb(sb, opt_id);
		if (opt->get_sb) {
			u64 v = bch2_opt_from_sb(sb, opt_id, -1);

			prt_printf(out, "Invalid option ");
			ret = bch2_opt_validate(opt, v, out);
@@ -1473,8 +1473,8 @@ void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb,
		for (id = 0; id < bch2_opts_nr; id++) {
			const struct bch_option *opt = bch2_opt_table + id;

			if (opt->get_sb != BCH2_NO_SB_OPT) {
				u64 v = bch2_opt_from_sb(sb, id);
			if (opt->get_sb) {
				u64 v = bch2_opt_from_sb(sb, id, -1);

				prt_printf(out, "%s:\t", opt->attr.name);
				bch2_opt_to_text(out, NULL, sb, opt, v,