Commit 7d6f07ed authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

bcachefs: Fix compat code for superblock

The bkey compat code wasn't being run for btree roots in the superblock
clean section - this patch fixes it to use the journal entry validate
code.
Signed-off-by: default avatarKent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: default avatarKent Overstreet <kent.overstreet@linux.dev>
parent 61a19ce4
...@@ -1314,6 +1314,7 @@ LE64_BITMASK(BCH_SB_PRJQUOTA, struct bch_sb, flags[0], 59, 60); ...@@ -1314,6 +1314,7 @@ LE64_BITMASK(BCH_SB_PRJQUOTA, struct bch_sb, flags[0], 59, 60);
LE64_BITMASK(BCH_SB_HAS_ERRORS, struct bch_sb, flags[0], 60, 61); LE64_BITMASK(BCH_SB_HAS_ERRORS, struct bch_sb, flags[0], 60, 61);
LE64_BITMASK(BCH_SB_REFLINK, struct bch_sb, flags[0], 61, 62); LE64_BITMASK(BCH_SB_REFLINK, struct bch_sb, flags[0], 61, 62);
LE64_BITMASK(BCH_SB_BIG_ENDIAN, struct bch_sb, flags[0], 62, 63);
/* 61-64 unused */ /* 61-64 unused */
......
...@@ -201,22 +201,19 @@ static void journal_entry_null_range(void *start, void *end) ...@@ -201,22 +201,19 @@ static void journal_entry_null_range(void *start, void *end)
#define FSCK_DELETED_KEY 5 #define FSCK_DELETED_KEY 5
static int journal_validate_key(struct bch_fs *c, struct jset *jset, static int journal_validate_key(struct bch_fs *c, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
unsigned level, enum btree_id btree_id, unsigned level, enum btree_id btree_id,
struct bkey_i *k, struct bkey_i *k, const char *type,
const char *type, int write) unsigned version, int big_endian, int write)
{ {
void *next = vstruct_next(entry); void *next = vstruct_next(entry);
const char *invalid; const char *invalid;
unsigned version = le32_to_cpu(jset->version);
int ret = 0; int ret = 0;
if (journal_entry_err_on(!k->k.u64s, c, if (journal_entry_err_on(!k->k.u64s, c,
"invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: k->u64s 0", "invalid %s in %s entry offset %zi/%u: k->u64s 0",
type, le64_to_cpu(jset->seq), type, where,
(u64 *) entry - jset->_data,
le32_to_cpu(jset->u64s),
(u64 *) k - entry->_data, (u64 *) k - entry->_data,
le16_to_cpu(entry->u64s))) { le16_to_cpu(entry->u64s))) {
entry->u64s = cpu_to_le16((u64 *) k - entry->_data); entry->u64s = cpu_to_le16((u64 *) k - entry->_data);
...@@ -226,10 +223,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, ...@@ -226,10 +223,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset,
if (journal_entry_err_on((void *) bkey_next(k) > if (journal_entry_err_on((void *) bkey_next(k) >
(void *) vstruct_next(entry), c, (void *) vstruct_next(entry), c,
"invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: extends past end of journal entry", "invalid %s in %s entry offset %zi/%u: extends past end of journal entry",
type, le64_to_cpu(jset->seq), type, where,
(u64 *) entry - jset->_data,
le32_to_cpu(jset->u64s),
(u64 *) k - entry->_data, (u64 *) k - entry->_data,
le16_to_cpu(entry->u64s))) { le16_to_cpu(entry->u64s))) {
entry->u64s = cpu_to_le16((u64 *) k - entry->_data); entry->u64s = cpu_to_le16((u64 *) k - entry->_data);
...@@ -238,10 +233,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, ...@@ -238,10 +233,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset,
} }
if (journal_entry_err_on(k->k.format != KEY_FORMAT_CURRENT, c, if (journal_entry_err_on(k->k.format != KEY_FORMAT_CURRENT, c,
"invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: bad format %u", "invalid %s in %s entry offset %zi/%u: bad format %u",
type, le64_to_cpu(jset->seq), type, where,
(u64 *) entry - jset->_data,
le32_to_cpu(jset->u64s),
(u64 *) k - entry->_data, (u64 *) k - entry->_data,
le16_to_cpu(entry->u64s), le16_to_cpu(entry->u64s),
k->k.format)) { k->k.format)) {
...@@ -252,9 +245,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, ...@@ -252,9 +245,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset,
} }
if (!write) if (!write)
bch2_bkey_compat(level, btree_id, version, bch2_bkey_compat(level, btree_id, version, big_endian,
JSET_BIG_ENDIAN(jset), write, write, NULL, bkey_to_packed(k));
NULL, bkey_to_packed(k));
invalid = bch2_bkey_invalid(c, bkey_i_to_s_c(k), invalid = bch2_bkey_invalid(c, bkey_i_to_s_c(k),
__btree_node_type(level, btree_id)); __btree_node_type(level, btree_id));
...@@ -262,10 +254,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, ...@@ -262,10 +254,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset,
char buf[160]; char buf[160];
bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(k)); bch2_bkey_val_to_text(&PBUF(buf), c, bkey_i_to_s_c(k));
mustfix_fsck_err(c, "invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: %s\n%s", mustfix_fsck_err(c, "invalid %s in %s entry offset %zi/%u: %s\n%s",
type, le64_to_cpu(jset->seq), type, where,
(u64 *) entry - jset->_data,
le32_to_cpu(jset->u64s),
(u64 *) k - entry->_data, (u64 *) k - entry->_data,
le16_to_cpu(entry->u64s), le16_to_cpu(entry->u64s),
invalid, buf); invalid, buf);
...@@ -277,25 +267,24 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, ...@@ -277,25 +267,24 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset,
} }
if (write) if (write)
bch2_bkey_compat(level, btree_id, version, bch2_bkey_compat(level, btree_id, version, big_endian,
JSET_BIG_ENDIAN(jset), write, write, NULL, bkey_to_packed(k));
NULL, bkey_to_packed(k));
fsck_err: fsck_err:
return ret; return ret;
} }
static int journal_entry_validate_btree_keys(struct bch_fs *c, static int journal_entry_validate_btree_keys(struct bch_fs *c,
struct jset *jset, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
int write) unsigned version, int big_endian, int write)
{ {
struct bkey_i *k = entry->start; struct bkey_i *k = entry->start;
while (k != vstruct_last(entry)) { while (k != vstruct_last(entry)) {
int ret = journal_validate_key(c, jset, entry, int ret = journal_validate_key(c, where, entry,
entry->level, entry->level,
entry->btree_id, entry->btree_id,
k, "key", write); k, "key", version, big_endian, write);
if (ret == FSCK_DELETED_KEY) if (ret == FSCK_DELETED_KEY)
continue; continue;
...@@ -306,9 +295,9 @@ static int journal_entry_validate_btree_keys(struct bch_fs *c, ...@@ -306,9 +295,9 @@ static int journal_entry_validate_btree_keys(struct bch_fs *c,
} }
static int journal_entry_validate_btree_root(struct bch_fs *c, static int journal_entry_validate_btree_root(struct bch_fs *c,
struct jset *jset, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
int write) unsigned version, int big_endian, int write)
{ {
struct bkey_i *k = entry->start; struct bkey_i *k = entry->start;
int ret = 0; int ret = 0;
...@@ -327,25 +316,25 @@ static int journal_entry_validate_btree_root(struct bch_fs *c, ...@@ -327,25 +316,25 @@ static int journal_entry_validate_btree_root(struct bch_fs *c,
return 0; return 0;
} }
return journal_validate_key(c, jset, entry, 1, entry->btree_id, k, return journal_validate_key(c, where, entry, 1, entry->btree_id, k,
"btree root", write); "btree root", version, big_endian, write);
fsck_err: fsck_err:
return ret; return ret;
} }
static int journal_entry_validate_prio_ptrs(struct bch_fs *c, static int journal_entry_validate_prio_ptrs(struct bch_fs *c,
struct jset *jset, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
int write) unsigned version, int big_endian, int write)
{ {
/* obsolete, don't care: */ /* obsolete, don't care: */
return 0; return 0;
} }
static int journal_entry_validate_blacklist(struct bch_fs *c, static int journal_entry_validate_blacklist(struct bch_fs *c,
struct jset *jset, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
int write) unsigned version, int big_endian, int write)
{ {
int ret = 0; int ret = 0;
...@@ -358,9 +347,9 @@ static int journal_entry_validate_blacklist(struct bch_fs *c, ...@@ -358,9 +347,9 @@ static int journal_entry_validate_blacklist(struct bch_fs *c,
} }
static int journal_entry_validate_blacklist_v2(struct bch_fs *c, static int journal_entry_validate_blacklist_v2(struct bch_fs *c,
struct jset *jset, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
int write) unsigned version, int big_endian, int write)
{ {
struct jset_entry_blacklist_v2 *bl_entry; struct jset_entry_blacklist_v2 *bl_entry;
int ret = 0; int ret = 0;
...@@ -384,9 +373,9 @@ static int journal_entry_validate_blacklist_v2(struct bch_fs *c, ...@@ -384,9 +373,9 @@ static int journal_entry_validate_blacklist_v2(struct bch_fs *c,
} }
static int journal_entry_validate_usage(struct bch_fs *c, static int journal_entry_validate_usage(struct bch_fs *c,
struct jset *jset, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
int write) unsigned version, int big_endian, int write)
{ {
struct jset_entry_usage *u = struct jset_entry_usage *u =
container_of(entry, struct jset_entry_usage, entry); container_of(entry, struct jset_entry_usage, entry);
...@@ -405,9 +394,9 @@ static int journal_entry_validate_usage(struct bch_fs *c, ...@@ -405,9 +394,9 @@ static int journal_entry_validate_usage(struct bch_fs *c,
} }
static int journal_entry_validate_data_usage(struct bch_fs *c, static int journal_entry_validate_data_usage(struct bch_fs *c,
struct jset *jset, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
int write) unsigned version, int big_endian, int write)
{ {
struct jset_entry_data_usage *u = struct jset_entry_data_usage *u =
container_of(entry, struct jset_entry_data_usage, entry); container_of(entry, struct jset_entry_data_usage, entry);
...@@ -427,9 +416,9 @@ static int journal_entry_validate_data_usage(struct bch_fs *c, ...@@ -427,9 +416,9 @@ static int journal_entry_validate_data_usage(struct bch_fs *c,
} }
static int journal_entry_validate_clock(struct bch_fs *c, static int journal_entry_validate_clock(struct bch_fs *c,
struct jset *jset, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
int write) unsigned version, int big_endian, int write)
{ {
struct jset_entry_clock *clock = struct jset_entry_clock *clock =
container_of(entry, struct jset_entry_clock, entry); container_of(entry, struct jset_entry_clock, entry);
...@@ -453,9 +442,9 @@ static int journal_entry_validate_clock(struct bch_fs *c, ...@@ -453,9 +442,9 @@ static int journal_entry_validate_clock(struct bch_fs *c,
} }
static int journal_entry_validate_dev_usage(struct bch_fs *c, static int journal_entry_validate_dev_usage(struct bch_fs *c,
struct jset *jset, const char *where,
struct jset_entry *entry, struct jset_entry *entry,
int write) unsigned version, int big_endian, int write)
{ {
struct jset_entry_dev_usage *u = struct jset_entry_dev_usage *u =
container_of(entry, struct jset_entry_dev_usage, entry); container_of(entry, struct jset_entry_dev_usage, entry);
...@@ -490,8 +479,8 @@ static int journal_entry_validate_dev_usage(struct bch_fs *c, ...@@ -490,8 +479,8 @@ static int journal_entry_validate_dev_usage(struct bch_fs *c,
} }
struct jset_entry_ops { struct jset_entry_ops {
int (*validate)(struct bch_fs *, struct jset *, int (*validate)(struct bch_fs *, const char *,
struct jset_entry *, int); struct jset_entry *, unsigned, int, int);
}; };
static const struct jset_entry_ops bch2_jset_entry_ops[] = { static const struct jset_entry_ops bch2_jset_entry_ops[] = {
...@@ -503,22 +492,29 @@ static const struct jset_entry_ops bch2_jset_entry_ops[] = { ...@@ -503,22 +492,29 @@ static const struct jset_entry_ops bch2_jset_entry_ops[] = {
#undef x #undef x
}; };
static int journal_entry_validate(struct bch_fs *c, struct jset *jset, int bch2_journal_entry_validate(struct bch_fs *c, const char *where,
struct jset_entry *entry, int write) struct jset_entry *entry,
unsigned version, int big_endian, int write)
{ {
return entry->type < BCH_JSET_ENTRY_NR return entry->type < BCH_JSET_ENTRY_NR
? bch2_jset_entry_ops[entry->type].validate(c, jset, ? bch2_jset_entry_ops[entry->type].validate(c, where, entry,
entry, write) version, big_endian, write)
: 0; : 0;
} }
static int jset_validate_entries(struct bch_fs *c, struct jset *jset, static int jset_validate_entries(struct bch_fs *c, struct jset *jset,
int write) int write)
{ {
char buf[100];
struct jset_entry *entry; struct jset_entry *entry;
int ret = 0; int ret = 0;
vstruct_for_each(jset, entry) { vstruct_for_each(jset, entry) {
scnprintf(buf, sizeof(buf), "jset %llu entry offset %zi/%u",
le64_to_cpu(jset->seq),
(u64 *) entry - jset->_data,
le32_to_cpu(jset->u64s));
if (journal_entry_err_on(vstruct_next(entry) > if (journal_entry_err_on(vstruct_next(entry) >
vstruct_last(jset), c, vstruct_last(jset), c,
"journal entry extends past end of jset")) { "journal entry extends past end of jset")) {
...@@ -526,7 +522,9 @@ static int jset_validate_entries(struct bch_fs *c, struct jset *jset, ...@@ -526,7 +522,9 @@ static int jset_validate_entries(struct bch_fs *c, struct jset *jset,
break; break;
} }
ret = journal_entry_validate(c, jset, entry, write); ret = bch2_journal_entry_validate(c, buf, entry,
le32_to_cpu(jset->version),
JSET_BIG_ENDIAN(jset), write);
if (ret) if (ret)
break; break;
} }
......
...@@ -40,6 +40,9 @@ static inline struct jset_entry *__jset_entry_type_next(struct jset *jset, ...@@ -40,6 +40,9 @@ static inline struct jset_entry *__jset_entry_type_next(struct jset *jset,
for_each_jset_entry_type(entry, jset, BCH_JSET_ENTRY_btree_keys) \ for_each_jset_entry_type(entry, jset, BCH_JSET_ENTRY_btree_keys) \
vstruct_for_each_safe(entry, k, _n) vstruct_for_each_safe(entry, k, _n)
int bch2_journal_entry_validate(struct bch_fs *, const char *, struct jset_entry *,
unsigned, int, int);
int bch2_journal_read(struct bch_fs *, struct list_head *, u64 *, u64 *); int bch2_journal_read(struct bch_fs *, struct list_head *, u64 *, u64 *);
void bch2_journal_write(struct closure *); void bch2_journal_write(struct closure *);
......
...@@ -908,9 +908,11 @@ static struct bch_sb_field_clean *read_superblock_clean(struct bch_fs *c) ...@@ -908,9 +908,11 @@ static struct bch_sb_field_clean *read_superblock_clean(struct bch_fs *c)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
} }
if (le16_to_cpu(c->disk_sb.sb->version) < ret = bch2_sb_clean_validate(c, clean, READ);
bcachefs_metadata_version_bkey_renumber) if (ret) {
bch2_sb_clean_renumber(clean, READ); mutex_unlock(&c->sb_lock);
return ERR_PTR(ret);
}
mutex_unlock(&c->sb_lock); mutex_unlock(&c->sb_lock);
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "error.h" #include "error.h"
#include "io.h" #include "io.h"
#include "journal.h" #include "journal.h"
#include "journal_io.h"
#include "journal_seq_blacklist.h" #include "journal_seq_blacklist.h"
#include "replicas.h" #include "replicas.h"
#include "quota.h" #include "quota.h"
...@@ -715,6 +716,8 @@ int bch2_write_super(struct bch_fs *c) ...@@ -715,6 +716,8 @@ int bch2_write_super(struct bch_fs *c)
if (test_bit(BCH_FS_ERROR, &c->flags)) if (test_bit(BCH_FS_ERROR, &c->flags))
SET_BCH_SB_HAS_ERRORS(c->disk_sb.sb, 1); SET_BCH_SB_HAS_ERRORS(c->disk_sb.sb, 1);
SET_BCH_SB_BIG_ENDIAN(c->disk_sb.sb, CPU_BIG_ENDIAN);
for_each_online_member(ca, c, i) for_each_online_member(ca, c, i)
bch2_sb_from_fs(c, ca); bch2_sb_from_fs(c, ca);
...@@ -938,14 +941,23 @@ static const struct bch_sb_field_ops bch_sb_field_ops_crypt = { ...@@ -938,14 +941,23 @@ static const struct bch_sb_field_ops bch_sb_field_ops_crypt = {
/* BCH_SB_FIELD_clean: */ /* BCH_SB_FIELD_clean: */
void bch2_sb_clean_renumber(struct bch_sb_field_clean *clean, int write) int bch2_sb_clean_validate(struct bch_fs *c, struct bch_sb_field_clean *clean, int write)
{ {
struct jset_entry *entry; struct jset_entry *entry;
int ret;
for (entry = clean->start; for (entry = clean->start;
entry < (struct jset_entry *) vstruct_end(&clean->field); entry < (struct jset_entry *) vstruct_end(&clean->field);
entry = vstruct_next(entry)) entry = vstruct_next(entry)) {
bch2_bkey_renumber(BKEY_TYPE_btree, bkey_to_packed(entry->start), write); ret = bch2_journal_entry_validate(c, "superblock", entry,
le16_to_cpu(c->disk_sb.sb->version),
BCH_SB_BIG_ENDIAN(c->disk_sb.sb),
write);
if (ret)
return ret;
}
return 0;
} }
int bch2_fs_mark_dirty(struct bch_fs *c) int bch2_fs_mark_dirty(struct bch_fs *c)
...@@ -1079,6 +1091,7 @@ void bch2_fs_mark_clean(struct bch_fs *c) ...@@ -1079,6 +1091,7 @@ void bch2_fs_mark_clean(struct bch_fs *c)
struct bch_sb_field_clean *sb_clean; struct bch_sb_field_clean *sb_clean;
struct jset_entry *entry; struct jset_entry *entry;
unsigned u64s; unsigned u64s;
int ret;
mutex_lock(&c->sb_lock); mutex_lock(&c->sb_lock);
if (BCH_SB_CLEAN(c->disk_sb.sb)) if (BCH_SB_CLEAN(c->disk_sb.sb))
...@@ -1113,9 +1126,15 @@ void bch2_fs_mark_clean(struct bch_fs *c) ...@@ -1113,9 +1126,15 @@ void bch2_fs_mark_clean(struct bch_fs *c)
memset(entry, 0, memset(entry, 0,
vstruct_end(&sb_clean->field) - (void *) entry); vstruct_end(&sb_clean->field) - (void *) entry);
if (le16_to_cpu(c->disk_sb.sb->version) < /*
bcachefs_metadata_version_bkey_renumber) * this should be in the write path, and we should be validating every
bch2_sb_clean_renumber(sb_clean, WRITE); * superblock section:
*/
ret = bch2_sb_clean_validate(c, sb_clean, WRITE);
if (ret) {
bch_err(c, "error writing marking filesystem clean: validate error");
goto out;
}
bch2_write_super(c); bch2_write_super(c);
out: out:
......
...@@ -125,7 +125,7 @@ static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi) ...@@ -125,7 +125,7 @@ static inline struct bch_member_cpu bch2_mi_to_cpu(struct bch_member *mi)
void bch2_journal_super_entries_add_common(struct bch_fs *, void bch2_journal_super_entries_add_common(struct bch_fs *,
struct jset_entry **, u64); struct jset_entry **, u64);
void bch2_sb_clean_renumber(struct bch_sb_field_clean *, int); int bch2_sb_clean_validate(struct bch_fs *, struct bch_sb_field_clean *, int);
int bch2_fs_mark_dirty(struct bch_fs *); int bch2_fs_mark_dirty(struct bch_fs *);
void bch2_fs_mark_clean(struct bch_fs *); void bch2_fs_mark_clean(struct bch_fs *);
......
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