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 static 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 lockdep_assert_held(&c->state_lock);
486
487 int ret = 0;
488
489 switch (id) {
490 case Opt_state:
491 if (ca)
492 return __bch2_dev_set_state(c, ca, v, BCH_FORCE_IF_DEGRADED);
493 break;
494
495 case Opt_compression:
496 case Opt_background_compression:
497 ret = bch2_check_set_has_compressed_data(c, v);
498 break;
499 case Opt_erasure_code:
500 if (v)
501 bch2_check_set_feature(c, BCH_FEATURE_ec);
502 break;
503 }
504
505 return ret;
506 }
507
bch2_opts_check_may_set(struct bch_fs * c)508 int bch2_opts_check_may_set(struct bch_fs *c)
509 {
510 for (unsigned i = 0; i < bch2_opts_nr; i++) {
511 int ret = bch2_opt_check_may_set(c, NULL, i, bch2_opt_get_by_id(&c->opts, i));
512 if (ret)
513 return ret;
514 }
515
516 return 0;
517 }
518
bch2_parse_one_mount_opt(struct bch_fs * c,struct bch_opts * opts,struct printbuf * parse_later,const char * name,const char * val)519 int bch2_parse_one_mount_opt(struct bch_fs *c, struct bch_opts *opts,
520 struct printbuf *parse_later,
521 const char *name, const char *val)
522 {
523 struct printbuf err = PRINTBUF;
524 u64 v;
525 int ret, id;
526
527 id = bch2_mount_opt_lookup(name);
528
529 /* Check for the form "noopt", negation of a boolean opt: */
530 if (id < 0 &&
531 !val &&
532 !strncmp("no", name, 2)) {
533 id = bch2_mount_opt_lookup(name + 2);
534 val = "0";
535 }
536
537 /* Unknown options are ignored: */
538 if (id < 0)
539 return 0;
540
541 if (!(bch2_opt_table[id].flags & OPT_MOUNT))
542 goto bad_opt;
543
544 if (id == Opt_acl &&
545 !IS_ENABLED(CONFIG_BCACHEFS_POSIX_ACL))
546 goto bad_opt;
547
548 if ((id == Opt_usrquota ||
549 id == Opt_grpquota) &&
550 !IS_ENABLED(CONFIG_BCACHEFS_QUOTA))
551 goto bad_opt;
552
553 ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err);
554 if (ret == -BCH_ERR_option_needs_open_fs && parse_later) {
555 prt_printf(parse_later, "%s=%s,", name, val);
556 if (parse_later->allocation_failure) {
557 ret = -ENOMEM;
558 goto out;
559 }
560
561 ret = 0;
562 goto out;
563 }
564
565 if (ret < 0)
566 goto bad_val;
567
568 if (opts)
569 bch2_opt_set_by_id(opts, id, v);
570
571 ret = 0;
572 goto out;
573
574 bad_opt:
575 pr_err("Bad mount option %s", name);
576 ret = -BCH_ERR_option_name;
577 goto out;
578
579 bad_val:
580 pr_err("Invalid mount option %s", err.buf);
581 ret = -BCH_ERR_option_value;
582
583 out:
584 printbuf_exit(&err);
585 return ret;
586 }
587
bch2_parse_mount_opts(struct bch_fs * c,struct bch_opts * opts,struct printbuf * parse_later,char * options)588 int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts,
589 struct printbuf *parse_later, char *options)
590 {
591 char *copied_opts, *copied_opts_start;
592 char *opt, *name, *val;
593 int ret;
594
595 if (!options)
596 return 0;
597
598 /*
599 * sys_fsconfig() is now occasionally providing us with option lists
600 * starting with a comma - weird.
601 */
602 if (*options == ',')
603 options++;
604
605 copied_opts = kstrdup(options, GFP_KERNEL);
606 if (!copied_opts)
607 return -ENOMEM;
608 copied_opts_start = copied_opts;
609
610 while ((opt = strsep(&copied_opts, ",")) != NULL) {
611 if (!*opt)
612 continue;
613
614 name = strsep(&opt, "=");
615 val = opt;
616
617 ret = bch2_parse_one_mount_opt(c, opts, parse_later, name, val);
618 if (ret < 0)
619 goto out;
620 }
621
622 ret = 0;
623 goto out;
624
625 out:
626 kfree(copied_opts_start);
627 return ret;
628 }
629
bch2_opt_from_sb(struct bch_sb * sb,enum bch_opt_id id,int dev_idx)630 u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id, int dev_idx)
631 {
632 const struct bch_option *opt = bch2_opt_table + id;
633 u64 v;
634
635 if (dev_idx < 0) {
636 v = opt->get_sb(sb);
637 } else {
638 if (WARN(!bch2_member_exists(sb, dev_idx),
639 "tried to set device option %s on nonexistent device %i",
640 opt->attr.name, dev_idx))
641 return 0;
642
643 struct bch_member m = bch2_sb_member_get(sb, dev_idx);
644 v = opt->get_member(&m);
645 }
646
647 if (opt->flags & OPT_SB_FIELD_ONE_BIAS)
648 --v;
649
650 if (opt->flags & OPT_SB_FIELD_ILOG2)
651 v = 1ULL << v;
652
653 if (opt->flags & OPT_SB_FIELD_SECTORS)
654 v <<= 9;
655
656 return v;
657 }
658
659 /*
660 * Initial options from superblock - here we don't want any options undefined,
661 * any options the superblock doesn't specify are set to 0:
662 */
bch2_opts_from_sb(struct bch_opts * opts,struct bch_sb * sb)663 int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)
664 {
665 for (unsigned id = 0; id < bch2_opts_nr; id++) {
666 const struct bch_option *opt = bch2_opt_table + id;
667
668 if (opt->get_sb)
669 bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id, -1));
670 }
671
672 return 0;
673 }
674
__bch2_opt_set_sb(struct bch_sb * sb,int dev_idx,const struct bch_option * opt,u64 v)675 void __bch2_opt_set_sb(struct bch_sb *sb, int dev_idx,
676 const struct bch_option *opt, u64 v)
677 {
678 if (opt->flags & OPT_SB_FIELD_SECTORS)
679 v >>= 9;
680
681 if (opt->flags & OPT_SB_FIELD_ILOG2)
682 v = ilog2(v);
683
684 if (opt->flags & OPT_SB_FIELD_ONE_BIAS)
685 v++;
686
687 if ((opt->flags & OPT_FS) && opt->set_sb && dev_idx < 0)
688 opt->set_sb(sb, v);
689
690 if ((opt->flags & OPT_DEVICE) && opt->set_member && dev_idx >= 0) {
691 if (WARN(!bch2_member_exists(sb, dev_idx),
692 "tried to set device option %s on nonexistent device %i",
693 opt->attr.name, dev_idx))
694 return;
695
696 opt->set_member(bch2_members_v2_get_mut(sb, dev_idx), v);
697 }
698 }
699
bch2_opt_set_sb(struct bch_fs * c,struct bch_dev * ca,const struct bch_option * opt,u64 v)700 void 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
bch2_opts_to_inode_opts(struct bch_opts src)711 struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src)
712 {
713 struct bch_io_opts opts = {
714 #define x(_name, _bits) ._name = src._name,
715 BCH_INODE_OPTS()
716 #undef x
717 };
718
719 bch2_io_opts_fixups(&opts);
720 return opts;
721 }
722
bch2_opt_is_inode_opt(enum bch_opt_id id)723 bool bch2_opt_is_inode_opt(enum bch_opt_id id)
724 {
725 static const enum bch_opt_id inode_opt_list[] = {
726 #define x(_name, _bits) Opt_##_name,
727 BCH_INODE_OPTS()
728 #undef x
729 };
730 unsigned i;
731
732 for (i = 0; i < ARRAY_SIZE(inode_opt_list); i++)
733 if (inode_opt_list[i] == id)
734 return true;
735
736 return false;
737 }
738