diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2018-05-02 16:29:40 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2018-05-03 19:29:18 -0400 |
commit | 05e35e816e280e05a9a680a188d88323bcccf51e (patch) | |
tree | 92739bf19ebe23595ec24248c8d8fbeccfbca6c9 | |
parent | 606140f4d5ffe96d79cc204db952cfd20cc8ec6b (diff) |
bcachefs: journal_seq_blacklist_v2
-rw-r--r-- | fs/bcachefs/bcachefs_format.h | 3 | ||||
-rw-r--r-- | fs/bcachefs/journal.c | 6 | ||||
-rw-r--r-- | fs/bcachefs/journal.h | 39 | ||||
-rw-r--r-- | fs/bcachefs/journal_io.c | 35 | ||||
-rw-r--r-- | fs/bcachefs/journal_seq_blacklist.c | 119 | ||||
-rw-r--r-- | fs/bcachefs/journal_types.h | 6 |
6 files changed, 135 insertions, 73 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index 99f3016af80d..48d14a30e03e 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -1200,7 +1200,8 @@ struct jset_entry { x(btree_keys, 0) \ x(btree_root, 1) \ x(prio_ptrs, 2) \ - x(blacklist, 3) + x(blacklist, 3) \ + x(blacklist_v2, 4) enum { #define x(f, nr) BCH_JSET_ENTRY_##f = nr, diff --git a/fs/bcachefs/journal.c b/fs/bcachefs/journal.c index 7610e59765f9..b9449eb66d10 100644 --- a/fs/bcachefs/journal.c +++ b/fs/bcachefs/journal.c @@ -886,16 +886,16 @@ void bch2_fs_journal_stop(struct journal *j) void bch2_fs_journal_start(struct journal *j) { struct journal_seq_blacklist *bl; - u64 new_seq = 0; + u64 blacklist = 0; list_for_each_entry(bl, &j->seq_blacklist, list) - new_seq = max(new_seq, bl->seq); + blacklist = max(blacklist, bl->end); spin_lock(&j->lock); set_bit(JOURNAL_STARTED, &j->flags); - while (journal_cur_seq(j) < new_seq) + while (journal_cur_seq(j) < blacklist) journal_pin_new_entry(j, 0); /* diff --git a/fs/bcachefs/journal.h b/fs/bcachefs/journal.h index b106f32f96f1..4cec7bb56948 100644 --- a/fs/bcachefs/journal.h +++ b/fs/bcachefs/journal.h @@ -178,33 +178,18 @@ static inline unsigned jset_u64s(unsigned u64s) return u64s + sizeof(struct jset_entry) / sizeof(u64); } -static inline void bch2_journal_add_entry_at(struct journal_buf *buf, - unsigned offset, - unsigned type, enum btree_id id, - unsigned level, - const void *data, size_t u64s) +static inline struct jset_entry * +bch2_journal_add_entry_noreservation(struct journal_buf *buf, size_t u64s) { - struct jset_entry *entry = vstruct_idx(buf->data, offset); + struct jset *jset = buf->data; + struct jset_entry *entry = vstruct_idx(jset, le32_to_cpu(jset->u64s)); memset(entry, 0, sizeof(*entry)); - entry->u64s = cpu_to_le16(u64s); - entry->btree_id = id; - entry->level = level; - entry->type = type; + entry->u64s = cpu_to_le16(u64s); - memcpy_u64s(entry->_data, data, u64s); -} - -static inline void bch2_journal_add_entry_noreservation(struct journal_buf *buf, - unsigned type, enum btree_id id, - unsigned level, - const void *data, size_t u64s) -{ - struct jset *jset = buf->data; - - bch2_journal_add_entry_at(buf, le32_to_cpu(jset->u64s), - type, id, level, data, u64s); le32_add_cpu(&jset->u64s, jset_u64s(u64s)); + + return entry; } static inline void bch2_journal_add_entry(struct journal *j, struct journal_res *res, @@ -213,15 +198,21 @@ static inline void bch2_journal_add_entry(struct journal *j, struct journal_res const void *data, unsigned u64s) { struct journal_buf *buf = &j->buf[res->idx]; + struct jset_entry *entry = vstruct_idx(buf->data, res->offset); unsigned actual = jset_u64s(u64s); EBUG_ON(!res->ref); EBUG_ON(actual > res->u64s); - bch2_journal_add_entry_at(buf, res->offset, type, - id, level, data, u64s); res->offset += actual; res->u64s -= actual; + + memset(entry, 0, sizeof(*entry)); + entry->u64s = cpu_to_le16(u64s); + entry->type = type; + entry->btree_id = id; + entry->level = level; + memcpy_u64s(entry->_data, data, u64s); } static inline void bch2_journal_add_keys(struct journal *j, struct journal_res *res, diff --git a/fs/bcachefs/journal_io.c b/fs/bcachefs/journal_io.c index c9e7ee8abca0..5fd714ba6725 100644 --- a/fs/bcachefs/journal_io.c +++ b/fs/bcachefs/journal_io.c @@ -294,6 +294,31 @@ fsck_err: return ret; } +static int journal_entry_validate_blacklist_v2(struct bch_fs *c, + struct jset *jset, + struct jset_entry *entry, + int write) +{ + struct jset_entry_blacklist_v2 *bl_entry; + int ret = 0; + + if (journal_entry_err_on(le16_to_cpu(entry->u64s) != 2, c, + "invalid journal seq blacklist entry: bad size")) { + journal_entry_null_range(entry, vstruct_next(entry)); + } + + 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, + "invalid journal seq blacklist entry: start > end")) { + journal_entry_null_range(entry, vstruct_next(entry)); + } + +fsck_err: + return ret; +} + struct jset_entry_ops { int (*validate)(struct bch_fs *, struct jset *, struct jset_entry *, int); @@ -944,9 +969,13 @@ static void bch2_journal_add_btree_root(struct journal_buf *buf, enum btree_id id, struct bkey_i *k, unsigned level) { - bch2_journal_add_entry_noreservation(buf, - BCH_JSET_ENTRY_btree_root, id, level, - k, k->k.u64s); + struct jset_entry *entry; + + entry = bch2_journal_add_entry_noreservation(buf, k->k.u64s); + entry->type = BCH_JSET_ENTRY_btree_root; + entry->btree_id = id; + entry->level = level; + memcpy_u64s(entry->_data, k, k->k.u64s); } static unsigned journal_dev_buckets_available(struct journal *j, diff --git a/fs/bcachefs/journal_seq_blacklist.c b/fs/bcachefs/journal_seq_blacklist.c index 093e3147ce76..b5301d96469e 100644 --- a/fs/bcachefs/journal_seq_blacklist.c +++ b/fs/bcachefs/journal_seq_blacklist.c @@ -147,7 +147,7 @@ bch2_journal_seq_blacklist_find(struct journal *j, u64 seq) lockdep_assert_held(&j->blacklist_lock); list_for_each_entry(bl, &j->seq_blacklist, list) - if (seq == bl->seq) + if (seq >= bl->start && seq <= bl->end) return bl; return NULL; @@ -157,7 +157,7 @@ bch2_journal_seq_blacklist_find(struct journal *j, u64 seq) * Allocate a new, in memory blacklist entry: */ static struct journal_seq_blacklist * -bch2_journal_seq_blacklisted_new(struct journal *j, u64 seq) +bch2_journal_seq_blacklisted_new(struct journal *j, u64 start, u64 end) { struct journal_seq_blacklist *bl; @@ -171,7 +171,9 @@ bch2_journal_seq_blacklisted_new(struct journal *j, u64 seq) if (!bl) return NULL; - bl->seq = seq; + bl->start = start; + bl->end = end; + list_add_tail(&bl->list, &j->seq_blacklist); return bl; } @@ -187,7 +189,7 @@ int bch2_journal_seq_should_ignore(struct bch_fs *c, u64 seq, struct btree *b) struct journal *j = &c->journal; struct journal_seq_blacklist *bl = NULL; struct blacklisted_node *n; - u64 journal_seq, i; + u64 journal_seq; int ret = 0; if (!seq) @@ -205,9 +207,9 @@ int bch2_journal_seq_should_ignore(struct bch_fs *c, u64 seq, struct btree *b) * Decrease this back to j->seq + 2 when we next rev the on disk format: * increasing it temporarily to work around bug in old kernels */ - bch2_fs_inconsistent_on(seq > journal_seq + 4, c, - "bset journal seq too far in the future: %llu > %llu", - seq, journal_seq); + fsck_err_on(seq > journal_seq + 4, c, + "bset journal seq too far in the future: %llu > %llu", + seq, journal_seq); if (seq <= journal_seq && list_empty_careful(&j->seq_blacklist)) @@ -223,14 +225,17 @@ int bch2_journal_seq_should_ignore(struct bch_fs *c, u64 seq, struct btree *b) bch_verbose(c, "btree node %u:%llu:%llu has future journal sequence number %llu, blacklisting", b->btree_id, b->key.k.p.inode, b->key.k.p.offset, seq); - for (i = journal_seq + 1; i <= seq; i++) { - bl = bch2_journal_seq_blacklist_find(j, i) ?: - bch2_journal_seq_blacklisted_new(j, i); - if (!bl) { + if (!j->new_blacklist) { + j->new_blacklist = bch2_journal_seq_blacklisted_new(j, + journal_seq + 1, + journal_seq + 1); + if (!j->new_blacklist) { ret = -ENOMEM; goto out; } } + bl = j->new_blacklist; + bl->end = max(bl->end, seq); } for (n = bl->entries; n < bl->entries + bl->nr_entries; n++) @@ -259,10 +264,30 @@ int bch2_journal_seq_should_ignore(struct bch_fs *c, u64 seq, struct btree *b) found_entry: ret = 1; out: +fsck_err: mutex_unlock(&j->blacklist_lock); return ret; } +static int __bch2_journal_seq_blacklist_read(struct journal *j, + struct journal_replay *i, + u64 start, u64 end) +{ + struct bch_fs *c = container_of(j, struct bch_fs, journal); + struct journal_seq_blacklist *bl; + + bch_verbose(c, "blacklisting existing journal seq %llu-%llu", + start, end); + + bl = bch2_journal_seq_blacklisted_new(j, start, end); + if (!bl) + return -ENOMEM; + + bch2_journal_pin_add(j, le64_to_cpu(i->j.seq), &bl->pin, + journal_seq_blacklist_flush); + return 0; +} + /* * After reading the journal, find existing journal seq blacklist entries and * read them into memory: @@ -270,29 +295,36 @@ out: int bch2_journal_seq_blacklist_read(struct journal *j, struct journal_replay *i) { - struct bch_fs *c = container_of(j, struct bch_fs, journal); struct jset_entry *entry; - struct journal_seq_blacklist *bl; - u64 seq; + int ret = 0; - for_each_jset_entry_type(entry, &i->j, - 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); + vstruct_for_each(&i->j, entry) { + switch (entry->type) { + case BCH_JSET_ENTRY_blacklist: { + struct jset_entry_blacklist *bl_entry = + container_of(entry, struct jset_entry_blacklist, entry); - bch_verbose(c, "blacklisting existing journal seq %llu", seq); + ret = __bch2_journal_seq_blacklist_read(j, i, + le64_to_cpu(bl_entry->seq), + le64_to_cpu(bl_entry->seq)); + break; + } + case BCH_JSET_ENTRY_blacklist_v2: { + struct jset_entry_blacklist_v2 *bl_entry = + container_of(entry, struct jset_entry_blacklist_v2, entry); - bl = bch2_journal_seq_blacklisted_new(j, seq); - if (!bl) - return -ENOMEM; + ret = __bch2_journal_seq_blacklist_read(j, i, + le64_to_cpu(bl_entry->start), + le64_to_cpu(bl_entry->end)); + break; + } + } - bch2_journal_pin_add(j, le64_to_cpu(i->j.seq), &bl->pin, - journal_seq_blacklist_flush); - bl->written = true; + if (ret) + break; } - return 0; + return ret; } /* @@ -302,18 +334,25 @@ int bch2_journal_seq_blacklist_read(struct journal *j, */ void bch2_journal_seq_blacklist_write(struct journal *j) { - struct journal_seq_blacklist *bl; + struct journal_seq_blacklist *bl = j->new_blacklist; + struct jset_entry_blacklist_v2 *bl_entry; + struct jset_entry *entry; - list_for_each_entry(bl, &j->seq_blacklist, list) - if (!bl->written) { - bch2_journal_add_entry_noreservation(journal_cur_buf(j), - BCH_JSET_ENTRY_blacklist, - 0, 0, &bl->seq, 1); - - bch2_journal_pin_add(j, - journal_cur_seq(j), - &bl->pin, - journal_seq_blacklist_flush); - bl->written = true; - } + if (!bl) + return; + + entry = bch2_journal_add_entry_noreservation(journal_cur_buf(j), + (sizeof(*bl_entry) - sizeof(*entry)) / sizeof(u64)); + + bl_entry = container_of(entry, struct jset_entry_blacklist_v2, entry); + bl_entry->entry.type = BCH_JSET_ENTRY_blacklist_v2; + bl_entry->start = cpu_to_le64(bl->start); + bl_entry->end = cpu_to_le64(bl->end); + + bch2_journal_pin_add(j, + journal_cur_seq(j), + &bl->pin, + journal_seq_blacklist_flush); + + j->new_blacklist = NULL; } diff --git a/fs/bcachefs/journal_types.h b/fs/bcachefs/journal_types.h index 8a8059ee70db..a27e0548c098 100644 --- a/fs/bcachefs/journal_types.h +++ b/fs/bcachefs/journal_types.h @@ -59,8 +59,9 @@ struct blacklisted_node { struct journal_seq_blacklist { struct list_head list; - u64 seq; - bool written; + u64 start; + u64 end; + struct journal_entry_pin pin; struct blacklisted_node *entries; @@ -175,6 +176,7 @@ struct journal { struct mutex blacklist_lock; struct list_head seq_blacklist; + struct journal_seq_blacklist *new_blacklist; BKEY_PADDED(key); struct write_point wp; |