for (i = bch2_opt_val_synonyms;
i < bch2_opt_val_synonyms + ARRAY_SIZE(bch2_opt_val_synonyms);
i++) if (!strcmp(opt, i->opt) && !strcmp(val, i->v1)) return i->v2;
return val;
}
int bch2_opt_validate(conststruct bch_option *opt, u64 v, struct printbuf *err)
{ if (v < opt->min) { if (err)
prt_printf(err, "%s: too small (min %llu)",
opt->attr.name, opt->min); return -BCH_ERR_ERANGE_option_too_small;
}
if (opt->max && v >= opt->max) { if (err)
prt_printf(err, "%s: too big (max %llu)",
opt->attr.name, opt->max); return -BCH_ERR_ERANGE_option_too_big;
}
if ((opt->flags & OPT_SB_FIELD_SECTORS) && (v & 511)) { if (err)
prt_printf(err, "%s: not a multiple of 512",
opt->attr.name); return -BCH_ERR_opt_parse_error;
}
if ((opt->flags & OPT_MUST_BE_POW_2) && !is_power_of_2(v)) { if (err)
prt_printf(err, "%s: must be a power of two",
opt->attr.name); return -BCH_ERR_opt_parse_error;
}
if (opt->fn.validate) return opt->fn.validate(v, err);
switch (opt->type) { case BCH_OPT_BOOL: if (!val)
val = "1";
ret = lookup_constant(bool_names, val, -BCH_ERR_option_not_bool); if (ret != -BCH_ERR_option_not_bool) {
*res = ret;
} else { if (err)
prt_printf(err, "%s: must be bool", opt->attr.name); return ret;
} break; case BCH_OPT_UINT: if (!val) {
prt_printf(err, "%s: required value",
opt->attr.name); return -EINVAL;
}
if (*val != '-') {
ret = opt->flags & OPT_HUMAN_READABLE
? bch2_strtou64_h(val, res)
: kstrtou64(val, 10, res);
} else {
prt_printf(err, "%s: must be a non-negative number", opt->attr.name); return -BCH_ERR_option_negative;
}
if (ret < 0) { if (err)
prt_printf(err, "%s: must be a number",
opt->attr.name); return ret;
} break; case BCH_OPT_STR: if (!val) {
prt_printf(err, "%s: required value",
opt->attr.name); return -EINVAL;
}
ret = match_string(opt->choices, -1, val); if (ret < 0) { if (err)
prt_printf(err, "%s: invalid selection",
opt->attr.name); return ret;
}
*res = ret; break; case BCH_OPT_BITFIELD: {
s64 v = bch2_read_flag_list(val, opt->choices); if (v < 0) return v;
*res = v; break;
} case BCH_OPT_FN:
ret = opt->fn.parse(c, val, res, err);
if (ret == -BCH_ERR_option_needs_open_fs) return ret;
if (ret < 0) { if (err)
prt_printf(err, "%s: parse error",
opt->attr.name); return ret;
}
}
for (enum bch_opt_id i = 0; i < bch2_opts_nr; i++) { conststruct bch_option *opt = &bch2_opt_table[i];
if ((opt->flags & hide_mask) || !(opt->flags & show_mask)) continue;
u64 v = bch2_opt_get_by_id(&opts, i); if (v == bch2_opt_get_by_id(&bch2_opts_default, i)) continue;
if (!first)
prt_char(out, ',');
first = false;
bch2_opt_to_text(out, c, sb, opt, v, flags);
}
}
int bch2_opt_hook_pre_set(struct bch_fs *c, struct bch_dev *ca, enum bch_opt_id id, u64 v)
{ int ret = 0;
switch (id) { case Opt_state: if (ca) return bch2_dev_set_state(c, ca, v, BCH_FORCE_IF_DEGRADED); break;
case Opt_compression: case Opt_background_compression:
ret = bch2_check_set_has_compressed_data(c, v); break; case Opt_erasure_code: if (v)
bch2_check_set_feature(c, BCH_FEATURE_ec); break; default: break;
}
return ret;
}
int bch2_opts_hooks_pre_set(struct bch_fs *c)
{ for (unsigned i = 0; i < bch2_opts_nr; i++) { int ret = bch2_opt_hook_pre_set(c, NULL, i, bch2_opt_get_by_id(&c->opts, i)); if (ret) return ret;
}
return 0;
}
void bch2_opt_hook_post_set(struct bch_fs *c, struct bch_dev *ca, u64 inum, struct bch_opts *new_opts, enum bch_opt_id id)
{ switch (id) { case Opt_foreground_target: if (new_opts->foreground_target &&
!new_opts->background_target)
bch2_set_rebalance_needs_scan(c, inum); break; case Opt_compression: if (new_opts->compression &&
!new_opts->background_compression)
bch2_set_rebalance_needs_scan(c, inum); break; case Opt_background_target: if (new_opts->background_target)
bch2_set_rebalance_needs_scan(c, inum); break; case Opt_background_compression: if (new_opts->background_compression)
bch2_set_rebalance_needs_scan(c, inum); break; case Opt_rebalance_enabled:
bch2_rebalance_wakeup(c); break; case Opt_copygc_enabled:
bch2_copygc_wakeup(c); break; case Opt_discard: if (!ca) {
mutex_lock(&c->sb_lock);
for_each_member_device(c, ca) { struct bch_member *m =
bch2_members_v2_get_mut(ca->disk_sb.sb, ca->dev_idx);
SET_BCH_MEMBER_DISCARD(m, c->opts.discard);
}
bch2_write_super(c);
mutex_unlock(&c->sb_lock);
} break; case Opt_version_upgrade: /* * XXX: in the future we'll likely want to do compatible * upgrades at runtime as well, but right now there's nothing * that does that:
*/ if (new_opts->version_upgrade == BCH_VERSION_UPGRADE_incompatible)
bch2_sb_upgrade_incompat(c); break; default: break;
}
}
/* Check for the form "noopt", negation of a boolean opt: */ if (id < 0 &&
!val &&
!strncmp("no", name, 2)) {
id = bch2_mount_opt_lookup(name + 2);
val = "0";
}
/* Unknown options are ignored: */ if (id < 0) return 0;
/* must have a value for synonym lookup - but OPT_FN is weird */ if (!val && bch2_opt_table[id].type != BCH_OPT_FN)
val = "1";
val = bch2_opt_val_synonym_lookup(name, val);
if (!(bch2_opt_table[id].flags & OPT_MOUNT)) goto bad_opt;
if (id == Opt_acl &&
!IS_ENABLED(CONFIG_BCACHEFS_POSIX_ACL)) goto bad_opt;
if ((id == Opt_usrquota ||
id == Opt_grpquota) &&
!IS_ENABLED(CONFIG_BCACHEFS_QUOTA)) goto bad_opt;
ret = bch2_opt_parse(c, &bch2_opt_table[id], val, &v, &err); if (ret == -BCH_ERR_option_needs_open_fs) {
ret = 0;
if (parse_later) {
prt_printf(parse_later, "%s=%s,", name, val); if (parse_later->allocation_failure)
ret = -ENOMEM;
}
goto out;
}
if (ret < 0) goto bad_val;
if (opts)
bch2_opt_set_by_id(opts, id, v);
ret = 0;
out:
printbuf_exit(&err); return ret;
bad_opt:
ret = -BCH_ERR_option_name; goto out;
bad_val:
ret = -BCH_ERR_option_value; goto out;
}
int bch2_parse_mount_opts(struct bch_fs *c, struct bch_opts *opts, struct printbuf *parse_later, char *options, bool ignore_unknown)
{ char *copied_opts, *copied_opts_start; char *opt, *name, *val; int ret = 0;
if (!options) return 0;
/* * sys_fsconfig() is now occasionally providing us with option lists * starting with a comma - weird.
*/ if (*options == ',')
options++;
if (dev_idx < 0) {
v = opt->get_sb(sb);
} else { if (WARN(!bch2_member_exists(sb, dev_idx), "tried to set device option %s on nonexistent device %i",
opt->attr.name, dev_idx)) return 0;
struct bch_member m = bch2_sb_member_get(sb, dev_idx);
v = opt->get_member(&m);
}
if (opt->flags & OPT_SB_FIELD_ONE_BIAS)
--v;
if (opt->flags & OPT_SB_FIELD_ILOG2)
v = 1ULL << v;
if (opt->flags & OPT_SB_FIELD_SECTORS)
v <<= 9;
return v;
}
/* * Initial options from superblock - here we don't want any options undefined, * any options the superblock doesn't specify are set to 0:
*/ int bch2_opts_from_sb(struct bch_opts *opts, struct bch_sb *sb)
{ for (unsigned id = 0; id < bch2_opts_nr; id++) { conststruct bch_option *opt = bch2_opt_table + id;
if (opt->get_sb)
bch2_opt_set_by_id(opts, id, bch2_opt_from_sb(sb, id, -1));
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.