1// SPDX-License-Identifier: GPL-2.0
2
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 NULL
19};
20
21const char * const bch2_fsck_fix_opts[] = {
22 BCH_FIX_ERRORS_OPTS()
23 NULL
24};
25
26const char * const bch2_version_upgrade_opts[] = {
27 BCH_VERSION_UPGRADE_OPTS()
28 NULL
29};
30
31const char * const bch2_sb_features[] = {
32 BCH_SB_FEATURES()
33 NULL
34};
35
36const char * const bch2_sb_compat[] = {
37 BCH_SB_COMPAT()
38 NULL
39};
40
41const char * const __bch2_btree_ids[] = {
42 BCH_BTREE_IDS()
43 NULL
44};
45
46static const char * const __bch2_csum_types[] = {
47 BCH_CSUM_TYPES()
48 NULL
49};
50
51const char * const bch2_csum_opts[] = {
52 BCH_CSUM_OPTS()
53 NULL
54};
55
56static const char * const __bch2_compression_types[] = {
57 BCH_COMPRESSION_TYPES()
58 NULL
59};
60
61const char * const bch2_compression_opts[] = {
62 BCH_COMPRESSION_OPTS()
63 NULL
64};
65
66const char * const bch2_str_hash_types[] = {
67 BCH_STR_HASH_TYPES()
68 NULL
69};
70
71const char * const bch2_str_hash_opts[] = {
72 BCH_STR_HASH_OPTS()
73 NULL
74};
75
76const char * const __bch2_data_types[] = {
77 BCH_DATA_TYPES()
78 NULL
79};
80
81const char * const bch2_member_states[] = {
82 BCH_MEMBER_STATES()
83 NULL
84};
85
86static const char * const __bch2_jset_entry_types[] = {
87 BCH_JSET_ENTRY_TYPES()
88 NULL
89};
90
91static const char * const __bch2_fs_usage_types[] = {
92 BCH_FS_USAGE_TYPES()
93 NULL
94};
95
96#undef x
97
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, str: opts[idx]);
103 else
104 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);
118
119static int bch2_opt_fix_errors_parse(struct bch_fs *c, const char *val, u64 *res,
120 struct printbuf *err)
121{
122 if (!val) {
123 *res = FSCK_FIX_yes;
124 } else {
125 int ret = match_string(array: bch2_fsck_fix_opts, n: -1, string: val);
126
127 if (ret < 0 && err)
128 prt_str(out: err, str: "fix_errors: invalid selection");
129 if (ret < 0)
130 return ret;
131 *res = ret;
132 }
133
134 return 0;
135}
136
137static void bch2_opt_fix_errors_to_text(struct printbuf *out,
138 struct bch_fs *c,
139 struct bch_sb *sb,
140 u64 v)
141{
142 prt_str(out, str: bch2_fsck_fix_opts[v]);
143}
144
145#define bch2_opt_fix_errors (struct bch_opt_fn) { \
146 .parse = bch2_opt_fix_errors_parse, \
147 .to_text = bch2_opt_fix_errors_to_text, \
148}
149
150const char * const bch2_d_types[BCH_DT_MAX] = {
151 [DT_UNKNOWN] = "unknown",
152 [DT_FIFO] = "fifo",
153 [DT_CHR] = "chr",
154 [DT_DIR] = "dir",
155 [DT_BLK] = "blk",
156 [DT_REG] = "reg",
157 [DT_LNK] = "lnk",
158 [DT_SOCK] = "sock",
159 [DT_WHT] = "whiteout",
160 [DT_SUBVOL] = "subvol",
161};
162
163u64 BCH2_NO_SB_OPT(const struct bch_sb *sb)
164{
165 BUG();
166}
167
168void SET_BCH2_NO_SB_OPT(struct bch_sb *sb, u64 v)
169{
170 BUG();
171}
172
173void bch2_opts_apply(struct bch_opts *dst, struct bch_opts src)
174{
175#define x(_name, ...) \
176 if (opt_defined(src, _name)) \
177 opt_set(*dst, _name, src._name);
178
179 BCH_OPTS()
180#undef x
181}
182
183bool bch2_opt_defined_by_id(const struct bch_opts *opts, enum bch_opt_id id)
184{
185 switch (id) {
186#define x(_name, ...) \
187 case Opt_##_name: \
188 return opt_defined(*opts, _name);
189 BCH_OPTS()
190#undef x
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) {
199#define x(_name, ...) \
200 case Opt_##_name: \
201 return opts->_name;
202 BCH_OPTS()
203#undef x
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) {
212#define x(_name, ...) \
213 case Opt_##_name: \
214 opt_set(*opts, _name, v); \
215 break;
216 BCH_OPTS()
217#undef x
218 default:
219 BUG();
220 }
221}
222
223const struct bch_option bch2_opt_table[] = {
224#define OPT_BOOL() .type = BCH_OPT_BOOL, .min = 0, .max = 2
225#define OPT_UINT(_min, _max) .type = BCH_OPT_UINT, \
226 .min = _min, .max = _max
227#define OPT_STR(_choices) .type = BCH_OPT_STR, \
228 .min = 0, .max = ARRAY_SIZE(_choices), \
229 .choices = _choices
230#define OPT_STR_NOLIMIT(_choices) .type = BCH_OPT_STR, \
231 .min = 0, .max = U64_MAX, \
232 .choices = _choices
233#define OPT_FN(_fn) .type = BCH_OPT_FN, .fn = _fn
234
235#define x(_name, _bits, _flags, _type, _sb_opt, _default, _hint, _help) \
236 [Opt_##_name] = { \
237 .attr = { \
238 .name = #_name, \
239 .mode = (_flags) & OPT_RUNTIME ? 0644 : 0444, \
240 }, \
241 .flags = _flags, \
242 .hint = _hint, \
243 .help = _help, \
244 .get_sb = _sb_opt, \
245 .set_sb = SET_##_sb_opt, \
246 _type \
247 },
248
249 BCH_OPTS()
250#undef x
251};
252
253int bch2_opt_lookup(const char *name)
254{
255 const struct bch_option *i;
256
257 for (i = bch2_opt_table;
258 i < bch2_opt_table + ARRAY_SIZE(bch2_opt_table);
259 i++)
260 if (!strcmp(name, i->attr.name))
261 return i - bch2_opt_table;
262
263 return -1;
264}
265
266struct synonym {
267 const char *s1, *s2;
268};
269
270static const struct synonym bch_opt_synonyms[] = {
271 { "quota", "usrquota" },
272};
273
274static int bch2_mount_opt_lookup(const char *name)
275{
276 const struct synonym *i;
277
278 for (i = bch_opt_synonyms;
279 i < bch_opt_synonyms + ARRAY_SIZE(bch_opt_synonyms);
280 i++)
281 if (!strcmp(name, i->s1))
282 name = i->s2;
283
284 return bch2_opt_lookup(name);
285}
286
287int bch2_opt_validate(const struct bch_option *opt, u64 v, struct printbuf *err)
288{
289 if (v < opt->min) {
290 if (err)
291 prt_printf(err, "%s: too small (min %llu)",
292 opt->attr.name, opt->min);
293 return -BCH_ERR_ERANGE_option_too_small;
294 }
295
296 if (opt->max && v >= opt->max) {
297 if (err)
298 prt_printf(err, "%s: too big (max %llu)",
299 opt->attr.name, opt->max);
300 return -BCH_ERR_ERANGE_option_too_big;
301 }
302
303 if ((opt->flags & OPT_SB_FIELD_SECTORS) && (v & 511)) {
304 if (err)
305 prt_printf(err, "%s: not a multiple of 512",
306 opt->attr.name);
307 return -BCH_ERR_opt_parse_error;
308 }
309
310 if ((opt->flags & OPT_MUST_BE_POW_2) && !is_power_of_2(n: v)) {
311 if (err)
312 prt_printf(err, "%s: must be a power of two",
313 opt->attr.name);
314 return -BCH_ERR_opt_parse_error;
315 }
316
317 if (opt->fn.validate)
318 return opt->fn.validate(v, err);
319
320 return 0;
321}
322
323int bch2_opt_parse(struct bch_fs *c,
324 const struct bch_option *opt,
325 const char *val, u64 *res,
326 struct printbuf *err)
327{
328 ssize_t ret;
329
330 switch (opt->type) {
331 case BCH_OPT_BOOL:
332 if (val) {
333 ret = kstrtou64(s: val, base: 10, res);
334 } else {
335 ret = 0;
336 *res = 1;
337 }
338
339 if (ret < 0 || (*res != 0 && *res != 1)) {
340 if (err)
341 prt_printf(err, "%s: must be bool", opt->attr.name);
342 return ret < 0 ? ret : -BCH_ERR_option_not_bool;
343 }
344 break;
345 case BCH_OPT_UINT:
346 if (!val) {
347 prt_printf(err, "%s: required value",
348 opt->attr.name);
349 return -EINVAL;
350 }
351
352 ret = opt->flags & OPT_HUMAN_READABLE
353 ? bch2_strtou64_h(val, res)
354 : kstrtou64(s: val, base: 10, res);
355 if (ret < 0) {
356 if (err)
357 prt_printf(err, "%s: must be a number",
358 opt->attr.name);
359 return ret;
360 }
361 break;
362 case BCH_OPT_STR:
363 if (!val) {
364 prt_printf(err, "%s: required value",
365 opt->attr.name);
366 return -EINVAL;
367 }
368
369 ret = match_string(array: opt->choices, n: -1, string: val);
370 if (ret < 0) {
371 if (err)
372 prt_printf(err, "%s: invalid selection",
373 opt->attr.name);
374 return ret;
375 }
376
377 *res = ret;
378 break;
379 case BCH_OPT_FN:
380 ret = opt->fn.parse(c, val, res, err);
381 if (ret < 0) {
382 if (err)
383 prt_printf(err, "%s: parse error",
384 opt->attr.name);
385 return ret;
386 }
387 }
388
389 return bch2_opt_validate(opt, v: *res, err);
390}
391
392void bch2_opt_to_text(struct printbuf *out,
393 struct bch_fs *c, struct bch_sb *sb,
394 const struct bch_option *opt, u64 v,
395 unsigned flags)
396{
397 if (flags & OPT_SHOW_MOUNT_STYLE) {
398 if (opt->type == BCH_OPT_BOOL) {
399 prt_printf(out, "%s%s",
400 v ? "" : "no",
401 opt->attr.name);
402 return;
403 }
404
405 prt_printf(out, "%s=", opt->attr.name);
406 }
407
408 switch (opt->type) {
409 case BCH_OPT_BOOL:
410 case BCH_OPT_UINT:
411 if (opt->flags & OPT_HUMAN_READABLE)
412 prt_human_readable_u64(out, v);
413 else
414 prt_printf(out, "%lli", v);
415 break;
416 case BCH_OPT_STR:
417 if (flags & OPT_SHOW_FULL_LIST)
418 prt_string_option(out, opt->choices, v);
419 else
420 prt_str(out, str: opt->choices[v]);
421 break;
422 case BCH_OPT_FN:
423 opt->fn.to_text(out, c, sb, v);
424 break;
425 default:
426 BUG();
427 }
428}
429
430int bch2_opt_check_may_set(struct bch_fs *c, int id, u64 v)
431{
432 int ret = 0;
433
434 switch (id) {
435 case Opt_compression:
436 case Opt_background_compression:
437 ret = bch2_check_set_has_compressed_data(c, v);
438 break;
439 case Opt_erasure_code:
440 if (v)
441 bch2_check_set_feature(c, feat: BCH_FEATURE_ec);
442 break;
443 }
444
445 return ret;
446}
447
448int bch2_opts_check_may_set(struct bch_fs *c)
449{
450 unsigned i;
451 int ret;
452
453 for (i = 0; i < bch2_opts_nr; i++) {
454 ret = bch2_opt_check_may_set(c, id: i,
455 v: bch2_opt_get_by_id(opts: &c->opts, id: i));
456 if (ret)
457 return ret;
458 }
459
460 return 0;
461}
462
463int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
464 char *options)
465{
466 char *copied_opts, *copied_opts_start;
467 char *opt, *name, *val;
468 int ret, id;
469 struct printbuf err = PRINTBUF;
470 u64 v;
471
472 if (!options)
473 return 0;
474
475 /*
476 * sys_fsconfig() is now occasionally providing us with option lists
477 * starting with a comma - weird.
478 */
479 if (*options == ',')
480 options++;
481
482 copied_opts = kstrdup(s: options, GFP_KERNEL);
483 if (!copied_opts)
484 return -ENOMEM;
485 copied_opts_start = copied_opts;
486
487 while ((opt = strsep(&copied_opts, ",")) != NULL) {
488 name = strsep(&opt, "=");
489 val = opt;
490
491 id = bch2_mount_opt_lookup(name);
492
493 /* Check for the form "noopt", negation of a boolean opt: */
494 if (id < 0 &&
495 !val &&
496 !strncmp("no", name, 2)) {
497 id = bch2_mount_opt_lookup(name: name + 2);
498 val = "0";
499 }
500
501 /* Unknown options are ignored: */
502 if (id < 0)
503 continue;
504
505 if (!(bch2_opt_table[id].flags & OPT_MOUNT))
506 goto bad_opt;
507
508 if (id == Opt_acl &&
509 !IS_ENABLED(CONFIG_BCACHEFS_POSIX_ACL))
510 goto bad_opt;
511
512 if ((id == Opt_usrquota ||
513 id == Opt_grpquota) &&
514 !IS_ENABLED(CONFIG_BCACHEFS_QUOTA))
515 goto bad_opt;
516
517 ret = bch2_opt_parse(c, opt: &bch2_opt_table[id], val, res: &v, err: &err);
518 if (ret < 0)
519 goto bad_val;
520
521 bch2_opt_set_by_id(opts, id, v);
522 }
523
524 ret = 0;
525 goto out;
526
527bad_opt:
528 pr_err("Bad mount option %s", name);
529 ret = -BCH_ERR_option_name;
530 goto out;
531bad_val:
532 pr_err("Invalid mount option %s", err.buf);
533 ret = -BCH_ERR_option_value;
534 goto out;
535out:
536 kfree(objp: copied_opts_start);
537 printbuf_exit(&err);
538 return ret;
539}
540
541u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id)
542{
543 const struct bch_option *opt = bch2_opt_table + id;
544 u64 v;
545
546 v = opt->get_sb(sb);
547
548 if (opt->flags & OPT_SB_FIELD_ILOG2)
549 v = 1ULL << v;
550
551 if (opt->flags & OPT_SB_FIELD_SECTORS)
552 v <<= 9;
553
554 return v;
555}
556
557/*
558 * Initial options from superblock - here we don't want any options undefined,
559 * any options the superblock doesn't specify are set to 0:
560 */
561int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)
562{
563 unsigned id;
564
565 for (id = 0; id < bch2_opts_nr; id++) {
566 const struct bch_option *opt = bch2_opt_table + id;
567
568 if (opt->get_sb == BCH2_NO_SB_OPT)
569 continue;
570
571 bch2_opt_set_by_id(opts, id, v: bch2_opt_from_sb(sb, id));
572 }
573
574 return 0;
575}
576
577void __bch2_opt_set_sb(struct bch_sb *sb, const struct bch_option *opt, u64 v)
578{
579 if (opt->set_sb == SET_BCH2_NO_SB_OPT)
580 return;
581
582 if (opt->flags & OPT_SB_FIELD_SECTORS)
583 v >>= 9;
584
585 if (opt->flags & OPT_SB_FIELD_ILOG2)
586 v = ilog2(v);
587
588 opt->set_sb(sb, v);
589}
590
591void bch2_opt_set_sb(struct bch_fs *c, const struct bch_option *opt, u64 v)
592{
593 if (opt->set_sb == SET_BCH2_NO_SB_OPT)
594 return;
595
596 mutex_lock(&c->sb_lock);
597 __bch2_opt_set_sb(sb: c->disk_sb.sb, opt, v);
598 bch2_write_super(c);
599 mutex_unlock(lock: &c->sb_lock);
600}
601
602/* io opts: */
603
604struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src)
605{
606 return (struct bch_io_opts) {
607#define x(_name, _bits) ._name = src._name,
608 BCH_INODE_OPTS()
609#undef x
610 };
611}
612
613bool bch2_opt_is_inode_opt(enum bch_opt_id id)
614{
615 static const enum bch_opt_id inode_opt_list[] = {
616#define x(_name, _bits) Opt_##_name,
617 BCH_INODE_OPTS()
618#undef x
619 };
620 unsigned i;
621
622 for (i = 0; i < ARRAY_SIZE(inode_opt_list); i++)
623 if (inode_opt_list[i] == id)
624 return true;
625
626 return false;
627}
628

source code of linux/fs/bcachefs/opts.c