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