diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-05-02 16:31:37 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2018-05-02 16:31:37 -0400 |
commit | 783468809d4e820aae3c8cf48ab856c47b169bea (patch) | |
tree | fe988c70635d56f01cf9d0d87240ef9f4adf727a | |
parent | d86b5f5134f1eddf922a27ea794c700e2eb00678 (diff) |
bcachefs: Add an ops struct for jset entries
-rw-r--r-- | fs/bcachefs/bcachefs_format.h | 47 | ||||
-rw-r--r-- | fs/bcachefs/journal.h | 4 | ||||
-rw-r--r-- | fs/bcachefs/journal_io.c | 200 | ||||
-rw-r--r-- | fs/bcachefs/journal_io.h | 2 | ||||
-rw-r--r-- | fs/bcachefs/journal_seq_blacklist.c | 4 |
5 files changed, 159 insertions, 98 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index 730a46a6ed6f..99f3016af80d 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -1194,29 +1194,40 @@ struct jset_entry { }; }; +#define JSET_KEYS_U64s (sizeof(struct jset_entry) / sizeof(__u64)) + +#define BCH_JSET_ENTRY_TYPES() \ + x(btree_keys, 0) \ + x(btree_root, 1) \ + x(prio_ptrs, 2) \ + x(blacklist, 3) + +enum { +#define x(f, nr) BCH_JSET_ENTRY_##f = nr, + BCH_JSET_ENTRY_TYPES() +#undef x + BCH_JSET_ENTRY_NR +}; + +/* + * Journal sequence numbers can be blacklisted: bsets record the max sequence + * number of all the journal entries they contain updates for, so that on + * recovery we can ignore those bsets that contain index updates newer that what + * made it into the journal. + * + * This means that we can't reuse that journal_seq - we have to skip it, and + * then record that we skipped it so that the next time we crash and recover we + * don't think there was a missing journal entry. + */ struct jset_entry_blacklist { struct jset_entry entry; __le64 seq; }; -#define JSET_KEYS_U64s (sizeof(struct jset_entry) / sizeof(__u64)) - -enum { - JOURNAL_ENTRY_BTREE_KEYS = 0, - JOURNAL_ENTRY_BTREE_ROOT = 1, - JOURNAL_ENTRY_PRIO_PTRS = 2, /* Obsolete */ - - /* - * Journal sequence numbers can be blacklisted: bsets record the max - * sequence number of all the journal entries they contain updates for, - * so that on recovery we can ignore those bsets that contain index - * updates newer that what made it into the journal. - * - * This means that we can't reuse that journal_seq - we have to skip it, - * and then record that we skipped it so that the next time we crash and - * recover we don't think there was a missing journal entry. - */ - JOURNAL_ENTRY_JOURNAL_SEQ_BLACKLISTED = 3, +struct jset_entry_blacklist_v2 { + struct jset_entry entry; + __le64 start; + __le64 end; }; /* diff --git a/fs/bcachefs/journal.h b/fs/bcachefs/journal.h index 3fef5c104ebf..b106f32f96f1 100644 --- a/fs/bcachefs/journal.h +++ b/fs/bcachefs/journal.h @@ -227,7 +227,7 @@ static inline void bch2_journal_add_entry(struct journal *j, struct journal_res static inline void bch2_journal_add_keys(struct journal *j, struct journal_res *res, enum btree_id id, const struct bkey_i *k) { - bch2_journal_add_entry(j, res, JOURNAL_ENTRY_BTREE_KEYS, + bch2_journal_add_entry(j, res, BCH_JSET_ENTRY_btree_keys, id, 0, k, k->k.u64s); } @@ -269,7 +269,7 @@ static inline void bch2_journal_res_put(struct journal *j, while (res->u64s) bch2_journal_add_entry(j, res, - JOURNAL_ENTRY_BTREE_KEYS, + BCH_JSET_ENTRY_btree_keys, 0, 0, NULL, 0); bch2_journal_buf_put(j, res->idx, false); diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index c158d5d03b4d..41aad0305d43 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -30,7 +30,7 @@ struct bkey_i *bch2_journal_find_btree_root(struct bch_fs *c, struct jset *j, { struct bkey_i *k; struct jset_entry *entry = - bch2_journal_find_entry(j, JOURNAL_ENTRY_BTREE_ROOT, id); + bch2_journal_find_entry(j, BCH_JSET_ENTRY_btree_root, id); if (!entry) return NULL; @@ -218,85 +218,135 @@ fsck_err: #define journal_entry_err_on(cond, c, msg, ...) \ ((cond) ? journal_entry_err(c, msg, ##__VA_ARGS__) : false) -static int journal_entry_validate_entries(struct bch_fs *c, struct jset *jset, - int write) +static int journal_entry_validate_btree_keys(struct bch_fs *c, + struct jset *jset, + struct jset_entry *entry, + int write) { - struct jset_entry *entry; + struct bkey_i *k; + + vstruct_for_each(entry, k) { + int ret = journal_validate_key(c, jset, entry, k, + bkey_type(entry->level, + entry->btree_id), + "key"); + if (ret) + return ret; + } + + return 0; +} + +static int journal_entry_validate_btree_root(struct bch_fs *c, + struct jset *jset, + struct jset_entry *entry, + int write) +{ + struct bkey_i *k = entry->start; int ret = 0; - vstruct_for_each(jset, entry) { + if (journal_entry_err_on(!entry->u64s || + le16_to_cpu(entry->u64s) != k->k.u64s, c, + "invalid btree root journal entry: wrong number of keys")) { void *next = vstruct_next(entry); - struct bkey_i *k; + /* + * we don't want to null out this jset_entry, + * just the contents, so that later we can tell + * we were _supposed_ to have a btree root + */ + entry->u64s = 0; + journal_entry_null_range(vstruct_next(entry), next); + return 0; + } - if (journal_entry_err_on(vstruct_next(entry) > - vstruct_last(jset), c, - "journal entry extends past end of jset")) { - jset->u64s = cpu_to_le32((u64 *) entry - jset->_data); - break; - } + return journal_validate_key(c, jset, entry, k, + BKEY_TYPE_BTREE, "btree root"); +fsck_err: + return ret; +} - switch (entry->type) { - case JOURNAL_ENTRY_BTREE_KEYS: - vstruct_for_each(entry, k) { - ret = journal_validate_key(c, jset, entry, k, - bkey_type(entry->level, - entry->btree_id), - "key"); - if (ret) - goto fsck_err; - } - break; +static int journal_entry_validate_prio_ptrs(struct bch_fs *c, + struct jset *jset, + struct jset_entry *entry, + int write) +{ + /* obsolete, don't care: */ + return 0; +} - case JOURNAL_ENTRY_BTREE_ROOT: - k = entry->start; +static int journal_entry_validate_blacklist(struct bch_fs *c, + struct jset *jset, + struct jset_entry *entry, + int write) +{ + int ret = 0; - if (journal_entry_err_on(!entry->u64s || - le16_to_cpu(entry->u64s) != k->k.u64s, c, - "invalid btree root journal entry: wrong number of keys")) { - /* - * we don't want to null out this jset_entry, - * just the contents, so that later we can tell - * we were _supposed_ to have a btree root - */ - entry->u64s = 0; - journal_entry_null_range(vstruct_next(entry), next); - continue; - } + if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 1, c, + "invalid journal seq blacklist entry: bad size")) { + journal_entry_null_range(entry, vstruct_next(entry)); + } +fsck_err: + return ret; +} - ret = journal_validate_key(c, jset, entry, k, - BKEY_TYPE_BTREE, "btree root"); - if (ret) - goto fsck_err; - break; +struct jset_entry_ops { + int (*validate)(struct bch_fs *, struct jset *, + struct jset_entry *, int); +}; - case JOURNAL_ENTRY_PRIO_PTRS: - break; +const struct jset_entry_ops bch2_jset_entry_ops[] = { +#define x(f, nr) \ + [BCH_JSET_ENTRY_##f] = (struct jset_entry_ops) { \ + .validate = journal_entry_validate_##f, \ + }, + BCH_JSET_ENTRY_TYPES() +#undef x +}; - case JOURNAL_ENTRY_JOURNAL_SEQ_BLACKLISTED: - if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 1, c, - "invalid journal seq blacklist entry: bad size")) { - journal_entry_null_range(entry, - vstruct_next(entry)); - } +static int journal_entry_validate(struct bch_fs *c, struct jset *jset, + struct jset_entry *entry, int write) +{ + int ret = 0; - break; - default: - journal_entry_err(c, "invalid journal entry type %u", - entry->type); - journal_entry_null_range(entry, vstruct_next(entry)); + if (entry->type >= BCH_JSET_ENTRY_NR) { + journal_entry_err(c, "invalid journal entry type %u", + entry->type); + journal_entry_null_range(entry, vstruct_next(entry)); + return 0; + } + + ret = bch2_jset_entry_ops[entry->type].validate(c, jset, entry, write); +fsck_err: + return ret; +} + +static int jset_validate_entries(struct bch_fs *c, struct jset *jset, + int write) +{ + struct jset_entry *entry; + int ret = 0; + + vstruct_for_each(jset, entry) { + if (journal_entry_err_on(vstruct_next(entry) > + vstruct_last(jset), c, + "journal entry extends past end of jset")) { + jset->u64s = cpu_to_le32((u64 *) entry - jset->_data); break; } - } + ret = journal_entry_validate(c, jset, entry, write); + if (ret) + break; + } fsck_err: return ret; } -static int journal_entry_validate(struct bch_fs *c, - struct jset *jset, u64 sector, - unsigned bucket_sectors_left, - unsigned sectors_read, - int write) +static int jset_validate(struct bch_fs *c, + struct jset *jset, u64 sector, + unsigned bucket_sectors_left, + unsigned sectors_read, + int write) { size_t bytes = vstruct_bytes(jset); struct bch_csum csum; @@ -312,8 +362,8 @@ static int journal_entry_validate(struct bch_fs *c, } if (journal_entry_err_on(bytes > bucket_sectors_left << 9, c, - "journal entry too big (%zu bytes), sector %lluu", - bytes, sector)) { + "journal entry too big (%zu bytes), sector %lluu", + bytes, sector)) { /* XXX: note we might have missing journal entries */ return JOURNAL_ENTRY_BAD; } @@ -328,18 +378,18 @@ static int journal_entry_validate(struct bch_fs *c, csum = csum_vstruct(c, JSET_CSUM_TYPE(jset), journal_nonce(jset), jset); if (journal_entry_err_on(bch2_crc_cmp(csum, jset->csum), c, - "journal checksum bad, sector %llu", sector)) { + "journal checksum bad, sector %llu", sector)) { /* XXX: retry IO, when we start retrying checksum errors */ /* XXX: note we might have missing journal entries */ return JOURNAL_ENTRY_BAD; } bch2_encrypt(c, JSET_CSUM_TYPE(jset), journal_nonce(jset), - jset->encrypted_start, - vstruct_end(jset) - (void *) jset->encrypted_start); + jset->encrypted_start, + vstruct_end(jset) - (void *) jset->encrypted_start); if (journal_entry_err_on(le64_to_cpu(jset->last_seq) > le64_to_cpu(jset->seq), c, - "invalid journal entry: last_seq > seq")) + "invalid journal entry: last_seq > seq")) jset->last_seq = jset->seq; return 0; @@ -412,9 +462,9 @@ reread: sectors_read = min_t(unsigned, j = buf->data; } - ret = journal_entry_validate(c, j, offset, - end - offset, sectors_read, - READ); + ret = jset_validate(c, j, offset, + end - offset, sectors_read, + READ); switch (ret) { case BCH_FSCK_OK: break; @@ -696,7 +746,7 @@ int bch2_journal_read(struct bch_fs *c, struct list_head *list) "filesystem marked clean but journal has keys to replay"); list_for_each_entry(i, list, list) { - ret = journal_entry_validate_entries(c, &i->j, READ); + ret = jset_validate_entries(c, &i->j, READ); if (ret) goto fsck_err; @@ -890,7 +940,7 @@ static void bch2_journal_add_btree_root(struct journal_buf *buf, unsigned level) { bch2_journal_add_entry_noreservation(buf, - JOURNAL_ENTRY_BTREE_ROOT, id, level, + BCH_JSET_ENTRY_btree_root, id, level, k, k->k.u64s); } @@ -1106,7 +1156,7 @@ static void journal_write_compact(struct jset *jset) i->btree_id == prev->btree_id && i->level == prev->level && i->type == prev->type && - i->type == JOURNAL_ENTRY_BTREE_KEYS && + i->type == BCH_JSET_ENTRY_btree_keys && le16_to_cpu(prev->u64s) + u64s <= U16_MAX) { memmove_u64s_down(vstruct_next(prev), i->_data, @@ -1251,7 +1301,7 @@ void bch2_journal_write(struct closure *cl) SET_JSET_CSUM_TYPE(jset, bch2_meta_checksum_type(c)); if (bch2_csum_type_is_encryption(JSET_CSUM_TYPE(jset)) && - journal_entry_validate_entries(c, jset, WRITE)) + jset_validate_entries(c, jset, WRITE)) goto err; bch2_encrypt(c, JSET_CSUM_TYPE(jset), journal_nonce(jset), @@ -1262,7 +1312,7 @@ void bch2_journal_write(struct closure *cl) journal_nonce(jset), jset); if (!bch2_csum_type_is_encryption(JSET_CSUM_TYPE(jset)) && - journal_entry_validate_entries(c, jset, WRITE)) + jset_validate_entries(c, jset, WRITE)) goto err; sectors = vstruct_sectors(jset, c->block_bits); diff --git a/fs/bcachefs/journal_io.h b/fs/bcachefs/journal_io.h index 9b0cb6d99889..4236b7fc37ff 100644 --- a/fs/bcachefs/journal_io.h +++ b/fs/bcachefs/journal_io.h @@ -34,7 +34,7 @@ static inline struct jset_entry *__jset_entry_type_next(struct jset *jset, entry = vstruct_next(entry)) #define for_each_jset_key(k, _n, entry, jset) \ - for_each_jset_entry_type(entry, jset, JOURNAL_ENTRY_BTREE_KEYS) \ + for_each_jset_entry_type(entry, jset, BCH_JSET_ENTRY_btree_keys) \ vstruct_for_each_safe(entry, k, _n) int bch2_journal_read(struct bch_fs *, struct list_head *); diff --git a/fs/bcachefs/journal_seq_blacklist.c b/fs/bcachefs/journal_seq_blacklist.c index bc0cad3c43b7..093e3147ce76 100644 --- a/fs/bcachefs/journal_seq_blacklist.c +++ b/fs/bcachefs/journal_seq_blacklist.c @@ -276,7 +276,7 @@ int bch2_journal_seq_blacklist_read(struct journal *j, u64 seq; for_each_jset_entry_type(entry, &i->j, - JOURNAL_ENTRY_JOURNAL_SEQ_BLACKLISTED) { + BCH_JSET_ENTRY_blacklist) { struct jset_entry_blacklist *bl_entry = container_of(entry, struct jset_entry_blacklist, entry); seq = le64_to_cpu(bl_entry->seq); @@ -307,7 +307,7 @@ void bch2_journal_seq_blacklist_write(struct journal *j) list_for_each_entry(bl, &j->seq_blacklist, list) if (!bl->written) { bch2_journal_add_entry_noreservation(journal_cur_buf(j), - JOURNAL_ENTRY_JOURNAL_SEQ_BLACKLISTED, + BCH_JSET_ENTRY_blacklist, 0, 0, &bl->seq, 1); bch2_journal_pin_add(j, |