18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Assorted bcache debug code
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2010, 2011 Kent Overstreet <kent.overstreet@gmail.com>
68c2ecf20Sopenharmony_ci * Copyright 2012 Google, Inc.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "bcache.h"
108c2ecf20Sopenharmony_ci#include "btree.h"
118c2ecf20Sopenharmony_ci#include "debug.h"
128c2ecf20Sopenharmony_ci#include "extents.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/console.h>
158c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
168c2ecf20Sopenharmony_ci#include <linux/module.h>
178c2ecf20Sopenharmony_ci#include <linux/random.h>
188c2ecf20Sopenharmony_ci#include <linux/seq_file.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_cistruct dentry *bcache_debug;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#ifdef CONFIG_BCACHE_DEBUG
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define for_each_written_bset(b, start, i)				\
258c2ecf20Sopenharmony_ci	for (i = (start);						\
268c2ecf20Sopenharmony_ci	     (void *) i < (void *) (start) + (KEY_SIZE(&b->key) << 9) &&\
278c2ecf20Sopenharmony_ci	     i->seq == (start)->seq;					\
288c2ecf20Sopenharmony_ci	     i = (void *) i + set_blocks(i, block_bytes(b->c->cache)) *	\
298c2ecf20Sopenharmony_ci		 block_bytes(b->c->cache))
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_civoid bch_btree_verify(struct btree *b)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	struct btree *v = b->c->verify_data;
348c2ecf20Sopenharmony_ci	struct bset *ondisk, *sorted, *inmemory;
358c2ecf20Sopenharmony_ci	struct bio *bio;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	if (!b->c->verify || !b->c->verify_ondisk)
388c2ecf20Sopenharmony_ci		return;
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci	down(&b->io_mutex);
418c2ecf20Sopenharmony_ci	mutex_lock(&b->c->verify_lock);
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	ondisk = b->c->verify_ondisk;
448c2ecf20Sopenharmony_ci	sorted = b->c->verify_data->keys.set->data;
458c2ecf20Sopenharmony_ci	inmemory = b->keys.set->data;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	bkey_copy(&v->key, &b->key);
488c2ecf20Sopenharmony_ci	v->written = 0;
498c2ecf20Sopenharmony_ci	v->level = b->level;
508c2ecf20Sopenharmony_ci	v->keys.ops = b->keys.ops;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci	bio = bch_bbio_alloc(b->c);
538c2ecf20Sopenharmony_ci	bio_set_dev(bio, PTR_CACHE(b->c, &b->key, 0)->bdev);
548c2ecf20Sopenharmony_ci	bio->bi_iter.bi_sector	= PTR_OFFSET(&b->key, 0);
558c2ecf20Sopenharmony_ci	bio->bi_iter.bi_size	= KEY_SIZE(&v->key) << 9;
568c2ecf20Sopenharmony_ci	bio->bi_opf		= REQ_OP_READ | REQ_META;
578c2ecf20Sopenharmony_ci	bch_bio_map(bio, sorted);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	submit_bio_wait(bio);
608c2ecf20Sopenharmony_ci	bch_bbio_free(bio, b->c);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	memcpy(ondisk, sorted, KEY_SIZE(&v->key) << 9);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	bch_btree_node_read_done(v);
658c2ecf20Sopenharmony_ci	sorted = v->keys.set->data;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (inmemory->keys != sorted->keys ||
688c2ecf20Sopenharmony_ci	    memcmp(inmemory->start,
698c2ecf20Sopenharmony_ci		   sorted->start,
708c2ecf20Sopenharmony_ci		   (void *) bset_bkey_last(inmemory) -
718c2ecf20Sopenharmony_ci		   (void *) inmemory->start)) {
728c2ecf20Sopenharmony_ci		struct bset *i;
738c2ecf20Sopenharmony_ci		unsigned int j;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci		console_lock();
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci		pr_err("*** in memory:\n");
788c2ecf20Sopenharmony_ci		bch_dump_bset(&b->keys, inmemory, 0);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci		pr_err("*** read back in:\n");
818c2ecf20Sopenharmony_ci		bch_dump_bset(&v->keys, sorted, 0);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		for_each_written_bset(b, ondisk, i) {
848c2ecf20Sopenharmony_ci			unsigned int block = ((void *) i - (void *) ondisk) /
858c2ecf20Sopenharmony_ci				block_bytes(b->c->cache);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci			pr_err("*** on disk block %u:\n", block);
888c2ecf20Sopenharmony_ci			bch_dump_bset(&b->keys, i, block);
898c2ecf20Sopenharmony_ci		}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		pr_err("*** block %zu not written\n",
928c2ecf20Sopenharmony_ci		       ((void *) i - (void *) ondisk) / block_bytes(b->c->cache));
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_ci		for (j = 0; j < inmemory->keys; j++)
958c2ecf20Sopenharmony_ci			if (inmemory->d[j] != sorted->d[j])
968c2ecf20Sopenharmony_ci				break;
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci		pr_err("b->written %u\n", b->written);
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		console_unlock();
1018c2ecf20Sopenharmony_ci		panic("verify failed at %u\n", j);
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	mutex_unlock(&b->c->verify_lock);
1058c2ecf20Sopenharmony_ci	up(&b->io_mutex);
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_civoid bch_data_verify(struct cached_dev *dc, struct bio *bio)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	struct bio *check;
1118c2ecf20Sopenharmony_ci	struct bio_vec bv, cbv;
1128c2ecf20Sopenharmony_ci	struct bvec_iter iter, citer = { 0 };
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	check = bio_kmalloc(GFP_NOIO, bio_segments(bio));
1158c2ecf20Sopenharmony_ci	if (!check)
1168c2ecf20Sopenharmony_ci		return;
1178c2ecf20Sopenharmony_ci	check->bi_disk = bio->bi_disk;
1188c2ecf20Sopenharmony_ci	check->bi_opf = REQ_OP_READ;
1198c2ecf20Sopenharmony_ci	check->bi_iter.bi_sector = bio->bi_iter.bi_sector;
1208c2ecf20Sopenharmony_ci	check->bi_iter.bi_size = bio->bi_iter.bi_size;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	bch_bio_map(check, NULL);
1238c2ecf20Sopenharmony_ci	if (bch_bio_alloc_pages(check, GFP_NOIO))
1248c2ecf20Sopenharmony_ci		goto out_put;
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	submit_bio_wait(check);
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	citer.bi_size = UINT_MAX;
1298c2ecf20Sopenharmony_ci	bio_for_each_segment(bv, bio, iter) {
1308c2ecf20Sopenharmony_ci		void *p1 = kmap_atomic(bv.bv_page);
1318c2ecf20Sopenharmony_ci		void *p2;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci		cbv = bio_iter_iovec(check, citer);
1348c2ecf20Sopenharmony_ci		p2 = page_address(cbv.bv_page);
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci		cache_set_err_on(memcmp(p1 + bv.bv_offset,
1378c2ecf20Sopenharmony_ci					p2 + bv.bv_offset,
1388c2ecf20Sopenharmony_ci					bv.bv_len),
1398c2ecf20Sopenharmony_ci				 dc->disk.c,
1408c2ecf20Sopenharmony_ci				 "verify failed at dev %s sector %llu",
1418c2ecf20Sopenharmony_ci				 dc->backing_dev_name,
1428c2ecf20Sopenharmony_ci				 (uint64_t) bio->bi_iter.bi_sector);
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		kunmap_atomic(p1);
1458c2ecf20Sopenharmony_ci		bio_advance_iter(check, &citer, bv.bv_len);
1468c2ecf20Sopenharmony_ci	}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	bio_free_pages(check);
1498c2ecf20Sopenharmony_ciout_put:
1508c2ecf20Sopenharmony_ci	bio_put(check);
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci#endif
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/* XXX: cache set refcounting */
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistruct dump_iterator {
1608c2ecf20Sopenharmony_ci	char			buf[PAGE_SIZE];
1618c2ecf20Sopenharmony_ci	size_t			bytes;
1628c2ecf20Sopenharmony_ci	struct cache_set	*c;
1638c2ecf20Sopenharmony_ci	struct keybuf		keys;
1648c2ecf20Sopenharmony_ci};
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_cistatic bool dump_pred(struct keybuf *buf, struct bkey *k)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	return true;
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic ssize_t bch_dump_read(struct file *file, char __user *buf,
1728c2ecf20Sopenharmony_ci			     size_t size, loff_t *ppos)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	struct dump_iterator *i = file->private_data;
1758c2ecf20Sopenharmony_ci	ssize_t ret = 0;
1768c2ecf20Sopenharmony_ci	char kbuf[80];
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	while (size) {
1798c2ecf20Sopenharmony_ci		struct keybuf_key *w;
1808c2ecf20Sopenharmony_ci		unsigned int bytes = min(i->bytes, size);
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci		if (copy_to_user(buf, i->buf, bytes))
1838c2ecf20Sopenharmony_ci			return -EFAULT;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci		ret	 += bytes;
1868c2ecf20Sopenharmony_ci		buf	 += bytes;
1878c2ecf20Sopenharmony_ci		size	 -= bytes;
1888c2ecf20Sopenharmony_ci		i->bytes -= bytes;
1898c2ecf20Sopenharmony_ci		memmove(i->buf, i->buf + bytes, i->bytes);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci		if (i->bytes)
1928c2ecf20Sopenharmony_ci			break;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci		w = bch_keybuf_next_rescan(i->c, &i->keys, &MAX_KEY, dump_pred);
1958c2ecf20Sopenharmony_ci		if (!w)
1968c2ecf20Sopenharmony_ci			break;
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci		bch_extent_to_text(kbuf, sizeof(kbuf), &w->key);
1998c2ecf20Sopenharmony_ci		i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", kbuf);
2008c2ecf20Sopenharmony_ci		bch_keybuf_del(&i->keys, w);
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return ret;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic int bch_dump_open(struct inode *inode, struct file *file)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	struct cache_set *c = inode->i_private;
2098c2ecf20Sopenharmony_ci	struct dump_iterator *i;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	i = kzalloc(sizeof(struct dump_iterator), GFP_KERNEL);
2128c2ecf20Sopenharmony_ci	if (!i)
2138c2ecf20Sopenharmony_ci		return -ENOMEM;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	file->private_data = i;
2168c2ecf20Sopenharmony_ci	i->c = c;
2178c2ecf20Sopenharmony_ci	bch_keybuf_init(&i->keys);
2188c2ecf20Sopenharmony_ci	i->keys.last_scanned = KEY(0, 0, 0);
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	return 0;
2218c2ecf20Sopenharmony_ci}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_cistatic int bch_dump_release(struct inode *inode, struct file *file)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	kfree(file->private_data);
2268c2ecf20Sopenharmony_ci	return 0;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic const struct file_operations cache_set_debug_ops = {
2308c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
2318c2ecf20Sopenharmony_ci	.open		= bch_dump_open,
2328c2ecf20Sopenharmony_ci	.read		= bch_dump_read,
2338c2ecf20Sopenharmony_ci	.release	= bch_dump_release
2348c2ecf20Sopenharmony_ci};
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_civoid bch_debug_init_cache_set(struct cache_set *c)
2378c2ecf20Sopenharmony_ci{
2388c2ecf20Sopenharmony_ci	if (!IS_ERR_OR_NULL(bcache_debug)) {
2398c2ecf20Sopenharmony_ci		char name[50];
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci		snprintf(name, 50, "bcache-%pU", c->set_uuid);
2428c2ecf20Sopenharmony_ci		c->debug = debugfs_create_file(name, 0400, bcache_debug, c,
2438c2ecf20Sopenharmony_ci					       &cache_set_debug_ops);
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci#endif
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_civoid bch_debug_exit(void)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	debugfs_remove_recursive(bcache_debug);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_civoid __init bch_debug_init(void)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	/*
2578c2ecf20Sopenharmony_ci	 * it is unnecessary to check return value of
2588c2ecf20Sopenharmony_ci	 * debugfs_create_file(), we should not care
2598c2ecf20Sopenharmony_ci	 * about this.
2608c2ecf20Sopenharmony_ci	 */
2618c2ecf20Sopenharmony_ci	bcache_debug = debugfs_create_dir("bcache", NULL);
2628c2ecf20Sopenharmony_ci}
263