diff options
author | Kent Overstreet <kmo@daterainc.com> | 2013-09-24 02:17:35 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-10-05 10:13:09 -0400 |
commit | df8b0d944cae63df86dba0edaa8fa8f5efaa7e03 (patch) | |
tree | 350da3f4b0ef9e6b05b07404f0b1df06c31b975e | |
parent | 7866bece346caecd88c53c6603e178ce4ebda87b (diff) |
bcache: Fix for handling overlapping extents when reading in a btree node
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>
-rw-r--r-- | drivers/md/bcache/bset.c | 39 |
1 files changed, 28 insertions, 11 deletions
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c index cb4578a327b9..14032e8c7731 100644 --- a/drivers/md/bcache/bset.c +++ b/drivers/md/bcache/bset.c | |||
@@ -918,28 +918,45 @@ struct bkey *bch_next_recurse_key(struct btree *b, struct bkey *search) | |||
918 | 918 | ||
919 | /* Mergesort */ | 919 | /* Mergesort */ |
920 | 920 | ||
921 | static void sort_key_next(struct btree_iter *iter, | ||
922 | struct btree_iter_set *i) | ||
923 | { | ||
924 | i->k = bkey_next(i->k); | ||
925 | |||
926 | if (i->k == i->end) | ||
927 | *i = iter->data[--iter->used]; | ||
928 | } | ||
929 | |||
921 | static void btree_sort_fixup(struct btree_iter *iter) | 930 | static void btree_sort_fixup(struct btree_iter *iter) |
922 | { | 931 | { |
923 | while (iter->used > 1) { | 932 | while (iter->used > 1) { |
924 | struct btree_iter_set *top = iter->data, *i = top + 1; | 933 | struct btree_iter_set *top = iter->data, *i = top + 1; |
925 | struct bkey *k; | ||
926 | 934 | ||
927 | if (iter->used > 2 && | 935 | if (iter->used > 2 && |
928 | btree_iter_cmp(i[0], i[1])) | 936 | btree_iter_cmp(i[0], i[1])) |
929 | i++; | 937 | i++; |
930 | 938 | ||
931 | for (k = i->k; | 939 | if (bkey_cmp(top->k, &START_KEY(i->k)) <= 0) |
932 | k != i->end && bkey_cmp(top->k, &START_KEY(k)) > 0; | ||
933 | k = bkey_next(k)) | ||
934 | if (top->k > i->k) | ||
935 | __bch_cut_front(top->k, k); | ||
936 | else if (KEY_SIZE(k)) | ||
937 | bch_cut_back(&START_KEY(k), top->k); | ||
938 | |||
939 | if (top->k < i->k || k == i->k) | ||
940 | break; | 940 | break; |
941 | 941 | ||
942 | heap_sift(iter, i - top, btree_iter_cmp); | 942 | if (!KEY_SIZE(i->k)) { |
943 | sort_key_next(iter, i); | ||
944 | heap_sift(iter, i - top, btree_iter_cmp); | ||
945 | continue; | ||
946 | } | ||
947 | |||
948 | if (top->k > i->k) { | ||
949 | if (bkey_cmp(top->k, i->k) >= 0) | ||
950 | sort_key_next(iter, i); | ||
951 | else | ||
952 | bch_cut_front(top->k, i->k); | ||
953 | |||
954 | heap_sift(iter, i - top, btree_iter_cmp); | ||
955 | } else { | ||
956 | /* can't happen because of comparison func */ | ||
957 | BUG_ON(!bkey_cmp(&START_KEY(top->k), &START_KEY(i->k))); | ||
958 | bch_cut_back(&START_KEY(i->k), top->k); | ||
959 | } | ||
943 | } | 960 | } |
944 | } | 961 | } |
945 | 962 | ||