aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorKent Overstreet <kmo@daterainc.com>2013-12-18 01:49:08 -0500
committerKent Overstreet <kmo@daterainc.com>2014-01-08 16:05:10 -0500
commit78b77bf8b20431f8ad8a4db7e3120103bd922337 (patch)
tree58ba4fd6e8a069a10a23562275a97554dcde89f9 /drivers/md
parent88b9f8c426f35e04738220c1bc05dd1ea1b513a3 (diff)
bcache: Btree verify code improvements
Used this fixed code to find and fix the bug fixed by a4d885097b0ac0cd1337f171f2d4b83e946094d4. Signed-off-by: Kent Overstreet <kmo@daterainc.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/bcache/bcache.h1
-rw-r--r--drivers/md/bcache/bset.c3
-rw-r--r--drivers/md/bcache/btree.c16
-rw-r--r--drivers/md/bcache/btree.h2
-rw-r--r--drivers/md/bcache/debug.c97
-rw-r--r--drivers/md/bcache/debug.h4
6 files changed, 83 insertions, 40 deletions
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index d955a4934616..eb6f2e6927ad 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -629,6 +629,7 @@ struct cache_set {
629 629
630#ifdef CONFIG_BCACHE_DEBUG 630#ifdef CONFIG_BCACHE_DEBUG
631 struct btree *verify_data; 631 struct btree *verify_data;
632 struct bset *verify_ondisk;
632 struct mutex verify_lock; 633 struct mutex verify_lock;
633#endif 634#endif
634 635
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c
index e51a739f7514..98f0ced236b6 100644
--- a/drivers/md/bcache/bset.c
+++ b/drivers/md/bcache/bset.c
@@ -1060,9 +1060,6 @@ static void __btree_sort(struct btree *b, struct btree_iter *iter,
1060 btree_mergesort(b, out, iter, fixup, remove_stale); 1060 btree_mergesort(b, out, iter, fixup, remove_stale);
1061 b->nsets = start; 1061 b->nsets = start;
1062 1062
1063 if (!fixup && !start && b->written)
1064 bch_btree_verify(b, out);
1065
1066 if (!start && order == b->page_order) { 1063 if (!start && order == b->page_order) {
1067 /* 1064 /*
1068 * Our temporary buffer is the same size as the btree node's 1065 * Our temporary buffer is the same size as the btree node's
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c
index 8e2573a009f9..f035ae3b1289 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -203,7 +203,7 @@ static uint64_t btree_csum_set(struct btree *b, struct bset *i)
203 return crc ^ 0xffffffffffffffffULL; 203 return crc ^ 0xffffffffffffffffULL;
204} 204}
205 205
206static void bch_btree_node_read_done(struct btree *b) 206void bch_btree_node_read_done(struct btree *b)
207{ 207{
208 const char *err = "bad btree header"; 208 const char *err = "bad btree header";
209 struct bset *i = b->sets[0].data; 209 struct bset *i = b->sets[0].data;
@@ -290,7 +290,7 @@ static void btree_node_read_endio(struct bio *bio, int error)
290 closure_put(cl); 290 closure_put(cl);
291} 291}
292 292
293void bch_btree_node_read(struct btree *b) 293static void bch_btree_node_read(struct btree *b)
294{ 294{
295 uint64_t start_time = local_clock(); 295 uint64_t start_time = local_clock();
296 struct closure cl; 296 struct closure cl;
@@ -478,6 +478,13 @@ void bch_btree_node_write(struct btree *b, struct closure *parent)
478 478
479 bch_btree_sort_lazy(b); 479 bch_btree_sort_lazy(b);
480 480
481 /*
482 * do verify if there was more than one set initially (i.e. we did a
483 * sort) and we sorted down to a single set:
484 */
485 if (i != b->sets->data && !b->nsets)
486 bch_btree_verify(b);
487
481 if (b->written < btree_blocks(b)) 488 if (b->written < btree_blocks(b))
482 bch_bset_init_next(b); 489 bch_bset_init_next(b);
483} 490}
@@ -782,6 +789,8 @@ void bch_btree_cache_free(struct cache_set *c)
782#ifdef CONFIG_BCACHE_DEBUG 789#ifdef CONFIG_BCACHE_DEBUG
783 if (c->verify_data) 790 if (c->verify_data)
784 list_move(&c->verify_data->list, &c->btree_cache); 791 list_move(&c->verify_data->list, &c->btree_cache);
792
793 free_pages((unsigned long) c->verify_ondisk, ilog2(bucket_pages(c)));
785#endif 794#endif
786 795
787 list_splice(&c->btree_cache_freeable, 796 list_splice(&c->btree_cache_freeable,
@@ -822,6 +831,9 @@ int bch_btree_cache_alloc(struct cache_set *c)
822#ifdef CONFIG_BCACHE_DEBUG 831#ifdef CONFIG_BCACHE_DEBUG
823 mutex_init(&c->verify_lock); 832 mutex_init(&c->verify_lock);
824 833
834 c->verify_ondisk = (void *)
835 __get_free_pages(GFP_KERNEL, ilog2(bucket_pages(c)));
836
825 c->verify_data = mca_bucket_alloc(c, &ZERO_KEY, GFP_KERNEL); 837 c->verify_data = mca_bucket_alloc(c, &ZERO_KEY, GFP_KERNEL);
826 838
827 if (c->verify_data && 839 if (c->verify_data &&
diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h
index 12c99b1a764d..580b01137264 100644
--- a/drivers/md/bcache/btree.h
+++ b/drivers/md/bcache/btree.h
@@ -292,7 +292,7 @@ static inline void rw_unlock(bool w, struct btree *b)
292 (w ? up_write : up_read)(&b->lock); 292 (w ? up_write : up_read)(&b->lock);
293} 293}
294 294
295void bch_btree_node_read(struct btree *); 295void bch_btree_node_read_done(struct btree *);
296void bch_btree_node_write(struct btree *, struct closure *); 296void bch_btree_node_write(struct btree *, struct closure *);
297 297
298void bch_btree_set_root(struct btree *); 298void bch_btree_set_root(struct btree *);
diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c
index 473e8d5a7fe1..8887c550d56c 100644
--- a/drivers/md/bcache/debug.c
+++ b/drivers/md/bcache/debug.c
@@ -53,18 +53,18 @@ int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k)
53 53
54#define p(...) (out += scnprintf(out, end - out, __VA_ARGS__)) 54#define p(...) (out += scnprintf(out, end - out, __VA_ARGS__))
55 55
56 p("%llu:%llu len %llu -> [", KEY_INODE(k), KEY_OFFSET(k), KEY_SIZE(k)); 56 p("%llu:%llu len %llu -> [", KEY_INODE(k), KEY_START(k), KEY_SIZE(k));
57
58 if (KEY_PTRS(k))
59 while (1) {
60 p("%llu:%llu gen %llu",
61 PTR_DEV(k, i), PTR_OFFSET(k, i), PTR_GEN(k, i));
62
63 if (++i == KEY_PTRS(k))
64 break;
65 57
58 for (i = 0; i < KEY_PTRS(k); i++) {
59 if (i)
66 p(", "); 60 p(", ");
67 } 61
62 if (PTR_DEV(k, i) == PTR_CHECK_DEV)
63 p("check dev");
64 else
65 p("%llu:%llu gen %llu", PTR_DEV(k, i),
66 PTR_OFFSET(k, i), PTR_GEN(k, i));
67 }
68 68
69 p("]"); 69 p("]");
70 70
@@ -78,7 +78,7 @@ int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k)
78 78
79#ifdef CONFIG_BCACHE_DEBUG 79#ifdef CONFIG_BCACHE_DEBUG
80 80
81static void dump_bset(struct btree *b, struct bset *i) 81static void dump_bset(struct btree *b, struct bset *i, unsigned set)
82{ 82{
83 struct bkey *k, *next; 83 struct bkey *k, *next;
84 unsigned j; 84 unsigned j;
@@ -88,7 +88,7 @@ static void dump_bset(struct btree *b, struct bset *i)
88 next = bkey_next(k); 88 next = bkey_next(k);
89 89
90 bch_bkey_to_text(buf, sizeof(buf), k); 90 bch_bkey_to_text(buf, sizeof(buf), k);
91 printk(KERN_ERR "block %u key %zi/%u: %s", bset_block_offset(b, i), 91 printk(KERN_ERR "b %u k %zi/%u: %s", set,
92 (uint64_t *) k - i->d, i->keys, buf); 92 (uint64_t *) k - i->d, i->keys, buf);
93 93
94 for (j = 0; j < KEY_PTRS(k); j++) { 94 for (j = 0; j < KEY_PTRS(k); j++) {
@@ -114,50 +114,83 @@ static void bch_dump_bucket(struct btree *b)
114 114
115 console_lock(); 115 console_lock();
116 for (i = 0; i <= b->nsets; i++) 116 for (i = 0; i <= b->nsets; i++)
117 dump_bset(b, b->sets[i].data); 117 dump_bset(b, b->sets[i].data,
118 bset_block_offset(b, b->sets[i].data));
118 console_unlock(); 119 console_unlock();
119} 120}
120 121
121void bch_btree_verify(struct btree *b, struct bset *new) 122#define for_each_written_bset(b, start, i) \
123 for (i = (start); \
124 (void *) i < (void *) (start) + (KEY_SIZE(&b->key) << 9) &&\
125 i->seq == (start)->seq; \
126 i = (void *) i + set_blocks(i, b->c) * block_bytes(b->c))
127
128void bch_btree_verify(struct btree *b)
122{ 129{
123 struct btree *v = b->c->verify_data; 130 struct btree *v = b->c->verify_data;
124 struct closure cl; 131 struct bset *ondisk, *sorted, *inmemory;
125 closure_init_stack(&cl); 132 struct bio *bio;
126 133
127 if (!b->c->verify) 134 if (!b->c->verify || !b->c->verify_ondisk)
128 return; 135 return;
129 136
130 down(&b->io_mutex); 137 down(&b->io_mutex);
131 mutex_lock(&b->c->verify_lock); 138 mutex_lock(&b->c->verify_lock);
132 139
140 ondisk = b->c->verify_ondisk;
141 sorted = b->c->verify_data->sets->data;
142 inmemory = b->sets->data;
143
133 bkey_copy(&v->key, &b->key); 144 bkey_copy(&v->key, &b->key);
134 v->written = 0; 145 v->written = 0;
135 v->level = b->level; 146 v->level = b->level;
136 147
137 bch_btree_node_read(v); 148 bio = bch_bbio_alloc(b->c);
149 bio->bi_bdev = PTR_CACHE(b->c, &b->key, 0)->bdev;
150 bio->bi_iter.bi_sector = PTR_OFFSET(&b->key, 0);
151 bio->bi_iter.bi_size = KEY_SIZE(&v->key) << 9;
152 bch_bio_map(bio, sorted);
138 153
139 if (new->keys != v->sets[0].data->keys || 154 submit_bio_wait(REQ_META|READ_SYNC, bio);
140 memcmp(new->start, 155 bch_bbio_free(bio, b->c);
141 v->sets[0].data->start, 156
142 (void *) end(new) - (void *) new->start)) { 157 memcpy(ondisk, sorted, KEY_SIZE(&v->key) << 9);
143 unsigned i, j; 158
159 bch_btree_node_read_done(v);
160 sorted = v->sets->data;
161
162 if (inmemory->keys != sorted->keys ||
163 memcmp(inmemory->start,
164 sorted->start,
165 (void *) end(inmemory) - (void *) inmemory->start)) {
166 struct bset *i;
167 unsigned j;
144 168
145 console_lock(); 169 console_lock();
146 170
147 printk(KERN_ERR "*** original memory node:\n"); 171 printk(KERN_ERR "*** in memory:\n");
148 for (i = 0; i <= b->nsets; i++) 172 dump_bset(b, inmemory, 0);
149 dump_bset(b, b->sets[i].data);
150 173
151 printk(KERN_ERR "*** sorted memory node:\n"); 174 printk(KERN_ERR "*** read back in:\n");
152 dump_bset(b, new); 175 dump_bset(v, sorted, 0);
153 176
154 printk(KERN_ERR "*** on disk node:\n"); 177 for_each_written_bset(b, ondisk, i) {
155 dump_bset(v, v->sets[0].data); 178 unsigned block = ((void *) i - (void *) ondisk) /
179 block_bytes(b->c);
156 180
157 for (j = 0; j < new->keys; j++) 181 printk(KERN_ERR "*** on disk block %u:\n", block);
158 if (new->d[j] != v->sets[0].data->d[j]) 182 dump_bset(b, i, block);
183 }
184
185 printk(KERN_ERR "*** block %zu not written\n",
186 ((void *) i - (void *) ondisk) / block_bytes(b->c));
187
188 for (j = 0; j < inmemory->keys; j++)
189 if (inmemory->d[j] != sorted->d[j])
159 break; 190 break;
160 191
192 printk(KERN_ERR "b->written %u\n", b->written);
193
161 console_unlock(); 194 console_unlock();
162 panic("verify failed at %u\n", j); 195 panic("verify failed at %u\n", j);
163 } 196 }
diff --git a/drivers/md/bcache/debug.h b/drivers/md/bcache/debug.h
index 2ede60e31874..08e116e74d36 100644
--- a/drivers/md/bcache/debug.h
+++ b/drivers/md/bcache/debug.h
@@ -7,7 +7,7 @@ int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k);
7 7
8#ifdef CONFIG_BCACHE_DEBUG 8#ifdef CONFIG_BCACHE_DEBUG
9 9
10void bch_btree_verify(struct btree *, struct bset *); 10void bch_btree_verify(struct btree *);
11void bch_data_verify(struct cached_dev *, struct bio *); 11void bch_data_verify(struct cached_dev *, struct bio *);
12int __bch_count_data(struct btree *); 12int __bch_count_data(struct btree *);
13void __bch_check_keys(struct btree *, const char *, ...); 13void __bch_check_keys(struct btree *, const char *, ...);
@@ -20,7 +20,7 @@ void bch_btree_iter_next_check(struct btree_iter *);
20 20
21#else /* DEBUG */ 21#else /* DEBUG */
22 22
23static inline void bch_btree_verify(struct btree *b, struct bset *i) {} 23static inline void bch_btree_verify(struct btree *b) {}
24static inline void bch_data_verify(struct cached_dev *dc, struct bio *bio) {} 24static inline void bch_data_verify(struct cached_dev *dc, struct bio *bio) {}
25static inline int __bch_count_data(struct btree *b) { return -1; } 25static inline int __bch_count_data(struct btree *b) { return -1; }
26static inline void __bch_check_keys(struct btree *b, const char *fmt, ...) {} 26static inline void __bch_check_keys(struct btree *b, const char *fmt, ...) {}