diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2021-03-04 19:06:26 -0500 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 17:08:55 -0400 |
commit | 7d6f07edc28c3c34bad7e6a92921e3fbf8c8dd4e (patch) | |
tree | 395f866b3f9dd9b2fb49923160c3fe12dfc495cb /fs | |
parent | 61a19ce4255abd1133d4e7cd64a6cfa40d1f37fa (diff) |
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: Kent Overstreet <kent.overstreet@gmail.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/bcachefs_format.h | 1 | ||||
-rw-r--r-- | fs/bcachefs/journal_io.c | 108 | ||||
-rw-r--r-- | fs/bcachefs/journal_io.h | 3 | ||||
-rw-r--r-- | fs/bcachefs/recovery.c | 8 | ||||
-rw-r--r-- | fs/bcachefs/super-io.c | 31 | ||||
-rw-r--r-- | fs/bcachefs/super-io.h | 2 |
6 files changed, 88 insertions, 65 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index 17cc6131de0c..5d0e340c4dcb 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -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_REFLINK, struct bch_sb, flags[0], 61, 62); +LE64_BITMASK(BCH_SB_BIG_ENDIAN, struct bch_sb, flags[0], 62, 63); /* 61-64 unused */ diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index 756154b85526..7783a874640a 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -201,22 +201,19 @@ static void journal_entry_null_range(void *start, void *end) #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, unsigned level, enum btree_id btree_id, - struct bkey_i *k, - const char *type, int write) + struct bkey_i *k, const char *type, + unsigned version, int big_endian, int write) { void *next = vstruct_next(entry); const char *invalid; - unsigned version = le32_to_cpu(jset->version); int ret = 0; if (journal_entry_err_on(!k->k.u64s, c, - "invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: k->u64s 0", - type, le64_to_cpu(jset->seq), - (u64 *) entry - jset->_data, - le32_to_cpu(jset->u64s), + "invalid %s in %s entry offset %zi/%u: k->u64s 0", + type, where, (u64 *) k - entry->_data, le16_to_cpu(entry->u64s))) { 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, if (journal_entry_err_on((void *) bkey_next(k) > (void *) vstruct_next(entry), c, - "invalid %s in jset %llu offset %zi/%u entry offset %zi/%u: extends past end of journal entry", - type, le64_to_cpu(jset->seq), - (u64 *) entry - jset->_data, - le32_to_cpu(jset->u64s), + "invalid %s in %s entry offset %zi/%u: extends past end of journal entry", + type, where, (u64 *) k - entry->_data, le16_to_cpu(entry->u64s))) { 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, } 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", - type, le64_to_cpu(jset->seq), - (u64 *) entry - jset->_data, - le32_to_cpu(jset->u64s), + "invalid %s in %s entry offset %zi/%u: bad format %u", + type, where, (u64 *) k - entry->_data, le16_to_cpu(entry->u64s), k->k.format)) { @@ -252,9 +245,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, } if (!write) - bch2_bkey_compat(level, btree_id, version, - JSET_BIG_ENDIAN(jset), write, - NULL, bkey_to_packed(k)); + bch2_bkey_compat(level, btree_id, version, big_endian, + write, NULL, bkey_to_packed(k)); invalid = bch2_bkey_invalid(c, bkey_i_to_s_c(k), __btree_node_type(level, btree_id)); @@ -262,10 +254,8 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, char buf[160]; 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", - type, le64_to_cpu(jset->seq), - (u64 *) entry - jset->_data, - le32_to_cpu(jset->u64s), + mustfix_fsck_err(c, "invalid %s in %s entry offset %zi/%u: %s\n%s", + type, where, (u64 *) k - entry->_data, le16_to_cpu(entry->u64s), invalid, buf); @@ -277,25 +267,24 @@ static int journal_validate_key(struct bch_fs *c, struct jset *jset, } if (write) - bch2_bkey_compat(level, btree_id, version, - JSET_BIG_ENDIAN(jset), write, - NULL, bkey_to_packed(k)); + bch2_bkey_compat(level, btree_id, version, big_endian, + write, NULL, bkey_to_packed(k)); fsck_err: return ret; } static int journal_entry_validate_btree_keys(struct bch_fs *c, - struct jset *jset, + const char *where, struct jset_entry *entry, - int write) + unsigned version, int big_endian, int write) { struct bkey_i *k = entry->start; while (k != vstruct_last(entry)) { - int ret = journal_validate_key(c, jset, entry, + int ret = journal_validate_key(c, where, entry, entry->level, entry->btree_id, - k, "key", write); + k, "key", version, big_endian, write); if (ret == FSCK_DELETED_KEY) continue; @@ -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, - struct jset *jset, + const char *where, struct jset_entry *entry, - int write) + unsigned version, int big_endian, int write) { struct bkey_i *k = entry->start; int ret = 0; @@ -327,25 +316,25 @@ static int journal_entry_validate_btree_root(struct bch_fs *c, return 0; } - return journal_validate_key(c, jset, entry, 1, entry->btree_id, k, - "btree root", write); + return journal_validate_key(c, where, entry, 1, entry->btree_id, k, + "btree root", version, big_endian, write); fsck_err: return ret; } static int journal_entry_validate_prio_ptrs(struct bch_fs *c, - struct jset *jset, + const char *where, struct jset_entry *entry, - int write) + unsigned version, int big_endian, int write) { /* obsolete, don't care: */ return 0; } static int journal_entry_validate_blacklist(struct bch_fs *c, - struct jset *jset, + const char *where, struct jset_entry *entry, - int write) + unsigned version, int big_endian, int write) { int ret = 0; @@ -358,9 +347,9 @@ fsck_err: } static int journal_entry_validate_blacklist_v2(struct bch_fs *c, - struct jset *jset, + const char *where, struct jset_entry *entry, - int write) + unsigned version, int big_endian, int write) { struct jset_entry_blacklist_v2 *bl_entry; int ret = 0; @@ -384,9 +373,9 @@ fsck_err: } static int journal_entry_validate_usage(struct bch_fs *c, - struct jset *jset, + const char *where, struct jset_entry *entry, - int write) + unsigned version, int big_endian, int write) { struct jset_entry_usage *u = container_of(entry, struct jset_entry_usage, entry); @@ -405,9 +394,9 @@ fsck_err: } static int journal_entry_validate_data_usage(struct bch_fs *c, - struct jset *jset, + const char *where, struct jset_entry *entry, - int write) + unsigned version, int big_endian, int write) { struct jset_entry_data_usage *u = container_of(entry, struct jset_entry_data_usage, entry); @@ -427,9 +416,9 @@ fsck_err: } static int journal_entry_validate_clock(struct bch_fs *c, - struct jset *jset, + const char *where, struct jset_entry *entry, - int write) + unsigned version, int big_endian, int write) { struct jset_entry_clock *clock = container_of(entry, struct jset_entry_clock, entry); @@ -453,9 +442,9 @@ fsck_err: } static int journal_entry_validate_dev_usage(struct bch_fs *c, - struct jset *jset, + const char *where, struct jset_entry *entry, - int write) + unsigned version, int big_endian, int write) { struct jset_entry_dev_usage *u = container_of(entry, struct jset_entry_dev_usage, entry); @@ -490,8 +479,8 @@ fsck_err: } struct jset_entry_ops { - int (*validate)(struct bch_fs *, struct jset *, - struct jset_entry *, int); + int (*validate)(struct bch_fs *, const char *, + struct jset_entry *, unsigned, int, int); }; 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 }; -static int journal_entry_validate(struct bch_fs *c, struct jset *jset, - struct jset_entry *entry, int write) +int bch2_journal_entry_validate(struct bch_fs *c, const char *where, + struct jset_entry *entry, + unsigned version, int big_endian, int write) { return entry->type < BCH_JSET_ENTRY_NR - ? bch2_jset_entry_ops[entry->type].validate(c, jset, - entry, write) + ? bch2_jset_entry_ops[entry->type].validate(c, where, entry, + version, big_endian, write) : 0; } static int jset_validate_entries(struct bch_fs *c, struct jset *jset, int write) { + char buf[100]; struct jset_entry *entry; int ret = 0; 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) > vstruct_last(jset), c, "journal entry extends past end of jset")) { @@ -526,7 +522,9 @@ static int jset_validate_entries(struct bch_fs *c, struct jset *jset, 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) break; } diff --git a/fs/bcachefs/journal_io.h b/fs/bcachefs/journal_io.h index a4931ab93a68..f34281a28f12 100644 --- a/fs/bcachefs/journal_io.h +++ b/fs/bcachefs/journal_io.h @@ -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) \ 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 *); void bch2_journal_write(struct closure *); diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index b68fcd1d19e4..11d4894b3d63 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -908,9 +908,11 @@ static struct bch_sb_field_clean *read_superblock_clean(struct bch_fs *c) return ERR_PTR(-ENOMEM); } - if (le16_to_cpu(c->disk_sb.sb->version) < - bcachefs_metadata_version_bkey_renumber) - bch2_sb_clean_renumber(clean, READ); + ret = bch2_sb_clean_validate(c, clean, READ); + if (ret) { + mutex_unlock(&c->sb_lock); + return ERR_PTR(ret); + } mutex_unlock(&c->sb_lock); diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c index f843a3b34ba2..6e61cf5ab217 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -9,6 +9,7 @@ #include "error.h" #include "io.h" #include "journal.h" +#include "journal_io.h" #include "journal_seq_blacklist.h" #include "replicas.h" #include "quota.h" @@ -715,6 +716,8 @@ int bch2_write_super(struct bch_fs *c) if (test_bit(BCH_FS_ERROR, &c->flags)) 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) bch2_sb_from_fs(c, ca); @@ -938,14 +941,23 @@ static const struct bch_sb_field_ops bch_sb_field_ops_crypt = { /* 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; + int ret; for (entry = clean->start; entry < (struct jset_entry *) vstruct_end(&clean->field); - entry = vstruct_next(entry)) - bch2_bkey_renumber(BKEY_TYPE_btree, bkey_to_packed(entry->start), write); + entry = vstruct_next(entry)) { + 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) @@ -1079,6 +1091,7 @@ void bch2_fs_mark_clean(struct bch_fs *c) struct bch_sb_field_clean *sb_clean; struct jset_entry *entry; unsigned u64s; + int ret; mutex_lock(&c->sb_lock); if (BCH_SB_CLEAN(c->disk_sb.sb)) @@ -1113,9 +1126,15 @@ void bch2_fs_mark_clean(struct bch_fs *c) memset(entry, 0, vstruct_end(&sb_clean->field) - (void *) entry); - if (le16_to_cpu(c->disk_sb.sb->version) < - bcachefs_metadata_version_bkey_renumber) - bch2_sb_clean_renumber(sb_clean, WRITE); + /* + * this should be in the write path, and we should be validating every + * 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); out: diff --git a/fs/bcachefs/super-io.h b/fs/bcachefs/super-io.h index dd8d4ba911f0..62d040d571c0 100644 --- a/fs/bcachefs/super-io.h +++ b/fs/bcachefs/super-io.h @@ -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 *, 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 *); void bch2_fs_mark_clean(struct bch_fs *); |