mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-15 21:23:23 +00:00
bcachefs: Plumb bkey_validate_context to journal_entry_validate
This lets us print the exact location in the journal if it was found in the journal, or correctly print if it was found in the superblock. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
488249b3f6
commit
e8d604148b
@ -213,16 +213,16 @@ BCH_BKEY_TYPES();
|
||||
enum bch_validate_flags {
|
||||
BCH_VALIDATE_write = BIT(0),
|
||||
BCH_VALIDATE_commit = BIT(1),
|
||||
BCH_VALIDATE_journal = BIT(2),
|
||||
BCH_VALIDATE_silent = BIT(3),
|
||||
BCH_VALIDATE_silent = BIT(2),
|
||||
};
|
||||
|
||||
#define BKEY_VALIDATE_CONTEXTS() \
|
||||
x(unknown) \
|
||||
x(commit) \
|
||||
x(superblock) \
|
||||
x(journal) \
|
||||
x(btree_root) \
|
||||
x(btree_node)
|
||||
x(btree_node) \
|
||||
x(commit)
|
||||
|
||||
struct bkey_validate_context {
|
||||
enum {
|
||||
@ -230,10 +230,12 @@ struct bkey_validate_context {
|
||||
BKEY_VALIDATE_CONTEXTS()
|
||||
#undef x
|
||||
} from:8;
|
||||
enum bch_validate_flags flags:8;
|
||||
u8 level;
|
||||
enum btree_id btree;
|
||||
bool root:1;
|
||||
enum bch_validate_flags flags:8;
|
||||
unsigned journal_offset;
|
||||
u64 journal_seq;
|
||||
};
|
||||
|
||||
#endif /* _BCACHEFS_BKEY_TYPES_H */
|
||||
|
@ -719,19 +719,29 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, unsigned flags,
|
||||
goto fatal_err;
|
||||
}
|
||||
|
||||
struct bkey_validate_context validate_context = { .from = BKEY_VALIDATE_commit };
|
||||
|
||||
if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
|
||||
validate_context.flags = BCH_VALIDATE_write|BCH_VALIDATE_commit;
|
||||
|
||||
for (struct jset_entry *i = trans->journal_entries;
|
||||
i != (void *) ((u64 *) trans->journal_entries + trans->journal_entries_u64s);
|
||||
i = vstruct_next(i)) {
|
||||
ret = bch2_journal_entry_validate(c, NULL, i,
|
||||
bcachefs_metadata_version_current,
|
||||
CPU_BIG_ENDIAN, validate_context);
|
||||
if (unlikely(ret)) {
|
||||
bch2_trans_inconsistent(trans, "invalid journal entry on insert from %s\n",
|
||||
trans->fn);
|
||||
goto fatal_err;
|
||||
}
|
||||
}
|
||||
|
||||
trans_for_each_update(trans, i) {
|
||||
enum bch_validate_flags invalid_flags = 0;
|
||||
validate_context.level = i->level;
|
||||
validate_context.btree = i->btree_id;
|
||||
|
||||
if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
|
||||
invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
|
||||
|
||||
ret = bch2_bkey_validate(c, bkey_i_to_s_c(i->k),
|
||||
(struct bkey_validate_context) {
|
||||
.from = BKEY_VALIDATE_commit,
|
||||
.level = i->level,
|
||||
.btree = i->btree_id,
|
||||
.flags = invalid_flags,
|
||||
});
|
||||
ret = bch2_bkey_validate(c, bkey_i_to_s_c(i->k), validate_context);
|
||||
if (unlikely(ret)){
|
||||
bch2_trans_inconsistent(trans, "invalid bkey on insert from %s -> %ps\n",
|
||||
trans->fn, (void *) i->ip_allocated);
|
||||
@ -740,24 +750,6 @@ bch2_trans_commit_write_locked(struct btree_trans *trans, unsigned flags,
|
||||
btree_insert_entry_checks(trans, i);
|
||||
}
|
||||
|
||||
for (struct jset_entry *i = trans->journal_entries;
|
||||
i != (void *) ((u64 *) trans->journal_entries + trans->journal_entries_u64s);
|
||||
i = vstruct_next(i)) {
|
||||
enum bch_validate_flags invalid_flags = 0;
|
||||
|
||||
if (!(flags & BCH_TRANS_COMMIT_no_journal_res))
|
||||
invalid_flags |= BCH_VALIDATE_write|BCH_VALIDATE_commit;
|
||||
|
||||
ret = bch2_journal_entry_validate(c, NULL, i,
|
||||
bcachefs_metadata_version_current,
|
||||
CPU_BIG_ENDIAN, invalid_flags);
|
||||
if (unlikely(ret)) {
|
||||
bch2_trans_inconsistent(trans, "invalid journal entry on insert from %s\n",
|
||||
trans->fn);
|
||||
goto fatal_err;
|
||||
}
|
||||
}
|
||||
|
||||
if (likely(!(flags & BCH_TRANS_COMMIT_no_journal_res))) {
|
||||
struct journal *j = &c->journal;
|
||||
struct jset_entry *entry;
|
||||
|
@ -486,9 +486,14 @@ int __bch2_bkey_fsck_err(struct bch_fs *c,
|
||||
fsck_flags |= fsck_flags_extra[err];
|
||||
|
||||
struct printbuf buf = PRINTBUF;
|
||||
|
||||
prt_printf(&buf, "invalid bkey in %s btree=",
|
||||
prt_printf(&buf, "invalid bkey in %s",
|
||||
bch2_bkey_validate_contexts[from.from]);
|
||||
|
||||
if (from.from == BKEY_VALIDATE_journal)
|
||||
prt_printf(&buf, " journal seq=%llu offset=%u",
|
||||
from.journal_seq, from.journal_offset);
|
||||
|
||||
prt_str(&buf, " btree=");
|
||||
bch2_btree_id_to_text(&buf, from.btree);
|
||||
prt_printf(&buf, " level=%u: ", from.level);
|
||||
|
||||
|
@ -1238,6 +1238,12 @@ static int extent_ptr_validate(struct bch_fs *c,
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
||||
bkey_for_each_ptr(ptrs, ptr2)
|
||||
bkey_fsck_err_on(ptr != ptr2 && ptr->dev == ptr2->dev,
|
||||
c, ptr_to_duplicate_device,
|
||||
"multiple pointers to same device (%u)", ptr->dev);
|
||||
|
||||
/* bad pointers are repaired by check_fix_ptrs(): */
|
||||
rcu_read_lock();
|
||||
struct bch_dev *ca = bch2_dev_rcu_noerror(c, ptr->dev);
|
||||
@ -1252,13 +1258,6 @@ static int extent_ptr_validate(struct bch_fs *c,
|
||||
unsigned bucket_size = ca->mi.bucket_size;
|
||||
rcu_read_unlock();
|
||||
|
||||
struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c(k);
|
||||
bkey_for_each_ptr(ptrs, ptr2)
|
||||
bkey_fsck_err_on(ptr != ptr2 && ptr->dev == ptr2->dev,
|
||||
c, ptr_to_duplicate_device,
|
||||
"multiple pointers to same device (%u)", ptr->dev);
|
||||
|
||||
|
||||
bkey_fsck_err_on(bucket >= nbuckets,
|
||||
c, ptr_after_last_bucket,
|
||||
"pointer past last bucket (%llu > %llu)", bucket, nbuckets);
|
||||
|
@ -301,7 +301,7 @@ static void journal_entry_err_msg(struct printbuf *out,
|
||||
journal_entry_err_msg(&_buf, version, jset, entry); \
|
||||
prt_printf(&_buf, msg, ##__VA_ARGS__); \
|
||||
\
|
||||
switch (flags & BCH_VALIDATE_write) { \
|
||||
switch (from.flags & BCH_VALIDATE_write) { \
|
||||
case READ: \
|
||||
mustfix_fsck_err(c, _err, "%s", _buf.buf); \
|
||||
break; \
|
||||
@ -390,15 +390,12 @@ static int journal_entry_btree_keys_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
struct bkey_i *k = entry->start;
|
||||
struct bkey_validate_context from = {
|
||||
.from = BKEY_VALIDATE_journal,
|
||||
.level = entry->level,
|
||||
.btree = entry->btree_id,
|
||||
.flags = flags|BCH_VALIDATE_journal,
|
||||
};
|
||||
|
||||
from.level = entry->level;
|
||||
from.btree = entry->btree_id;
|
||||
|
||||
while (k != vstruct_last(entry)) {
|
||||
int ret = journal_validate_key(c, jset, entry, k, from, version, big_endian);
|
||||
@ -435,11 +432,15 @@ static int journal_entry_btree_root_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
struct bkey_i *k = entry->start;
|
||||
int ret = 0;
|
||||
|
||||
from.root = true;
|
||||
from.level = entry->level + 1;
|
||||
from.btree = entry->btree_id;
|
||||
|
||||
if (journal_entry_err_on(!entry->u64s ||
|
||||
le16_to_cpu(entry->u64s) != k->k.u64s,
|
||||
c, version, jset, entry,
|
||||
@ -456,13 +457,6 @@ static int journal_entry_btree_root_validate(struct bch_fs *c,
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bkey_validate_context from = {
|
||||
.from = BKEY_VALIDATE_journal,
|
||||
.level = entry->level + 1,
|
||||
.btree = entry->btree_id,
|
||||
.root = true,
|
||||
.flags = flags,
|
||||
};
|
||||
ret = journal_validate_key(c, jset, entry, k, from, version, big_endian);
|
||||
if (ret == FSCK_DELETED_KEY)
|
||||
ret = 0;
|
||||
@ -480,7 +474,7 @@ static int journal_entry_prio_ptrs_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
/* obsolete, don't care: */
|
||||
return 0;
|
||||
@ -495,7 +489,7 @@ static int journal_entry_blacklist_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@ -522,7 +516,7 @@ static int journal_entry_blacklist_v2_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
struct jset_entry_blacklist_v2 *bl_entry;
|
||||
int ret = 0;
|
||||
@ -564,7 +558,7 @@ static int journal_entry_usage_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
struct jset_entry_usage *u =
|
||||
container_of(entry, struct jset_entry_usage, entry);
|
||||
@ -598,7 +592,7 @@ static int journal_entry_data_usage_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
struct jset_entry_data_usage *u =
|
||||
container_of(entry, struct jset_entry_data_usage, entry);
|
||||
@ -642,7 +636,7 @@ static int journal_entry_clock_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
struct jset_entry_clock *clock =
|
||||
container_of(entry, struct jset_entry_clock, entry);
|
||||
@ -682,7 +676,7 @@ static int journal_entry_dev_usage_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
struct jset_entry_dev_usage *u =
|
||||
container_of(entry, struct jset_entry_dev_usage, entry);
|
||||
@ -739,7 +733,7 @@ static int journal_entry_log_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -756,10 +750,11 @@ static int journal_entry_overwrite_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
from.flags = 0;
|
||||
return journal_entry_btree_keys_validate(c, jset, entry,
|
||||
version, big_endian, READ);
|
||||
version, big_endian, from);
|
||||
}
|
||||
|
||||
static void journal_entry_overwrite_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
@ -772,10 +767,10 @@ static int journal_entry_write_buffer_keys_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
return journal_entry_btree_keys_validate(c, jset, entry,
|
||||
version, big_endian, READ);
|
||||
version, big_endian, from);
|
||||
}
|
||||
|
||||
static void journal_entry_write_buffer_keys_to_text(struct printbuf *out, struct bch_fs *c,
|
||||
@ -788,7 +783,7 @@ static int journal_entry_datetime_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
unsigned bytes = vstruct_bytes(entry);
|
||||
unsigned expected = 16;
|
||||
@ -818,7 +813,7 @@ static void journal_entry_datetime_to_text(struct printbuf *out, struct bch_fs *
|
||||
struct jset_entry_ops {
|
||||
int (*validate)(struct bch_fs *, struct jset *,
|
||||
struct jset_entry *, unsigned, int,
|
||||
enum bch_validate_flags);
|
||||
struct bkey_validate_context);
|
||||
void (*to_text)(struct printbuf *, struct bch_fs *, struct jset_entry *);
|
||||
};
|
||||
|
||||
@ -836,11 +831,11 @@ int bch2_journal_entry_validate(struct bch_fs *c,
|
||||
struct jset *jset,
|
||||
struct jset_entry *entry,
|
||||
unsigned version, int big_endian,
|
||||
enum bch_validate_flags flags)
|
||||
struct bkey_validate_context from)
|
||||
{
|
||||
return entry->type < BCH_JSET_ENTRY_NR
|
||||
? bch2_jset_entry_ops[entry->type].validate(c, jset, entry,
|
||||
version, big_endian, flags)
|
||||
version, big_endian, from)
|
||||
: 0;
|
||||
}
|
||||
|
||||
@ -858,10 +853,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,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
struct bkey_validate_context from = {
|
||||
.flags = flags,
|
||||
.from = BKEY_VALIDATE_journal,
|
||||
.journal_seq = le64_to_cpu(jset->seq),
|
||||
};
|
||||
|
||||
unsigned version = le32_to_cpu(jset->version);
|
||||
int ret = 0;
|
||||
|
||||
vstruct_for_each(jset, entry) {
|
||||
from.journal_offset = (u64 *) entry - jset->_data;
|
||||
|
||||
if (journal_entry_err_on(vstruct_next(entry) > vstruct_last(jset),
|
||||
c, version, jset, entry,
|
||||
journal_entry_past_jset_end,
|
||||
@ -870,8 +873,8 @@ static int jset_validate_entries(struct bch_fs *c, struct jset *jset,
|
||||
break;
|
||||
}
|
||||
|
||||
ret = bch2_journal_entry_validate(c, jset, entry,
|
||||
version, JSET_BIG_ENDIAN(jset), flags);
|
||||
ret = bch2_journal_entry_validate(c, jset, entry, version,
|
||||
JSET_BIG_ENDIAN(jset), from);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
@ -884,13 +887,17 @@ static int jset_validate(struct bch_fs *c,
|
||||
struct jset *jset, u64 sector,
|
||||
enum bch_validate_flags flags)
|
||||
{
|
||||
unsigned version;
|
||||
struct bkey_validate_context from = {
|
||||
.flags = flags,
|
||||
.from = BKEY_VALIDATE_journal,
|
||||
.journal_seq = le64_to_cpu(jset->seq),
|
||||
};
|
||||
int ret = 0;
|
||||
|
||||
if (le64_to_cpu(jset->magic) != jset_magic(c))
|
||||
return JOURNAL_ENTRY_NONE;
|
||||
|
||||
version = le32_to_cpu(jset->version);
|
||||
unsigned version = le32_to_cpu(jset->version);
|
||||
if (journal_entry_err_on(!bch2_version_compatible(version),
|
||||
c, version, jset, NULL,
|
||||
jset_unsupported_version,
|
||||
@ -935,15 +942,16 @@ static int jset_validate_early(struct bch_fs *c,
|
||||
unsigned bucket_sectors_left,
|
||||
unsigned sectors_read)
|
||||
{
|
||||
size_t bytes = vstruct_bytes(jset);
|
||||
unsigned version;
|
||||
enum bch_validate_flags flags = BCH_VALIDATE_journal;
|
||||
struct bkey_validate_context from = {
|
||||
.from = BKEY_VALIDATE_journal,
|
||||
.journal_seq = le64_to_cpu(jset->seq),
|
||||
};
|
||||
int ret = 0;
|
||||
|
||||
if (le64_to_cpu(jset->magic) != jset_magic(c))
|
||||
return JOURNAL_ENTRY_NONE;
|
||||
|
||||
version = le32_to_cpu(jset->version);
|
||||
unsigned version = le32_to_cpu(jset->version);
|
||||
if (journal_entry_err_on(!bch2_version_compatible(version),
|
||||
c, version, jset, NULL,
|
||||
jset_unsupported_version,
|
||||
@ -956,6 +964,7 @@ static int jset_validate_early(struct bch_fs *c,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
size_t bytes = vstruct_bytes(jset);
|
||||
if (bytes > (sectors_read << 9) &&
|
||||
sectors_read < bucket_sectors_left)
|
||||
return JOURNAL_ENTRY_REREAD;
|
||||
@ -1240,8 +1249,6 @@ int bch2_journal_read(struct bch_fs *c,
|
||||
* those entries will be blacklisted:
|
||||
*/
|
||||
genradix_for_each_reverse(&c->journal_entries, radix_iter, _i) {
|
||||
enum bch_validate_flags flags = BCH_VALIDATE_journal;
|
||||
|
||||
i = *_i;
|
||||
|
||||
if (journal_replay_ignore(i))
|
||||
@ -1261,6 +1268,10 @@ int bch2_journal_read(struct bch_fs *c,
|
||||
continue;
|
||||
}
|
||||
|
||||
struct bkey_validate_context from = {
|
||||
.from = BKEY_VALIDATE_journal,
|
||||
.journal_seq = le64_to_cpu(i->j.seq),
|
||||
};
|
||||
if (journal_entry_err_on(le64_to_cpu(i->j.last_seq) > le64_to_cpu(i->j.seq),
|
||||
c, le32_to_cpu(i->j.version), &i->j, NULL,
|
||||
jset_last_seq_newer_than_seq,
|
||||
|
@ -63,7 +63,7 @@ static inline struct jset_entry *__jset_entry_type_next(struct jset *jset,
|
||||
|
||||
int bch2_journal_entry_validate(struct bch_fs *, struct jset *,
|
||||
struct jset_entry *, unsigned, int,
|
||||
enum bch_validate_flags);
|
||||
struct bkey_validate_context);
|
||||
void bch2_journal_entry_to_text(struct printbuf *, struct bch_fs *,
|
||||
struct jset_entry *);
|
||||
|
||||
|
@ -23,6 +23,10 @@
|
||||
int bch2_sb_clean_validate_late(struct bch_fs *c, struct bch_sb_field_clean *clean,
|
||||
int write)
|
||||
{
|
||||
struct bkey_validate_context from = {
|
||||
.flags = write,
|
||||
.from = BKEY_VALIDATE_superblock,
|
||||
};
|
||||
struct jset_entry *entry;
|
||||
int ret;
|
||||
|
||||
@ -40,7 +44,7 @@ int bch2_sb_clean_validate_late(struct bch_fs *c, struct bch_sb_field_clean *cle
|
||||
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);
|
||||
from);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user