summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/md/bcache/bcache.h7
-rw-r--r--drivers/md/bcache/btree.c8
-rw-r--r--drivers/md/bcache/btree.h2
-rw-r--r--drivers/md/bcache/debug.c161
-rw-r--r--drivers/md/bcache/debug.h2
-rw-r--r--drivers/md/bcache/move.c10
-rw-r--r--drivers/md/bcache/super.c3
7 files changed, 150 insertions, 43 deletions
diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h
index e0439f45f65a..c3e349495915 100644
--- a/drivers/md/bcache/bcache.h
+++ b/drivers/md/bcache/bcache.h
@@ -388,6 +388,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;
int minor;
@@ -555,6 +561,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 12dace3f0358..643d25abcd89 100644
--- a/drivers/md/bcache/btree.c
+++ b/drivers/md/bcache/btree.c
@@ -42,6 +42,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 *,
diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h
index ac84a355acf0..94808dc5d23f 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 34dc52846ee4..cf3acc643440 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
@@ -174,6 +174,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 */
@@ -202,8 +203,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;
@@ -221,19 +245,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, k, i->from) {
+ 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;
}
@@ -242,43 +269,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, b, i->from) {
+ 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);
}
}
@@ -286,14 +383,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 a8b4761c7672..fba161e05db3 100644
--- a/drivers/md/bcache/move.c
+++ b/drivers/md/bcache/move.c
@@ -1113,14 +1113,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;
@@ -1129,7 +1121,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 793ccbb87a74..d741131b1a8c 100644
--- a/drivers/md/bcache/super.c
+++ b/drivers/md/bcache/super.c
@@ -748,8 +748,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);