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