for (unsigned i = 0; i < ARRAY_SIZE(bch2_metadata_versions); i++) if (bch2_metadata_versions[i].version == v) {
str = bch2_metadata_versions[i].name; break;
}
enum bcachefs_metadata_version bch2_latest_compatible_version(enum bcachefs_metadata_version v)
{ if (!BCH_VERSION_MAJOR(v)) return v;
for (unsigned i = 0; i < ARRAY_SIZE(bch2_metadata_versions); i++) if (bch2_metadata_versions[i].version > v &&
BCH_VERSION_MAJOR(bch2_metadata_versions[i].version) ==
BCH_VERSION_MAJOR(v))
v = bch2_metadata_versions[i].version;
return v;
}
int bch2_set_version_incompat(struct bch_fs *c, enum bcachefs_metadata_version version)
{ int ret = ((c->sb.features & BIT_ULL(BCH_FEATURE_incompat_version_field)) &&
version <= c->sb.version_incompat_allowed)
? 0
: -BCH_ERR_may_not_use_incompat_feature;
mutex_lock(&c->sb_lock); if (!ret) {
SET_BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb,
max(BCH_SB_VERSION_INCOMPAT(c->disk_sb.sb), version));
bch2_write_super(c);
} else {
darray_for_each(c->incompat_versions_requested, i) if (version == *i) goto out;
darray_push(&c->incompat_versions_requested, version); struct printbuf buf = PRINTBUF;
prt_str(&buf, "requested incompat feature ");
bch2_version_to_text(&buf, version);
prt_str(&buf, " currently not enabled, allowed up to ");
bch2_version_to_text(&buf, version);
prt_printf(&buf, "\n set version_upgrade=incompat to enable");
if (!uuid_equal(&layout->magic, &BCACHE_MAGIC) &&
!uuid_equal(&layout->magic, &BCHFS_MAGIC)) {
prt_printf(out, "Not a bcachefs superblock layout"); return -BCH_ERR_invalid_sb_layout;
}
if (layout->layout_type != 0) {
prt_printf(out, "Invalid superblock layout type %u",
layout->layout_type); return -BCH_ERR_invalid_sb_layout_type;
}
if (!layout->nr_superblocks) {
prt_printf(out, "Invalid superblock layout: no superblocks"); return -BCH_ERR_invalid_sb_layout_nr_superblocks;
}
if (layout->nr_superblocks > ARRAY_SIZE(layout->sb_offset)) {
prt_printf(out, "Invalid superblock layout: too many superblocks"); return -BCH_ERR_invalid_sb_layout_nr_superblocks;
}
if (layout->sb_max_size_bits > BCH_SB_LAYOUT_SIZE_BITS_MAX) {
prt_printf(out, "Invalid superblock layout: max_size_bits too high"); return -BCH_ERR_invalid_sb_layout_sb_max_size_bits;
}
max_sectors = 1 << layout->sb_max_size_bits;
prev_offset = le64_to_cpu(layout->sb_offset[0]);
for (i = 1; i < layout->nr_superblocks; i++) {
offset = le64_to_cpu(layout->sb_offset[i]);
if (offset < prev_offset + max_sectors) {
prt_printf(out, "Invalid superblock layout: superblocks overlap\n" " (sb %u ends at %llu next starts at %llu",
i - 1, prev_offset + max_sectors, offset); return -BCH_ERR_invalid_sb_layout_superblocks_overlap;
}
prev_offset = offset;
}
if (version_min > version) {
prt_str(out, "Bad minimum version ");
bch2_version_to_text(out, version_min);
prt_str(out, ", greater than version field ");
bch2_version_to_text(out, version); return -BCH_ERR_invalid_sb_version;
}
return0;
}
int bch2_sb_validate(struct bch_sb *sb, u64 read_offset, enum bch_validate_flags flags, struct printbuf *out)
{ enum bch_opt_id opt_id; int ret;
ret = bch2_sb_compatible(sb, out); if (ret) return ret;
if (!sb->time_precision ||
le32_to_cpu(sb->time_precision) > NSEC_PER_SEC) {
prt_printf(out, "Invalid time precision: %u (min 1, max %lu)",
le32_to_cpu(sb->time_precision), NSEC_PER_SEC); return -BCH_ERR_invalid_sb_time_precision;
}
/* old versions didn't know to downgrade this field */ if (BCH_SB_VERSION_INCOMPAT_ALLOWED(sb) > le16_to_cpu(sb->version))
SET_BCH_SB_VERSION_INCOMPAT_ALLOWED(sb, le16_to_cpu(sb->version));
if (sb->nr_devices > 1)
SET_BCH_SB_MULTI_DEVICE(sb, true);
if (!flags) { /* * Been seeing a bug where these are getting inexplicably * zeroed, so we're now validating them, but we have to be * careful not to preven people's filesystems from mounting:
*/ if (!BCH_SB_JOURNAL_FLUSH_DELAY(sb))
SET_BCH_SB_JOURNAL_FLUSH_DELAY(sb, 1000); if (!BCH_SB_JOURNAL_RECLAIM_DELAY(sb))
SET_BCH_SB_JOURNAL_RECLAIM_DELAY(sb, 1000);
if (!BCH_SB_VERSION_UPGRADE_COMPLETE(sb))
SET_BCH_SB_VERSION_UPGRADE_COMPLETE(sb, le16_to_cpu(sb->version));
if (le16_to_cpu(sb->version) <= bcachefs_metadata_version_disk_accounting_v2 &&
!BCH_SB_ALLOCATOR_STUCK_TIMEOUT(sb))
SET_BCH_SB_ALLOCATOR_STUCK_TIMEOUT(sb, 30);
if (le16_to_cpu(sb->version) <= bcachefs_metadata_version_disk_accounting_v2)
SET_BCH_SB_PROMOTE_WHOLE_EXTENTS(sb, true);
if (!BCH_SB_WRITE_ERROR_TIMEOUT(sb))
SET_BCH_SB_WRITE_ERROR_TIMEOUT(sb, 30);
if (le16_to_cpu(sb->version) <= bcachefs_metadata_version_extent_flags &&
!BCH_SB_CSUM_ERR_RETRY_NR(sb))
SET_BCH_SB_CSUM_ERR_RETRY_NR(sb, 3);
}
#ifdef __KERNEL__ if (!BCH_SB_SHARD_INUMS_NBITS(sb))
SET_BCH_SB_SHARD_INUMS_NBITS(sb, ilog2(roundup_pow_of_two(num_online_cpus()))); #endif
if (opt->get_sb) {
u64 v = bch2_opt_from_sb(sb, opt_id, -1);
prt_printf(out, "Invalid option ");
ret = bch2_opt_validate(opt, v, out); if (ret) return ret;
printbuf_reset(out);
}
}
/* validate layout */
ret = validate_sb_layout(&sb->layout, out); if (ret) return ret;
vstruct_for_each(sb, f) { if (!f->u64s) {
prt_printf(out, "Invalid superblock: optional field with size 0 (type %u)",
le32_to_cpu(f->type)); return -BCH_ERR_invalid_sb_field_size;
}
if (vstruct_next(f) > vstruct_last(sb)) {
prt_printf(out, "Invalid superblock: optional field extends past end of superblock (type %u)",
le32_to_cpu(f->type)); return -BCH_ERR_invalid_sb_field_size;
}
}
/* members must be validated first: */ if (!mi) {
prt_printf(out, "Invalid superblock: member info area missing"); return -BCH_ERR_invalid_sb_members_missing;
}
ret = bch2_sb_field_validate(sb, mi, flags, out); if (ret) return ret;
vstruct_for_each(sb, f) { if (le32_to_cpu(f->type) == BCH_SB_FIELD_members_v1) continue;
ret = bch2_sb_field_validate(sb, f, flags, out); if (ret) return ret;
}
/* XXX this is wrong, we need a 96 or 128 bit integer type */
c->sb.time_base_lo = div_u64(le64_to_cpu(src->time_base_lo),
c->sb.nsec_per_time_unit);
c->sb.time_base_hi = le32_to_cpu(src->time_base_hi);
/* * Note: we do writes to RO devices here, and we might want to change * that in the future. * * For now, we expect to be able to call write_super() when we're not * yet RW:
*/
for_each_online_member(c, ca, BCH_DEV_READ_REF_write_super) {
ret = darray_push(&online_devices, ca); if (bch2_fs_fatal_err_on(ret, c, "%s: error allocating online devices", __func__)) {
enumerated_ref_put(&ca->io_ref[READ], BCH_DEV_READ_REF_write_super); goto out;
}
enumerated_ref_get(&ca->io_ref[READ], BCH_DEV_READ_REF_write_super);
}
/* Make sure we're using the new magic numbers: */
c->disk_sb.sb->magic = BCHFS_MAGIC;
c->disk_sb.sb->layout.magic = BCHFS_MAGIC;
if (test_bit(BCH_FS_error, &c->flags))
SET_BCH_SB_HAS_ERRORS(c->disk_sb.sb, 1); if (test_bit(BCH_FS_topology_error, &c->flags))
SET_BCH_SB_HAS_TOPOLOGY_ERRORS(c->disk_sb.sb, 1);
ret = bch2_sb_validate((*ca)->disk_sb.sb, 0, BCH_VALIDATE_write, &err); if (ret) {
bch2_fs_inconsistent(c, "sb invalid before write: %s", err.buf); goto out;
}
}
if (c->opts.nochanges) goto out;
/* * Defer writing the superblock until filesystem initialization is * complete - don't write out a partly initialized superblock:
*/ if (!BCH_SB_INITIALIZED(c->disk_sb.sb)) goto out;
if (le16_to_cpu(c->disk_sb.sb->version) > bcachefs_metadata_version_current) { struct printbuf buf = PRINTBUF;
prt_printf(&buf, "attempting to write superblock that wasn't version downgraded (");
bch2_version_to_text(&buf, le16_to_cpu(c->disk_sb.sb->version));
prt_str(&buf, " > ");
bch2_version_to_text(&buf, bcachefs_metadata_version_current);
prt_str(&buf, ")");
bch2_fs_fatal_error(c, ": %s", buf.buf);
printbuf_exit(&buf);
ret = bch_err_throw(c, sb_not_downgraded); goto out;
}
/* * If we would be able to mount _without_ the devices we successfully * wrote superblocks to, we weren't able to write to enough devices: * * Exception: if we can mount without the successes because we haven't * written anything (new filesystem), we continue if we'd be able to * mount with the devices we did successfully write to:
*/ if (bch2_fs_fatal_err_on(!nr_wrote ||
!can_mount_with_written ||
(can_mount_without_written &&
!can_mount_with_written), c, ": Unable to write superblock to sufficient devices (from %ps)",
(void *) _RET_IP_))
ret = bch_err_throw(c, erofs_sb_err);
out: /* Make new options visible after they're persistent: */
bch2_sb_update(c);
darray_for_each(online_devices, ca)
enumerated_ref_put(&(*ca)->io_ref[READ], BCH_DEV_READ_REF_write_super);
darray_exit(&online_devices);
printbuf_exit(&err); return ret;
}
/* Downgrade if superblock is at a higher version than currently supported: */ bool bch2_check_version_downgrade(struct bch_fs *c)
{ bool ret = bcachefs_metadata_version_current < c->sb.version;
lockdep_assert_held(&c->sb_lock);
/* * Downgrade, if superblock is at a higher version than currently * supported: * * c->sb will be checked before we write the superblock, so update it as * well:
*/ if (BCH_SB_VERSION_UPGRADE_COMPLETE(c->disk_sb.sb) > bcachefs_metadata_version_current)
SET_BCH_SB_VERSION_UPGRADE_COMPLETE(c->disk_sb.sb, bcachefs_metadata_version_current); if (BCH_SB_VERSION_INCOMPAT_ALLOWED(c->disk_sb.sb) > bcachefs_metadata_version_current)
SET_BCH_SB_VERSION_INCOMPAT_ALLOWED(c->disk_sb.sb, bcachefs_metadata_version_current); if (c->sb.version > bcachefs_metadata_version_current)
c->disk_sb.sb->version = cpu_to_le16(bcachefs_metadata_version_current); if (c->sb.version_min > bcachefs_metadata_version_current)
c->disk_sb.sb->version_min = cpu_to_le16(bcachefs_metadata_version_current);
c->disk_sb.sb->compat[0] &= cpu_to_le64((1ULL << BCH_COMPAT_NR) - 1); return ret;
}
prt_str(&buf, "Now allowing incompatible features up to ");
bch2_version_to_text(&buf, c->sb.version);
prt_str(&buf, ", previously allowed up to ");
bch2_version_to_text(&buf, c->sb.version_incompat_allowed);
prt_newline(&buf);
¤ 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.0.6Bemerkung:
(vorverarbeitet am 2026-06-05)
¤
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.