summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/bcachefs/bcachefs.h1
-rw-r--r--fs/bcachefs/bcachefs_format.h53
-rw-r--r--fs/bcachefs/btree_io.c12
-rw-r--r--fs/bcachefs/journal_io.c24
-rw-r--r--fs/bcachefs/opts.c5
-rw-r--r--fs/bcachefs/opts.h1
-rw-r--r--fs/bcachefs/recovery.c18
-rw-r--r--fs/bcachefs/super-io.c132
-rw-r--r--fs/bcachefs/super-io.h8
-rw-r--r--fs/bcachefs/super.c3
10 files changed, 155 insertions, 102 deletions
diff --git a/fs/bcachefs/bcachefs.h b/fs/bcachefs/bcachefs.h
index ba8cd35bfd35..96d881d38915 100644
--- a/fs/bcachefs/bcachefs.h
+++ b/fs/bcachefs/bcachefs.h
@@ -713,6 +713,7 @@ struct bch_fs {
u16 version;
u16 version_min;
+ u16 version_upgrade_complete;
u8 nr_devices;
u8 clean;
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h
index b2d210b865cf..5b3e206c2aeb 100644
--- a/fs/bcachefs/bcachefs_format.h
+++ b/fs/bcachefs/bcachefs_format.h
@@ -1574,30 +1574,32 @@ struct bch_sb_field_journal_seq_blacklist {
* One common version number for all on disk data structures - superblock, btree
* nodes, journal entries
*/
-#define BCH_JSET_VERSION_OLD 2
-#define BCH_BSET_VERSION_OLD 3
+#define BCH_VERSION_MAJOR(_v) ((__u8) ((_v) >> 10))
+#define BCH_VERSION_MINOR(_v) ((__u8) ((_v) >> 0))
+#define BCH_VERSION(_major, _minor) (((_major) << 10)|(_minor) << 0)
#define BCH_METADATA_VERSIONS() \
- x(bkey_renumber, 10) \
- x(inode_btree_change, 11) \
- x(snapshot, 12) \
- x(inode_backpointers, 13) \
- x(btree_ptr_sectors_written, 14) \
- x(snapshot_2, 15) \
- x(reflink_p_fix, 16) \
- x(subvol_dirent, 17) \
- x(inode_v2, 18) \
- x(freespace, 19) \
- x(alloc_v4, 20) \
- x(new_data_types, 21) \
- x(backpointers, 22) \
- x(inode_v3, 23) \
- x(unwritten_extents, 24) \
- x(bucket_gens, 25) \
- x(lru_v2, 26) \
- x(fragmentation_lru, 27) \
- x(no_bps_in_alloc_keys, 28) \
- x(snapshot_trees, 29)
+ x(bkey_renumber, BCH_VERSION(0, 10)) \
+ x(inode_btree_change, BCH_VERSION(0, 11)) \
+ x(snapshot, BCH_VERSION(0, 12)) \
+ x(inode_backpointers, BCH_VERSION(0, 13)) \
+ x(btree_ptr_sectors_written, BCH_VERSION(0, 14)) \
+ x(snapshot_2, BCH_VERSION(0, 15)) \
+ x(reflink_p_fix, BCH_VERSION(0, 16)) \
+ x(subvol_dirent, BCH_VERSION(0, 17)) \
+ x(inode_v2, BCH_VERSION(0, 18)) \
+ x(freespace, BCH_VERSION(0, 19)) \
+ x(alloc_v4, BCH_VERSION(0, 20)) \
+ x(new_data_types, BCH_VERSION(0, 21)) \
+ x(backpointers, BCH_VERSION(0, 22)) \
+ x(inode_v3, BCH_VERSION(0, 23)) \
+ x(unwritten_extents, BCH_VERSION(0, 24)) \
+ x(bucket_gens, BCH_VERSION(0, 25)) \
+ x(lru_v2, BCH_VERSION(0, 26)) \
+ x(fragmentation_lru, BCH_VERSION(0, 27)) \
+ x(no_bps_in_alloc_keys, BCH_VERSION(0, 28)) \
+ x(snapshot_trees, BCH_VERSION(0, 29)) \
+ x(major_minor, BCH_VERSION(1, 0))
enum bcachefs_metadata_version {
bcachefs_metadata_version_min = 9,
@@ -1607,7 +1609,7 @@ enum bcachefs_metadata_version {
bcachefs_metadata_version_max
};
-static const unsigned bcachefs_metadata_required_upgrade_below = bcachefs_metadata_version_snapshot_trees;
+static const unsigned bcachefs_metadata_required_upgrade_below = bcachefs_metadata_version_major_minor;
#define bcachefs_metadata_version_current (bcachefs_metadata_version_max - 1)
@@ -1751,6 +1753,11 @@ LE64_BITMASK(BCH_SB_NOCOW, struct bch_sb, flags[4], 33, 34);
LE64_BITMASK(BCH_SB_WRITE_BUFFER_SIZE, struct bch_sb, flags[4], 34, 54);
LE64_BITMASK(BCH_SB_VERSION_UPGRADE, struct bch_sb, flags[4], 54, 56);
+/* flags[4] 56-64 unused: */
+
+LE64_BITMASK(BCH_SB_VERSION_UPGRADE_COMPLETE,
+ struct bch_sb, flags[5], 0, 16);
+
/*
* Features:
*
diff --git a/fs/bcachefs/btree_io.c b/fs/bcachefs/btree_io.c
index 990c2fa28114..54f8c8c76fbb 100644
--- a/fs/bcachefs/btree_io.c
+++ b/fs/bcachefs/btree_io.c
@@ -699,11 +699,11 @@ static int validate_bset(struct bch_fs *c, struct bch_dev *ca,
struct printbuf buf2 = PRINTBUF;
int ret = 0;
- btree_err_on((version != BCH_BSET_VERSION_OLD &&
- version < bcachefs_metadata_version_min) ||
- version >= bcachefs_metadata_version_max,
+ btree_err_on(!bch2_version_compatible(version),
BTREE_ERR_INCOMPATIBLE, c, ca, b, i,
- "unsupported bset version");
+ "unsupported bset version %u.%u",
+ BCH_VERSION_MAJOR(version),
+ BCH_VERSION_MINOR(version));
if (btree_err_on(version < c->sb.version_min,
BTREE_ERR_FIXABLE, c, NULL, b, i,
@@ -2019,9 +2019,7 @@ do_write:
BUG_ON(BSET_BIG_ENDIAN(i) != CPU_BIG_ENDIAN);
BUG_ON(i->seq != b->data->keys.seq);
- i->version = c->sb.version < bcachefs_metadata_version_bkey_renumber
- ? cpu_to_le16(BCH_BSET_VERSION_OLD)
- : cpu_to_le16(c->sb.version);
+ i->version = cpu_to_le16(c->sb.version);
SET_BSET_OFFSET(i, b->written);
SET_BSET_CSUM_TYPE(i, bch2_meta_checksum_type(c));
diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c
index 7d0dd1b1d5cf..49f2fe413d4f 100644
--- a/fs/bcachefs/journal_io.c
+++ b/fs/bcachefs/journal_io.c
@@ -745,14 +745,12 @@ static int jset_validate(struct bch_fs *c,
return JOURNAL_ENTRY_NONE;
version = le32_to_cpu(jset->version);
- if (journal_entry_err_on((version != BCH_JSET_VERSION_OLD &&
- version < bcachefs_metadata_version_min) ||
- version >= bcachefs_metadata_version_max,
- c, jset, NULL,
- "%s sector %llu seq %llu: unknown journal entry version %u",
+ if (journal_entry_err_on(!bch2_version_compatible(version), c, jset, NULL,
+ "%s sector %llu seq %llu: incompatible journal entry version %u.%u",
ca ? ca->name : c->name,
sector, le64_to_cpu(jset->seq),
- version)) {
+ BCH_VERSION_MAJOR(version),
+ BCH_VERSION_MINOR(version))) {
/* don't try to continue: */
return -EINVAL;
}
@@ -796,14 +794,12 @@ static int jset_validate_early(struct bch_fs *c,
return JOURNAL_ENTRY_NONE;
version = le32_to_cpu(jset->version);
- if (journal_entry_err_on((version != BCH_JSET_VERSION_OLD &&
- version < bcachefs_metadata_version_min) ||
- version >= bcachefs_metadata_version_max,
- c, jset, NULL,
- "%s sector %llu seq %llu: unknown journal entry version %u",
+ if (journal_entry_err_on(!bch2_version_compatible(version), c, jset, NULL,
+ "%s sector %llu seq %llu: unknown journal entry version %u.%u",
ca ? ca->name : c->name,
sector, le64_to_cpu(jset->seq),
- version)) {
+ BCH_VERSION_MAJOR(version),
+ BCH_VERSION_MINOR(version))) {
/* don't try to continue: */
return -EINVAL;
}
@@ -1755,9 +1751,7 @@ void bch2_journal_write(struct closure *cl)
}
jset->magic = cpu_to_le64(jset_magic(c));
- jset->version = c->sb.version < bcachefs_metadata_version_bkey_renumber
- ? cpu_to_le32(BCH_JSET_VERSION_OLD)
- : cpu_to_le32(c->sb.version);
+ jset->version = cpu_to_le32(c->sb.version);
SET_JSET_BIG_ENDIAN(jset, CPU_BIG_ENDIAN);
SET_JSET_CSUM_TYPE(jset, bch2_meta_checksum_type(c));
diff --git a/fs/bcachefs/opts.c b/fs/bcachefs/opts.c
index 647b2338acc9..0c0c83fa4264 100644
--- a/fs/bcachefs/opts.c
+++ b/fs/bcachefs/opts.c
@@ -11,11 +11,6 @@
#define x(t, n) [n] = #t,
-const char * const bch2_metadata_versions[] = {
- BCH_METADATA_VERSIONS()
- NULL
-};
-
const char * const bch2_error_actions[] = {
BCH_ERROR_ACTIONS()
NULL
diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h
index 9727e29f7766..e105a742fd44 100644
--- a/fs/bcachefs/opts.h
+++ b/fs/bcachefs/opts.h
@@ -8,7 +8,6 @@
#include <linux/sysfs.h>
#include "bcachefs_format.h"
-extern const char * const bch2_metadata_versions[];
extern const char * const bch2_error_actions[];
extern const char * const bch2_version_upgrade_opts[];
extern const char * const bch2_sb_features[];
diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c
index deb1c4f37007..0ed3f60b878c 100644
--- a/fs/bcachefs/recovery.c
+++ b/fs/bcachefs/recovery.c
@@ -1114,11 +1114,16 @@ static bool should_do_version_upgrade(struct bch_fs *c)
if (!c->opts.nochanges &&
c->sb.version < bcachefs_metadata_required_upgrade_below) {
- bch_info(c, "version %s (%u) prior to %s (%u), upgrade and fsck required",
- bch2_metadata_versions[c->sb.version],
- c->sb.version,
- bch2_metadata_versions[bcachefs_metadata_required_upgrade_below],
- bcachefs_metadata_required_upgrade_below);
+ struct printbuf buf = PRINTBUF;
+
+ prt_str(&buf, "version ");
+ bch2_version_to_text(&buf, c->sb.version_upgrade_complete ?: c->sb.version);
+ prt_str(&buf, " prior to ");
+ bch2_version_to_text(&buf, bcachefs_metadata_required_upgrade_below);
+ prt_str(&buf, ", upgrade and fsck required");
+
+ bch_info(c, "%s", buf.buf);
+ printbuf_exit(&buf);
c->opts.fsck = true;
c->opts.fix_errors = FSCK_OPT_YES;
return true;
@@ -1449,8 +1454,7 @@ use_clean:
mutex_lock(&c->sb_lock);
if (test_bit(BCH_FS_VERSION_UPGRADE, &c->flags)) {
- c->disk_sb.sb->version = cpu_to_le16(bcachefs_metadata_version_current);
- c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_SB_FEATURES_ALL);
+ SET_BCH_SB_VERSION_UPGRADE_COMPLETE(c->disk_sb.sb, bcachefs_metadata_version_current);
write_sb = true;
}
diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c
index 0acdcbfcec5c..ce3f100a2fab 100644
--- a/fs/bcachefs/super-io.c
+++ b/fs/bcachefs/super-io.c
@@ -23,6 +23,30 @@
#include <linux/backing-dev.h>
#include <linux/sort.h>
+struct bch2_metadata_version_str {
+ u16 version;
+ const char *name;
+};
+
+static const struct bch2_metadata_version_str bch2_metadata_versions[] = {
+#define x(n, v) { .version = v, .name = #n },
+ BCH_METADATA_VERSIONS()
+#undef x
+};
+
+void bch2_version_to_text(struct printbuf *out, unsigned v)
+{
+ const char *str = "(unknown version)";
+
+ 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;
+ }
+
+ prt_printf(out, "%u.%u: %s", BCH_VERSION_MAJOR(v), BCH_VERSION_MINOR(v), str);
+}
+
const char * const bch2_sb_fields[] = {
#define x(name, nr) #name,
BCH_SB_FIELDS()
@@ -250,40 +274,58 @@ static int validate_sb_layout(struct bch_sb_layout *layout, struct printbuf *out
return 0;
}
-static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
- int rw)
+static int bch2_sb_compatible(struct bch_sb *sb, struct printbuf *out)
{
- struct bch_sb *sb = disk_sb->sb;
- struct bch_sb_field *f;
- struct bch_sb_field_members *mi;
- enum bch_opt_id opt_id;
- u32 version, version_min;
- u16 block_size;
- int ret;
-
- version = le16_to_cpu(sb->version);
- version_min = version >= bcachefs_metadata_version_bkey_renumber
- ? le16_to_cpu(sb->version_min)
- : 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);
+ u16 version = le16_to_cpu(sb->version);
+ u16 version_min = le16_to_cpu(sb->version_min);
+
+ if (!bch2_version_compatible(version)) {
+ prt_str(out, "Unsupported superblock version ");
+ bch2_version_to_text(out, version);
+ 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;
}
- if (version_min < bcachefs_metadata_version_min) {
- prt_printf(out, "Unsupported superblock version %u (min %u, max %u)",
- version_min, bcachefs_metadata_version_min, bcachefs_metadata_version_max);
+ if (!bch2_version_compatible(version_min)) {
+ prt_str(out, "Unsupported superblock version_min ");
+ 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;
}
if (version_min > version) {
- prt_printf(out, "Bad minimum version %u, greater than version field %u",
- 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;
}
+ 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] ||
(le64_to_cpu(sb->features[0]) & (~0ULL << BCH_FEATURE_NR))) {
prt_printf(out, "Filesystem has incompatible features");
@@ -331,7 +373,7 @@ static int bch2_sb_validate(struct bch_sb_handle *disk_sb, struct printbuf *out,
if (rw == READ) {
/*
* 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:
*/
if (!BCH_SB_JOURNAL_FLUSH_DELAY(sb))
@@ -412,6 +454,7 @@ static void bch2_sb_update(struct bch_fs *c)
c->sb.user_uuid = src->user_uuid;
c->sb.version = le16_to_cpu(src->version);
c->sb.version_min = le16_to_cpu(src->version_min);
+ c->sb.version_upgrade_complete = BCH_SB_VERSION_UPGRADE_COMPLETE(src);
c->sb.nr_devices = src->nr_devices;
c->sb.clean = BCH_SB_CLEAN(src);
c->sb.encryption_type = BCH_SB_ENCRYPTION_TYPE(src);
@@ -512,7 +555,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)
{
struct bch_csum csum;
- u32 version, version_min;
size_t bytes;
int ret;
reread:
@@ -532,22 +574,9 @@ reread:
return -BCH_ERR_invalid_sb_magic;
}
- version = le16_to_cpu(sb->sb->version);
- version_min = version >= bcachefs_metadata_version_bkey_renumber
- ? le16_to_cpu(sb->sb->version_min)
- : 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;
- }
+ ret = bch2_sb_compatible(sb->sb, err);
+ if (ret)
+ return ret;
bytes = vstruct_bytes(sb->sb);
@@ -1169,7 +1198,19 @@ int bch2_fs_mark_dirty(struct bch_fs *c)
mutex_lock(&c->sb_lock);
SET_BCH_SB_CLEAN(c->disk_sb.sb, false);
+
+ 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 (test_bit(BCH_FS_VERSION_UPGRADE, &c->flags) ||
+ c->sb.version > bcachefs_metadata_version_current)
+ c->disk_sb.sb->version = cpu_to_le16(bcachefs_metadata_version_current);
+
+ if (test_bit(BCH_FS_VERSION_UPGRADE, &c->flags))
+ c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_SB_FEATURES_ALL);
+
c->disk_sb.sb->features[0] |= cpu_to_le64(BCH_SB_FEATURES_ALWAYS);
+
c->disk_sb.sb->compat[0] &= cpu_to_le64((1ULL << BCH_COMPAT_NR) - 1);
ret = bch2_write_super(c);
mutex_unlock(&c->sb_lock);
@@ -1503,12 +1544,17 @@ void bch2_sb_to_text(struct printbuf *out, struct bch_sb *sb,
prt_str(out, "Version:");
prt_tab(out);
- prt_printf(out, "%s", bch2_metadata_versions[le16_to_cpu(sb->version)]);
+ bch2_version_to_text(out, le16_to_cpu(sb->version));
+ prt_newline(out);
+
+ prt_str(out, "Version upgrade complete:");
+ prt_tab(out);
+ bch2_version_to_text(out, BCH_SB_VERSION_UPGRADE_COMPLETE(sb));
prt_newline(out);
prt_printf(out, "Oldest version on disk:");
prt_tab(out);
- prt_printf(out, "%s", bch2_metadata_versions[le16_to_cpu(sb->version_min)]);
+ bch2_version_to_text(out, le16_to_cpu(sb->version_min));
prt_newline(out);
prt_printf(out, "Created:");
diff --git a/fs/bcachefs/super-io.h b/fs/bcachefs/super-io.h
index ab0ad3248e8f..a5a80c481242 100644
--- a/fs/bcachefs/super-io.h
+++ b/fs/bcachefs/super-io.h
@@ -9,6 +9,14 @@
#include <asm/byteorder.h>
+static inline bool bch2_version_compatible(u16 version)
+{
+ return BCH_VERSION_MAJOR(version) <= BCH_VERSION_MAJOR(bcachefs_metadata_version_current) &&
+ version >= bcachefs_metadata_version_min;
+}
+
+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_resize(struct bch_sb_handle *,
enum bch_sb_field_type, unsigned);
diff --git a/fs/bcachefs/super.c b/fs/bcachefs/super.c
index bb648cadd712..d342e3ba91d9 100644
--- a/fs/bcachefs/super.c
+++ b/fs/bcachefs/super.c
@@ -876,7 +876,8 @@ static void print_mount_opts(struct bch_fs *c)
struct printbuf p = PRINTBUF;
bool first = true;
- prt_printf(&p, "mounted version=%s", bch2_metadata_versions[c->sb.version]);
+ prt_str(&p, "mounted version=");
+ bch2_version_to_text(&p, c->sb.version);
if (c->opts.read_only) {
prt_str(&p, " opts=");