diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2015-08-21 01:44:09 -0800 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2016-10-07 12:33:28 -0800 |
commit | 421943eb7648d9caf8ff9ee506b2f84765e5d8e9 (patch) | |
tree | a44024340562a290e8e528e92e0e1259b8e47895 | |
parent | f0262b55c678bcc424ab93c8b23c8b24f9683d5f (diff) |
bcache: New debugfs code
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
-rw-r--r-- | drivers/md/bcache/bcache.h | 7 | ||||
-rw-r--r-- | drivers/md/bcache/btree.c | 8 | ||||
-rw-r--r-- | drivers/md/bcache/btree.h | 2 | ||||
-rw-r--r-- | drivers/md/bcache/debug.c | 161 | ||||
-rw-r--r-- | drivers/md/bcache/debug.h | 2 | ||||
-rw-r--r-- | drivers/md/bcache/move.c | 10 | ||||
-rw-r--r-- | drivers/md/bcache/super.c | 3 |
7 files changed, 150 insertions, 43 deletions
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index a989f54f091e..896450f59497 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -386,6 +386,12 @@ struct cache_member_rcu { struct cache_member m[]; }; +struct btree_debug { + unsigned id; + struct dentry *btree; + struct dentry *btree_format; +}; + struct cache_set { struct closure cl; @@ -564,6 +570,7 @@ struct cache_set { /* DEBUG JUNK */ struct dentry *debug; + struct btree_debug btree_debug[BTREE_ID_NR]; #ifdef CONFIG_BCACHE_DEBUG struct btree *verify_data; struct bset *verify_ondisk; diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index bdb6ecfecb35..abaceb5a4ee8 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -44,6 +44,14 @@ #include <linux/rcupdate.h> #include <trace/events/bcache.h> +#define DEF_BTREE_ID(kwd, val, name) name, + +const char *bch_btree_id_names[BTREE_ID_NR] = { + DEFINE_BCH_BTREE_IDS() +}; + +#undef DEF_BTREE_ID + static int bch_btree_iter_traverse(struct btree_iter *); static int __bch_btree_insert_node(struct btree *, struct btree_iter *, struct keylist *, struct bch_replace_info *, diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h index 4ba91553c016..90eb128c7d33 100644 --- a/drivers/md/bcache/btree.h +++ b/drivers/md/bcache/btree.h @@ -84,6 +84,8 @@ #include "six.h" #include "journal_types.h" +extern const char *bch_btree_id_names[BTREE_ID_NR]; + struct btree_write { atomic_t *journal; }; diff --git a/drivers/md/bcache/debug.c b/drivers/md/bcache/debug.c index da381f7fa74c..7e01e8192c8c 100644 --- a/drivers/md/bcache/debug.c +++ b/drivers/md/bcache/debug.c @@ -19,7 +19,7 @@ #include <linux/random.h> #include <linux/seq_file.h> -static struct dentry *debug; +static struct dentry *bch_debug; #ifdef CONFIG_BCACHE_DEBUG @@ -176,6 +176,7 @@ out_put: struct dump_iter { struct bpos from; struct cache_set *c; + enum btree_id id; char buf[PAGE_SIZE]; size_t bytes; /* what's currently in buf */ @@ -204,8 +205,31 @@ static int flush_buf(struct dump_iter *i) return 0; } -static ssize_t bch_dump_read(struct file *file, char __user *buf, - size_t size, loff_t *ppos) +static int bch_dump_open(struct inode *inode, struct file *file) +{ + struct btree_debug *bd = inode->i_private; + struct dump_iter *i; + + i = kzalloc(sizeof(struct dump_iter), GFP_KERNEL); + if (!i) + return -ENOMEM; + + file->private_data = i; + i->from = POS_MIN; + i->c = container_of(bd, struct cache_set, btree_debug[bd->id]); + i->id = bd->id; + + return 0; +} + +static int bch_dump_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + return 0; +} + +static ssize_t bch_read_btree(struct file *file, char __user *buf, + size_t size, loff_t *ppos) { struct dump_iter *i = file->private_data; struct btree_iter iter; @@ -223,19 +247,22 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf, if (!i->size) return i->ret; - for_each_btree_key(&iter, i->c, BTREE_ID_EXTENTS, i->from, k) { + bch_btree_iter_init(&iter, i->c, i->id, i->from); + + while ((k = bch_btree_iter_peek(&iter)).k) { bch_bkey_val_to_text(iter.nodes[0], i->buf, sizeof(i->buf), k); i->bytes = strlen(i->buf); BUG_ON(i->bytes >= PAGE_SIZE); i->buf[i->bytes] = '\n'; i->bytes++; + bch_btree_iter_advance_pos(&iter); + i->from = iter.pos; + err = flush_buf(i); if (err) break; - i->from = k.k->p; - if (!i->size) break; } @@ -244,43 +271,113 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf, return err < 0 ? err : i->ret; } -static int bch_dump_open(struct inode *inode, struct file *file) +static const struct file_operations btree_debug_ops = { + .owner = THIS_MODULE, + .open = bch_dump_open, + .release = bch_dump_release, + .read = bch_read_btree, +}; + +static ssize_t bch_read_btree_formats(struct file *file, char __user *buf, + size_t size, loff_t *ppos) { - struct cache_set *c = inode->i_private; - struct dump_iter *i; + struct dump_iter *i = file->private_data; + struct btree_iter iter; + struct btree *b; + int err; - i = kzalloc(sizeof(struct dump_iter), GFP_KERNEL); - if (!i) - return -ENOMEM; + i->ubuf = buf; + i->size = size; + i->ret = 0; - file->private_data = i; - i->from = POS_MIN; - i->c = c; + err = flush_buf(i); + if (err) + return err; - return 0; -} + if (!i->size || !bkey_cmp(POS_MAX, i->from)) + return i->ret; -static int bch_dump_release(struct inode *inode, struct file *file) -{ - kfree(file->private_data); - return 0; + for_each_btree_node(&iter, i->c, i->id, i->from, b) { + const struct bkey_format *f = &b->keys.set->data->format; + struct bset_stats stats = { 0 }; + + bch_btree_keys_stats(&b->keys, &stats); + + i->bytes = scnprintf(i->buf, sizeof(i->buf), + "l %u %llu:%llu:\n" + "\tformat: u64s %u fields %u %u %u %u %u\n" + "\tfloats %zu failed %zu\n", + b->level, + b->key.k.p.inode, + b->key.k.p.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], + stats.floats, + stats.failed); + + err = flush_buf(i); + if (err) + break; + + /* + * can't easily correctly restart a btree node traversal across + * all nodes, meh + */ + i->from = bkey_cmp(POS_MAX, b->key.k.p) + ? bkey_successor(b->key.k.p) + : b->key.k.p; + + if (!i->size) + break; + } + bch_btree_iter_unlock(&iter); + + return err < 0 ? err : i->ret; } -static const struct file_operations cache_set_debug_ops = { +static const struct file_operations btree_format_debug_ops = { .owner = THIS_MODULE, .open = bch_dump_open, - .read = bch_dump_read, - .release = bch_dump_release + .release = bch_dump_release, + .read = bch_read_btree_formats, }; +void bch_debug_exit_cache_set(struct cache_set *c) +{ + if (!IS_ERR_OR_NULL(c->debug)) + debugfs_remove(c->debug); +} + void bch_debug_init_cache_set(struct cache_set *c) { - if (!IS_ERR_OR_NULL(debug)) { - char name[50]; - snprintf(name, 50, "bcache-%pU", c->sb.set_uuid.b); + struct btree_debug *bd; + char name[50]; + + if (IS_ERR_OR_NULL(bch_debug)) + return; + + snprintf(name, sizeof(name), "%pU", c->sb.set_uuid.b); + c->debug = debugfs_create_dir(name, bch_debug); + if (IS_ERR_OR_NULL(c->debug)) + return; + + for (bd = c->btree_debug; + bd < c->btree_debug + ARRAY_SIZE(c->btree_debug); + bd++) { + bd->id = bd - c->btree_debug; + bd->btree = debugfs_create_file(bch_btree_id_names[bd->id], + 0400, c->debug, bd, + &btree_debug_ops); + + snprintf(name, sizeof(name), "%s-formats", + bch_btree_id_names[bd->id]); - c->debug = debugfs_create_file(name, 0400, debug, c, - &cache_set_debug_ops); + bd->btree_format = debugfs_create_file(name, 0400, c->debug, bd, + &btree_format_debug_ops); } } @@ -288,14 +385,14 @@ void bch_debug_init_cache_set(struct cache_set *c) void bch_debug_exit(void) { - if (!IS_ERR_OR_NULL(debug)) - debugfs_remove_recursive(debug); + if (!IS_ERR_OR_NULL(bch_debug)) + debugfs_remove_recursive(bch_debug); } int __init bch_debug_init(void) { int ret = 0; - debug = debugfs_create_dir("bcache", NULL); + bch_debug = debugfs_create_dir("bcache", NULL); return ret; } diff --git a/drivers/md/bcache/debug.h b/drivers/md/bcache/debug.h index 1f63c195d247..83dad863dc17 100644 --- a/drivers/md/bcache/debug.h +++ b/drivers/md/bcache/debug.h @@ -26,8 +26,10 @@ static inline void bch_data_verify(struct cached_dev *dc, struct bio *bio) {} #endif #ifdef CONFIG_DEBUG_FS +void bch_debug_exit_cache_set(struct cache_set *); void bch_debug_init_cache_set(struct cache_set *); #else +static inline void bch_debug_exit_cache_set(struct cache_set *c) {} static inline void bch_debug_init_cache_set(struct cache_set *c) {} #endif diff --git a/drivers/md/bcache/move.c b/drivers/md/bcache/move.c index 67f110fa0d69..1577dfdc9bab 100644 --- a/drivers/md/bcache/move.c +++ b/drivers/md/bcache/move.c @@ -1114,14 +1114,6 @@ retry: * is written. */ -#define DEF_BTREE_ID(kwd, val, name) name, - -static const char *btree_id_names[BTREE_ID_NR] = { - DEFINE_BCH_BTREE_IDS() -}; - -#undef DEF_BTREE_ID - int bch_move_meta_data_off_device(struct cache *ca) { unsigned i; @@ -1130,7 +1122,7 @@ int bch_move_meta_data_off_device(struct cache *ca) /* 1st, Move the btree nodes off the device */ for (i = 0; i < BTREE_ID_NR; i++) - if (bch_move_btree_off(ca, i, btree_id_names[i]) != 0) + if (bch_move_btree_off(ca, i, bch_btree_id_names[i]) != 0) return 1; /* There are no prios/gens to move -- they are already in the device. */ diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index bbce5fed879e..971c1506e32e 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -724,8 +724,7 @@ static void cache_set_free(struct closure *cl) struct cache *ca; unsigned i; - if (!IS_ERR_OR_NULL(c->debug)) - debugfs_remove(c->debug); + bch_debug_exit_cache_set(c); bch_btree_cache_free(c); bch_journal_free(c); |