diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-12-23 17:50:58 -0900 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2017-01-18 21:41:33 -0900 |
commit | 8d8f1adfb5a592283cdb9966d6dbf718a5b90652 (patch) | |
tree | 41370110eae98abfaa3b288e8a85b64a09e4999f | |
parent | c41663001c1af67b631b991c5b208a4f782a497d (diff) |
bcache: Check for duplicate journal entries
-rw-r--r-- | drivers/md/bcache/journal.c | 62 |
1 files changed, 33 insertions, 29 deletions
diff --git a/drivers/md/bcache/journal.c b/drivers/md/bcache/journal.c index b9ff105b8518..4fd14101224a 100644 --- a/drivers/md/bcache/journal.c +++ b/drivers/md/bcache/journal.c @@ -382,36 +382,34 @@ struct journal_list { int ret; }; +#define JOURNAL_ENTRY_ADD_OK 0 +#define JOURNAL_ENTRY_ADD_OUT_OF_RANGE 5 + /* * Given a journal entry we just read, add it to the list of journal entries to * be replayed: */ -static enum { - JOURNAL_ENTRY_ADD_ERROR, - JOURNAL_ENTRY_ADD_OUT_OF_RANGE, - JOURNAL_ENTRY_ADD_OK, - -} journal_entry_add(struct journal_list *jlist, struct jset *j) +static int journal_entry_add(struct cache_set *c, struct journal_list *jlist, + struct jset *j) { struct journal_replay *i, *pos; struct list_head *where; size_t bytes = __set_bytes(j, le32_to_cpu(j->u64s)); - int ret = JOURNAL_ENTRY_ADD_OUT_OF_RANGE; + __le64 last_seq; + int ret; mutex_lock(&jlist->lock); - /* This entry too old? */ - if (!list_empty(jlist->head)) { - i = list_last_entry(jlist->head, struct journal_replay, list); - if (le64_to_cpu(j->seq) < le64_to_cpu(i->j.last_seq)) { - pr_debug("j->seq %llu i->j.seq %llu", - le64_to_cpu(j->seq), - le64_to_cpu(i->j.seq)); - goto out; - } - } + last_seq = !list_empty(jlist->head) + ? list_last_entry(jlist->head, struct journal_replay, + list)->j.last_seq + : 0; - ret = JOURNAL_ENTRY_ADD_OK; + /* Is this entry older than the range we need? */ + if (le64_to_cpu(j->seq) < le64_to_cpu(last_seq)) { + ret = JOURNAL_ENTRY_ADD_OUT_OF_RANGE; + goto out; + } /* Drop entries we don't need anymore */ list_for_each_entry_safe(i, pos, jlist->head, list) { @@ -422,9 +420,15 @@ static enum { } list_for_each_entry_reverse(i, jlist->head, list) { + /* Duplicate? */ if (le64_to_cpu(j->seq) == le64_to_cpu(i->j.seq)) { - pr_debug("j->seq %llu i->j.seq %llu", - j->seq, i->j.seq); + fsck_err_on(bytes != __set_bytes(&i->j, + le32_to_cpu(i->j.u64s)) || + memcmp(j, &i->j, bytes), c, + "found duplicate but non identical journal entries (seq %llu)", + le64_to_cpu(j->seq)); + + ret = JOURNAL_ENTRY_ADD_OK; goto out; } @@ -438,15 +442,15 @@ static enum { add: i = kvmalloc(offsetof(struct journal_replay, j) + bytes, GFP_KERNEL); if (!i) { - ret = JOURNAL_ENTRY_ADD_ERROR; + ret = -ENOMEM; goto out; } memcpy(&i->j, j, bytes); list_add(&i->list, where); - - pr_debug("seq %llu", le64_to_cpu(j->seq)); + ret = JOURNAL_ENTRY_ADD_OK; out: +fsck_err: mutex_unlock(&jlist->lock); return ret; } @@ -715,15 +719,15 @@ reread: ja->bucket_seq[bucket] = le64_to_cpu(j->seq); - switch (journal_entry_add(jlist, j)) { - case JOURNAL_ENTRY_ADD_ERROR: - ret = -ENOMEM; - goto err; - case JOURNAL_ENTRY_ADD_OUT_OF_RANGE: - break; + ret = journal_entry_add(c, jlist, j); + switch (ret) { case JOURNAL_ENTRY_ADD_OK: *entries_found = true; break; + case JOURNAL_ENTRY_ADD_OUT_OF_RANGE: + break; + default: + goto err; } if (le64_to_cpu(j->seq) > *seq) |