Commit a02a0121 authored by Kent Overstreet's avatar Kent Overstreet

bcachefs: bch2_version_compatible()

This adds a new helper for checking if an on-disk version is compatible
with the running version of bcachefs - prep work for introducing
major:minor version numbers.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent e3804b55
...@@ -1574,8 +1574,6 @@ struct bch_sb_field_journal_seq_blacklist { ...@@ -1574,8 +1574,6 @@ struct bch_sb_field_journal_seq_blacklist {
* One common version number for all on disk data structures - superblock, btree * One common version number for all on disk data structures - superblock, btree
* nodes, journal entries * nodes, journal entries
*/ */
#define BCH_JSET_VERSION_OLD 2
#define BCH_BSET_VERSION_OLD 3
#define BCH_METADATA_VERSIONS() \ #define BCH_METADATA_VERSIONS() \
x(bkey_renumber, 10) \ x(bkey_renumber, 10) \
......
...@@ -699,11 +699,9 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca, ...@@ -699,11 +699,9 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca,
struct printbuf buf2 = PRINTBUF; struct printbuf buf2 = PRINTBUF;
int ret = 0; int ret = 0;
btree_err_on((version != BCH_BSET_VERSION_OLD && btree_err_on(!bch2_version_compatible(version),
version < bcachefs_metadata_version_min) ||
version >= bcachefs_metadata_version_max,
BTREE_ERR_INCOMPATIBLE, c, ca, b, i, BTREE_ERR_INCOMPATIBLE, c, ca, b, i,
"unsupported bset version"); "unsupported bset version %u", version);
if (btree_err_on(version < c->sb.version_min, if (btree_err_on(version < c->sb.version_min,
BTREE_ERR_FIXABLE, c, NULL, b, i, BTREE_ERR_FIXABLE, c, NULL, b, i,
...@@ -2019,9 +2017,7 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b, unsigned flags) ...@@ -2019,9 +2017,7 @@ void __bch2_btree_node_write(struct bch_fs *c, struct btree *b, unsigned flags)
BUG_ON(BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN); BUG_ON(BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN);
BUG_ON(i->seq != b->data->keys.seq); BUG_ON(i->seq != b->data->keys.seq);
i->version = c->sb.version < bcachefs_metadata_version_bkey_renumber i->version = cpu_to_le16(c->sb.version);
? cpu_to_le16(BCH_BSET_VERSION_OLD)
: cpu_to_le16(c->sb.version);
SET_BSET_OFFSET(i, b->written); SET_BSET_OFFSET(i, b->written);
SET_BSET_CSUM_TYPE(i, bch2_meta_checksum_type(c)); SET_BSET_CSUM_TYPE(i, bch2_meta_checksum_type(c));
......
...@@ -745,14 +745,10 @@ static int jset_validate(struct bch_fs *c, ...@@ -745,14 +745,10 @@ static int jset_validate(struct bch_fs *c,
return JOURNAL_ENTRY_NONE; return JOURNAL_ENTRY_NONE;
version = le32_to_cpu(jset->version); version = le32_to_cpu(jset->version);
if (journal_entry_err_on((version != BCH_JSET_VERSION_OLD && if (journal_entry_err_on(!bch2_version_compatible(version), c, jset, NULL,
version < bcachefs_metadata_version_min) || "%s sector %llu seq %llu: incompatible journal entry version %u",
version >= bcachefs_metadata_version_max,
c, jset, NULL,
"%s sector %llu seq %llu: unknown journal entry version %u",
ca ? ca->name : c->name, ca ? ca->name : c->name,
sector, le64_to_cpu(jset->seq), sector, le64_to_cpu(jset->seq), version)) {
version)) {
/* don't try to continue: */ /* don't try to continue: */
return -EINVAL; return -EINVAL;
} }
...@@ -796,14 +792,10 @@ static int jset_validate_early(struct bch_fs *c, ...@@ -796,14 +792,10 @@ static int jset_validate_early(struct bch_fs *c,
return JOURNAL_ENTRY_NONE; return JOURNAL_ENTRY_NONE;
version = le32_to_cpu(jset->version); version = le32_to_cpu(jset->version);
if (journal_entry_err_on((version != BCH_JSET_VERSION_OLD && if (journal_entry_err_on(!bch2_version_compatible(version), c, jset, NULL,
version < bcachefs_metadata_version_min) ||
version >= bcachefs_metadata_version_max,
c, jset, NULL,
"%s sector %llu seq %llu: unknown journal entry version %u", "%s sector %llu seq %llu: unknown journal entry version %u",
ca ? ca->name : c->name, ca ? ca->name : c->name,
sector, le64_to_cpu(jset->seq), sector, le64_to_cpu(jset->seq), version)) {
version)) {
/* don't try to continue: */ /* don't try to continue: */
return -EINVAL; return -EINVAL;
} }
...@@ -1755,9 +1747,7 @@ void bch2_journal_write(struct closure *cl) ...@@ -1755,9 +1747,7 @@ void bch2_journal_write(struct closure *cl)
} }
jset->magic = cpu_to_le64(jset_magic(c)); jset->magic = cpu_to_le64(jset_magic(c));
jset->version = c->sb.version < bcachefs_metadata_version_bkey_renumber jset->version = cpu_to_le32(c->sb.version);
? cpu_to_le32(BCH_JSET_VERSION_OLD)
: cpu_to_le32(c->sb.version);
SET_JSET_BIG_ENDIAN(jset, CPU_BIG_ENDIAN); SET_JSET_BIG_ENDIAN(jset, CPU_BIG_ENDIAN);
SET_JSET_CSUM_TYPE(jset, bch2_meta_checksum_type(c)); SET_JSET_CSUM_TYPE(jset, bch2_meta_checksum_type(c));
......
...@@ -269,40 +269,58 @@ static int validate_sb_layout(struct bch_sb_layout *layout, struct printbuf *out ...@@ -269,40 +269,58 @@ static int validate_sb_layout(struct bch_sb_layout *layout, struct printbuf *out
return 0; return 0;
} }
static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out, static int bch2_sb_compatible(struct bch_sb *sb, struct printbuf *out)
int rw)
{ {
struct bch_sb *sb = disk_sb->sb; u16 version = le16_to_cpu(sb->version);
struct bch_sb_field *f; u16 version_min = le16_to_cpu(sb->version_min);
struct bch_sb_field_members *mi;
enum bch_opt_id opt_id; if (!bch2_version_compatible(version)) {
u32 version, version_min; prt_str(out, "Unsupported superblock version ");
u16 block_size; bch2_version_to_text(out, version);
int ret; prt_str(out, " (min ");
bch2_version_to_text(out, bcachefs_metadata_version_min);
version = le16_to_cpu(sb->version); prt_str(out, ", max ");
version_min = version >= bcachefs_metadata_version_bkey_renumber bch2_version_to_text(out, bcachefs_metadata_version_current);
? le16_to_cpu(sb->version_min) prt_str(out, ")");
: version;
if (version >= bcachefs_metadata_version_max) {
prt_printf(out, "Unsupported superblock version %u (min %u, max %u)",
version, bcachefs_metadata_version_min, bcachefs_metadata_version_max);
return -BCH_ERR_invalid_sb_version; return -BCH_ERR_invalid_sb_version;
} }
if (version_min < bcachefs_metadata_version_min) { if (!bch2_version_compatible(version_min)) {
prt_printf(out, "Unsupported superblock version %u (min %u, max %u)", prt_str(out, "Unsupported superblock version_min ");
version_min, bcachefs_metadata_version_min, bcachefs_metadata_version_max); bch2_version_to_text(out, version_min);
prt_str(out, " (min ");
bch2_version_to_text(out, bcachefs_metadata_version_min);
prt_str(out, ", max ");
bch2_version_to_text(out, bcachefs_metadata_version_current);
prt_str(out, ")");
return -BCH_ERR_invalid_sb_version; return -BCH_ERR_invalid_sb_version;
} }
if (version_min > version) { if (version_min > version) {
prt_printf(out, "Bad minimum version %u, greater than version field %u", prt_str(out, "Bad minimum version ");
version_min, 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; return -BCH_ERR_invalid_sb_version;
} }
return 0;
}
static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
int rw)
{
struct bch_sb *sb = disk_sb->sb;
struct bch_sb_field *f;
struct bch_sb_field_members *mi;
enum bch_opt_id opt_id;
u16 block_size;
int ret;
ret = bch2_sb_compatible(sb, out);
if (ret)
return ret;
if (sb->features[1] || if (sb->features[1] ||
(le64_to_cpu(sb->features[0]) & (~0ULL << BCH_FEATURE_NR))) { (le64_to_cpu(sb->features[0]) & (~0ULL << BCH_FEATURE_NR))) {
prt_printf(out, "Filesystem has incompatible features"); prt_printf(out, "Filesystem has incompatible features");
...@@ -350,7 +368,7 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out, ...@@ -350,7 +368,7 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
if (rw == READ) { if (rw == READ) {
/* /*
* Been seeing a bug where these are getting inexplicably * Been seeing a bug where these are getting inexplicably
* zeroed, so we'r now validating them, but we have to be * zeroed, so we're now validating them, but we have to be
* careful not to preven people's filesystems from mounting: * careful not to preven people's filesystems from mounting:
*/ */
if (!BCH_SB_JOURNAL_FLUSH_DELAY(sb)) if (!BCH_SB_JOURNAL_FLUSH_DELAY(sb))
...@@ -531,7 +549,6 @@ int bch2_sb_from_fs(struct bch_fs *c, struct bch_dev *ca) ...@@ -531,7 +549,6 @@ int bch2_sb_from_fs(struct bch_fs *c, struct bch_dev *ca)
static int read_one_super(struct bch_sb_handle *sb, u64 offset, struct printbuf *err) static int read_one_super(struct bch_sb_handle *sb, u64 offset, struct printbuf *err)
{ {
struct bch_csum csum; struct bch_csum csum;
u32 version, version_min;
size_t bytes; size_t bytes;
int ret; int ret;
reread: reread:
...@@ -551,22 +568,9 @@ static int read_one_super(struct bch_sb_handle *sb, u64 offset, struct printbuf ...@@ -551,22 +568,9 @@ static int read_one_super(struct bch_sb_handle *sb, u64 offset, struct printbuf
return -BCH_ERR_invalid_sb_magic; return -BCH_ERR_invalid_sb_magic;
} }
version = le16_to_cpu(sb->sb->version); ret = bch2_sb_compatible(sb->sb, err);
version_min = version >= bcachefs_metadata_version_bkey_renumber if (ret)
? le16_to_cpu(sb->sb->version_min) return ret;
: version;
if (version >= bcachefs_metadata_version_max) {
prt_printf(err, "Unsupported superblock version %u (min %u, max %u)",
version, bcachefs_metadata_version_min, bcachefs_metadata_version_max);
return -BCH_ERR_invalid_sb_version;
}
if (version_min < bcachefs_metadata_version_min) {
prt_printf(err, "Unsupported superblock version %u (min %u, max %u)",
version_min, bcachefs_metadata_version_min, bcachefs_metadata_version_max);
return -BCH_ERR_invalid_sb_version;
}
bytes = vstruct_bytes(sb->sb); bytes = vstruct_bytes(sb->sb);
......
...@@ -9,6 +9,12 @@ ...@@ -9,6 +9,12 @@
#include <asm/byteorder.h> #include <asm/byteorder.h>
static inline bool bch2_version_compatible(u16 version)
{
return version <= bcachefs_metadata_version_current &&
version >= bcachefs_metadata_version_min;
}
void bch2_version_to_text(struct printbuf *, unsigned); void bch2_version_to_text(struct printbuf *, unsigned);
struct bch_sb_field *bch2_sb_field_get(struct bch_sb *, enum bch_sb_field_type); struct bch_sb_field *bch2_sb_field_get(struct bch_sb *, enum bch_sb_field_type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment