diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2016-10-23 04:41:04 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2017-01-18 21:40:45 -0900 |
commit | 126c1475c8f4a3d88408a9c2aac54688bec5af6c (patch) | |
tree | ac22197e5fb52cc322e5a79cbb53804ed9a93f7b | |
parent | 9417155cc0877b0120103c201fe8e5bd5ec5f8cf (diff) |
bcache: add debugfs interface for seeing failed bfloats
-rw-r--r-- | drivers/md/bcache/bcache.h | 1 | ||||
-rw-r--r-- | drivers/md/bcache/bkey.c | 35 | ||||
-rw-r--r-- | drivers/md/bcache/bkey.h | 1 | ||||
-rw-r--r-- | drivers/md/bcache/bset.c | 68 | ||||
-rw-r--r-- | drivers/md/bcache/bset.h | 2 | ||||
-rw-r--r-- | drivers/md/bcache/debug.c | 155 |
6 files changed, 204 insertions, 58 deletions
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 3f9294c17cda..8ee369bcbf13 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -488,6 +488,7 @@ struct btree_debug { unsigned id; struct dentry *btree; struct dentry *btree_format; + struct dentry *failed; }; struct cache_set { diff --git a/drivers/md/bcache/bkey.c b/drivers/md/bcache/bkey.c index 37e3cb134ae9..1c48ea3e8a6c 100644 --- a/drivers/md/bcache/bkey.c +++ b/drivers/md/bcache/bkey.c @@ -9,29 +9,30 @@ const struct bkey_format bch_bkey_format_current = BKEY_FORMAT_CURRENT; -#ifdef CONFIG_BCACHE_DEBUG - -static void to_binary(char *out, const void *p, unsigned nr_bytes) +void bch_to_binary(char *out, const u64 *p, unsigned nr_bits) { - unsigned i; + unsigned bit = high_bit_offset, done = 0; while (1) { - u8 b = *((u8 *) p); - - for (i = 0; i < 8; i++) { - *out++ = b & (1U << (7 - i)) ? '1' : '0'; + while (bit < 64) { + if (done && !(done % 8)) + *out++ = ' '; + *out++ = *p & (1ULL << (63 - bit)) ? '1' : '0'; + bit++; + done++; + if (done == nr_bits) { + *out++ = '\0'; + return; + } } - if (!--nr_bytes) - break; - - *out++ = ' '; - p++; + p = next_word(p); + bit = 0; } - - *out++ = '\0'; } +#ifdef CONFIG_BCACHE_DEBUG + static void bch_bkey_pack_verify(const struct bkey_packed *packed, const struct bkey *unpacked, const struct bkey_format *format) @@ -51,8 +52,8 @@ static void bch_bkey_pack_verify(const struct bkey_packed *packed, bch_bkey_to_text(buf1, sizeof(buf1), unpacked); bch_bkey_to_text(buf2, sizeof(buf2), &tmp); - to_binary(buf3, unpacked, 10); - to_binary(buf4, high_word(format, packed), 10); + bch_to_binary(buf3, (void *) unpacked, 80); + bch_to_binary(buf4, high_word(format, packed), 80); panic("keys differ: format u64s %u fields %u %u %u %u %u\n%s\n%s\n%s\n%s\n", format->key_u64s, diff --git a/drivers/md/bcache/bkey.h b/drivers/md/bcache/bkey.h index 1e68822e13bd..f0bd3faf0d76 100644 --- a/drivers/md/bcache/bkey.h +++ b/drivers/md/bcache/bkey.h @@ -6,6 +6,7 @@ #include "util.h" +void bch_to_binary(char *, const u64 *, unsigned); int bch_bkey_to_text(char *, size_t, const struct bkey *); /* bkey with split value, const */ diff --git a/drivers/md/bcache/bset.c b/drivers/md/bcache/bset.c index fb559e3f2115..4940d961755f 100644 --- a/drivers/md/bcache/bset.c +++ b/drivers/md/bcache/bset.c @@ -1773,3 +1773,71 @@ void bch_btree_keys_stats(struct btree_keys *b, struct bset_stats *stats) } } } + +int bch_bkey_print_bfloat(struct btree_keys *b, struct bkey_packed *k, + char *buf, size_t size) +{ + struct bset_tree *t = bch_bkey_to_bset(b, k); + struct bkey_packed *l, *r, *p; + struct bkey uk, up; + char buf1[200], buf2[200]; + unsigned j; + + if (!size) + return 0; + + if (!bset_has_aux_tree(t)) + goto out; + + j = inorder_to_tree(bkey_to_cacheline(t, k), t); + if (j && + j < t->size && + k == tree_to_bkey(t, j)) + switch (t->tree[j].exponent) { + case BFLOAT_FAILED_UNPACKED: + uk = bkey_unpack_key(&b->format, k); + return scnprintf(buf, size, + " failed unpacked at depth %u\n" + "\t%llu:%llu\n", + ilog2(j), + uk.p.inode, uk.p.offset); + case BFLOAT_FAILED_PREV: + p = tree_to_prev_bkey(t, j); + l = is_power_of_2(j) + ? t->data->start + : tree_to_prev_bkey(t, j >> ffs(j)); + r = is_power_of_2(j + 1) + ? bset_bkey_idx(t->data, + le16_to_cpu(t->data->u64s) - t->end.u64s) + : tree_to_bkey(t, j >> (ffz(j) + 1)); + + up = bkey_unpack_key(&b->format, p); + uk = bkey_unpack_key(&b->format, k); + bch_to_binary(buf1, high_word(&b->format, p), bkey_format_key_bits(&b->format)); + bch_to_binary(buf2, high_word(&b->format, k), bkey_format_key_bits(&b->format)); + + return scnprintf(buf, size, + " failed prev at depth %u\n" + "\tkey starts at bit %u but first differing bit at %u\n" + "\t%llu:%llu\n" + "\t%llu:%llu\n" + "\t%s\n" + "\t%s\n", + ilog2(j), + bkey_greatest_differing_bit(&b->format, l, r), + bkey_greatest_differing_bit(&b->format, p, k), + uk.p.inode, uk.p.offset, + up.p.inode, up.p.offset, + buf1, buf2); + case BFLOAT_FAILED_OVERFLOW: + uk = bkey_unpack_key(&b->format, k); + return scnprintf(buf, size, + " failed overflow at depth %u\n" + "\t%llu:%llu\n", + ilog2(j), + uk.p.inode, uk.p.offset); + } +out: + *buf = '\0'; + return 0; +} diff --git a/drivers/md/bcache/bset.h b/drivers/md/bcache/bset.h index 512bea8b033e..bf136be0873f 100644 --- a/drivers/md/bcache/bset.h +++ b/drivers/md/bcache/bset.h @@ -596,6 +596,8 @@ struct bset_stats { }; void bch_btree_keys_stats(struct btree_keys *, struct bset_stats *); +int bch_bkey_print_bfloat(struct btree_keys *, struct bkey_packed *, + char *, size_t); /* Debug stuff */ diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index 88c082a4ec39..3ada6d9c4e56 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -295,6 +295,50 @@ static const struct file_operations btree_debug_ops = { .read = bch_read_btree, }; +static int print_btree_node(struct dump_iter *i, struct btree *b) +{ + const struct bkey_format *f = &b->keys.format; + struct bset_stats stats; + + memset(&stats, 0, sizeof(stats)); + + bch_btree_keys_stats(&b->keys, &stats); + + i->bytes = scnprintf(i->buf, sizeof(i->buf), + "l %u %llu:%llu - %llu:%llu:\n" + " format: u64s %u fields %u %u %u %u %u\n" + " bytes used %zu/%zu (%zu%% full)\n" + " nr packed keys %u\n" + " nr unpacked keys %u\n" + " floats %zu\n" + " failed unpacked %zu\n" + " failed prev %zu\n" + " failed overflow %zu\n", + b->level, + b->data->min_key.inode, + b->data->min_key.offset, + b->data->max_key.inode, + b->data->max_key.offset, + f->key_u64s, + f->bits_per_field[0], + f->bits_per_field[1], + f->bits_per_field[2], + f->bits_per_field[3], + f->bits_per_field[4], + b->keys.nr.live_u64s * sizeof(u64), + btree_bytes(i->c) - sizeof(struct btree_node), + (b->keys.nr.live_u64s * sizeof(u64) * 100) / + (btree_bytes(i->c) - sizeof(struct btree_node)), + b->keys.nr.packed_keys, + b->keys.nr.unpacked_keys, + stats.floats, + stats.failed_unpacked, + stats.failed_prev, + stats.failed_overflow); + + return flush_buf(i); +} + static ssize_t bch_read_btree_formats(struct file *file, char __user *buf, size_t size, loff_t *ppos) { @@ -315,46 +359,7 @@ static ssize_t bch_read_btree_formats(struct file *file, char __user *buf, return i->ret; for_each_btree_node(&iter, i->c, i->id, i->from, 0, b) { - const struct bkey_format *f = &b->keys.format; - struct bset_stats stats; - - memset(&stats, 0, sizeof(stats)); - - bch_btree_keys_stats(&b->keys, &stats); - - i->bytes = scnprintf(i->buf, sizeof(i->buf), - "l %u %llu:%llu - %llu:%llu:\n" - "\tformat: u64s %u fields %u %u %u %u %u\n" - "\tbytes used %zu/%zu (%zu%% full)\n" - "\tnr packed keys %u\n" - "\tnr unpacked keys %u\n" - "\tfloats %zu\n" - "\tfailed unpacked %zu\n" - "\tfailed prev %zu\n" - "\tfailed overflow %zu\n", - b->level, - b->data->min_key.inode, - b->data->min_key.offset, - b->data->max_key.inode, - b->data->max_key.offset, - f->key_u64s, - f->bits_per_field[0], - f->bits_per_field[1], - f->bits_per_field[2], - f->bits_per_field[3], - f->bits_per_field[4], - b->keys.nr.live_u64s * sizeof(u64), - btree_bytes(i->c) - sizeof(struct btree_node), - (b->keys.nr.live_u64s * sizeof(u64) * 100) / - (btree_bytes(i->c) - sizeof(struct btree_node)), - b->keys.nr.packed_keys, - b->keys.nr.unpacked_keys, - stats.floats, - stats.failed_unpacked, - stats.failed_prev, - stats.failed_overflow); - - err = flush_buf(i); + err = print_btree_node(i, b); if (err) break; @@ -381,6 +386,68 @@ static const struct file_operations btree_format_debug_ops = { .read = bch_read_btree_formats, }; +static ssize_t bch_read_bfloat_failed(struct file *file, char __user *buf, + size_t size, loff_t *ppos) +{ + struct dump_iter *i = file->private_data; + struct btree_iter iter; + struct bkey_s_c k; + struct btree *prev_node = NULL; + int err; + + i->ubuf = buf; + i->size = size; + i->ret = 0; + + err = flush_buf(i); + if (err) + return err; + + if (!i->size) + return i->ret; + + bch_btree_iter_init(&iter, i->c, i->id, i->from); + + while ((k = bch_btree_iter_peek(&iter)).k) { + struct btree_keys *b = &iter.nodes[0]->keys; + struct btree_node_iter *node_iter = &iter.node_iters[0]; + struct bkey_packed *_k = bch_btree_node_iter_peek(node_iter, b); + + if (iter.nodes[0] != prev_node) { + err = print_btree_node(i, iter.nodes[0]); + if (err) + break; + } + prev_node = iter.nodes[0]; + + i->bytes = bch_bkey_print_bfloat(b, _k, i->buf, sizeof(i->buf)); + + err = flush_buf(i); + if (err) + break; + + bch_btree_iter_advance_pos(&iter); + i->from = iter.pos; + + err = flush_buf(i); + if (err) + break; + + if (!i->size) + break; + } + bch_btree_iter_unlock(&iter); + + return err < 0 ? err : i->ret; +} + +static const struct file_operations bfloat_failed_debug_ops = { + .owner = THIS_MODULE, + .open = bch_dump_open, + .release = bch_dump_release, + .read = bch_read_bfloat_failed, +}; + void bch_debug_exit_cache_set(struct cache_set *c) { if (!IS_ERR_OR_NULL(c->debug)) @@ -390,7 +457,7 @@ void bch_debug_exit_cache_set(struct cache_set *c) void bch_debug_init_cache_set(struct cache_set *c) { struct btree_debug *bd; - char name[50]; + char name[100]; if (IS_ERR_OR_NULL(bch_debug)) return; @@ -413,6 +480,12 @@ void bch_debug_init_cache_set(struct cache_set *c) bd->btree_format = debugfs_create_file(name, 0400, c->debug, bd, &btree_format_debug_ops); + + snprintf(name, sizeof(name), "%s-bfloat-failed", + bch_btree_id_names[bd->id]); + + bd->failed = debugfs_create_file(name, 0400, c->debug, bd, + &bfloat_failed_debug_ops); } } |