summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-05-02 16:29:40 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2018-05-03 19:29:18 -0400
commit05e35e816e280e05a9a680a188d88323bcccf51e (patch)
tree92739bf19ebe23595ec24248c8d8fbeccfbca6c9
parent606140f4d5ffe96d79cc204db952cfd20cc8ec6b (diff)
bcachefs: journal_seq_blacklist_v2
-rw-r--r--fs/bcachefs/bcachefs_format.h3
-rw-r--r--fs/bcachefs/journal.c6
-rw-r--r--fs/bcachefs/journal.h39
-rw-r--r--fs/bcachefs/journal_io.c35
-rw-r--r--fs/bcachefs/journal_seq_blacklist.c119
-rw-r--r--fs/bcachefs/journal_types.h6
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;