diff options
Diffstat (limited to 'libbcachefs/journal_io.c')
-rw-r--r-- | libbcachefs/journal_io.c | 205 |
1 files changed, 114 insertions, 91 deletions
diff --git a/libbcachefs/journal_io.c b/libbcachefs/journal_io.c index f861ae2f..d141c749 100644 --- a/libbcachefs/journal_io.c +++ b/libbcachefs/journal_io.c @@ -14,6 +14,7 @@ #include "journal_reclaim.h" #include "journal_seq_blacklist.h" #include "replicas.h" +#include "sb-clean.h" #include "trace.h" static struct nonce journal_nonce(const struct jset *jset) @@ -208,33 +209,41 @@ static void journal_entry_null_range(void *start, void *end) #define JOURNAL_ENTRY_BAD 7 static void journal_entry_err_msg(struct printbuf *out, + u32 version, 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, "invalid journal entry, version="); + bch2_version_to_text(out, version); + + if (entry) { + prt_str(out, " type="); + prt_str(out, bch2_jset_entry_types[entry->type]); + } + + if (!jset) { + prt_printf(out, " in superblock"); + } else { + + prt_printf(out, " seq=%llu", le64_to_cpu(jset->seq)); + + if (entry) + prt_printf(out, " offset=%zi/%u", + (u64 *) entry - jset->_data, + le32_to_cpu(jset->u64s)); + } + prt_str(out, ": "); } -#define journal_entry_err(c, jset, entry, msg, ...) \ +#define journal_entry_err(c, version, jset, entry, msg, ...) \ ({ \ struct printbuf buf = PRINTBUF; \ \ - journal_entry_err_msg(&buf, jset, entry); \ + journal_entry_err_msg(&buf, version, jset, entry); \ prt_printf(&buf, msg, ##__VA_ARGS__); \ \ - switch (write) { \ + switch (flags & BKEY_INVALID_WRITE) { \ case READ: \ mustfix_fsck_err(c, "%s", buf.buf); \ break; \ @@ -251,8 +260,8 @@ static void journal_entry_err_msg(struct printbuf *out, true; \ }) -#define journal_entry_err_on(cond, c, jset, entry, msg, ...) \ - ((cond) ? journal_entry_err(c, jset, entry, msg, ##__VA_ARGS__) : false) +#define journal_entry_err_on(cond, c, version, jset, entry, msg, ...) \ + ((cond) ? journal_entry_err(c, version, jset, entry, msg, ##__VA_ARGS__) : false) #define FSCK_DELETED_KEY 5 @@ -261,13 +270,15 @@ static int journal_validate_key(struct bch_fs *c, struct jset_entry *entry, unsigned level, enum btree_id btree_id, struct bkey_i *k, - unsigned version, int big_endian, int write) + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { + int write = flags & BKEY_INVALID_WRITE; void *next = vstruct_next(entry); struct printbuf buf = PRINTBUF; int ret = 0; - if (journal_entry_err_on(!k->k.u64s, c, jset, entry, "k->u64s 0")) { + if (journal_entry_err_on(!k->k.u64s, c, version, 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; @@ -275,7 +286,7 @@ static int journal_validate_key(struct bch_fs *c, if (journal_entry_err_on((void *) bkey_next(k) > (void *) vstruct_next(entry), - c, jset, entry, + c, version, 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); @@ -283,7 +294,7 @@ static int journal_validate_key(struct bch_fs *c, } if (journal_entry_err_on(k->k.format != KEY_FORMAT_CURRENT, - c, jset, entry, + c, version, 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)); @@ -298,11 +309,7 @@ static int journal_validate_key(struct bch_fs *c, 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 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)); + journal_entry_err_msg(&buf, version, jset, entry); prt_newline(&buf); printbuf_indent_add(&buf, 2); @@ -312,6 +319,7 @@ static int journal_validate_key(struct bch_fs *c, __btree_node_type(level, btree_id), write, &buf); mustfix_fsck_err(c, "%s", buf.buf); + BUG(); le16_add_cpu(&entry->u64s, -((u16) k->k.u64s)); memmove(k, bkey_next(k), next - (void *) bkey_next(k)); @@ -330,9 +338,10 @@ fsck_err: } static int journal_entry_btree_keys_validate(struct bch_fs *c, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { struct bkey_i *k = entry->start; @@ -341,7 +350,7 @@ static int journal_entry_btree_keys_validate(struct bch_fs *c, entry->level, entry->btree_id, k, version, big_endian, - write|BKEY_INVALID_JOURNAL); + flags|BKEY_INVALID_JOURNAL); if (ret == FSCK_DELETED_KEY) continue; @@ -369,16 +378,17 @@ 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, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { struct bkey_i *k = entry->start; int ret = 0; if (journal_entry_err_on(!entry->u64s || le16_to_cpu(entry->u64s) != k->k.u64s, - c, jset, entry, + c, version, jset, entry, "invalid btree root journal entry: wrong number of keys")) { void *next = vstruct_next(entry); /* @@ -392,7 +402,7 @@ static int journal_entry_btree_root_validate(struct bch_fs *c, } return journal_validate_key(c, jset, entry, 1, entry->btree_id, k, - version, big_endian, write); + version, big_endian, flags); fsck_err: return ret; } @@ -404,9 +414,10 @@ 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, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { /* obsolete, don't care: */ return 0; @@ -418,14 +429,15 @@ static void journal_entry_prio_ptrs_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_blacklist_validate(struct bch_fs *c, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { int ret = 0; if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 1, - c, jset, entry, + c, version, jset, entry, "invalid journal seq blacklist entry: bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); } @@ -443,15 +455,16 @@ static void journal_entry_blacklist_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_blacklist_v2_validate(struct bch_fs *c, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { struct jset_entry_blacklist_v2 *bl_entry; int ret = 0; if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 2, - c, jset, entry, + c, version, jset, entry, "invalid journal seq blacklist entry: bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); goto out; @@ -461,7 +474,7 @@ static int journal_entry_blacklist_v2_validate(struct bch_fs *c, if (journal_entry_err_on(le64_to_cpu(bl_entry->start) > le64_to_cpu(bl_entry->end), - c, jset, entry, + c, version, jset, entry, "invalid journal seq blacklist entry: start > end")) { journal_entry_null_range(entry, vstruct_next(entry)); } @@ -482,9 +495,10 @@ static void journal_entry_blacklist_v2_to_text(struct printbuf *out, struct bch_ } static int journal_entry_usage_validate(struct bch_fs *c, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { struct jset_entry_usage *u = container_of(entry, struct jset_entry_usage, entry); @@ -492,7 +506,7 @@ static int journal_entry_usage_validate(struct bch_fs *c, int ret = 0; if (journal_entry_err_on(bytes < sizeof(*u), - c, jset, entry, + c, version, jset, entry, "invalid journal entry usage: bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; @@ -514,9 +528,10 @@ 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, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { struct jset_entry_data_usage *u = container_of(entry, struct jset_entry_data_usage, entry); @@ -525,7 +540,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, jset, entry, + c, version, jset, entry, "invalid journal entry usage: bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; @@ -546,9 +561,10 @@ static void journal_entry_data_usage_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_clock_validate(struct bch_fs *c, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { struct jset_entry_clock *clock = container_of(entry, struct jset_entry_clock, entry); @@ -556,13 +572,13 @@ static int journal_entry_clock_validate(struct bch_fs *c, int ret = 0; if (journal_entry_err_on(bytes != sizeof(*clock), - c, jset, entry, "bad size")) { + c, version, jset, entry, "bad size")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; } if (journal_entry_err_on(clock->rw > 1, - c, jset, entry, "bad rw")) { + c, version, jset, entry, "bad rw")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; } @@ -581,9 +597,10 @@ 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, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { struct jset_entry_dev_usage *u = container_of(entry, struct jset_entry_dev_usage, entry); @@ -593,7 +610,7 @@ static int journal_entry_dev_usage_validate(struct bch_fs *c, int ret = 0; if (journal_entry_err_on(bytes < expected, - c, jset, entry, "bad size (%u < %u)", + c, version, jset, entry, "bad size (%u < %u)", bytes, expected)) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; @@ -602,13 +619,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, jset, entry, "bad dev")) { + c, version, jset, entry, "bad dev")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; } if (journal_entry_err_on(u->pad, - c, jset, entry, "bad pad")) { + c, version, jset, entry, "bad pad")) { journal_entry_null_range(entry, vstruct_next(entry)); return ret; } @@ -641,9 +658,10 @@ static void journal_entry_dev_usage_to_text(struct printbuf *out, struct bch_fs } static int journal_entry_log_validate(struct bch_fs *c, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { return 0; } @@ -658,9 +676,10 @@ static void journal_entry_log_to_text(struct printbuf *out, struct bch_fs *c, } static int journal_entry_overwrite_validate(struct bch_fs *c, - struct jset *jset, - struct jset_entry *entry, - unsigned version, int big_endian, int write) + struct jset *jset, + struct jset_entry *entry, + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { return journal_entry_btree_keys_validate(c, jset, entry, version, big_endian, READ); @@ -674,7 +693,8 @@ static void journal_entry_overwrite_to_text(struct printbuf *out, struct bch_fs struct jset_entry_ops { int (*validate)(struct bch_fs *, struct jset *, - struct jset_entry *, unsigned, int, int); + struct jset_entry *, unsigned, int, + enum bkey_invalid_flags); void (*to_text)(struct printbuf *, struct bch_fs *, struct jset_entry *); }; @@ -691,11 +711,12 @@ static const struct jset_entry_ops bch2_jset_entry_ops[] = { int bch2_journal_entry_validate(struct bch_fs *c, struct jset *jset, struct jset_entry *entry, - unsigned version, int big_endian, int write) + unsigned version, int big_endian, + enum bkey_invalid_flags flags) { return entry->type < BCH_JSET_ENTRY_NR ? bch2_jset_entry_ops[entry->type].validate(c, jset, entry, - version, big_endian, write) + version, big_endian, flags) : 0; } @@ -711,22 +732,22 @@ 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) + enum bkey_invalid_flags flags) { struct jset_entry *entry; + unsigned version = le32_to_cpu(jset->version); int ret = 0; vstruct_for_each(jset, entry) { - if (journal_entry_err_on(vstruct_next(entry) > - vstruct_last(jset), c, jset, entry, + if (journal_entry_err_on(vstruct_next(entry) > vstruct_last(jset), + c, version, 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, jset, entry, - le32_to_cpu(jset->version), - JSET_BIG_ENDIAN(jset), write); + version, JSET_BIG_ENDIAN(jset), flags); if (ret) break; } @@ -737,7 +758,7 @@ fsck_err: static int jset_validate(struct bch_fs *c, struct bch_dev *ca, struct jset *jset, u64 sector, - int write) + enum bkey_invalid_flags flags) { unsigned version; int ret = 0; @@ -746,7 +767,8 @@ static int jset_validate(struct bch_fs *c, return JOURNAL_ENTRY_NONE; version = le32_to_cpu(jset->version); - if (journal_entry_err_on(!bch2_version_compatible(version), c, jset, NULL, + if (journal_entry_err_on(!bch2_version_compatible(version), + c, version, jset, NULL, "%s sector %llu seq %llu: incompatible journal entry version %u.%u", ca ? ca->name : c->name, sector, le64_to_cpu(jset->seq), @@ -757,7 +779,7 @@ static int jset_validate(struct bch_fs *c, } if (journal_entry_err_on(!bch2_checksum_type_valid(c, JSET_CSUM_TYPE(jset)), - c, jset, NULL, + c, version, 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), @@ -767,7 +789,7 @@ static int jset_validate(struct bch_fs *c, /* 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, jset, NULL, + c, version, jset, NULL, "invalid journal entry: last_seq > seq (%llu > %llu)", le64_to_cpu(jset->last_seq), le64_to_cpu(jset->seq))) { @@ -775,7 +797,7 @@ static int jset_validate(struct bch_fs *c, return JOURNAL_ENTRY_BAD; } - ret = jset_validate_entries(c, jset, write); + ret = jset_validate_entries(c, jset, flags); fsck_err: return ret; } @@ -788,14 +810,15 @@ static int jset_validate_early(struct bch_fs *c, { size_t bytes = vstruct_bytes(jset); unsigned version; - int write = READ; + enum bkey_invalid_flags flags = BKEY_INVALID_JOURNAL; int ret = 0; if (le64_to_cpu(jset->magic) != jset_magic(c)) return JOURNAL_ENTRY_NONE; version = le32_to_cpu(jset->version); - if (journal_entry_err_on(!bch2_version_compatible(version), c, jset, NULL, + if (journal_entry_err_on(!bch2_version_compatible(version), + c, version, jset, NULL, "%s sector %llu seq %llu: unknown journal entry version %u.%u", ca ? ca->name : c->name, sector, le64_to_cpu(jset->seq), @@ -810,7 +833,7 @@ static int jset_validate_early(struct bch_fs *c, return JOURNAL_ENTRY_REREAD; if (journal_entry_err_on(bytes > bucket_sectors_left << 9, - c, jset, NULL, + c, version, 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)) @@ -1127,7 +1150,7 @@ int bch2_journal_read(struct bch_fs *c, * those entries will be blacklisted: */ genradix_for_each_reverse(&c->journal_entries, radix_iter, _i) { - int write = READ; + enum bkey_invalid_flags flags = BKEY_INVALID_JOURNAL; i = *_i; @@ -1149,7 +1172,7 @@ int bch2_journal_read(struct bch_fs *c, } if (journal_entry_err_on(le64_to_cpu(i->j.last_seq) > le64_to_cpu(i->j.seq), - c, &i->j, NULL, + c, le32_to_cpu(i->j.version), &i->j, NULL, "invalid journal entry: last_seq > seq (%llu > %llu)", le64_to_cpu(i->j.last_seq), le64_to_cpu(i->j.seq))) |