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