brintos

brintos / linux-shallow public Read only

0
0
Text · 14.7 KiB · 0e2ee26 Raw
735 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <linux/kernel.h>4 5#include "bcachefs.h"6#include "compress.h"7#include "disk_groups.h"8#include "error.h"9#include "opts.h"10#include "recovery_passes.h"11#include "super-io.h"12#include "util.h"13 14#define x(t, n, ...) [n] = #t,15 16const char * const bch2_error_actions[] = {17	BCH_ERROR_ACTIONS()18	NULL19};20 21const char * const bch2_fsck_fix_opts[] = {22	BCH_FIX_ERRORS_OPTS()23	NULL24};25 26const char * const bch2_version_upgrade_opts[] = {27	BCH_VERSION_UPGRADE_OPTS()28	NULL29};30 31const char * const bch2_sb_features[] = {32	BCH_SB_FEATURES()33	NULL34};35 36const char * const bch2_sb_compat[] = {37	BCH_SB_COMPAT()38	NULL39};40 41const char * const __bch2_btree_ids[] = {42	BCH_BTREE_IDS()43	NULL44};45 46static const char * const __bch2_csum_types[] = {47	BCH_CSUM_TYPES()48	NULL49};50 51const char * const bch2_csum_opts[] = {52	BCH_CSUM_OPTS()53	NULL54};55 56static const char * const __bch2_compression_types[] = {57	BCH_COMPRESSION_TYPES()58	NULL59};60 61const char * const bch2_compression_opts[] = {62	BCH_COMPRESSION_OPTS()63	NULL64};65 66const char * const __bch2_str_hash_types[] = {67	BCH_STR_HASH_TYPES()68	NULL69};70 71const char * const bch2_str_hash_opts[] = {72	BCH_STR_HASH_OPTS()73	NULL74};75 76const char * const __bch2_data_types[] = {77	BCH_DATA_TYPES()78	NULL79};80 81const char * const bch2_member_states[] = {82	BCH_MEMBER_STATES()83	NULL84};85 86static const char * const __bch2_jset_entry_types[] = {87	BCH_JSET_ENTRY_TYPES()88	NULL89};90 91static const char * const __bch2_fs_usage_types[] = {92	BCH_FS_USAGE_TYPES()93	NULL94};95 96#undef x97 98static void prt_str_opt_boundscheck(struct printbuf *out, const char * const opts[],99				    unsigned nr, const char *type, unsigned idx)100{101	if (idx < nr)102		prt_str(out, opts[idx]);103	else104		prt_printf(out, "(unknown %s %u)", type, idx);105}106 107#define PRT_STR_OPT_BOUNDSCHECKED(name, type)					\108void bch2_prt_##name(struct printbuf *out, type t)				\109{										\110	prt_str_opt_boundscheck(out, __bch2_##name##s, ARRAY_SIZE(__bch2_##name##s) - 1, #name, t);\111}112 113PRT_STR_OPT_BOUNDSCHECKED(jset_entry_type,	enum bch_jset_entry_type);114PRT_STR_OPT_BOUNDSCHECKED(fs_usage_type,	enum bch_fs_usage_type);115PRT_STR_OPT_BOUNDSCHECKED(data_type,		enum bch_data_type);116PRT_STR_OPT_BOUNDSCHECKED(csum_type,		enum bch_csum_type);117PRT_STR_OPT_BOUNDSCHECKED(compression_type,	enum bch_compression_type);118PRT_STR_OPT_BOUNDSCHECKED(str_hash_type,	enum bch_str_hash_type);119 120static int bch2_opt_fix_errors_parse(struct bch_fs *c, const char *val, u64 *res,121				     struct printbuf *err)122{123	if (!val) {124		*res = FSCK_FIX_yes;125	} else {126		int ret = match_string(bch2_fsck_fix_opts, -1, val);127 128		if (ret < 0 && err)129			prt_str(err, "fix_errors: invalid selection");130		if (ret < 0)131			return ret;132		*res = ret;133	}134 135	return 0;136}137 138static void bch2_opt_fix_errors_to_text(struct printbuf *out,139					struct bch_fs *c,140					struct bch_sb *sb,141					u64 v)142{143	prt_str(out, bch2_fsck_fix_opts[v]);144}145 146#define bch2_opt_fix_errors (struct bch_opt_fn) {	\147	.parse = bch2_opt_fix_errors_parse,		\148	.to_text = bch2_opt_fix_errors_to_text,		\149}150 151const char * const bch2_d_types[BCH_DT_MAX] = {152	[DT_UNKNOWN]	= "unknown",153	[DT_FIFO]	= "fifo",154	[DT_CHR]	= "chr",155	[DT_DIR]	= "dir",156	[DT_BLK]	= "blk",157	[DT_REG]	= "reg",158	[DT_LNK]	= "lnk",159	[DT_SOCK]	= "sock",160	[DT_WHT]	= "whiteout",161	[DT_SUBVOL]	= "subvol",162};163 164u64 BCH2_NO_SB_OPT(const struct bch_sb *sb)165{166	BUG();167}168 169void SET_BCH2_NO_SB_OPT(struct bch_sb *sb, u64 v)170{171	BUG();172}173 174void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)175{176#define x(_name, ...)						\177	if (opt_defined(src, _name))					\178		opt_set(*dst, _name, src._name);179 180	BCH_OPTS()181#undef x182}183 184bool bch2_opt_defined_by_id(const struct bch_opts *opts, enum bch_opt_id id)185{186	switch (id) {187#define x(_name, ...)						\188	case Opt_##_name:						\189		return opt_defined(*opts, _name);190	BCH_OPTS()191#undef x192	default:193		BUG();194	}195}196 197u64 bch2_opt_get_by_id(const struct bch_opts *opts, enum bch_opt_id id)198{199	switch (id) {200#define x(_name, ...)						\201	case Opt_##_name:						\202		return opts->_name;203	BCH_OPTS()204#undef x205	default:206		BUG();207	}208}209 210void bch2_opt_set_by_id(struct bch_opts *opts, enum bch_opt_id id, u64 v)211{212	switch (id) {213#define x(_name, ...)						\214	case Opt_##_name:						\215		opt_set(*opts, _name, v);				\216		break;217	BCH_OPTS()218#undef x219	default:220		BUG();221	}222}223 224const struct bch_option bch2_opt_table[] = {225#define OPT_BOOL()		.type = BCH_OPT_BOOL, .min = 0, .max = 2226#define OPT_UINT(_min, _max)	.type = BCH_OPT_UINT,			\227				.min = _min, .max = _max228#define OPT_STR(_choices)	.type = BCH_OPT_STR,			\229				.min = 0, .max = ARRAY_SIZE(_choices) - 1, \230				.choices = _choices231#define OPT_STR_NOLIMIT(_choices)	.type = BCH_OPT_STR,		\232				.min = 0, .max = U64_MAX,		\233				.choices = _choices234#define OPT_BITFIELD(_choices)	.type = BCH_OPT_BITFIELD,		\235				.choices = _choices236#define OPT_FN(_fn)		.type = BCH_OPT_FN, .fn	= _fn237 238#define x(_name, _bits, _flags, _type, _sb_opt, _default, _hint, _help)	\239	[Opt_##_name] = {						\240		.attr	= {						\241			.name	= #_name,				\242			.mode = (_flags) & OPT_RUNTIME ? 0644 : 0444,	\243		},							\244		.flags	= _flags,					\245		.hint	= _hint,					\246		.help	= _help,					\247		.get_sb = _sb_opt,					\248		.set_sb	= SET_##_sb_opt,				\249		_type							\250	},251 252	BCH_OPTS()253#undef x254};255 256int bch2_opt_lookup(const char *name)257{258	const struct bch_option *i;259 260	for (i = bch2_opt_table;261	     i < bch2_opt_table + ARRAY_SIZE(bch2_opt_table);262	     i++)263		if (!strcmp(name, i->attr.name))264			return i - bch2_opt_table;265 266	return -1;267}268 269struct synonym {270	const char	*s1, *s2;271};272 273static const struct synonym bch_opt_synonyms[] = {274	{ "quota",	"usrquota" },275};276 277static int bch2_mount_opt_lookup(const char *name)278{279	const struct synonym *i;280 281	for (i = bch_opt_synonyms;282	     i < bch_opt_synonyms + ARRAY_SIZE(bch_opt_synonyms);283	     i++)284		if (!strcmp(name, i->s1))285			name = i->s2;286 287	return bch2_opt_lookup(name);288}289 290int bch2_opt_validate(const struct bch_option *opt, u64 v, struct printbuf *err)291{292	if (v < opt->min) {293		if (err)294			prt_printf(err, "%s: too small (min %llu)",295			       opt->attr.name, opt->min);296		return -BCH_ERR_ERANGE_option_too_small;297	}298 299	if (opt->max && v >= opt->max) {300		if (err)301			prt_printf(err, "%s: too big (max %llu)",302			       opt->attr.name, opt->max);303		return -BCH_ERR_ERANGE_option_too_big;304	}305 306	if ((opt->flags & OPT_SB_FIELD_SECTORS) && (v & 511)) {307		if (err)308			prt_printf(err, "%s: not a multiple of 512",309			       opt->attr.name);310		return -BCH_ERR_opt_parse_error;311	}312 313	if ((opt->flags & OPT_MUST_BE_POW_2) && !is_power_of_2(v)) {314		if (err)315			prt_printf(err, "%s: must be a power of two",316			       opt->attr.name);317		return -BCH_ERR_opt_parse_error;318	}319 320	if (opt->fn.validate)321		return opt->fn.validate(v, err);322 323	return 0;324}325 326int bch2_opt_parse(struct bch_fs *c,327		   const struct bch_option *opt,328		   const char *val, u64 *res,329		   struct printbuf *err)330{331	ssize_t ret;332 333	switch (opt->type) {334	case BCH_OPT_BOOL:335		if (val) {336			ret = kstrtou64(val, 10, res);337		} else {338			ret = 0;339			*res = 1;340		}341 342		if (ret < 0 || (*res != 0 && *res != 1)) {343			if (err)344				prt_printf(err, "%s: must be bool", opt->attr.name);345			return ret < 0 ? ret : -BCH_ERR_option_not_bool;346		}347		break;348	case BCH_OPT_UINT:349		if (!val) {350			prt_printf(err, "%s: required value",351				   opt->attr.name);352			return -EINVAL;353		}354 355		ret = opt->flags & OPT_HUMAN_READABLE356			? bch2_strtou64_h(val, res)357			: kstrtou64(val, 10, res);358		if (ret < 0) {359			if (err)360				prt_printf(err, "%s: must be a number",361					   opt->attr.name);362			return ret;363		}364		break;365	case BCH_OPT_STR:366		if (!val) {367			prt_printf(err, "%s: required value",368				   opt->attr.name);369			return -EINVAL;370		}371 372		ret = match_string(opt->choices, -1, val);373		if (ret < 0) {374			if (err)375				prt_printf(err, "%s: invalid selection",376					   opt->attr.name);377			return ret;378		}379 380		*res = ret;381		break;382	case BCH_OPT_BITFIELD: {383		s64 v = bch2_read_flag_list(val, opt->choices);384		if (v < 0)385			return v;386		*res = v;387		break;388	}389	case BCH_OPT_FN:390		ret = opt->fn.parse(c, val, res, err);391 392		if (ret == -BCH_ERR_option_needs_open_fs)393			return ret;394 395		if (ret < 0) {396			if (err)397				prt_printf(err, "%s: parse error",398					   opt->attr.name);399			return ret;400		}401	}402 403	return bch2_opt_validate(opt, *res, err);404}405 406void bch2_opt_to_text(struct printbuf *out,407		      struct bch_fs *c, struct bch_sb *sb,408		      const struct bch_option *opt, u64 v,409		      unsigned flags)410{411	if (flags & OPT_SHOW_MOUNT_STYLE) {412		if (opt->type == BCH_OPT_BOOL) {413			prt_printf(out, "%s%s",414			       v ? "" : "no",415			       opt->attr.name);416			return;417		}418 419		prt_printf(out, "%s=", opt->attr.name);420	}421 422	switch (opt->type) {423	case BCH_OPT_BOOL:424	case BCH_OPT_UINT:425		if (opt->flags & OPT_HUMAN_READABLE)426			prt_human_readable_u64(out, v);427		else428			prt_printf(out, "%lli", v);429		break;430	case BCH_OPT_STR:431		if (v < opt->min || v >= opt->max)432			prt_printf(out, "(invalid option %lli)", v);433		else if (flags & OPT_SHOW_FULL_LIST)434			prt_string_option(out, opt->choices, v);435		else436			prt_str(out, opt->choices[v]);437		break;438	case BCH_OPT_BITFIELD:439		prt_bitflags(out, opt->choices, v);440		break;441	case BCH_OPT_FN:442		opt->fn.to_text(out, c, sb, v);443		break;444	default:445		BUG();446	}447}448 449void bch2_opts_to_text(struct printbuf *out,450		       struct bch_opts opts,451		       struct bch_fs *c, struct bch_sb *sb,452		       unsigned show_mask, unsigned hide_mask,453		       unsigned flags)454{455	bool first = true;456 457	for (enum bch_opt_id i = 0; i < bch2_opts_nr; i++) {458		const struct bch_option *opt = &bch2_opt_table[i];459 460		if ((opt->flags & hide_mask) || !(opt->flags & show_mask))461			continue;462 463		u64 v = bch2_opt_get_by_id(&opts, i);464		if (v == bch2_opt_get_by_id(&bch2_opts_default, i))465			continue;466 467		if (!first)468			prt_char(out, ',');469		first = false;470 471		bch2_opt_to_text(out, c, sb, opt, v, flags);472	}473}474 475int bch2_opt_check_may_set(struct bch_fs *c, int id, u64 v)476{477	int ret = 0;478 479	switch (id) {480	case Opt_compression:481	case Opt_background_compression:482		ret = bch2_check_set_has_compressed_data(c, v);483		break;484	case Opt_erasure_code:485		if (v)486			bch2_check_set_feature(c, BCH_FEATURE_ec);487		break;488	}489 490	return ret;491}492 493int bch2_opts_check_may_set(struct bch_fs *c)494{495	unsigned i;496	int ret;497 498	for (i = 0; i < bch2_opts_nr; i++) {499		ret = bch2_opt_check_may_set(c, i,500				bch2_opt_get_by_id(&c->opts, i));501		if (ret)502			return ret;503	}504 505	return 0;506}507 508int bch2_parse_one_mount_opt(struct bch_fs *c, struct bch_opts *opts,509			     struct printbuf *parse_later,510			     const char *name, const char *val)511{512	struct printbuf err = PRINTBUF;513	u64 v;514	int ret, id;515 516	id = bch2_mount_opt_lookup(name);517 518	/* Check for the form "noopt", negation of a boolean opt: */519	if (id < 0 &&520	    !val &&521	    !strncmp("no", name, 2)) {522		id = bch2_mount_opt_lookup(name + 2);523		val = "0";524	}525 526	/* Unknown options are ignored: */527	if (id < 0)528		return 0;529 530	if (!(bch2_opt_table[id].flags & OPT_MOUNT))531		goto bad_opt;532 533	if (id == Opt_acl &&534	    !IS_ENABLED(CONFIG_BCACHEFS_POSIX_ACL))535		goto bad_opt;536 537	if ((id == Opt_usrquota ||538	     id == Opt_grpquota) &&539	    !IS_ENABLED(CONFIG_BCACHEFS_QUOTA))540		goto bad_opt;541 542	ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err);543	if (ret == -BCH_ERR_option_needs_open_fs && parse_later) {544		prt_printf(parse_later, "%s=%s,", name, val);545		if (parse_later->allocation_failure) {546			ret = -ENOMEM;547			goto out;548		}549 550		ret = 0;551		goto out;552	}553 554	if (ret < 0)555		goto bad_val;556 557	if (opts)558		bch2_opt_set_by_id(opts, id, v);559 560	ret = 0;561	goto out;562 563bad_opt:564	pr_err("Bad mount option %s", name);565	ret = -BCH_ERR_option_name;566	goto out;567 568bad_val:569	pr_err("Invalid mount option %s", err.buf);570	ret = -BCH_ERR_option_value;571 572out:573	printbuf_exit(&err);574	return ret;575}576 577int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,578			  struct printbuf *parse_later, char *options)579{580	char *copied_opts, *copied_opts_start;581	char *opt, *name, *val;582	int ret;583 584	if (!options)585		return 0;586 587	/*588	 * sys_fsconfig() is now occasionally providing us with option lists589	 * starting with a comma - weird.590	 */591	if (*options == ',')592		options++;593 594	copied_opts = kstrdup(options, GFP_KERNEL);595	if (!copied_opts)596		return -ENOMEM;597	copied_opts_start = copied_opts;598 599	while ((opt = strsep(&copied_opts, ",")) != NULL) {600		if (!*opt)601			continue;602 603		name	= strsep(&opt, "=");604		val	= opt;605 606		ret = bch2_parse_one_mount_opt(c, opts, parse_later, name, val);607		if (ret < 0)608			goto out;609	}610 611	ret = 0;612	goto out;613 614out:615	kfree(copied_opts_start);616	return ret;617}618 619u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id)620{621	const struct bch_option *opt = bch2_opt_table + id;622	u64 v;623 624	v = opt->get_sb(sb);625 626	if (opt->flags & OPT_SB_FIELD_ILOG2)627		v = 1ULL << v;628 629	if (opt->flags & OPT_SB_FIELD_SECTORS)630		v <<= 9;631 632	return v;633}634 635/*636 * Initial options from superblock - here we don't want any options undefined,637 * any options the superblock doesn't specify are set to 0:638 */639int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)640{641	unsigned id;642 643	for (id = 0; id < bch2_opts_nr; id++) {644		const struct bch_option *opt = bch2_opt_table + id;645 646		if (opt->get_sb == BCH2_NO_SB_OPT)647			continue;648 649		bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id));650	}651 652	return 0;653}654 655struct bch_dev_sb_opt_set {656	void			(*set_sb)(struct bch_member *, u64);657};658 659static const struct bch_dev_sb_opt_set bch2_dev_sb_opt_setters [] = {660#define x(n, set)	[Opt_##n] = { .set_sb = SET_##set },661	BCH_DEV_OPT_SETTERS()662#undef x663};664 665void __bch2_opt_set_sb(struct bch_sb *sb, int dev_idx,666		       const struct bch_option *opt, u64 v)667{668	enum bch_opt_id id = opt - bch2_opt_table;669 670	if (opt->flags & OPT_SB_FIELD_SECTORS)671		v >>= 9;672 673	if (opt->flags & OPT_SB_FIELD_ILOG2)674		v = ilog2(v);675 676	if (opt->flags & OPT_SB_FIELD_ONE_BIAS)677		v++;678 679	if (opt->flags & OPT_FS) {680		if (opt->set_sb != SET_BCH2_NO_SB_OPT)681			opt->set_sb(sb, v);682	}683 684	if ((opt->flags & OPT_DEVICE) && dev_idx >= 0) {685		if (WARN(!bch2_member_exists(sb, dev_idx),686			 "tried to set device option %s on nonexistent device %i",687			 opt->attr.name, dev_idx))688			return;689 690		struct bch_member *m = bch2_members_v2_get_mut(sb, dev_idx);691 692		const struct bch_dev_sb_opt_set *set = bch2_dev_sb_opt_setters + id;693		if (set->set_sb)694			set->set_sb(m, v);695		else696			pr_err("option %s cannot be set via opt_set_sb()", opt->attr.name);697	}698}699 700void bch2_opt_set_sb(struct bch_fs *c, struct bch_dev *ca,701		     const struct bch_option *opt, u64 v)702{703	mutex_lock(&c->sb_lock);704	__bch2_opt_set_sb(c->disk_sb.sb, ca ? ca->dev_idx : -1, opt, v);705	bch2_write_super(c);706	mutex_unlock(&c->sb_lock);707}708 709/* io opts: */710 711struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src)712{713	return (struct bch_io_opts) {714#define x(_name, _bits)	._name = src._name,715	BCH_INODE_OPTS()716#undef x717	};718}719 720bool bch2_opt_is_inode_opt(enum bch_opt_id id)721{722	static const enum bch_opt_id inode_opt_list[] = {723#define x(_name, _bits)	Opt_##_name,724	BCH_INODE_OPTS()725#undef x726	};727	unsigned i;728 729	for (i = 0; i < ARRAY_SIZE(inode_opt_list); i++)730		if (inode_opt_list[i] == id)731			return true;732 733	return false;734}735