Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.17-rc5 844 lines 19 kB view raw
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 "movinggc.h" 11#include "opts.h" 12#include "rebalance.h" 13#include "recovery_passes.h" 14#include "super-io.h" 15#include "util.h" 16 17#define x(t, n, ...) [n] = #t, 18 19const char * const bch2_error_actions[] = { 20 BCH_ERROR_ACTIONS() 21 NULL 22}; 23 24const char * const bch2_degraded_actions[] = { 25 BCH_DEGRADED_ACTIONS() 26 NULL 27}; 28 29const char * const bch2_fsck_fix_opts[] = { 30 BCH_FIX_ERRORS_OPTS() 31 NULL 32}; 33 34const char * const bch2_version_upgrade_opts[] = { 35 BCH_VERSION_UPGRADE_OPTS() 36 NULL 37}; 38 39const char * const bch2_sb_features[] = { 40 BCH_SB_FEATURES() 41 NULL 42}; 43 44const char * const bch2_sb_compat[] = { 45 BCH_SB_COMPAT() 46 NULL 47}; 48 49const char * const __bch2_btree_ids[] = { 50 BCH_BTREE_IDS() 51 NULL 52}; 53 54const char * const __bch2_csum_types[] = { 55 BCH_CSUM_TYPES() 56 NULL 57}; 58 59const char * const __bch2_csum_opts[] = { 60 BCH_CSUM_OPTS() 61 NULL 62}; 63 64const char * const __bch2_compression_types[] = { 65 BCH_COMPRESSION_TYPES() 66 NULL 67}; 68 69const char * const bch2_compression_opts[] = { 70 BCH_COMPRESSION_OPTS() 71 NULL 72}; 73 74const char * const __bch2_str_hash_types[] = { 75 BCH_STR_HASH_TYPES() 76 NULL 77}; 78 79const char * const bch2_str_hash_opts[] = { 80 BCH_STR_HASH_OPTS() 81 NULL 82}; 83 84const char * const __bch2_data_types[] = { 85 BCH_DATA_TYPES() 86 NULL 87}; 88 89const char * const bch2_member_states[] = { 90 BCH_MEMBER_STATES() 91 NULL 92}; 93 94static const char * const __bch2_jset_entry_types[] = { 95 BCH_JSET_ENTRY_TYPES() 96 NULL 97}; 98 99static const char * const __bch2_fs_usage_types[] = { 100 BCH_FS_USAGE_TYPES() 101 NULL 102}; 103 104#undef x 105 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); 124PRT_STR_OPT_BOUNDSCHECKED(csum_opt, enum bch_csum_opt); 125PRT_STR_OPT_BOUNDSCHECKED(csum_type, enum bch_csum_type); 126PRT_STR_OPT_BOUNDSCHECKED(compression_type, enum bch_compression_type); 127PRT_STR_OPT_BOUNDSCHECKED(str_hash_type, enum bch_str_hash_type); 128 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 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} 159 160const char * const bch2_d_types[BCH_DT_MAX] = { 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", 170 [DT_SUBVOL] = "subvol", 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 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 238const struct bch_option bch2_opt_table[] = { 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, \ 243 .min = 0, .max = ARRAY_SIZE(_choices) - 1, \ 244 .choices = _choices 245#define OPT_STR_NOLIMIT(_choices) .type = BCH_OPT_STR, \ 246 .min = 0, .max = U64_MAX, \ 247 .choices = _choices 248#define OPT_BITFIELD(_choices) .type = BCH_OPT_BITFIELD, \ 249 .choices = _choices 250#define OPT_FN(_fn) .type = BCH_OPT_FN, .fn = _fn 251 252#define x(_name, _bits, _flags, _type, _sb_opt, _default, _hint, _help) \ 253 [Opt_##_name] = { \ 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),\ 263 _type \ 264 }, 265 266 BCH_OPTS() 267#undef x 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 283struct opt_synonym { 284 const char *s1, *s2; 285}; 286 287static const struct opt_synonym bch2_opt_synonyms[] = { 288 { "quota", "usrquota" }, 289}; 290 291static int bch2_mount_opt_lookup(const char *name) 292{ 293 const struct opt_synonym *i; 294 295 for (i = bch2_opt_synonyms; 296 i < bch2_opt_synonyms + ARRAY_SIZE(bch2_opt_synonyms); 297 i++) 298 if (!strcmp(name, i->s1)) 299 name = i->s2; 300 301 return bch2_opt_lookup(name); 302} 303 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 328int bch2_opt_validate(const struct bch_option *opt, u64 v, struct printbuf *err) 329{ 330 if (v < opt->min) { 331 if (err) 332 prt_printf(err, "%s: too small (min %llu)", 333 opt->attr.name, opt->min); 334 return -BCH_ERR_ERANGE_option_too_small; 335 } 336 337 if (opt->max && v >= opt->max) { 338 if (err) 339 prt_printf(err, "%s: too big (max %llu)", 340 opt->attr.name, opt->max); 341 return -BCH_ERR_ERANGE_option_too_big; 342 } 343 344 if ((opt->flags & OPT_SB_FIELD_SECTORS) && (v & 511)) { 345 if (err) 346 prt_printf(err, "%s: not a multiple of 512", 347 opt->attr.name); 348 return -BCH_ERR_opt_parse_error; 349 } 350 351 if ((opt->flags & OPT_MUST_BE_POW_2) && !is_power_of_2(v)) { 352 if (err) 353 prt_printf(err, "%s: must be a power of two", 354 opt->attr.name); 355 return -BCH_ERR_opt_parse_error; 356 } 357 358 if (opt->fn.validate) 359 return opt->fn.validate(v, err); 360 361 return 0; 362} 363 364int bch2_opt_parse(struct bch_fs *c, 365 const struct bch_option *opt, 366 const char *val, u64 *res, 367 struct printbuf *err) 368{ 369 ssize_t ret; 370 371 if (err) 372 printbuf_indent_add_nextline(err, 2); 373 374 switch (opt->type) { 375 case BCH_OPT_BOOL: 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; 382 } else { 383 if (err) 384 prt_printf(err, "%s: must be bool", opt->attr.name); 385 return ret; 386 } 387 break; 388 case BCH_OPT_UINT: 389 if (!val) { 390 prt_printf(err, "%s: required value", 391 opt->attr.name); 392 return -EINVAL; 393 } 394 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 404 if (ret < 0) { 405 if (err) 406 prt_printf(err, "%s: must be a number", 407 opt->attr.name); 408 return ret; 409 } 410 break; 411 case BCH_OPT_STR: 412 if (!val) { 413 prt_printf(err, "%s: required value", 414 opt->attr.name); 415 return -EINVAL; 416 } 417 418 ret = match_string(opt->choices, -1, val); 419 if (ret < 0) { 420 if (err) 421 prt_printf(err, "%s: invalid selection", 422 opt->attr.name); 423 return ret; 424 } 425 426 *res = ret; 427 break; 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 } 435 case BCH_OPT_FN: 436 ret = opt->fn.parse(c, val, res, err); 437 438 if (ret == -BCH_ERR_option_needs_open_fs) 439 return ret; 440 441 if (ret < 0) { 442 if (err) 443 prt_printf(err, "%s: parse error", 444 opt->attr.name); 445 return ret; 446 } 447 } 448 449 return bch2_opt_validate(opt, *res, err); 450} 451 452void bch2_opt_to_text(struct printbuf *out, 453 struct bch_fs *c, struct bch_sb *sb, 454 const struct bch_option *opt, u64 v, 455 unsigned flags) 456{ 457 if (flags & OPT_SHOW_MOUNT_STYLE) { 458 if (opt->type == BCH_OPT_BOOL) { 459 prt_printf(out, "%s%s", 460 v ? "" : "no", 461 opt->attr.name); 462 return; 463 } 464 465 prt_printf(out, "%s=", opt->attr.name); 466 } 467 468 switch (opt->type) { 469 case BCH_OPT_BOOL: 470 case BCH_OPT_UINT: 471 if (opt->flags & OPT_HUMAN_READABLE) 472 prt_human_readable_u64(out, v); 473 else 474 prt_printf(out, "%lli", v); 475 break; 476 case BCH_OPT_STR: 477 if (v < opt->min || v >= opt->max) 478 prt_printf(out, "(invalid option %lli)", v); 479 else if (flags & OPT_SHOW_FULL_LIST) 480 prt_string_option(out, opt->choices, v); 481 else 482 prt_str(out, opt->choices[v]); 483 break; 484 case BCH_OPT_BITFIELD: 485 prt_bitflags(out, opt->choices, v); 486 break; 487 case BCH_OPT_FN: 488 opt->fn.to_text(out, c, sb, v); 489 break; 490 default: 491 BUG(); 492 } 493} 494 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 521int bch2_opt_hook_pre_set(struct bch_fs *c, struct bch_dev *ca, enum bch_opt_id id, u64 v) 522{ 523 int ret = 0; 524 525 switch (id) { 526 case Opt_state: 527 if (ca) 528 return bch2_dev_set_state(c, ca, v, BCH_FORCE_IF_DEGRADED); 529 break; 530 531 case Opt_compression: 532 case Opt_background_compression: 533 ret = bch2_check_set_has_compressed_data(c, v); 534 break; 535 case Opt_erasure_code: 536 if (v) 537 bch2_check_set_feature(c, BCH_FEATURE_ec); 538 break; 539 default: 540 break; 541 } 542 543 return ret; 544} 545 546int bch2_opts_hooks_pre_set(struct bch_fs *c) 547{ 548 for (unsigned i = 0; i < bch2_opts_nr; i++) { 549 int ret = bch2_opt_hook_pre_set(c, NULL, i, bch2_opt_get_by_id(&c->opts, i)); 550 if (ret) 551 return ret; 552 } 553 554 return 0; 555} 556 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; 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; 607 default: 608 break; 609 } 610} 611 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 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 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); 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; 660 } 661 662 goto out; 663 } 664 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; 672out: 673 printbuf_exit(&err); 674 return ret; 675bad_opt: 676 ret = -BCH_ERR_option_name; 677 goto out; 678bad_val: 679 ret = -BCH_ERR_option_value; 680 goto out; 681} 682 683int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts, 684 struct printbuf *parse_later, char *options, 685 bool ignore_unknown) 686{ 687 char *copied_opts, *copied_opts_start; 688 char *opt, *name, *val; 689 int ret = 0; 690 691 if (!options) 692 return 0; 693 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 701 copied_opts = kstrdup(options, GFP_KERNEL); 702 if (!copied_opts) 703 return -ENOMEM; 704 copied_opts_start = copied_opts; 705 706 while ((opt = strsep(&copied_opts, ",")) != NULL) { 707 if (!*opt) 708 continue; 709 710 name = strsep(&opt, "="); 711 val = opt; 712 713 ret = bch2_parse_one_mount_opt(c, opts, parse_later, name, val); 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 } 720 } 721 722 kfree(copied_opts_start); 723 return ret; 724} 725 726u64 bch2_opt_from_sb(struct bch_sb *sb, enum bch_opt_id id, int dev_idx) 727{ 728 const struct bch_option *opt = bch2_opt_table + id; 729 u64 v; 730 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; 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 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{ 761 for (unsigned id = 0; id < bch2_opts_nr; id++) { 762 const struct bch_option *opt = bch2_opt_table + id; 763 764 if (opt->get_sb) 765 bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id, -1)); 766 } 767 768 return 0; 769} 770 771bool __bch2_opt_set_sb(struct bch_sb *sb, int dev_idx, 772 const struct bch_option *opt, u64 v) 773{ 774 bool changed = false; 775 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 782 if (opt->flags & OPT_SB_FIELD_ONE_BIAS) 783 v++; 784 785 if ((opt->flags & OPT_FS) && opt->set_sb && dev_idx < 0) { 786 changed = v != opt->get_sb(sb); 787 788 opt->set_sb(sb, v); 789 } 790 791 if ((opt->flags & OPT_DEVICE) && opt->set_member && dev_idx >= 0) { 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)) 795 return false; 796 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); 800 } 801 802 return changed; 803} 804 805bool bch2_opt_set_sb(struct bch_fs *c, struct bch_dev *ca, 806 const struct bch_option *opt, u64 v) 807{ 808 mutex_lock(&c->sb_lock); 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); 812 mutex_unlock(&c->sb_lock); 813 return changed; 814} 815 816/* io opts: */ 817 818struct bch_io_opts bch2_opts_to_inode_opts(struct bch_opts src) 819{ 820 struct bch_io_opts opts = { 821#define x(_name, _bits) ._name = src._name, 822 BCH_INODE_OPTS() 823#undef x 824 }; 825 826 bch2_io_opts_fixups(&opts); 827 return opts; 828} 829 830bool bch2_opt_is_inode_opt(enum bch_opt_id id) 831{ 832 static const enum bch_opt_id inode_opt_list[] = { 833#define x(_name, _bits) Opt_##_name, 834 BCH_INODE_OPTS() 835#undef x 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}