diff options
author | Kent Overstreet <kmo@daterainc.com> | 2013-12-18 02:47:33 -0500 |
---|---|---|
committer | Kent Overstreet <kmo@daterainc.com> | 2014-01-08 16:05:13 -0500 |
commit | dc9d98d621bdce0552997200ce855659875a5c9f (patch) | |
tree | d0339299ab01f50dd225446734a7d34164df2817 /drivers/md | |
parent | c052dd9a26f60bcf70c0c3fcc08e07abb60295cd (diff) |
bcache: Convert debug code to btree_keys
More work to disentangle various code from struct btree
Signed-off-by: Kent Overstreet <kmo@daterainc.com>
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/bcache/bset.c | 117 | ||||
-rw-r--r-- | drivers/md/bcache/bset.h | 56 | ||||
-rw-r--r-- | drivers/md/bcache/btree.c | 8 | ||||
-rw-r--r-- | drivers/md/bcache/debug.c | 179 | ||||
-rw-r--r-- | drivers/md/bcache/debug.h | 23 | ||||
-rw-r--r-- | drivers/md/bcache/extents.c | 93 | ||||
-rw-r--r-- | drivers/md/bcache/extents.h | 1 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 2 | ||||
-rw-r--r-- | drivers/md/bcache/util.h | 2 |
9 files changed, 264 insertions, 217 deletions
diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c index 097bd8d2acba..448cff8cc052 100644 --- a/drivers/md/bcache/bset.c +++ b/drivers/md/bcache/bset.c | |||
@@ -7,11 +7,121 @@ | |||
7 | 7 | ||
8 | #include "bcache.h" | 8 | #include "bcache.h" |
9 | #include "btree.h" | 9 | #include "btree.h" |
10 | #include "debug.h" | ||
11 | 10 | ||
11 | #include <linux/console.h> | ||
12 | #include <linux/random.h> | 12 | #include <linux/random.h> |
13 | #include <linux/prefetch.h> | 13 | #include <linux/prefetch.h> |
14 | 14 | ||
15 | #ifdef CONFIG_BCACHE_DEBUG | ||
16 | |||
17 | void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned set) | ||
18 | { | ||
19 | struct bkey *k, *next; | ||
20 | |||
21 | for (k = i->start; k < bset_bkey_last(i); k = next) { | ||
22 | next = bkey_next(k); | ||
23 | |||
24 | printk(KERN_ERR "block %u key %zi/%u: ", set, | ||
25 | (uint64_t *) k - i->d, i->keys); | ||
26 | |||
27 | if (b->ops->key_dump) | ||
28 | b->ops->key_dump(b, k); | ||
29 | else | ||
30 | printk("%llu:%llu\n", KEY_INODE(k), KEY_OFFSET(k)); | ||
31 | |||
32 | if (next < bset_bkey_last(i) && | ||
33 | bkey_cmp(k, b->ops->is_extents ? | ||
34 | &START_KEY(next) : next) > 0) | ||
35 | printk(KERN_ERR "Key skipped backwards\n"); | ||
36 | } | ||
37 | } | ||
38 | |||
39 | void bch_dump_bucket(struct btree_keys *b) | ||
40 | { | ||
41 | unsigned i; | ||
42 | |||
43 | console_lock(); | ||
44 | for (i = 0; i <= b->nsets; i++) | ||
45 | bch_dump_bset(b, b->set[i].data, | ||
46 | bset_sector_offset(b, b->set[i].data)); | ||
47 | console_unlock(); | ||
48 | } | ||
49 | |||
50 | int __bch_count_data(struct btree_keys *b) | ||
51 | { | ||
52 | unsigned ret = 0; | ||
53 | struct btree_iter iter; | ||
54 | struct bkey *k; | ||
55 | |||
56 | if (b->ops->is_extents) | ||
57 | for_each_key(b, k, &iter) | ||
58 | ret += KEY_SIZE(k); | ||
59 | return ret; | ||
60 | } | ||
61 | |||
62 | void __bch_check_keys(struct btree_keys *b, const char *fmt, ...) | ||
63 | { | ||
64 | va_list args; | ||
65 | struct bkey *k, *p = NULL; | ||
66 | struct btree_iter iter; | ||
67 | const char *err; | ||
68 | |||
69 | for_each_key(b, k, &iter) { | ||
70 | if (b->ops->is_extents) { | ||
71 | err = "Keys out of order"; | ||
72 | if (p && bkey_cmp(&START_KEY(p), &START_KEY(k)) > 0) | ||
73 | goto bug; | ||
74 | |||
75 | if (bch_ptr_invalid(b, k)) | ||
76 | continue; | ||
77 | |||
78 | err = "Overlapping keys"; | ||
79 | if (p && bkey_cmp(p, &START_KEY(k)) > 0) | ||
80 | goto bug; | ||
81 | } else { | ||
82 | if (bch_ptr_bad(b, k)) | ||
83 | continue; | ||
84 | |||
85 | err = "Duplicate keys"; | ||
86 | if (p && !bkey_cmp(p, k)) | ||
87 | goto bug; | ||
88 | } | ||
89 | p = k; | ||
90 | } | ||
91 | #if 0 | ||
92 | err = "Key larger than btree node key"; | ||
93 | if (p && bkey_cmp(p, &b->key) > 0) | ||
94 | goto bug; | ||
95 | #endif | ||
96 | return; | ||
97 | bug: | ||
98 | bch_dump_bucket(b); | ||
99 | |||
100 | va_start(args, fmt); | ||
101 | vprintk(fmt, args); | ||
102 | va_end(args); | ||
103 | |||
104 | panic("bch_check_keys error: %s:\n", err); | ||
105 | } | ||
106 | |||
107 | static void bch_btree_iter_next_check(struct btree_iter *iter) | ||
108 | { | ||
109 | struct bkey *k = iter->data->k, *next = bkey_next(k); | ||
110 | |||
111 | if (next < iter->data->end && | ||
112 | bkey_cmp(k, iter->b->ops->is_extents ? | ||
113 | &START_KEY(next) : next) > 0) { | ||
114 | bch_dump_bucket(iter->b); | ||
115 | panic("Key skipped backwards\n"); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | #else | ||
120 | |||
121 | static inline void bch_btree_iter_next_check(struct btree_iter *iter) {} | ||
122 | |||
123 | #endif | ||
124 | |||
15 | /* Keylists */ | 125 | /* Keylists */ |
16 | 126 | ||
17 | int __bch_keylist_realloc(struct keylist *l, unsigned u64s) | 127 | int __bch_keylist_realloc(struct keylist *l, unsigned u64s) |
@@ -1045,7 +1155,7 @@ void bch_btree_sort_partial(struct btree *b, unsigned start, | |||
1045 | { | 1155 | { |
1046 | size_t order = b->keys.page_order, keys = 0; | 1156 | size_t order = b->keys.page_order, keys = 0; |
1047 | struct btree_iter iter; | 1157 | struct btree_iter iter; |
1048 | int oldsize = bch_count_data(b); | 1158 | int oldsize = bch_count_data(&b->keys); |
1049 | 1159 | ||
1050 | __bch_btree_iter_init(&b->keys, &iter, NULL, &b->keys.set[start]); | 1160 | __bch_btree_iter_init(&b->keys, &iter, NULL, &b->keys.set[start]); |
1051 | 1161 | ||
@@ -1063,7 +1173,8 @@ void bch_btree_sort_partial(struct btree *b, unsigned start, | |||
1063 | 1173 | ||
1064 | __btree_sort(&b->keys, &iter, start, order, false, state); | 1174 | __btree_sort(&b->keys, &iter, start, order, false, state); |
1065 | 1175 | ||
1066 | EBUG_ON(b->written && oldsize >= 0 && bch_count_data(b) != oldsize); | 1176 | EBUG_ON(b->written && oldsize >= 0 && |
1177 | bch_count_data(&b->keys) != oldsize); | ||
1067 | } | 1178 | } |
1068 | EXPORT_SYMBOL(bch_btree_sort_partial); | 1179 | EXPORT_SYMBOL(bch_btree_sort_partial); |
1069 | 1180 | ||
diff --git a/drivers/md/bcache/bset.h b/drivers/md/bcache/bset.h index 563130c28142..e01e69e00654 100644 --- a/drivers/md/bcache/bset.h +++ b/drivers/md/bcache/bset.h | |||
@@ -193,6 +193,8 @@ struct btree_keys_ops { | |||
193 | bool (*key_bad)(struct btree_keys *, const struct bkey *); | 193 | bool (*key_bad)(struct btree_keys *, const struct bkey *); |
194 | bool (*key_merge)(struct btree_keys *, | 194 | bool (*key_merge)(struct btree_keys *, |
195 | struct bkey *, struct bkey *); | 195 | struct bkey *, struct bkey *); |
196 | void (*key_to_text)(char *, size_t, const struct bkey *); | ||
197 | void (*key_dump)(struct btree_keys *, const struct bkey *); | ||
196 | 198 | ||
197 | /* | 199 | /* |
198 | * Only used for deciding whether to use START_KEY(k) or just the key | 200 | * Only used for deciding whether to use START_KEY(k) or just the key |
@@ -243,15 +245,6 @@ static inline unsigned bset_sector_offset(struct btree_keys *b, struct bset *i) | |||
243 | return bset_byte_offset(b, i) >> 9; | 245 | return bset_byte_offset(b, i) >> 9; |
244 | } | 246 | } |
245 | 247 | ||
246 | static inline bool btree_keys_expensive_checks(struct btree_keys *b) | ||
247 | { | ||
248 | #ifdef CONFIG_BCACHE_DEBUG | ||
249 | return *b->expensive_debug_checks; | ||
250 | #else | ||
251 | return false; | ||
252 | #endif | ||
253 | } | ||
254 | |||
255 | #define __set_bytes(i, k) (sizeof(*(i)) + (k) * sizeof(uint64_t)) | 248 | #define __set_bytes(i, k) (sizeof(*(i)) + (k) * sizeof(uint64_t)) |
256 | #define set_bytes(i) __set_bytes(i, i->keys) | 249 | #define set_bytes(i) __set_bytes(i, i->keys) |
257 | 250 | ||
@@ -446,6 +439,12 @@ static inline bool bch_ptr_bad(struct btree_keys *b, const struct bkey *k) | |||
446 | return b->ops->key_bad(b, k); | 439 | return b->ops->key_bad(b, k); |
447 | } | 440 | } |
448 | 441 | ||
442 | static inline void bch_bkey_to_text(struct btree_keys *b, char *buf, | ||
443 | size_t size, const struct bkey *k) | ||
444 | { | ||
445 | return b->ops->key_to_text(buf, size, k); | ||
446 | } | ||
447 | |||
449 | /* Keylists */ | 448 | /* Keylists */ |
450 | 449 | ||
451 | struct keylist { | 450 | struct keylist { |
@@ -509,7 +508,42 @@ struct bkey *bch_keylist_pop(struct keylist *); | |||
509 | void bch_keylist_pop_front(struct keylist *); | 508 | void bch_keylist_pop_front(struct keylist *); |
510 | int __bch_keylist_realloc(struct keylist *, unsigned); | 509 | int __bch_keylist_realloc(struct keylist *, unsigned); |
511 | 510 | ||
512 | struct cache_set; | 511 | /* Debug stuff */ |
513 | const char *bch_ptr_status(struct cache_set *, const struct bkey *); | 512 | |
513 | #ifdef CONFIG_BCACHE_DEBUG | ||
514 | |||
515 | int __bch_count_data(struct btree_keys *); | ||
516 | void __bch_check_keys(struct btree_keys *, const char *, ...); | ||
517 | void bch_dump_bset(struct btree_keys *, struct bset *, unsigned); | ||
518 | void bch_dump_bucket(struct btree_keys *); | ||
519 | |||
520 | #else | ||
521 | |||
522 | static inline int __bch_count_data(struct btree_keys *b) { return -1; } | ||
523 | static inline void __bch_check_keys(struct btree_keys *b, const char *fmt, ...) {} | ||
524 | static inline void bch_dump_bucket(struct btree_keys *b) {} | ||
525 | void bch_dump_bset(struct btree_keys *, struct bset *, unsigned); | ||
526 | |||
527 | #endif | ||
528 | |||
529 | static inline bool btree_keys_expensive_checks(struct btree_keys *b) | ||
530 | { | ||
531 | #ifdef CONFIG_BCACHE_DEBUG | ||
532 | return *b->expensive_debug_checks; | ||
533 | #else | ||
534 | return false; | ||
535 | #endif | ||
536 | } | ||
537 | |||
538 | static inline int bch_count_data(struct btree_keys *b) | ||
539 | { | ||
540 | return btree_keys_expensive_checks(b) ? __bch_count_data(b) : -1; | ||
541 | } | ||
542 | |||
543 | #define bch_check_keys(b, ...) \ | ||
544 | do { \ | ||
545 | if (btree_keys_expensive_checks(b)) \ | ||
546 | __bch_check_keys(b, __VA_ARGS__); \ | ||
547 | } while (0) | ||
514 | 548 | ||
515 | #endif | 549 | #endif |
diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 9424c8a15e37..2128ee1e6916 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c | |||
@@ -460,7 +460,7 @@ void bch_btree_node_write(struct btree *b, struct closure *parent) | |||
460 | BUG_ON(b->written >= btree_blocks(b)); | 460 | BUG_ON(b->written >= btree_blocks(b)); |
461 | BUG_ON(b->written && !i->keys); | 461 | BUG_ON(b->written && !i->keys); |
462 | BUG_ON(btree_bset_first(b)->seq != i->seq); | 462 | BUG_ON(btree_bset_first(b)->seq != i->seq); |
463 | bch_check_keys(b, "writing"); | 463 | bch_check_keys(&b->keys, "writing"); |
464 | 464 | ||
465 | cancel_delayed_work(&b->work); | 465 | cancel_delayed_work(&b->work); |
466 | 466 | ||
@@ -2007,7 +2007,7 @@ static bool btree_insert_key(struct btree *b, struct btree_op *op, | |||
2007 | insert: bch_bset_insert(&b->keys, m, k); | 2007 | insert: bch_bset_insert(&b->keys, m, k); |
2008 | copy: bkey_copy(m, k); | 2008 | copy: bkey_copy(m, k); |
2009 | merged: | 2009 | merged: |
2010 | bch_check_keys(b, "%u for %s", status, | 2010 | bch_check_keys(&b->keys, "%u for %s", status, |
2011 | replace_key ? "replace" : "insert"); | 2011 | replace_key ? "replace" : "insert"); |
2012 | 2012 | ||
2013 | if (b->level && !KEY_OFFSET(k)) | 2013 | if (b->level && !KEY_OFFSET(k)) |
@@ -2036,7 +2036,7 @@ static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op, | |||
2036 | struct bkey *replace_key) | 2036 | struct bkey *replace_key) |
2037 | { | 2037 | { |
2038 | bool ret = false; | 2038 | bool ret = false; |
2039 | int oldsize = bch_count_data(b); | 2039 | int oldsize = bch_count_data(&b->keys); |
2040 | 2040 | ||
2041 | while (!bch_keylist_empty(insert_keys)) { | 2041 | while (!bch_keylist_empty(insert_keys)) { |
2042 | struct bkey *k = insert_keys->keys; | 2042 | struct bkey *k = insert_keys->keys; |
@@ -2066,7 +2066,7 @@ static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op, | |||
2066 | 2066 | ||
2067 | BUG_ON(!bch_keylist_empty(insert_keys) && b->level); | 2067 | BUG_ON(!bch_keylist_empty(insert_keys) && b->level); |
2068 | 2068 | ||
2069 | BUG_ON(bch_count_data(b) < oldsize); | 2069 | BUG_ON(bch_count_data(&b->keys) < oldsize); |
2070 | return ret; | 2070 | return ret; |
2071 | } | 2071 | } |
2072 | 2072 | ||
diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 3de27e2a4e07..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,108 +18,8 @@ | |||
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_START(k), KEY_SIZE(k)); | ||
57 | |||
58 | for (i = 0; i < KEY_PTRS(k); i++) { | ||
59 | if (i) | ||
60 | p(", "); | ||
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 | |||
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, unsigned set) | ||
82 | { | ||
83 | struct bkey *k, *next; | ||
84 | unsigned j; | ||
85 | char buf[80]; | ||
86 | |||
87 | for (k = i->start; k < bset_bkey_last(i); k = next) { | ||
88 | next = bkey_next(k); | ||
89 | |||
90 | bch_bkey_to_text(buf, sizeof(buf), k); | ||
91 | printk(KERN_ERR "b %u k %zi/%u: %s", set, | ||
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 | |||
103 | printk(" %s\n", bch_ptr_status(b->c, k)); | ||
104 | |||
105 | if (next < bset_bkey_last(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->keys.nsets; i++) | ||
117 | dump_bset(b, b->keys.set[i].data, | ||
118 | bset_block_offset(b, b->keys.set[i].data)); | ||
119 | console_unlock(); | ||
120 | } | ||
121 | |||
122 | #define for_each_written_bset(b, start, i) \ | 23 | #define for_each_written_bset(b, start, i) \ |
123 | for (i = (start); \ | 24 | for (i = (start); \ |
124 | (void *) i < (void *) (start) + (KEY_SIZE(&b->key) << 9) &&\ | 25 | (void *) i < (void *) (start) + (KEY_SIZE(&b->key) << 9) &&\ |
@@ -171,17 +72,17 @@ void bch_btree_verify(struct btree *b) | |||
171 | console_lock(); | 72 | console_lock(); |
172 | 73 | ||
173 | printk(KERN_ERR "*** in memory:\n"); | 74 | printk(KERN_ERR "*** in memory:\n"); |
174 | dump_bset(b, inmemory, 0); | 75 | bch_dump_bset(&b->keys, inmemory, 0); |
175 | 76 | ||
176 | printk(KERN_ERR "*** read back in:\n"); | 77 | printk(KERN_ERR "*** read back in:\n"); |
177 | dump_bset(v, sorted, 0); | 78 | bch_dump_bset(&v->keys, sorted, 0); |
178 | 79 | ||
179 | for_each_written_bset(b, ondisk, i) { | 80 | for_each_written_bset(b, ondisk, i) { |
180 | unsigned block = ((void *) i - (void *) ondisk) / | 81 | unsigned block = ((void *) i - (void *) ondisk) / |
181 | block_bytes(b->c); | 82 | block_bytes(b->c); |
182 | 83 | ||
183 | printk(KERN_ERR "*** on disk block %u:\n", block); | 84 | printk(KERN_ERR "*** on disk block %u:\n", block); |
184 | dump_bset(b, i, block); | 85 | bch_dump_bset(&b->keys, i, block); |
185 | } | 86 | } |
186 | 87 | ||
187 | printk(KERN_ERR "*** block %zu not written\n", | 88 | printk(KERN_ERR "*** block %zu not written\n", |
@@ -239,76 +140,6 @@ out_put: | |||
239 | bio_put(check); | 140 | bio_put(check); |
240 | } | 141 | } |
241 | 142 | ||
242 | int __bch_count_data(struct btree *b) | ||
243 | { | ||
244 | unsigned ret = 0; | ||
245 | struct btree_iter iter; | ||
246 | struct bkey *k; | ||
247 | |||
248 | if (!b->level) | ||
249 | for_each_key(&b->keys, k, &iter) | ||
250 | ret += KEY_SIZE(k); | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | void __bch_check_keys(struct btree *b, const char *fmt, ...) | ||
255 | { | ||
256 | va_list args; | ||
257 | struct bkey *k, *p = NULL; | ||
258 | struct btree_iter iter; | ||
259 | const char *err; | ||
260 | |||
261 | for_each_key(&b->keys, k, &iter) { | ||
262 | if (!b->level) { | ||
263 | err = "Keys out of order"; | ||
264 | if (p && bkey_cmp(&START_KEY(p), &START_KEY(k)) > 0) | ||
265 | goto bug; | ||
266 | |||
267 | if (bch_ptr_invalid(&b->keys, k)) | ||
268 | continue; | ||
269 | |||
270 | err = "Overlapping keys"; | ||
271 | if (p && bkey_cmp(p, &START_KEY(k)) > 0) | ||
272 | goto bug; | ||
273 | } else { | ||
274 | if (bch_ptr_bad(&b->keys, k)) | ||
275 | continue; | ||
276 | |||
277 | err = "Duplicate keys"; | ||
278 | if (p && !bkey_cmp(p, k)) | ||
279 | goto bug; | ||
280 | } | ||
281 | p = k; | ||
282 | } | ||
283 | |||
284 | err = "Key larger than btree node key"; | ||
285 | if (p && bkey_cmp(p, &b->key) > 0) | ||
286 | goto bug; | ||
287 | |||
288 | return; | ||
289 | bug: | ||
290 | bch_dump_bucket(b); | ||
291 | |||
292 | va_start(args, fmt); | ||
293 | vprintk(fmt, args); | ||
294 | va_end(args); | ||
295 | |||
296 | panic("bcache error: %s:\n", err); | ||
297 | } | ||
298 | |||
299 | void bch_btree_iter_next_check(struct btree_iter *iter) | ||
300 | { | ||
301 | #if 0 | ||
302 | struct bkey *k = iter->data->k, *next = bkey_next(k); | ||
303 | |||
304 | if (next < iter->data->end && | ||
305 | bkey_cmp(k, iter->b->level ? next : &START_KEY(next)) > 0) { | ||
306 | bch_dump_bucket(iter->b); | ||
307 | panic("Key skipped backwards\n"); | ||
308 | } | ||
309 | #endif | ||
310 | } | ||
311 | |||
312 | #endif | 143 | #endif |
313 | 144 | ||
314 | #ifdef CONFIG_DEBUG_FS | 145 | #ifdef CONFIG_DEBUG_FS |
@@ -355,7 +186,7 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf, | |||
355 | if (!w) | 186 | if (!w) |
356 | break; | 187 | break; |
357 | 188 | ||
358 | bch_bkey_to_text(kbuf, sizeof(kbuf), &w->key); | 189 | bch_extent_to_text(kbuf, sizeof(kbuf), &w->key); |
359 | i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", kbuf); | 190 | i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", kbuf); |
360 | bch_keybuf_del(&i->keys, w); | 191 | bch_keybuf_del(&i->keys, w); |
361 | } | 192 | } |
diff --git a/drivers/md/bcache/debug.h b/drivers/md/bcache/debug.h index 08e116e74d36..1f63c195d247 100644 --- a/drivers/md/bcache/debug.h +++ b/drivers/md/bcache/debug.h | |||
@@ -1,19 +1,15 @@ | |||
1 | #ifndef _BCACHE_DEBUG_H | 1 | #ifndef _BCACHE_DEBUG_H |
2 | #define _BCACHE_DEBUG_H | 2 | #define _BCACHE_DEBUG_H |
3 | 3 | ||
4 | /* Btree/bkey debug printing */ | 4 | struct bio; |
5 | 5 | struct cached_dev; | |
6 | int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k); | 6 | struct cache_set; |
7 | 7 | ||
8 | #ifdef CONFIG_BCACHE_DEBUG | 8 | #ifdef CONFIG_BCACHE_DEBUG |
9 | 9 | ||
10 | void bch_btree_verify(struct btree *); | 10 | void bch_btree_verify(struct btree *); |
11 | void bch_data_verify(struct cached_dev *, struct bio *); | 11 | void bch_data_verify(struct cached_dev *, struct bio *); |
12 | int __bch_count_data(struct btree *); | ||
13 | void __bch_check_keys(struct btree *, const char *, ...); | ||
14 | void bch_btree_iter_next_check(struct btree_iter *); | ||
15 | 12 | ||
16 | #define EBUG_ON(cond) BUG_ON(cond) | ||
17 | #define expensive_debug_checks(c) ((c)->expensive_debug_checks) | 13 | #define expensive_debug_checks(c) ((c)->expensive_debug_checks) |
18 | #define key_merging_disabled(c) ((c)->key_merging_disabled) | 14 | #define key_merging_disabled(c) ((c)->key_merging_disabled) |
19 | #define bypass_torture_test(d) ((d)->bypass_torture_test) | 15 | #define bypass_torture_test(d) ((d)->bypass_torture_test) |
@@ -22,26 +18,13 @@ void bch_btree_iter_next_check(struct btree_iter *); | |||
22 | 18 | ||
23 | static inline void bch_btree_verify(struct btree *b) {} | 19 | static inline void bch_btree_verify(struct btree *b) {} |
24 | static inline void bch_data_verify(struct cached_dev *dc, struct bio *bio) {} | 20 | static inline void bch_data_verify(struct cached_dev *dc, struct bio *bio) {} |
25 | static inline int __bch_count_data(struct btree *b) { return -1; } | ||
26 | static inline void __bch_check_keys(struct btree *b, const char *fmt, ...) {} | ||
27 | static inline void bch_btree_iter_next_check(struct btree_iter *iter) {} | ||
28 | 21 | ||
29 | #define EBUG_ON(cond) do { if (cond); } while (0) | ||
30 | #define expensive_debug_checks(c) 0 | 22 | #define expensive_debug_checks(c) 0 |
31 | #define key_merging_disabled(c) 0 | 23 | #define key_merging_disabled(c) 0 |
32 | #define bypass_torture_test(d) 0 | 24 | #define bypass_torture_test(d) 0 |
33 | 25 | ||
34 | #endif | 26 | #endif |
35 | 27 | ||
36 | #define bch_count_data(b) \ | ||
37 | (expensive_debug_checks((b)->c) ? __bch_count_data(b) : -1) | ||
38 | |||
39 | #define bch_check_keys(b, ...) \ | ||
40 | do { \ | ||
41 | if (expensive_debug_checks((b)->c)) \ | ||
42 | __bch_check_keys(b, __VA_ARGS__); \ | ||
43 | } while (0) | ||
44 | |||
45 | #ifdef CONFIG_DEBUG_FS | 28 | #ifdef CONFIG_DEBUG_FS |
46 | void bch_debug_init_cache_set(struct cache_set *); | 29 | void bch_debug_init_cache_set(struct cache_set *); |
47 | #else | 30 | #else |
diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c index ba3021128e7a..bc1c3eed07e7 100644 --- a/drivers/md/bcache/extents.c +++ b/drivers/md/bcache/extents.c | |||
@@ -62,6 +62,87 @@ static bool __ptr_invalid(struct cache_set *c, const struct bkey *k) | |||
62 | return false; | 62 | return false; |
63 | } | 63 | } |
64 | 64 | ||
65 | /* Common among btree and extent ptrs */ | ||
66 | |||
67 | static const char *bch_ptr_status(struct cache_set *c, const struct bkey *k) | ||
68 | { | ||
69 | unsigned i; | ||
70 | |||
71 | for (i = 0; i < KEY_PTRS(k); i++) | ||
72 | if (ptr_available(c, k, i)) { | ||
73 | struct cache *ca = PTR_CACHE(c, k, i); | ||
74 | size_t bucket = PTR_BUCKET_NR(c, k, i); | ||
75 | size_t r = bucket_remainder(c, PTR_OFFSET(k, i)); | ||
76 | |||
77 | if (KEY_SIZE(k) + r > c->sb.bucket_size) | ||
78 | return "bad, length too big"; | ||
79 | if (bucket < ca->sb.first_bucket) | ||
80 | return "bad, short offset"; | ||
81 | if (bucket >= ca->sb.nbuckets) | ||
82 | return "bad, offset past end of device"; | ||
83 | if (ptr_stale(c, k, i)) | ||
84 | return "stale"; | ||
85 | } | ||
86 | |||
87 | if (!bkey_cmp(k, &ZERO_KEY)) | ||
88 | return "bad, null key"; | ||
89 | if (!KEY_PTRS(k)) | ||
90 | return "bad, no pointers"; | ||
91 | if (!KEY_SIZE(k)) | ||
92 | return "zeroed key"; | ||
93 | return ""; | ||
94 | } | ||
95 | |||
96 | void bch_extent_to_text(char *buf, size_t size, const struct bkey *k) | ||
97 | { | ||
98 | unsigned i = 0; | ||
99 | char *out = buf, *end = buf + size; | ||
100 | |||
101 | #define p(...) (out += scnprintf(out, end - out, __VA_ARGS__)) | ||
102 | |||
103 | p("%llu:%llu len %llu -> [", KEY_INODE(k), KEY_START(k), KEY_SIZE(k)); | ||
104 | |||
105 | for (i = 0; i < KEY_PTRS(k); i++) { | ||
106 | if (i) | ||
107 | p(", "); | ||
108 | |||
109 | if (PTR_DEV(k, i) == PTR_CHECK_DEV) | ||
110 | p("check dev"); | ||
111 | else | ||
112 | p("%llu:%llu gen %llu", PTR_DEV(k, i), | ||
113 | PTR_OFFSET(k, i), PTR_GEN(k, i)); | ||
114 | } | ||
115 | |||
116 | p("]"); | ||
117 | |||
118 | if (KEY_DIRTY(k)) | ||
119 | p(" dirty"); | ||
120 | if (KEY_CSUM(k)) | ||
121 | p(" cs%llu %llx", KEY_CSUM(k), k->ptr[1]); | ||
122 | #undef p | ||
123 | } | ||
124 | |||
125 | static void bch_bkey_dump(struct btree_keys *keys, const struct bkey *k) | ||
126 | { | ||
127 | struct btree *b = container_of(keys, struct btree, keys); | ||
128 | unsigned j; | ||
129 | char buf[80]; | ||
130 | |||
131 | bch_extent_to_text(buf, sizeof(buf), k); | ||
132 | printk(" %s", buf); | ||
133 | |||
134 | for (j = 0; j < KEY_PTRS(k); j++) { | ||
135 | size_t n = PTR_BUCKET_NR(b->c, k, j); | ||
136 | printk(" bucket %zu", n); | ||
137 | |||
138 | if (n >= b->c->sb.first_bucket && n < b->c->sb.nbuckets) | ||
139 | printk(" prio %i", | ||
140 | PTR_BUCKET(b->c, k, j)->prio); | ||
141 | } | ||
142 | |||
143 | printk(" %s\n", bch_ptr_status(b->c, k)); | ||
144 | } | ||
145 | |||
65 | /* Btree ptrs */ | 146 | /* Btree ptrs */ |
66 | 147 | ||
67 | bool __bch_btree_ptr_invalid(struct cache_set *c, const struct bkey *k) | 148 | bool __bch_btree_ptr_invalid(struct cache_set *c, const struct bkey *k) |
@@ -76,7 +157,7 @@ bool __bch_btree_ptr_invalid(struct cache_set *c, const struct bkey *k) | |||
76 | 157 | ||
77 | return false; | 158 | return false; |
78 | bad: | 159 | bad: |
79 | bch_bkey_to_text(buf, sizeof(buf), k); | 160 | bch_extent_to_text(buf, sizeof(buf), k); |
80 | cache_bug(c, "spotted btree ptr %s: %s", buf, bch_ptr_status(c, k)); | 161 | cache_bug(c, "spotted btree ptr %s: %s", buf, bch_ptr_status(c, k)); |
81 | return true; | 162 | return true; |
82 | } | 163 | } |
@@ -111,7 +192,7 @@ static bool btree_ptr_bad_expensive(struct btree *b, const struct bkey *k) | |||
111 | return false; | 192 | return false; |
112 | err: | 193 | err: |
113 | mutex_unlock(&b->c->bucket_lock); | 194 | mutex_unlock(&b->c->bucket_lock); |
114 | bch_bkey_to_text(buf, sizeof(buf), k); | 195 | bch_extent_to_text(buf, sizeof(buf), k); |
115 | btree_bug(b, | 196 | btree_bug(b, |
116 | "inconsistent btree pointer %s: bucket %li pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i", | 197 | "inconsistent btree pointer %s: bucket %li pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i", |
117 | buf, PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin), | 198 | buf, PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin), |
@@ -145,6 +226,8 @@ const struct btree_keys_ops bch_btree_keys_ops = { | |||
145 | .sort_cmp = bch_key_sort_cmp, | 226 | .sort_cmp = bch_key_sort_cmp, |
146 | .key_invalid = bch_btree_ptr_invalid, | 227 | .key_invalid = bch_btree_ptr_invalid, |
147 | .key_bad = bch_btree_ptr_bad, | 228 | .key_bad = bch_btree_ptr_bad, |
229 | .key_to_text = bch_extent_to_text, | ||
230 | .key_dump = bch_bkey_dump, | ||
148 | }; | 231 | }; |
149 | 232 | ||
150 | /* Extents */ | 233 | /* Extents */ |
@@ -227,7 +310,7 @@ static bool bch_extent_invalid(struct btree_keys *bk, const struct bkey *k) | |||
227 | 310 | ||
228 | return false; | 311 | return false; |
229 | bad: | 312 | bad: |
230 | bch_bkey_to_text(buf, sizeof(buf), k); | 313 | bch_extent_to_text(buf, sizeof(buf), k); |
231 | cache_bug(b->c, "spotted extent %s: %s", buf, bch_ptr_status(b->c, k)); | 314 | cache_bug(b->c, "spotted extent %s: %s", buf, bch_ptr_status(b->c, k)); |
232 | return true; | 315 | return true; |
233 | } | 316 | } |
@@ -254,7 +337,7 @@ static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k, | |||
254 | return false; | 337 | return false; |
255 | err: | 338 | err: |
256 | mutex_unlock(&b->c->bucket_lock); | 339 | mutex_unlock(&b->c->bucket_lock); |
257 | bch_bkey_to_text(buf, sizeof(buf), k); | 340 | bch_extent_to_text(buf, sizeof(buf), k); |
258 | btree_bug(b, | 341 | btree_bug(b, |
259 | "inconsistent extent pointer %s:\nbucket %zu pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i", | 342 | "inconsistent extent pointer %s:\nbucket %zu pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i", |
260 | buf, PTR_BUCKET_NR(b->c, k, ptr), atomic_read(&g->pin), | 343 | buf, PTR_BUCKET_NR(b->c, k, ptr), atomic_read(&g->pin), |
@@ -355,5 +438,7 @@ const struct btree_keys_ops bch_extent_keys_ops = { | |||
355 | .key_invalid = bch_extent_invalid, | 438 | .key_invalid = bch_extent_invalid, |
356 | .key_bad = bch_extent_bad, | 439 | .key_bad = bch_extent_bad, |
357 | .key_merge = bch_extent_merge, | 440 | .key_merge = bch_extent_merge, |
441 | .key_to_text = bch_extent_to_text, | ||
442 | .key_dump = bch_bkey_dump, | ||
358 | .is_extents = true, | 443 | .is_extents = true, |
359 | }; | 444 | }; |
diff --git a/drivers/md/bcache/extents.h b/drivers/md/bcache/extents.h index e0c0b685d2f7..e4e23409782d 100644 --- a/drivers/md/bcache/extents.h +++ b/drivers/md/bcache/extents.h | |||
@@ -7,6 +7,7 @@ extern const struct btree_keys_ops bch_extent_keys_ops; | |||
7 | struct bkey; | 7 | struct bkey; |
8 | struct cache_set; | 8 | struct cache_set; |
9 | 9 | ||
10 | void bch_extent_to_text(char *, size_t, const struct bkey *); | ||
10 | bool __bch_btree_ptr_invalid(struct cache_set *, const struct bkey *); | 11 | bool __bch_btree_ptr_invalid(struct cache_set *, const struct bkey *); |
11 | 12 | ||
12 | #endif /* _BCACHE_EXTENTS_H */ | 13 | #endif /* _BCACHE_EXTENTS_H */ |
diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 6d6a7a15043e..24a3a1546caa 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c | |||
@@ -384,7 +384,7 @@ static void uuid_io(struct cache_set *c, unsigned long rw, | |||
384 | break; | 384 | break; |
385 | } | 385 | } |
386 | 386 | ||
387 | bch_bkey_to_text(buf, sizeof(buf), k); | 387 | bch_extent_to_text(buf, sizeof(buf), k); |
388 | pr_debug("%s UUIDs at %s", rw & REQ_WRITE ? "wrote" : "read", buf); | 388 | pr_debug("%s UUIDs at %s", rw & REQ_WRITE ? "wrote" : "read", buf); |
389 | 389 | ||
390 | for (u = c->uuids; u < c->uuids + c->nr_uuids; u++) | 390 | for (u = c->uuids; u < c->uuids + c->nr_uuids; u++) |
diff --git a/drivers/md/bcache/util.h b/drivers/md/bcache/util.h index 3ebaef5f645b..ac7d0d1f70d7 100644 --- a/drivers/md/bcache/util.h +++ b/drivers/md/bcache/util.h | |||
@@ -18,11 +18,13 @@ struct closure; | |||
18 | 18 | ||
19 | #ifdef CONFIG_BCACHE_DEBUG | 19 | #ifdef CONFIG_BCACHE_DEBUG |
20 | 20 | ||
21 | #define EBUG_ON(cond) BUG_ON(cond) | ||
21 | #define atomic_dec_bug(v) BUG_ON(atomic_dec_return(v) < 0) | 22 | #define atomic_dec_bug(v) BUG_ON(atomic_dec_return(v) < 0) |
22 | #define atomic_inc_bug(v, i) BUG_ON(atomic_inc_return(v) <= i) | 23 | #define atomic_inc_bug(v, i) BUG_ON(atomic_inc_return(v) <= i) |
23 | 24 | ||
24 | #else /* DEBUG */ | 25 | #else /* DEBUG */ |
25 | 26 | ||
27 | #define EBUG_ON(cond) do { if (cond); } while (0) | ||
26 | #define atomic_dec_bug(v) atomic_dec(v) | 28 | #define atomic_dec_bug(v) atomic_dec(v) |
27 | #define atomic_inc_bug(v, i) atomic_inc(v) | 29 | #define atomic_inc_bug(v, i) atomic_inc(v) |
28 | 30 | ||