diff options
Diffstat (limited to 'drivers/md/bcache/debug.c')
-rw-r--r-- | drivers/md/bcache/debug.c | 247 |
1 files changed, 56 insertions, 191 deletions
diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 03cb4d114e16..8b1f1d5c1819 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include "bcache.h" | 8 | #include "bcache.h" |
9 | #include "btree.h" | 9 | #include "btree.h" |
10 | #include "debug.h" | 10 | #include "debug.h" |
11 | #include "extents.h" | ||
11 | 12 | ||
12 | #include <linux/console.h> | 13 | #include <linux/console.h> |
13 | #include <linux/debugfs.h> | 14 | #include <linux/debugfs.h> |
@@ -17,156 +18,88 @@ | |||
17 | 18 | ||
18 | static struct dentry *debug; | 19 | static struct dentry *debug; |
19 | 20 | ||
20 | const char *bch_ptr_status(struct cache_set *c, const struct bkey *k) | ||
21 | { | ||
22 | unsigned i; | ||
23 | |||
24 | for (i = 0; i < KEY_PTRS(k); i++) | ||
25 | if (ptr_available(c, k, i)) { | ||
26 | struct cache *ca = PTR_CACHE(c, k, i); | ||
27 | size_t bucket = PTR_BUCKET_NR(c, k, i); | ||
28 | size_t r = bucket_remainder(c, PTR_OFFSET(k, i)); | ||
29 | |||
30 | if (KEY_SIZE(k) + r > c->sb.bucket_size) | ||
31 | return "bad, length too big"; | ||
32 | if (bucket < ca->sb.first_bucket) | ||
33 | return "bad, short offset"; | ||
34 | if (bucket >= ca->sb.nbuckets) | ||
35 | return "bad, offset past end of device"; | ||
36 | if (ptr_stale(c, k, i)) | ||
37 | return "stale"; | ||
38 | } | ||
39 | |||
40 | if (!bkey_cmp(k, &ZERO_KEY)) | ||
41 | return "bad, null key"; | ||
42 | if (!KEY_PTRS(k)) | ||
43 | return "bad, no pointers"; | ||
44 | if (!KEY_SIZE(k)) | ||
45 | return "zeroed key"; | ||
46 | return ""; | ||
47 | } | ||
48 | |||
49 | int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k) | ||
50 | { | ||
51 | unsigned i = 0; | ||
52 | char *out = buf, *end = buf + size; | ||
53 | |||
54 | #define p(...) (out += scnprintf(out, end - out, __VA_ARGS__)) | ||
55 | |||
56 | p("%llu:%llu len %llu -> [", KEY_INODE(k), KEY_OFFSET(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 | |||
66 | p(", "); | ||
67 | } | ||
68 | |||
69 | p("]"); | ||
70 | |||
71 | if (KEY_DIRTY(k)) | ||
72 | p(" dirty"); | ||
73 | if (KEY_CSUM(k)) | ||
74 | p(" cs%llu %llx", KEY_CSUM(k), k->ptr[1]); | ||
75 | #undef p | ||
76 | return out - buf; | ||
77 | } | ||
78 | |||
79 | #ifdef CONFIG_BCACHE_DEBUG | 21 | #ifdef CONFIG_BCACHE_DEBUG |
80 | 22 | ||
81 | static void dump_bset(struct btree *b, struct bset *i) | 23 | #define for_each_written_bset(b, start, i) \ |
82 | { | 24 | for (i = (start); \ |
83 | struct bkey *k, *next; | 25 | (void *) i < (void *) (start) + (KEY_SIZE(&b->key) << 9) &&\ |
84 | unsigned j; | 26 | i->seq == (start)->seq; \ |
85 | char buf[80]; | 27 | i = (void *) i + set_blocks(i, block_bytes(b->c)) * \ |
86 | 28 | block_bytes(b->c)) | |
87 | for (k = i->start; k < end(i); k = next) { | ||
88 | next = bkey_next(k); | ||
89 | |||
90 | bch_bkey_to_text(buf, sizeof(buf), k); | ||
91 | printk(KERN_ERR "block %zu key %zi/%u: %s", index(i, b), | ||
92 | (uint64_t *) k - i->d, i->keys, buf); | ||
93 | |||
94 | for (j = 0; j < KEY_PTRS(k); j++) { | ||
95 | size_t n = PTR_BUCKET_NR(b->c, k, j); | ||
96 | printk(" bucket %zu", n); | ||
97 | |||
98 | if (n >= b->c->sb.first_bucket && n < b->c->sb.nbuckets) | ||
99 | printk(" prio %i", | ||
100 | PTR_BUCKET(b->c, k, j)->prio); | ||
101 | } | ||
102 | 29 | ||
103 | printk(" %s\n", bch_ptr_status(b->c, k)); | 30 | void bch_btree_verify(struct btree *b) |
104 | |||
105 | if (next < end(i) && | ||
106 | bkey_cmp(k, !b->level ? &START_KEY(next) : next) > 0) | ||
107 | printk(KERN_ERR "Key skipped backwards\n"); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | static void bch_dump_bucket(struct btree *b) | ||
112 | { | ||
113 | unsigned i; | ||
114 | |||
115 | console_lock(); | ||
116 | for (i = 0; i <= b->nsets; i++) | ||
117 | dump_bset(b, b->sets[i].data); | ||
118 | console_unlock(); | ||
119 | } | ||
120 | |||
121 | void bch_btree_verify(struct btree *b, struct bset *new) | ||
122 | { | 31 | { |
123 | struct btree *v = b->c->verify_data; | 32 | struct btree *v = b->c->verify_data; |
124 | struct closure cl; | 33 | struct bset *ondisk, *sorted, *inmemory; |
125 | closure_init_stack(&cl); | 34 | struct bio *bio; |
126 | 35 | ||
127 | if (!b->c->verify) | 36 | if (!b->c->verify || !b->c->verify_ondisk) |
128 | return; | 37 | return; |
129 | 38 | ||
130 | closure_wait_event(&b->io.wait, &cl, | 39 | down(&b->io_mutex); |
131 | atomic_read(&b->io.cl.remaining) == -1); | ||
132 | |||
133 | mutex_lock(&b->c->verify_lock); | 40 | mutex_lock(&b->c->verify_lock); |
134 | 41 | ||
42 | ondisk = b->c->verify_ondisk; | ||
43 | sorted = b->c->verify_data->keys.set->data; | ||
44 | inmemory = b->keys.set->data; | ||
45 | |||
135 | bkey_copy(&v->key, &b->key); | 46 | bkey_copy(&v->key, &b->key); |
136 | v->written = 0; | 47 | v->written = 0; |
137 | v->level = b->level; | 48 | v->level = b->level; |
49 | v->keys.ops = b->keys.ops; | ||
50 | |||
51 | bio = bch_bbio_alloc(b->c); | ||
52 | bio->bi_bdev = PTR_CACHE(b->c, &b->key, 0)->bdev; | ||
53 | bio->bi_iter.bi_sector = PTR_OFFSET(&b->key, 0); | ||
54 | bio->bi_iter.bi_size = KEY_SIZE(&v->key) << 9; | ||
55 | bch_bio_map(bio, sorted); | ||
138 | 56 | ||
139 | bch_btree_node_read(v); | 57 | submit_bio_wait(REQ_META|READ_SYNC, bio); |
140 | closure_wait_event(&v->io.wait, &cl, | 58 | bch_bbio_free(bio, b->c); |
141 | atomic_read(&b->io.cl.remaining) == -1); | ||
142 | 59 | ||
143 | if (new->keys != v->sets[0].data->keys || | 60 | memcpy(ondisk, sorted, KEY_SIZE(&v->key) << 9); |
144 | memcmp(new->start, | 61 | |
145 | v->sets[0].data->start, | 62 | bch_btree_node_read_done(v); |
146 | (void *) end(new) - (void *) new->start)) { | 63 | sorted = v->keys.set->data; |
147 | unsigned i, j; | 64 | |
65 | if (inmemory->keys != sorted->keys || | ||
66 | memcmp(inmemory->start, | ||
67 | sorted->start, | ||
68 | (void *) bset_bkey_last(inmemory) - (void *) inmemory->start)) { | ||
69 | struct bset *i; | ||
70 | unsigned j; | ||
148 | 71 | ||
149 | console_lock(); | 72 | console_lock(); |
150 | 73 | ||
151 | printk(KERN_ERR "*** original memory node:\n"); | 74 | printk(KERN_ERR "*** in memory:\n"); |
152 | for (i = 0; i <= b->nsets; i++) | 75 | bch_dump_bset(&b->keys, inmemory, 0); |
153 | dump_bset(b, b->sets[i].data); | ||
154 | 76 | ||
155 | printk(KERN_ERR "*** sorted memory node:\n"); | 77 | printk(KERN_ERR "*** read back in:\n"); |
156 | dump_bset(b, new); | 78 | bch_dump_bset(&v->keys, sorted, 0); |
157 | 79 | ||
158 | printk(KERN_ERR "*** on disk node:\n"); | 80 | for_each_written_bset(b, ondisk, i) { |
159 | dump_bset(v, v->sets[0].data); | 81 | unsigned block = ((void *) i - (void *) ondisk) / |
82 | block_bytes(b->c); | ||
83 | |||
84 | printk(KERN_ERR "*** on disk block %u:\n", block); | ||
85 | bch_dump_bset(&b->keys, i, block); | ||
86 | } | ||
160 | 87 | ||
161 | for (j = 0; j < new->keys; j++) | 88 | printk(KERN_ERR "*** block %zu not written\n", |
162 | if (new->d[j] != v->sets[0].data->d[j]) | 89 | ((void *) i - (void *) ondisk) / block_bytes(b->c)); |
90 | |||
91 | for (j = 0; j < inmemory->keys; j++) | ||
92 | if (inmemory->d[j] != sorted->d[j]) | ||
163 | break; | 93 | break; |
164 | 94 | ||
95 | printk(KERN_ERR "b->written %u\n", b->written); | ||
96 | |||
165 | console_unlock(); | 97 | console_unlock(); |
166 | panic("verify failed at %u\n", j); | 98 | panic("verify failed at %u\n", j); |
167 | } | 99 | } |
168 | 100 | ||
169 | mutex_unlock(&b->c->verify_lock); | 101 | mutex_unlock(&b->c->verify_lock); |
102 | up(&b->io_mutex); | ||
170 | } | 103 | } |
171 | 104 | ||
172 | void bch_data_verify(struct cached_dev *dc, struct bio *bio) | 105 | void bch_data_verify(struct cached_dev *dc, struct bio *bio) |
@@ -207,74 +140,6 @@ out_put: | |||
207 | bio_put(check); | 140 | bio_put(check); |
208 | } | 141 | } |
209 | 142 | ||
210 | int __bch_count_data(struct btree *b) | ||
211 | { | ||
212 | unsigned ret = 0; | ||
213 | struct btree_iter iter; | ||
214 | struct bkey *k; | ||
215 | |||
216 | if (!b->level) | ||
217 | for_each_key(b, k, &iter) | ||
218 | ret += KEY_SIZE(k); | ||
219 | return ret; | ||
220 | } | ||
221 | |||
222 | void __bch_check_keys(struct btree *b, const char *fmt, ...) | ||
223 | { | ||
224 | va_list args; | ||
225 | struct bkey *k, *p = NULL; | ||
226 | struct btree_iter iter; | ||
227 | const char *err; | ||
228 | |||
229 | for_each_key(b, k, &iter) { | ||
230 | if (!b->level) { | ||
231 | err = "Keys out of order"; | ||
232 | if (p && bkey_cmp(&START_KEY(p), &START_KEY(k)) > 0) | ||
233 | goto bug; | ||
234 | |||
235 | if (bch_ptr_invalid(b, k)) | ||
236 | continue; | ||
237 | |||
238 | err = "Overlapping keys"; | ||
239 | if (p && bkey_cmp(p, &START_KEY(k)) > 0) | ||
240 | goto bug; | ||
241 | } else { | ||
242 | if (bch_ptr_bad(b, k)) | ||
243 | continue; | ||
244 | |||
245 | err = "Duplicate keys"; | ||
246 | if (p && !bkey_cmp(p, k)) | ||
247 | goto bug; | ||
248 | } | ||
249 | p = k; | ||
250 | } | ||
251 | |||
252 | err = "Key larger than btree node key"; | ||
253 | if (p && bkey_cmp(p, &b->key) > 0) | ||
254 | goto bug; | ||
255 | |||
256 | return; | ||
257 | bug: | ||
258 | bch_dump_bucket(b); | ||
259 | |||
260 | va_start(args, fmt); | ||
261 | vprintk(fmt, args); | ||
262 | va_end(args); | ||
263 | |||
264 | panic("bcache error: %s:\n", err); | ||
265 | } | ||
266 | |||
267 | void bch_btree_iter_next_check(struct btree_iter *iter) | ||
268 | { | ||
269 | struct bkey *k = iter->data->k, *next = bkey_next(k); | ||
270 | |||
271 | if (next < iter->data->end && | ||
272 | bkey_cmp(k, iter->b->level ? next : &START_KEY(next)) > 0) { | ||
273 | bch_dump_bucket(iter->b); | ||
274 | panic("Key skipped backwards\n"); | ||
275 | } | ||
276 | } | ||
277 | |||
278 | #endif | 143 | #endif |
279 | 144 | ||
280 | #ifdef CONFIG_DEBUG_FS | 145 | #ifdef CONFIG_DEBUG_FS |
@@ -321,7 +186,7 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf, | |||
321 | if (!w) | 186 | if (!w) |
322 | break; | 187 | break; |
323 | 188 | ||
324 | bch_bkey_to_text(kbuf, sizeof(kbuf), &w->key); | 189 | bch_extent_to_text(kbuf, sizeof(kbuf), &w->key); |
325 | i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", kbuf); | 190 | i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", kbuf); |
326 | bch_keybuf_del(&i->keys, w); | 191 | bch_keybuf_del(&i->keys, w); |
327 | } | 192 | } |