bcachefs: Fix compat code for superblock
authorKent Overstreet <kent.overstreet@gmail.com>
Fri, 5 Mar 2021 00:06:26 +0000 (19:06 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:55 +0000 (17:08 -0400)
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>
fs/bcachefs/bcachefs_format.h
fs/bcachefs/journal_io.c
fs/bcachefs/journal_io.h
fs/bcachefs/recovery.c
fs/bcachefs/super-io.c
fs/bcachefs/super-io.h

index 17cc6131de0cfd0465a816c5f22e5c8b332774db..5d0e340c4dcbd94b972b22c9b1afb73ce770eacd 100644 (file)
@@ -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 */
 
index 756154b855267d07a6909541ce41a79555383c37..7783a874640a1e367985e662666042e0a547958a 100644 (file)
@@ -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;
        }
index a4931ab93a68dc0a18415a141aee4094d4d87e3e..f34281a28f12bc64f06dc62383c16af1f3389129 100644 (file)
@@ -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 *);
index b68fcd1d19e421081f8213df833bb222b5e3552d..11d4894b3d633b08ec4d7eb02e3a90d51798c11b 100644 (file)
@@ -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);
 
index f843a3b34ba239299a891ee465f38f0acd030fe3..6e61cf5ab2174e25f2d8719a6808e3b2106a6b91 100644 (file)
@@ -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:
index dd8d4ba911f0393ff18a2d4789de313df3a6e6e5..62d040d571c086373c7f5d7d186de5f5fc37cffe 100644 (file)
@@ -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 *);