summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-05-02 16:31:37 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2018-05-02 16:31:37 -0400
commit783468809d4e820aae3c8cf48ab856c47b169bea (patch)
treefe988c70635d56f01cf9d0d87240ef9f4adf727a
parentd86b5f5134f1eddf922a27ea794c700e2eb00678 (diff)
bcachefs: Add an ops struct for jset entries
-rw-r--r--fs/bcachefs/bcachefs_format.h47
-rw-r--r--fs/bcachefs/journal.h4
-rw-r--r--fs/bcachefs/journal_io.c200
-rw-r--r--fs/bcachefs/journal_io.h2
-rw-r--r--fs/bcachefs/journal_seq_blacklist.c4
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,