Merge tag 'pci-v6.16-fixes-3' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci
[linux-block.git] / fs / bcachefs / opts.c
CommitLineData
1c6fdbd8
KO
1// SPDX-License-Identifier: GPL-2.0
2
3#include <linux/kernel.h>
394033dc 4#include <linux/fs_parser.h>
1c6fdbd8
KO
5
6#include "bcachefs.h"
c258f28e 7#include "compress.h"
1c6fdbd8 8#include "disk_groups.h"
a0f8faea 9#include "error.h"
c79eb06d 10#include "movinggc.h"
1c6fdbd8 11#include "opts.h"
c79eb06d 12#include "rebalance.h"
13c1e583 13#include "recovery_passes.h"
1c6fdbd8
KO
14#include "super-io.h"
15#include "util.h"
16
e8d2fe3b 17#define x(t, n, ...) [n] = #t,
74b33393 18
1c6fdbd8 19const char * const bch2_error_actions[] = {
2436cb9f 20 BCH_ERROR_ACTIONS()
1c6fdbd8
KO
21 NULL
22};
23
ef8dd631
KO
24const char * const bch2_degraded_actions[] = {
25 BCH_DEGRADED_ACTIONS()
26 NULL
27};
28
a0f8faea
KO
29const char * const bch2_fsck_fix_opts[] = {
30 BCH_FIX_ERRORS_OPTS()
31 NULL
32};
33
3045bb95
KO
34const char * const bch2_version_upgrade_opts[] = {
35 BCH_VERSION_UPGRADE_OPTS()
36 NULL
37};
38
1c3ff72c 39const char * const bch2_sb_features[] = {
1c3ff72c 40 BCH_SB_FEATURES()
1c3ff72c
KO
41 NULL
42};
43
19dd3172 44const char * const bch2_sb_compat[] = {
19dd3172 45 BCH_SB_COMPAT()
19dd3172
KO
46 NULL
47};
48
88dfe193 49const char * const __bch2_btree_ids[] = {
41f8b09e 50 BCH_BTREE_IDS()
41f8b09e
KO
51 NULL
52};
53
a76db26a 54const char * const __bch2_csum_types[] = {
6404dcc9
KO
55 BCH_CSUM_TYPES()
56 NULL
57};
58
ed13bb57 59const char * const __bch2_csum_opts[] = {
2436cb9f 60 BCH_CSUM_OPTS()
1c6fdbd8
KO
61 NULL
62};
63
3d0b3b51 64const char * const __bch2_compression_types[] = {
6404dcc9
KO
65 BCH_COMPRESSION_TYPES()
66 NULL
67};
68
1c3ff72c 69const char * const bch2_compression_opts[] = {
1c3ff72c 70 BCH_COMPRESSION_OPTS()
1c6fdbd8
KO
71 NULL
72};
73
d8e87937 74const char * const __bch2_str_hash_types[] = {
6404dcc9
KO
75 BCH_STR_HASH_TYPES()
76 NULL
77};
78
79const char * const bch2_str_hash_opts[] = {
2436cb9f 80 BCH_STR_HASH_OPTS()
1c6fdbd8
KO
81 NULL
82};
83
e58f963c 84const char * const __bch2_data_types[] = {
89fd25be 85 BCH_DATA_TYPES()
1c6fdbd8
KO
86 NULL
87};
88
2436cb9f
KO
89const char * const bch2_member_states[] = {
90 BCH_MEMBER_STATES()
1c6fdbd8
KO
91 NULL
92};
93
9abb6dd7 94static const char * const __bch2_jset_entry_types[] = {
528b18e6
KO
95 BCH_JSET_ENTRY_TYPES()
96 NULL
97};
98
9abb6dd7 99static const char * const __bch2_fs_usage_types[] = {
528b18e6
KO
100 BCH_FS_USAGE_TYPES()
101 NULL
102};
103
2436cb9f 104#undef x
1c6fdbd8 105
9abb6dd7
KO
106static void prt_str_opt_boundscheck(struct printbuf *out, const char * const opts[],
107 unsigned nr, const char *type, unsigned idx)
108{
109 if (idx < nr)
110 prt_str(out, opts[idx]);
111 else
112 prt_printf(out, "(unknown %s %u)", type, idx);
113}
114
115#define PRT_STR_OPT_BOUNDSCHECKED(name, type) \
116void bch2_prt_##name(struct printbuf *out, type t) \
117{ \
118 prt_str_opt_boundscheck(out, __bch2_##name##s, ARRAY_SIZE(__bch2_##name##s) - 1, #name, t);\
119}
120
121PRT_STR_OPT_BOUNDSCHECKED(jset_entry_type, enum bch_jset_entry_type);
122PRT_STR_OPT_BOUNDSCHECKED(fs_usage_type, enum bch_fs_usage_type);
123PRT_STR_OPT_BOUNDSCHECKED(data_type, enum bch_data_type);
ed13bb57 124PRT_STR_OPT_BOUNDSCHECKED(csum_opt, enum bch_csum_opt);
9abb6dd7
KO
125PRT_STR_OPT_BOUNDSCHECKED(csum_type, enum bch_csum_type);
126PRT_STR_OPT_BOUNDSCHECKED(compression_type, enum bch_compression_type);
d8e87937 127PRT_STR_OPT_BOUNDSCHECKED(str_hash_type, enum bch_str_hash_type);
9abb6dd7 128
a0f8faea
KO
129static int bch2_opt_fix_errors_parse(struct bch_fs *c, const char *val, u64 *res,
130 struct printbuf *err)
131{
132 if (!val) {
133 *res = FSCK_FIX_yes;
134 } else {
135 int ret = match_string(bch2_fsck_fix_opts, -1, val);
136
137 if (ret < 0 && err)
138 prt_str(err, "fix_errors: invalid selection");
139 if (ret < 0)
140 return ret;
141 *res = ret;
142 }
143
144 return 0;
145}
146
147static void bch2_opt_fix_errors_to_text(struct printbuf *out,
148 struct bch_fs *c,
149 struct bch_sb *sb,
150 u64 v)
151{
152 prt_str(out, bch2_fsck_fix_opts[v]);
153}
154
bf5a261c
KO
155#define bch2_opt_fix_errors (struct bch_opt_fn) { \
156 .parse = bch2_opt_fix_errors_parse, \
157 .to_text = bch2_opt_fix_errors_to_text, \
158}
a0f8faea 159
14b393ee 160const char * const bch2_d_types[BCH_DT_MAX] = {
d5bee8ca
KO
161 [DT_UNKNOWN] = "unknown",
162 [DT_FIFO] = "fifo",
163 [DT_CHR] = "chr",
164 [DT_DIR] = "dir",
165 [DT_BLK] = "blk",
166 [DT_REG] = "reg",
167 [DT_LNK] = "lnk",
168 [DT_SOCK] = "sock",
169 [DT_WHT] = "whiteout",
14b393ee 170 [DT_SUBVOL] = "subvol",
d5bee8ca
KO
171};
172
1c6fdbd8
KO
173void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
174{
0b847a19 175#define x(_name, ...) \
1c6fdbd8
KO
176 if (opt_defined(src, _name)) \
177 opt_set(*dst, _name, src._name);
178
179 BCH_OPTS()
0b847a19 180#undef x
1c6fdbd8
KO
181}
182
183bool bch2_opt_defined_by_id(const struct bch_opts *opts, enum bch_opt_id id)
184{
185 switch (id) {
0b847a19 186#define x(_name, ...) \
1c6fdbd8
KO
187 case Opt_##_name: \
188 return opt_defined(*opts, _name);
189 BCH_OPTS()
0b847a19 190#undef x
1c6fdbd8
KO
191 default:
192 BUG();
193 }
194}
195
196u64 bch2_opt_get_by_id(const struct bch_opts *opts, enum bch_opt_id id)
197{
198 switch (id) {
0b847a19 199#define x(_name, ...) \
1c6fdbd8
KO
200 case Opt_##_name: \
201 return opts->_name;
202 BCH_OPTS()
0b847a19 203#undef x
1c6fdbd8
KO
204 default:
205 BUG();
206 }
207}
208
209void bch2_opt_set_by_id(struct bch_opts *opts, enum bch_opt_id id, u64 v)
210{
211 switch (id) {
0b847a19 212#define x(_name, ...) \
1c6fdbd8
KO
213 case Opt_##_name: \
214 opt_set(*opts, _name, v); \
215 break;
216 BCH_OPTS()
0b847a19 217#undef x
1c6fdbd8
KO
218 default:
219 BUG();
220 }
221}
222
d2bad592
KO
223/* dummy option, for options that aren't stored in the superblock */
224typedef u64 (*sb_opt_get_fn)(const struct bch_sb *);
225typedef void (*sb_opt_set_fn)(struct bch_sb *, u64);
226typedef u64 (*member_opt_get_fn)(const struct bch_member *);
227typedef void (*member_opt_set_fn)(struct bch_member *, u64);
228
229__maybe_unused static const sb_opt_get_fn BCH2_NO_SB_OPT = NULL;
230__maybe_unused static const sb_opt_set_fn SET_BCH2_NO_SB_OPT = NULL;
231__maybe_unused static const member_opt_get_fn BCH2_NO_MEMBER_OPT = NULL;
232__maybe_unused static const member_opt_set_fn SET_BCH2_NO_MEMBER_OPT = NULL;
233
234#define type_compatible_or_null(_p, _type) \
235 __builtin_choose_expr( \
236 __builtin_types_compatible_p(typeof(_p), typeof(_type)), _p, NULL)
237
1c6fdbd8 238const struct bch_option bch2_opt_table[] = {
8244f320
KO
239#define OPT_BOOL() .type = BCH_OPT_BOOL, .min = 0, .max = 2
240#define OPT_UINT(_min, _max) .type = BCH_OPT_UINT, \
241 .min = _min, .max = _max
242#define OPT_STR(_choices) .type = BCH_OPT_STR, \
f9f0a539 243 .min = 0, .max = ARRAY_SIZE(_choices) - 1, \
8244f320 244 .choices = _choices
13c1e583
KO
245#define OPT_STR_NOLIMIT(_choices) .type = BCH_OPT_STR, \
246 .min = 0, .max = U64_MAX, \
247 .choices = _choices
afefc986
KO
248#define OPT_BITFIELD(_choices) .type = BCH_OPT_BITFIELD, \
249 .choices = _choices
9f343e24 250#define OPT_FN(_fn) .type = BCH_OPT_FN, .fn = _fn
1c6fdbd8 251
8244f320 252#define x(_name, _bits, _flags, _type, _sb_opt, _default, _hint, _help) \
1c6fdbd8 253 [Opt_##_name] = { \
d2bad592
KO
254 .attr.name = #_name, \
255 .attr.mode = (_flags) & OPT_RUNTIME ? 0644 : 0444, \
256 .flags = _flags, \
257 .hint = _hint, \
258 .help = _help, \
259 .get_sb = type_compatible_or_null(_sb_opt, *BCH2_NO_SB_OPT), \
260 .set_sb = type_compatible_or_null(SET_##_sb_opt,*SET_BCH2_NO_SB_OPT), \
261 .get_member = type_compatible_or_null(_sb_opt, *BCH2_NO_MEMBER_OPT), \
262 .set_member = type_compatible_or_null(SET_##_sb_opt,*SET_BCH2_NO_MEMBER_OPT),\
1c6fdbd8
KO
263 _type \
264 },
265
266 BCH_OPTS()
0b847a19 267#undef x
1c6fdbd8
KO
268};
269
270int bch2_opt_lookup(const char *name)
271{
272 const struct bch_option *i;
273
274 for (i = bch2_opt_table;
275 i < bch2_opt_table + ARRAY_SIZE(bch2_opt_table);
276 i++)
277 if (!strcmp(name, i->attr.name))
278 return i - bch2_opt_table;
279
280 return -1;
281}
282
ef8dd631 283struct opt_synonym {
1c6fdbd8
KO
284 const char *s1, *s2;
285};
286
ef8dd631 287static const struct opt_synonym bch2_opt_synonyms[] = {
1c6fdbd8
KO
288 { "quota", "usrquota" },
289};
290
291static int bch2_mount_opt_lookup(const char *name)
292{
ef8dd631 293 const struct opt_synonym *i;
1c6fdbd8 294
ef8dd631
KO
295 for (i = bch2_opt_synonyms;
296 i < bch2_opt_synonyms + ARRAY_SIZE(bch2_opt_synonyms);
1c6fdbd8
KO
297 i++)
298 if (!strcmp(name, i->s1))
299 name = i->s2;
300
301 return bch2_opt_lookup(name);
302}
303
ef8dd631
KO
304struct opt_val_synonym {
305 const char *opt, *v1, *v2;
306};
307
308static const struct opt_val_synonym bch2_opt_val_synonyms[] = {
309 { "degraded", "true", "yes" },
310 { "degraded", "false", "no" },
311 { "degraded", "1", "yes" },
312 { "degraded", "0", "no" },
313};
314
315static const char *bch2_opt_val_synonym_lookup(const char *opt, const char *val)
316{
317 const struct opt_val_synonym *i;
318
319 for (i = bch2_opt_val_synonyms;
320 i < bch2_opt_val_synonyms + ARRAY_SIZE(bch2_opt_val_synonyms);
321 i++)
322 if (!strcmp(opt, i->opt) && !strcmp(val, i->v1))
323 return i->v2;
324
325 return val;
326}
327
63c4b254 328int bch2_opt_validate(const struct bch_option *opt, u64 v, struct printbuf *err)
8244f320
KO
329{
330 if (v < opt->min) {
63c4b254 331 if (err)
401ec4db 332 prt_printf(err, "%s: too small (min %llu)",
63c4b254 333 opt->attr.name, opt->min);
a973de85 334 return -BCH_ERR_ERANGE_option_too_small;
8244f320
KO
335 }
336
337 if (opt->max && v >= opt->max) {
63c4b254 338 if (err)
401ec4db 339 prt_printf(err, "%s: too big (max %llu)",
63c4b254 340 opt->attr.name, opt->max);
a973de85 341 return -BCH_ERR_ERANGE_option_too_big;
8244f320
KO
342 }
343
344 if ((opt->flags & OPT_SB_FIELD_SECTORS) && (v & 511)) {
63c4b254 345 if (err)
401ec4db 346 prt_printf(err, "%s: not a multiple of 512",
63c4b254 347 opt->attr.name);
56ec287d 348 return -BCH_ERR_opt_parse_error;
8244f320
KO
349 }
350
351 if ((opt->flags & OPT_MUST_BE_POW_2) && !is_power_of_2(v)) {
63c4b254 352 if (err)
401ec4db 353 prt_printf(err, "%s: must be a power of two",
63c4b254 354 opt->attr.name);
56ec287d 355 return -BCH_ERR_opt_parse_error;
8244f320
KO
356 }
357
6ddedca2
KO
358 if (opt->fn.validate)
359 return opt->fn.validate(v, err);
360
8244f320
KO
361 return 0;
362}
363
63c4b254 364int bch2_opt_parse(struct bch_fs *c,
8244f320 365 const struct bch_option *opt,
63c4b254
KO
366 const char *val, u64 *res,
367 struct printbuf *err)
1c6fdbd8
KO
368{
369 ssize_t ret;
370
dd1b99f7
I
371 if (err)
372 printbuf_indent_add_nextline(err, 2);
373
1c6fdbd8
KO
374 switch (opt->type) {
375 case BCH_OPT_BOOL:
ef8dd631
KO
376 if (!val)
377 val = "1";
378
379 ret = lookup_constant(bool_names, val, -BCH_ERR_option_not_bool);
380 if (ret != -BCH_ERR_option_not_bool) {
381 *res = ret;
a0f8faea 382 } else {
ef8dd631
KO
383 if (err)
384 prt_printf(err, "%s: must be bool", opt->attr.name);
385 return ret;
a0f8faea 386 }
1c6fdbd8
KO
387 break;
388 case BCH_OPT_UINT:
a0f8faea
KO
389 if (!val) {
390 prt_printf(err, "%s: required value",
391 opt->attr.name);
392 return -EINVAL;
393 }
394
0e790469
I
395 if (*val != '-') {
396 ret = opt->flags & OPT_HUMAN_READABLE
397 ? bch2_strtou64_h(val, res)
398 : kstrtou64(val, 10, res);
399 } else {
400 prt_printf(err, "%s: must be a non-negative number", opt->attr.name);
401 return -BCH_ERR_option_negative;
402 }
403
4a7a7ea1
KO
404 if (ret < 0) {
405 if (err)
401ec4db
KO
406 prt_printf(err, "%s: must be a number",
407 opt->attr.name);
1c6fdbd8 408 return ret;
4a7a7ea1 409 }
1c6fdbd8
KO
410 break;
411 case BCH_OPT_STR:
a0f8faea
KO
412 if (!val) {
413 prt_printf(err, "%s: required value",
414 opt->attr.name);
415 return -EINVAL;
416 }
417
1c6fdbd8 418 ret = match_string(opt->choices, -1, val);
4a7a7ea1
KO
419 if (ret < 0) {
420 if (err)
401ec4db
KO
421 prt_printf(err, "%s: invalid selection",
422 opt->attr.name);
1c6fdbd8 423 return ret;
4a7a7ea1 424 }
1c6fdbd8
KO
425
426 *res = ret;
427 break;
afefc986
KO
428 case BCH_OPT_BITFIELD: {
429 s64 v = bch2_read_flag_list(val, opt->choices);
430 if (v < 0)
431 return v;
432 *res = v;
433 break;
434 }
1c6fdbd8 435 case BCH_OPT_FN:
9f343e24 436 ret = opt->fn.parse(c, val, res, err);
1c12d1ca
TB
437
438 if (ret == -BCH_ERR_option_needs_open_fs)
439 return ret;
440
4a7a7ea1
KO
441 if (ret < 0) {
442 if (err)
401ec4db
KO
443 prt_printf(err, "%s: parse error",
444 opt->attr.name);
8244f320 445 return ret;
4a7a7ea1 446 }
1c6fdbd8
KO
447 }
448
63c4b254 449 return bch2_opt_validate(opt, *res, err);
1c6fdbd8
KO
450}
451
5521b1df
KO
452void bch2_opt_to_text(struct printbuf *out,
453 struct bch_fs *c, struct bch_sb *sb,
319f9ac3
KO
454 const struct bch_option *opt, u64 v,
455 unsigned flags)
1c6fdbd8 456{
1c6fdbd8 457 if (flags & OPT_SHOW_MOUNT_STYLE) {
319f9ac3 458 if (opt->type == BCH_OPT_BOOL) {
401ec4db 459 prt_printf(out, "%s%s",
319f9ac3
KO
460 v ? "" : "no",
461 opt->attr.name);
462 return;
463 }
464
401ec4db 465 prt_printf(out, "%s=", opt->attr.name);
1c6fdbd8
KO
466 }
467
468 switch (opt->type) {
469 case BCH_OPT_BOOL:
470 case BCH_OPT_UINT:
8244f320 471 if (opt->flags & OPT_HUMAN_READABLE)
401ec4db 472 prt_human_readable_u64(out, v);
8244f320 473 else
401ec4db 474 prt_printf(out, "%lli", v);
0b847a19 475 break;
1c6fdbd8 476 case BCH_OPT_STR:
f9f0a539 477 if (v < opt->min || v >= opt->max)
a30f3222
MA
478 prt_printf(out, "(invalid option %lli)", v);
479 else if (flags & OPT_SHOW_FULL_LIST)
401ec4db 480 prt_string_option(out, opt->choices, v);
319f9ac3 481 else
a0f8faea 482 prt_str(out, opt->choices[v]);
1c6fdbd8 483 break;
4f19a60c
KO
484 case BCH_OPT_BITFIELD:
485 prt_bitflags(out, opt->choices, v);
486 break;
1c6fdbd8 487 case BCH_OPT_FN:
9f343e24 488 opt->fn.to_text(out, c, sb, v);
319f9ac3 489 break;
1c6fdbd8
KO
490 default:
491 BUG();
492 }
1c6fdbd8
KO
493}
494
3621ecc1
KO
495void bch2_opts_to_text(struct printbuf *out,
496 struct bch_opts opts,
497 struct bch_fs *c, struct bch_sb *sb,
498 unsigned show_mask, unsigned hide_mask,
499 unsigned flags)
500{
501 bool first = true;
502
503 for (enum bch_opt_id i = 0; i < bch2_opts_nr; i++) {
504 const struct bch_option *opt = &bch2_opt_table[i];
505
506 if ((opt->flags & hide_mask) || !(opt->flags & show_mask))
507 continue;
508
509 u64 v = bch2_opt_get_by_id(&opts, i);
510 if (v == bch2_opt_get_by_id(&bch2_opts_default, i))
511 continue;
512
513 if (!first)
514 prt_char(out, ',');
515 first = false;
516
517 bch2_opt_to_text(out, c, sb, opt, v, flags);
518 }
519}
520
c79eb06d 521int bch2_opt_hook_pre_set(struct bch_fs *c, struct bch_dev *ca, enum bch_opt_id id, u64 v)
c258f28e
KO
522{
523 int ret = 0;
524
525 switch (id) {
8d7b7ac3
KO
526 case Opt_state:
527 if (ca)
2dd202db 528 return bch2_dev_set_state(c, ca, v, BCH_FORCE_IF_DEGRADED);
8d7b7ac3
KO
529 break;
530
c258f28e
KO
531 case Opt_compression:
532 case Opt_background_compression:
533 ret = bch2_check_set_has_compressed_data(c, v);
534 break;
cd575ddf 535 case Opt_erasure_code:
ba239c95 536 if (v)
1c3ff72c 537 bch2_check_set_feature(c, BCH_FEATURE_ec);
cd575ddf 538 break;
c79eb06d
KO
539 default:
540 break;
c258f28e
KO
541 }
542
543 return ret;
544}
545
c79eb06d 546int bch2_opts_hooks_pre_set(struct bch_fs *c)
cd575ddf 547{
d2bad592 548 for (unsigned i = 0; i < bch2_opts_nr; i++) {
c79eb06d 549 int ret = bch2_opt_hook_pre_set(c, NULL, i, bch2_opt_get_by_id(&c->opts, i));
cd575ddf
KO
550 if (ret)
551 return ret;
552 }
553
554 return 0;
555}
556
c79eb06d
KO
557void bch2_opt_hook_post_set(struct bch_fs *c, struct bch_dev *ca, u64 inum,
558 struct bch_opts *new_opts, enum bch_opt_id id)
559{
560 switch (id) {
561 case Opt_foreground_target:
562 if (new_opts->foreground_target &&
563 !new_opts->background_target)
564 bch2_set_rebalance_needs_scan(c, inum);
565 break;
566 case Opt_compression:
567 if (new_opts->compression &&
568 !new_opts->background_compression)
569 bch2_set_rebalance_needs_scan(c, inum);
570 break;
571 case Opt_background_target:
572 if (new_opts->background_target)
573 bch2_set_rebalance_needs_scan(c, inum);
574 break;
575 case Opt_background_compression:
576 if (new_opts->background_compression)
577 bch2_set_rebalance_needs_scan(c, inum);
578 break;
579 case Opt_rebalance_enabled:
580 bch2_rebalance_wakeup(c);
581 break;
582 case Opt_copygc_enabled:
583 bch2_copygc_wakeup(c);
584 break;
585 case Opt_discard:
586 if (!ca) {
587 mutex_lock(&c->sb_lock);
588 for_each_member_device(c, ca) {
589 struct bch_member *m =
590 bch2_members_v2_get_mut(ca->disk_sb.sb, ca->dev_idx);
591 SET_BCH_MEMBER_DISCARD(m, c->opts.discard);
592 }
593
594 bch2_write_super(c);
595 mutex_unlock(&c->sb_lock);
596 }
597 break;
5022d0e1
KO
598 case Opt_version_upgrade:
599 /*
600 * XXX: in the future we'll likely want to do compatible
601 * upgrades at runtime as well, but right now there's nothing
602 * that does that:
603 */
604 if (new_opts->version_upgrade == BCH_VERSION_UPGRADE_incompatible)
605 bch2_sb_upgrade_incompat(c);
606 break;
c79eb06d
KO
607 default:
608 break;
609 }
610}
611
9b7f0b5d
TB
612int bch2_parse_one_mount_opt(struct bch_fs *c, struct bch_opts *opts,
613 struct printbuf *parse_later,
614 const char *name, const char *val)
615{
616 struct printbuf err = PRINTBUF;
617 u64 v;
618 int ret, id;
619
620 id = bch2_mount_opt_lookup(name);
621
622 /* Check for the form "noopt", negation of a boolean opt: */
623 if (id < 0 &&
624 !val &&
625 !strncmp("no", name, 2)) {
626 id = bch2_mount_opt_lookup(name + 2);
627 val = "0";
628 }
629
630 /* Unknown options are ignored: */
631 if (id < 0)
632 return 0;
633
ef8dd631
KO
634 /* must have a value for synonym lookup - but OPT_FN is weird */
635 if (!val && bch2_opt_table[id].type != BCH_OPT_FN)
636 val = "1";
637
638 val = bch2_opt_val_synonym_lookup(name, val);
639
9b7f0b5d
TB
640 if (!(bch2_opt_table[id].flags & OPT_MOUNT))
641 goto bad_opt;
642
643 if (id == Opt_acl &&
644 !IS_ENABLED(CONFIG_BCACHEFS_POSIX_ACL))
645 goto bad_opt;
646
647 if ((id == Opt_usrquota ||
648 id == Opt_grpquota) &&
649 !IS_ENABLED(CONFIG_BCACHEFS_QUOTA))
650 goto bad_opt;
651
652 ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err);
a7cdf227
KO
653 if (ret == -BCH_ERR_option_needs_open_fs) {
654 ret = 0;
655
656 if (parse_later) {
657 prt_printf(parse_later, "%s=%s,", name, val);
658 if (parse_later->allocation_failure)
659 ret = -ENOMEM;
1c12d1ca
TB
660 }
661
1c12d1ca
TB
662 goto out;
663 }
664
9b7f0b5d
TB
665 if (ret < 0)
666 goto bad_val;
667
668 if (opts)
669 bch2_opt_set_by_id(opts, id, v);
670
671 ret = 0;
a7cdf227
KO
672out:
673 printbuf_exit(&err);
674 return ret;
9b7f0b5d 675bad_opt:
9b7f0b5d
TB
676 ret = -BCH_ERR_option_name;
677 goto out;
9b7f0b5d 678bad_val:
9b7f0b5d 679 ret = -BCH_ERR_option_value;
a7cdf227 680 goto out;
9b7f0b5d
TB
681}
682
a10e677a 683int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
a7cdf227
KO
684 struct printbuf *parse_later, char *options,
685 bool ignore_unknown)
1c6fdbd8 686{
baf056b8 687 char *copied_opts, *copied_opts_start;
1c6fdbd8 688 char *opt, *name, *val;
a7cdf227 689 int ret = 0;
1c6fdbd8 690
baf056b8
DR
691 if (!options)
692 return 0;
693
cf416e7a
KO
694 /*
695 * sys_fsconfig() is now occasionally providing us with option lists
696 * starting with a comma - weird.
697 */
698 if (*options == ',')
699 options++;
700
baf056b8
DR
701 copied_opts = kstrdup(options, GFP_KERNEL);
702 if (!copied_opts)
79162e82 703 return -ENOMEM;
baf056b8
DR
704 copied_opts_start = copied_opts;
705
706 while ((opt = strsep(&copied_opts, ",")) != NULL) {
489ecc4c
HL
707 if (!*opt)
708 continue;
709
1c6fdbd8
KO
710 name = strsep(&opt, "=");
711 val = opt;
712
9b7f0b5d 713 ret = bch2_parse_one_mount_opt(c, opts, parse_later, name, val);
a7cdf227
KO
714 if (ret == -BCH_ERR_option_name && ignore_unknown)
715 ret = 0;
716 if (ret) {
717 pr_err("Error parsing option %s: %s", name, bch2_err_str(ret));
718 break;
719 }
1c6fdbd8
KO
720 }
721
baf056b8
DR
722 kfree(copied_opts_start);
723 return ret;
1c6fdbd8
KO
724}
725
d2bad592 726u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id, int dev_idx)
5521b1df
KO
727{
728 const struct bch_option *opt = bch2_opt_table + id;
729 u64 v;
730
d2bad592
KO
731 if (dev_idx < 0) {
732 v = opt->get_sb(sb);
733 } else {
734 if (WARN(!bch2_member_exists(sb, dev_idx),
735 "tried to set device option %s on nonexistent device %i",
736 opt->attr.name, dev_idx))
737 return 0;
738
739 struct bch_member m = bch2_sb_member_get(sb, dev_idx);
740 v = opt->get_member(&m);
741 }
742
743 if (opt->flags & OPT_SB_FIELD_ONE_BIAS)
744 --v;
5521b1df
KO
745
746 if (opt->flags & OPT_SB_FIELD_ILOG2)
747 v = 1ULL << v;
748
749 if (opt->flags & OPT_SB_FIELD_SECTORS)
750 v <<= 9;
751
752 return v;
753}
754
8244f320
KO
755/*
756 * Initial options from superblock - here we don't want any options undefined,
757 * any options the superblock doesn't specify are set to 0:
758 */
759int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)
760{
d2bad592 761 for (unsigned id = 0; id < bch2_opts_nr; id++) {
8244f320 762 const struct bch_option *opt = bch2_opt_table + id;
8244f320 763
d2bad592
KO
764 if (opt->get_sb)
765 bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id, -1));
8244f320
KO
766 }
767
768 return 0;
769}
770
c79eb06d 771bool __bch2_opt_set_sb(struct bch_sb *sb, int dev_idx,
4aedeac5 772 const struct bch_option *opt, u64 v)
8244f320 773{
c79eb06d
KO
774 bool changed = false;
775
8244f320
KO
776 if (opt->flags & OPT_SB_FIELD_SECTORS)
777 v >>= 9;
778
779 if (opt->flags & OPT_SB_FIELD_ILOG2)
780 v = ilog2(v);
781
9092a38a
KO
782 if (opt->flags & OPT_SB_FIELD_ONE_BIAS)
783 v++;
784
c79eb06d
KO
785 if ((opt->flags & OPT_FS) && opt->set_sb && dev_idx < 0) {
786 changed = v != opt->get_sb(sb);
787
d2bad592 788 opt->set_sb(sb, v);
c79eb06d 789 }
4aedeac5 790
af2ff37d 791 if ((opt->flags & OPT_DEVICE) && opt->set_member && dev_idx >= 0) {
4aedeac5
KO
792 if (WARN(!bch2_member_exists(sb, dev_idx),
793 "tried to set device option %s on nonexistent device %i",
794 opt->attr.name, dev_idx))
c79eb06d 795 return false;
4aedeac5 796
c79eb06d
KO
797 struct bch_member *m = bch2_members_v2_get_mut(sb, dev_idx);
798 changed = v != opt->get_member(m);
799 opt->set_member(m, v);
4aedeac5 800 }
c79eb06d
KO
801
802 return changed;
8244f320
KO
803}
804
c79eb06d 805bool bch2_opt_set_sb(struct bch_fs *c, struct bch_dev *ca,
4aedeac5 806 const struct bch_option *opt, u64 v)
8244f320 807{
8244f320 808 mutex_lock(&c->sb_lock);
c79eb06d
KO
809 bool changed = __bch2_opt_set_sb(c->disk_sb.sb, ca ? ca->dev_idx : -1, opt, v);
810 if (changed)
811 bch2_write_super(c);
8244f320 812 mutex_unlock(&c->sb_lock);
c79eb06d 813 return changed;
8244f320
KO
814}
815
1c6fdbd8
KO
816/* io opts: */
817
818struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src)
819{
eacb7555 820 struct bch_io_opts opts = {
01ad6737 821#define x(_name, _bits) ._name = src._name,
1c6fdbd8 822 BCH_INODE_OPTS()
a3e70fb2 823#undef x
01ad6737 824 };
eacb7555
KO
825
826 bch2_io_opts_fixups(&opts);
827 return opts;
1c6fdbd8
KO
828}
829
830bool bch2_opt_is_inode_opt(enum bch_opt_id id)
831{
832 static const enum bch_opt_id inode_opt_list[] = {
a3e70fb2 833#define x(_name, _bits) Opt_##_name,
1c6fdbd8 834 BCH_INODE_OPTS()
a3e70fb2 835#undef x
1c6fdbd8
KO
836 };
837 unsigned i;
838
839 for (i = 0; i < ARRAY_SIZE(inode_opt_list); i++)
840 if (inode_opt_list[i] == id)
841 return true;
842
843 return false;
844}