| From 84786438ed17978d72eeced580ab757e4da8830b Mon Sep 17 00:00:00 2001 |
| From: Kent Overstreet <kmo@daterainc.com> |
| Date: Mon, 23 Sep 2013 23:17:35 -0700 |
| Subject: bcache: Fix for handling overlapping extents when reading in a btree node |
| |
| From: Kent Overstreet <kmo@daterainc.com> |
| |
| commit 84786438ed17978d72eeced580ab757e4da8830b upstream. |
| |
| btree_sort_fixup() was overly clever, because it was trying to avoid |
| pulling a key off the btree iterator in more than one place. |
| |
| This led to a really obscure bug where we'd break early from the loop in |
| btree_sort_fixup() if the current key overlapped with keys in more than |
| one older set, and the next key it overlapped with was zero size. |
| |
| Signed-off-by: Kent Overstreet <kmo@daterainc.com> |
| Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/md/bcache/bset.c | 39 ++++++++++++++++++++++++++++----------- |
| 1 file changed, 28 insertions(+), 11 deletions(-) |
| |
| --- a/drivers/md/bcache/bset.c |
| +++ b/drivers/md/bcache/bset.c |
| @@ -918,28 +918,45 @@ struct bkey *bch_next_recurse_key(struct |
| |
| /* Mergesort */ |
| |
| +static void sort_key_next(struct btree_iter *iter, |
| + struct btree_iter_set *i) |
| +{ |
| + i->k = bkey_next(i->k); |
| + |
| + if (i->k == i->end) |
| + *i = iter->data[--iter->used]; |
| +} |
| + |
| static void btree_sort_fixup(struct btree_iter *iter) |
| { |
| while (iter->used > 1) { |
| struct btree_iter_set *top = iter->data, *i = top + 1; |
| - struct bkey *k; |
| |
| if (iter->used > 2 && |
| btree_iter_cmp(i[0], i[1])) |
| i++; |
| |
| - for (k = i->k; |
| - k != i->end && bkey_cmp(top->k, &START_KEY(k)) > 0; |
| - k = bkey_next(k)) |
| - if (top->k > i->k) |
| - __bch_cut_front(top->k, k); |
| - else if (KEY_SIZE(k)) |
| - bch_cut_back(&START_KEY(k), top->k); |
| - |
| - if (top->k < i->k || k == i->k) |
| + if (bkey_cmp(top->k, &START_KEY(i->k)) <= 0) |
| break; |
| |
| - heap_sift(iter, i - top, btree_iter_cmp); |
| + if (!KEY_SIZE(i->k)) { |
| + sort_key_next(iter, i); |
| + heap_sift(iter, i - top, btree_iter_cmp); |
| + continue; |
| + } |
| + |
| + if (top->k > i->k) { |
| + if (bkey_cmp(top->k, i->k) >= 0) |
| + sort_key_next(iter, i); |
| + else |
| + bch_cut_front(top->k, i->k); |
| + |
| + heap_sift(iter, i - top, btree_iter_cmp); |
| + } else { |
| + /* can't happen because of comparison func */ |
| + BUG_ON(!bkey_cmp(&START_KEY(top->k), &START_KEY(i->k))); |
| + bch_cut_back(&START_KEY(i->k), top->k); |
| + } |
| } |
| } |
| |