diff options
-rw-r--r-- | fs/bcachefs/journal_io.c | 160 | ||||
-rw-r--r-- | fs/bcachefs/journal_io.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/super-io.c | 2 |
3 files changed, 94 insertions, 70 deletions
diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index 090a718b917f..0c82f1048e21 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -186,30 +186,57 @@ static void journal_entry_null_range(void *start, void *end) #define JOURNAL_ENTRY_NONE 6 #define JOURNAL_ENTRY_BAD 7 -#define journal_entry_err(c, msg, ...) \ +static void journal_entry_err_msg(struct printbuf *out, + struct jset *jset, + struct jset_entry *entry) +{ + prt_str(out, "invalid journal entry "); + if (entry) + prt_printf(out, "%s ", bch2_jset_entry_types[entry->type]); + + if (!jset) + prt_printf(out, "in superblock"); + else if (!entry) + prt_printf(out, "at seq %llu", le64_to_cpu(jset->seq)); + else + prt_printf(out, "at offset %zi/%u seq %llu", + (u64 *) entry - jset->_data, + le32_to_cpu(jset->u64s), + le64_to_cpu(jset->seq)); + prt_str(out, ": "); +} + +#define journal_entry_err(c, jset, entry, msg, ...) \ ({ \ + struct printbuf buf = PRINTBUF; \ + \ + journal_entry_err_msg(&buf, jset, entry); \ + prt_printf(&buf, msg, ##__VA_ARGS__); \ + \ switch (write) { \ case READ: \ - mustfix_fsck_err(c, msg, ##__VA_ARGS__); \ + mustfix_fsck_err(c, "%s", buf.buf); \ break; \ case WRITE: \ - bch_err(c, "corrupt metadata before write:\n" \ - msg, ##__VA_ARGS__); \ + bch_err(c, "corrupt metadata before write: %s\n", buf.buf);\ if (bch2_fs_inconsistent(c)) { \ ret = -BCH_ERR_fsck_errors_not_fixed; \ goto fsck_err; \ } \ break; \ } \ + \ + printbuf_exit(&buf); \ true; \ }) -#define journal_entry_err_on(cond, c, msg, ...) \ - ((cond) ? journal_entry_err(c, msg, ##__VA_ARGS__) : false) +#define journal_entry_err_on(cond, c, jset, entry, msg, ...) \ + ((cond) ? journal_entry_err(c, jset, entry, msg, ##__VA_ARGS__) : false) #define FSCK_DELETED_KEY 5 -static int journal_validate_key(struct bch_fs *c, const char *where, +static int journal_validate_key(struct bch_fs *c, + struct jset *jset, struct jset_entry *entry, unsigned level, enum btree_id btree_id, struct bkey_i *k, @@ -219,33 +246,24 @@ static int journal_validate_key(struct bch_fs *c, const char *where, struct printbuf buf = PRINTBUF; int ret = 0; - if (journal_entry_err_on(!k->k.u64s, c, - "invalid key in %s at %s offset %zi/%u: k->u64s 0", - bch2_jset_entry_types[entry->type], where, - (u64 *) k - entry->_data, - le16_to_cpu(entry->u64s))) { + if (journal_entry_err_on(!k->k.u64s, c, jset, entry, "k->u64s 0")) { entry->u64s = cpu_to_le16((u64 *) k - entry->_data); journal_entry_null_range(vstruct_next(entry), next); return FSCK_DELETED_KEY; } if (journal_entry_err_on((void *) bkey_next(k) > - (void *) vstruct_next(entry), c, - "invalid key in %s at %s offset %zi/%u: extends past end of journal entry", - bch2_jset_entry_types[entry->type], where, - (u64 *) k - entry->_data, - le16_to_cpu(entry->u64s))) { + (void *) vstruct_next(entry), + c, jset, entry, + "extends past end of journal entry")) { entry->u64s = cpu_to_le16((u64 *) k - entry->_data); journal_entry_null_range(vstruct_next(entry), next); return FSCK_DELETED_KEY; } - if (journal_entry_err_on(k->k.format != KEY_FORMAT_CURRENT, c, - "invalid key in %s at %s offset %zi/%u: bad format %u", - bch2_jset_entry_types[entry->type], where, - (u64 *) k - entry->_data, - le16_to_cpu(entry->u64s), - k->k.format)) { + if (journal_entry_err_on(k->k.format != KEY_FORMAT_CURRENT, + c, jset, entry, + "bad format %u", k->k.format)) { le16_add_cpu(&entry->u64s, -((u16) k->k.u64s)); memmove(k, bkey_next(k), next - (void *) bkey_next(k)); journal_entry_null_range(vstruct_next(entry), next); @@ -259,10 +277,11 @@ static int journal_validate_key(struct bch_fs *c, const char *where, if (bch2_bkey_invalid(c, bkey_i_to_s_c(k), __btree_node_type(level, btree_id), write, &buf)) { printbuf_reset(&buf); - prt_printf(&buf, "invalid key in %s at %s offset %zi/%u:", - bch2_jset_entry_types[entry->type], where, - (u64 *) k - entry->_data, - le16_to_cpu(entry->u64s)); + prt_printf(&buf, "invalid journal entry %s at offset %zi/%u seq %llu:", + bch2_jset_entry_types[entry->type], + (u64 *) entry - jset->_data, + le32_to_cpu(jset->u64s), + le64_to_cpu(jset->seq)); prt_newline(&buf); printbuf_indent_add(&buf, 2); @@ -290,14 +309,14 @@ fsck_err: } static int journal_entry_btree_keys_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { struct bkey_i *k = entry->start; while (k != vstruct_last(entry)) { - int ret = journal_validate_key(c, where, entry, + int ret = journal_validate_key(c, jset, entry, entry->level, entry->btree_id, k, version, big_endian, write); @@ -328,7 +347,7 @@ static void journal_entry_btree_keys_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_btree_root_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { @@ -336,7 +355,8 @@ static int journal_entry_btree_root_validate(struct bch_fs *c, int ret = 0; if (journal_entry_err_on(!entry->u64s || - le16_to_cpu(entry->u64s) != k->k.u64s, c, + le16_to_cpu(entry->u64s) != k->k.u64s, + c, jset, entry, "invalid btree root journal entry: wrong number of keys")) { void *next = vstruct_next(entry); /* @@ -349,7 +369,7 @@ static int journal_entry_btree_root_validate(struct bch_fs *c, return 0; } - return journal_validate_key(c, where, entry, 1, entry->btree_id, k, + return journal_validate_key(c, jset, entry, 1, entry->btree_id, k, version, big_endian, write); fsck_err: return ret; @@ -362,7 +382,7 @@ static void journal_entry_btree_root_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_prio_ptrs_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { @@ -376,13 +396,14 @@ static void journal_entry_prio_ptrs_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_blacklist_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { int ret = 0; - if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 1, c, + if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 1, + c, jset, entry, "invalid journal seq blacklist entry: bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); } @@ -400,14 +421,15 @@ static void journal_entry_blacklist_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_blacklist_v2_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { struct jset_entry_blacklist_v2 *bl_entry; int ret = 0; - if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 2, c, + if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 2, + c, jset, entry, "invalid journal seq blacklist entry: bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); goto out; @@ -416,7 +438,8 @@ static int journal_entry_blacklist_v2_validate(struct bch_fs *c, bl_entry = container_of(entry, struct jset_entry_blacklist_v2, entry); if (journal_entry_err_on(le64_to_cpu(bl_entry->start) > - le64_to_cpu(bl_entry->end), c, + le64_to_cpu(bl_entry->end), + c, jset, entry, "invalid journal seq blacklist entry: start > end")) { journal_entry_null_range(entry, vstruct_next(entry)); } @@ -437,7 +460,7 @@ static void journal_entry_blacklist_v2_to_text(struct printbuf *out, struct bch_ } static int journal_entry_usage_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { @@ -447,7 +470,7 @@ static int journal_entry_usage_validate(struct bch_fs *c, int ret = 0; if (journal_entry_err_on(bytes < sizeof(*u), - c, + c, jset, entry, "invalid journal entry usage: bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; @@ -469,7 +492,7 @@ static void journal_entry_usage_to_text(struct printbuf *out, struct bch_fs *c, } static int journal_entry_data_usage_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { @@ -480,7 +503,7 @@ static int journal_entry_data_usage_validate(struct bch_fs *c, if (journal_entry_err_on(bytes < sizeof(*u) || bytes < sizeof(*u) + u->r.nr_devs, - c, + c, jset, entry, "invalid journal entry usage: bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; @@ -501,7 +524,7 @@ static void journal_entry_data_usage_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_clock_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { @@ -511,13 +534,13 @@ static int journal_entry_clock_validate(struct bch_fs *c, int ret = 0; if (journal_entry_err_on(bytes != sizeof(*clock), - c, "invalid journal entry clock: bad size")) { + c, jset, entry, "bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; } if (journal_entry_err_on(clock->rw > 1, - c, "invalid journal entry clock: bad rw")) { + c, jset, entry, "bad rw")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; } @@ -536,7 +559,7 @@ static void journal_entry_clock_to_text(struct printbuf *out, struct bch_fs *c, } static int journal_entry_dev_usage_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { @@ -548,7 +571,7 @@ static int journal_entry_dev_usage_validate(struct bch_fs *c, int ret = 0; if (journal_entry_err_on(bytes < expected, - c, "invalid journal entry dev usage: bad size (%u < %u)", + c, jset, entry, "bad size (%u < %u)", bytes, expected)) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; @@ -557,13 +580,13 @@ static int journal_entry_dev_usage_validate(struct bch_fs *c, dev = le32_to_cpu(u->dev); if (journal_entry_err_on(!bch2_dev_exists2(c, dev), - c, "invalid journal entry dev usage: bad dev")) { + c, jset, entry, "bad dev")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; } if (journal_entry_err_on(u->pad, - c, "invalid journal entry dev usage: bad pad")) { + c, jset, entry, "bad pad")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; } @@ -596,7 +619,7 @@ static void journal_entry_dev_usage_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_log_validate(struct bch_fs *c, - const char *where, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { @@ -612,11 +635,12 @@ static void journal_entry_log_to_text(struct printbuf *out, struct bch_fs *c, prt_printf(out, "%.*s", bytes, l->d); } -static int journal_entry_overwrite_validate(struct bch_fs *c, const char *where, +static int journal_entry_overwrite_validate(struct bch_fs *c, + struct jset *jset, struct jset_entry *entry, unsigned version, int big_endian, int write) { - return journal_entry_btree_keys_validate(c, where, entry, version, big_endian, write); + return journal_entry_btree_keys_validate(c, jset, entry, version, big_endian, write); } static void journal_entry_overwrite_to_text(struct printbuf *out, struct bch_fs *c, @@ -626,7 +650,7 @@ static void journal_entry_overwrite_to_text(struct printbuf *out, struct bch_fs } struct jset_entry_ops { - int (*validate)(struct bch_fs *, const char *, + int (*validate)(struct bch_fs *, struct jset *, struct jset_entry *, unsigned, int, int); void (*to_text)(struct printbuf *, struct bch_fs *, struct jset_entry *); }; @@ -641,12 +665,13 @@ static const struct jset_entry_ops bch2_jset_entry_ops[] = { #undef x }; -int bch2_journal_entry_validate(struct bch_fs *c, const char *where, +int bch2_journal_entry_validate(struct bch_fs *c, + struct jset *jset, 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, where, entry, + ? bch2_jset_entry_ops[entry->type].validate(c, jset, entry, version, big_endian, write) : 0; } @@ -665,24 +690,18 @@ void bch2_journal_entry_to_text(struct printbuf *out, struct bch_fs *c, 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, + vstruct_last(jset), c, jset, entry, "journal entry extends past end of jset")) { jset->u64s = cpu_to_le32((u64 *) entry - jset->_data); break; } - ret = bch2_journal_entry_validate(c, buf, entry, + ret = bch2_journal_entry_validate(c, jset, entry, le32_to_cpu(jset->version), JSET_BIG_ENDIAN(jset), write); if (ret) @@ -710,7 +729,8 @@ static int jset_validate(struct bch_fs *c, 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, + version >= bcachefs_metadata_version_max, + c, jset, NULL, "%s sector %llu seq %llu: unknown journal entry version %u", ca ? ca->name : c->name, sector, le64_to_cpu(jset->seq), @@ -723,7 +743,8 @@ static int jset_validate(struct bch_fs *c, sectors_read < bucket_sectors_left) return JOURNAL_ENTRY_REREAD; - if (journal_entry_err_on(bytes > bucket_sectors_left << 9, c, + if (journal_entry_err_on(bytes > bucket_sectors_left << 9, + c, jset, NULL, "%s sector %llu seq %llu: journal entry too big (%zu bytes)", ca ? ca->name : c->name, sector, le64_to_cpu(jset->seq), bytes)) { @@ -732,7 +753,8 @@ static int jset_validate(struct bch_fs *c, -((bytes - (bucket_sectors_left << 9)) / 8)); } - if (journal_entry_err_on(!bch2_checksum_type_valid(c, JSET_CSUM_TYPE(jset)), c, + if (journal_entry_err_on(!bch2_checksum_type_valid(c, JSET_CSUM_TYPE(jset)), + c, jset, NULL, "%s sector %llu seq %llu: journal entry with unknown csum type %llu", ca ? ca->name : c->name, sector, le64_to_cpu(jset->seq), @@ -745,7 +767,8 @@ static int jset_validate(struct bch_fs *c, goto csum_done; csum = csum_vstruct(c, JSET_CSUM_TYPE(jset), journal_nonce(jset), jset); - if (journal_entry_err_on(bch2_crc_cmp(csum, jset->csum), c, + if (journal_entry_err_on(bch2_crc_cmp(csum, jset->csum), + c, jset, NULL, "%s sector %llu seq %llu: journal checksum bad", ca ? ca->name : c->name, sector, le64_to_cpu(jset->seq))) @@ -759,7 +782,8 @@ static int jset_validate(struct bch_fs *c, csum_done: /* last_seq is ignored when JSET_NO_FLUSH is true */ if (journal_entry_err_on(!JSET_NO_FLUSH(jset) && - le64_to_cpu(jset->last_seq) > le64_to_cpu(jset->seq), c, + le64_to_cpu(jset->last_seq) > le64_to_cpu(jset->seq), + c, jset, NULL, "invalid journal entry: last_seq > seq (%llu > %llu)", le64_to_cpu(jset->last_seq), le64_to_cpu(jset->seq))) { diff --git a/fs/bcachefs/journal_io.h b/fs/bcachefs/journal_io.h index 30e995c81fc4..1a91f2c0a26c 100644 --- a/fs/bcachefs/journal_io.h +++ b/fs/bcachefs/journal_io.h @@ -44,7 +44,7 @@ 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 *, +int bch2_journal_entry_validate(struct bch_fs *, struct jset *, struct jset_entry *, unsigned, int, int); void bch2_journal_entry_to_text(struct printbuf *, struct bch_fs *, struct jset_entry *); diff --git a/fs/bcachefs/super-io.c b/fs/bcachefs/super-io.c index 12edd4b9a44b..2a347efdbd83 100644 --- a/fs/bcachefs/super-io.c +++ b/fs/bcachefs/super-io.c @@ -1161,7 +1161,7 @@ int bch2_sb_clean_validate_late(struct bch_fs *c, struct bch_sb_field_clean *cle for (entry = clean->start; entry < (struct jset_entry *) vstruct_end(&clean->field); entry = vstruct_next(entry)) { - ret = bch2_journal_entry_validate(c, "superblock", entry, + ret = bch2_journal_entry_validate(c, NULL, entry, le16_to_cpu(c->disk_sb.sb->version), BCH_SB_BIG_ENDIAN(c->disk_sb.sb), write); |