brintos

brintos / linux-shallow public Read only

0
0
Text · 21.4 KiB · 45aec1a Raw
952 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Assorted bcachefs debug code4 *5 * Copyright 2010, 2011 Kent Overstreet <kent.overstreet@gmail.com>6 * Copyright 2012 Google, Inc.7 */8 9#include "bcachefs.h"10#include "bkey_methods.h"11#include "btree_cache.h"12#include "btree_io.h"13#include "btree_iter.h"14#include "btree_locking.h"15#include "btree_update.h"16#include "btree_update_interior.h"17#include "buckets.h"18#include "debug.h"19#include "error.h"20#include "extents.h"21#include "fsck.h"22#include "inode.h"23#include "super.h"24 25#include <linux/console.h>26#include <linux/debugfs.h>27#include <linux/module.h>28#include <linux/random.h>29#include <linux/seq_file.h>30 31static struct dentry *bch_debug;32 33static bool bch2_btree_verify_replica(struct bch_fs *c, struct btree *b,34				      struct extent_ptr_decoded pick)35{36	struct btree *v = c->verify_data;37	struct btree_node *n_ondisk = c->verify_ondisk;38	struct btree_node *n_sorted = c->verify_data->data;39	struct bset *sorted, *inmemory = &b->data->keys;40	struct bio *bio;41	bool failed = false, saw_error = false;42 43	struct bch_dev *ca = bch2_dev_get_ioref(c, pick.ptr.dev, READ);44	if (!ca)45		return false;46 47	bio = bio_alloc_bioset(ca->disk_sb.bdev,48			       buf_pages(n_sorted, btree_buf_bytes(b)),49			       REQ_OP_READ|REQ_META,50			       GFP_NOFS,51			       &c->btree_bio);52	bio->bi_iter.bi_sector	= pick.ptr.offset;53	bch2_bio_map(bio, n_sorted, btree_buf_bytes(b));54 55	submit_bio_wait(bio);56 57	bio_put(bio);58	percpu_ref_put(&ca->io_ref);59 60	memcpy(n_ondisk, n_sorted, btree_buf_bytes(b));61 62	v->written = 0;63	if (bch2_btree_node_read_done(c, ca, v, false, &saw_error) || saw_error)64		return false;65 66	n_sorted = c->verify_data->data;67	sorted = &n_sorted->keys;68 69	if (inmemory->u64s != sorted->u64s ||70	    memcmp(inmemory->start,71		   sorted->start,72		   vstruct_end(inmemory) - (void *) inmemory->start)) {73		unsigned offset = 0, sectors;74		struct bset *i;75		unsigned j;76 77		console_lock();78 79		printk(KERN_ERR "*** in memory:\n");80		bch2_dump_bset(c, b, inmemory, 0);81 82		printk(KERN_ERR "*** read back in:\n");83		bch2_dump_bset(c, v, sorted, 0);84 85		while (offset < v->written) {86			if (!offset) {87				i = &n_ondisk->keys;88				sectors = vstruct_blocks(n_ondisk, c->block_bits) <<89					c->block_bits;90			} else {91				struct btree_node_entry *bne =92					(void *) n_ondisk + (offset << 9);93				i = &bne->keys;94 95				sectors = vstruct_blocks(bne, c->block_bits) <<96					c->block_bits;97			}98 99			printk(KERN_ERR "*** on disk block %u:\n", offset);100			bch2_dump_bset(c, b, i, offset);101 102			offset += sectors;103		}104 105		for (j = 0; j < le16_to_cpu(inmemory->u64s); j++)106			if (inmemory->_data[j] != sorted->_data[j])107				break;108 109		console_unlock();110		bch_err(c, "verify failed at key %u", j);111 112		failed = true;113	}114 115	if (v->written != b->written) {116		bch_err(c, "written wrong: expected %u, got %u",117			b->written, v->written);118		failed = true;119	}120 121	return failed;122}123 124void __bch2_btree_verify(struct bch_fs *c, struct btree *b)125{126	struct bkey_ptrs_c ptrs;127	struct extent_ptr_decoded p;128	const union bch_extent_entry *entry;129	struct btree *v;130	struct bset *inmemory = &b->data->keys;131	struct bkey_packed *k;132	bool failed = false;133 134	if (c->opts.nochanges)135		return;136 137	bch2_btree_node_io_lock(b);138	mutex_lock(&c->verify_lock);139 140	if (!c->verify_ondisk) {141		c->verify_ondisk = kvmalloc(btree_buf_bytes(b), GFP_KERNEL);142		if (!c->verify_ondisk)143			goto out;144	}145 146	if (!c->verify_data) {147		c->verify_data = __bch2_btree_node_mem_alloc(c);148		if (!c->verify_data)149			goto out;150 151		list_del_init(&c->verify_data->list);152	}153 154	BUG_ON(b->nsets != 1);155 156	for (k = inmemory->start; k != vstruct_last(inmemory); k = bkey_p_next(k))157		if (k->type == KEY_TYPE_btree_ptr_v2)158			((struct bch_btree_ptr_v2 *) bkeyp_val(&b->format, k))->mem_ptr = 0;159 160	v = c->verify_data;161	bkey_copy(&v->key, &b->key);162	v->c.level	= b->c.level;163	v->c.btree_id	= b->c.btree_id;164	bch2_btree_keys_init(v);165 166	ptrs = bch2_bkey_ptrs_c(bkey_i_to_s_c(&b->key));167	bkey_for_each_ptr_decode(&b->key.k, ptrs, p, entry)168		failed |= bch2_btree_verify_replica(c, b, p);169 170	if (failed) {171		struct printbuf buf = PRINTBUF;172 173		bch2_bkey_val_to_text(&buf, c, bkey_i_to_s_c(&b->key));174		bch2_fs_fatal_error(c, ": btree node verify failed for: %s\n", buf.buf);175		printbuf_exit(&buf);176	}177out:178	mutex_unlock(&c->verify_lock);179	bch2_btree_node_io_unlock(b);180}181 182void bch2_btree_node_ondisk_to_text(struct printbuf *out, struct bch_fs *c,183				    const struct btree *b)184{185	struct btree_node *n_ondisk = NULL;186	struct extent_ptr_decoded pick;187	struct bch_dev *ca;188	struct bio *bio = NULL;189	unsigned offset = 0;190	int ret;191 192	if (bch2_bkey_pick_read_device(c, bkey_i_to_s_c(&b->key), NULL, &pick) <= 0) {193		prt_printf(out, "error getting device to read from: invalid device\n");194		return;195	}196 197	ca = bch2_dev_get_ioref(c, pick.ptr.dev, READ);198	if (!ca) {199		prt_printf(out, "error getting device to read from: not online\n");200		return;201	}202 203	n_ondisk = kvmalloc(btree_buf_bytes(b), GFP_KERNEL);204	if (!n_ondisk) {205		prt_printf(out, "memory allocation failure\n");206		goto out;207	}208 209	bio = bio_alloc_bioset(ca->disk_sb.bdev,210			       buf_pages(n_ondisk, btree_buf_bytes(b)),211			       REQ_OP_READ|REQ_META,212			       GFP_NOFS,213			       &c->btree_bio);214	bio->bi_iter.bi_sector	= pick.ptr.offset;215	bch2_bio_map(bio, n_ondisk, btree_buf_bytes(b));216 217	ret = submit_bio_wait(bio);218	if (ret) {219		prt_printf(out, "IO error reading btree node: %s\n", bch2_err_str(ret));220		goto out;221	}222 223	while (offset < btree_sectors(c)) {224		struct bset *i;225		struct nonce nonce;226		struct bch_csum csum;227		struct bkey_packed *k;228		unsigned sectors;229 230		if (!offset) {231			i = &n_ondisk->keys;232 233			if (!bch2_checksum_type_valid(c, BSET_CSUM_TYPE(i))) {234				prt_printf(out, "unknown checksum type at offset %u: %llu\n",235					   offset, BSET_CSUM_TYPE(i));236				goto out;237			}238 239			nonce = btree_nonce(i, offset << 9);240			csum = csum_vstruct(c, BSET_CSUM_TYPE(i), nonce, n_ondisk);241 242			if (bch2_crc_cmp(csum, n_ondisk->csum)) {243				prt_printf(out, "invalid checksum\n");244				goto out;245			}246 247			bset_encrypt(c, i, offset << 9);248 249			sectors = vstruct_sectors(n_ondisk, c->block_bits);250		} else {251			struct btree_node_entry *bne = (void *) n_ondisk + (offset << 9);252 253			i = &bne->keys;254 255			if (i->seq != n_ondisk->keys.seq)256				break;257 258			if (!bch2_checksum_type_valid(c, BSET_CSUM_TYPE(i))) {259				prt_printf(out, "unknown checksum type at offset %u: %llu\n",260					   offset, BSET_CSUM_TYPE(i));261				goto out;262			}263 264			nonce = btree_nonce(i, offset << 9);265			csum = csum_vstruct(c, BSET_CSUM_TYPE(i), nonce, bne);266 267			if (bch2_crc_cmp(csum, bne->csum)) {268				prt_printf(out, "invalid checksum");269				goto out;270			}271 272			bset_encrypt(c, i, offset << 9);273 274			sectors = vstruct_sectors(bne, c->block_bits);275		}276 277		prt_printf(out, "  offset %u version %u, journal seq %llu\n",278			   offset,279			   le16_to_cpu(i->version),280			   le64_to_cpu(i->journal_seq));281		offset += sectors;282 283		printbuf_indent_add(out, 4);284 285		for (k = i->start; k != vstruct_last(i); k = bkey_p_next(k)) {286			struct bkey u;287 288			bch2_bkey_val_to_text(out, c, bkey_disassemble(b, k, &u));289			prt_newline(out);290		}291 292		printbuf_indent_sub(out, 4);293	}294out:295	if (bio)296		bio_put(bio);297	kvfree(n_ondisk);298	percpu_ref_put(&ca->io_ref);299}300 301#ifdef CONFIG_DEBUG_FS302 303/* XXX: bch_fs refcounting */304 305struct dump_iter {306	struct bch_fs		*c;307	enum btree_id		id;308	struct bpos		from;309	struct bpos		prev_node;310	u64			iter;311 312	struct printbuf		buf;313 314	char __user		*ubuf;	/* destination user buffer */315	size_t			size;	/* size of requested read */316	ssize_t			ret;	/* bytes read so far */317};318 319static ssize_t flush_buf(struct dump_iter *i)320{321	if (i->buf.pos) {322		size_t bytes = min_t(size_t, i->buf.pos, i->size);323		int copied = bytes - copy_to_user(i->ubuf, i->buf.buf, bytes);324 325		i->ret	 += copied;326		i->ubuf	 += copied;327		i->size	 -= copied;328		i->buf.pos -= copied;329		memmove(i->buf.buf, i->buf.buf + copied, i->buf.pos);330 331		if (copied != bytes)332			return -EFAULT;333	}334 335	return i->size ? 0 : i->ret;336}337 338static int bch2_dump_open(struct inode *inode, struct file *file)339{340	struct btree_debug *bd = inode->i_private;341	struct dump_iter *i;342 343	i = kzalloc(sizeof(struct dump_iter), GFP_KERNEL);344	if (!i)345		return -ENOMEM;346 347	file->private_data = i;348	i->from = POS_MIN;349	i->iter	= 0;350	i->c	= container_of(bd, struct bch_fs, btree_debug[bd->id]);351	i->id	= bd->id;352	i->buf	= PRINTBUF;353 354	return 0;355}356 357static int bch2_dump_release(struct inode *inode, struct file *file)358{359	struct dump_iter *i = file->private_data;360 361	printbuf_exit(&i->buf);362	kfree(i);363	return 0;364}365 366static ssize_t bch2_read_btree(struct file *file, char __user *buf,367			       size_t size, loff_t *ppos)368{369	struct dump_iter *i = file->private_data;370 371	i->ubuf = buf;372	i->size	= size;373	i->ret	= 0;374 375	return flush_buf(i) ?:376		bch2_trans_run(i->c,377			for_each_btree_key(trans, iter, i->id, i->from,378					   BTREE_ITER_prefetch|379					   BTREE_ITER_all_snapshots, k, ({380				bch2_bkey_val_to_text(&i->buf, i->c, k);381				prt_newline(&i->buf);382				bch2_trans_unlock(trans);383				i->from = bpos_successor(iter.pos);384				flush_buf(i);385			}))) ?:386		i->ret;387}388 389static const struct file_operations btree_debug_ops = {390	.owner		= THIS_MODULE,391	.open		= bch2_dump_open,392	.release	= bch2_dump_release,393	.read		= bch2_read_btree,394};395 396static ssize_t bch2_read_btree_formats(struct file *file, char __user *buf,397				       size_t size, loff_t *ppos)398{399	struct dump_iter *i = file->private_data;400 401	i->ubuf = buf;402	i->size	= size;403	i->ret	= 0;404 405	ssize_t ret = flush_buf(i);406	if (ret)407		return ret;408 409	if (bpos_eq(SPOS_MAX, i->from))410		return i->ret;411 412	return bch2_trans_run(i->c,413		for_each_btree_node(trans, iter, i->id, i->from, 0, b, ({414			bch2_btree_node_to_text(&i->buf, i->c, b);415			i->from = !bpos_eq(SPOS_MAX, b->key.k.p)416				? bpos_successor(b->key.k.p)417				: b->key.k.p;418 419			drop_locks_do(trans, flush_buf(i));420		}))) ?: i->ret;421}422 423static const struct file_operations btree_format_debug_ops = {424	.owner		= THIS_MODULE,425	.open		= bch2_dump_open,426	.release	= bch2_dump_release,427	.read		= bch2_read_btree_formats,428};429 430static ssize_t bch2_read_bfloat_failed(struct file *file, char __user *buf,431				       size_t size, loff_t *ppos)432{433	struct dump_iter *i = file->private_data;434 435	i->ubuf = buf;436	i->size	= size;437	i->ret	= 0;438 439	return flush_buf(i) ?:440		bch2_trans_run(i->c,441			for_each_btree_key(trans, iter, i->id, i->from,442					   BTREE_ITER_prefetch|443					   BTREE_ITER_all_snapshots, k, ({444				struct btree_path_level *l =445					&btree_iter_path(trans, &iter)->l[0];446				struct bkey_packed *_k =447					bch2_btree_node_iter_peek(&l->iter, l->b);448 449				if (bpos_gt(l->b->key.k.p, i->prev_node)) {450					bch2_btree_node_to_text(&i->buf, i->c, l->b);451					i->prev_node = l->b->key.k.p;452				}453 454				bch2_bfloat_to_text(&i->buf, l->b, _k);455				bch2_trans_unlock(trans);456				i->from = bpos_successor(iter.pos);457				flush_buf(i);458			}))) ?:459		i->ret;460}461 462static const struct file_operations bfloat_failed_debug_ops = {463	.owner		= THIS_MODULE,464	.open		= bch2_dump_open,465	.release	= bch2_dump_release,466	.read		= bch2_read_bfloat_failed,467};468 469static void bch2_cached_btree_node_to_text(struct printbuf *out, struct bch_fs *c,470					   struct btree *b)471{472	if (!out->nr_tabstops)473		printbuf_tabstop_push(out, 32);474 475	prt_printf(out, "%px btree=%s l=%u\n", b, bch2_btree_id_str(b->c.btree_id), b->c.level);476 477	printbuf_indent_add(out, 2);478 479	bch2_bkey_val_to_text(out, c, bkey_i_to_s_c(&b->key));480	prt_newline(out);481 482	prt_printf(out, "flags:\t");483	prt_bitflags(out, bch2_btree_node_flags, b->flags);484	prt_newline(out);485 486	prt_printf(out, "pcpu read locks:\t%u\n",	b->c.lock.readers != NULL);487	prt_printf(out, "written:\t%u\n",		b->written);488	prt_printf(out, "writes blocked:\t%u\n",	!list_empty_careful(&b->write_blocked));489	prt_printf(out, "will make reachable:\t%lx\n",	b->will_make_reachable);490 491	prt_printf(out, "journal pin %px:\t%llu\n",492		   &b->writes[0].journal, b->writes[0].journal.seq);493	prt_printf(out, "journal pin %px:\t%llu\n",494		   &b->writes[1].journal, b->writes[1].journal.seq);495 496	printbuf_indent_sub(out, 2);497}498 499static ssize_t bch2_cached_btree_nodes_read(struct file *file, char __user *buf,500					    size_t size, loff_t *ppos)501{502	struct dump_iter *i = file->private_data;503	struct bch_fs *c = i->c;504	bool done = false;505	ssize_t ret = 0;506 507	i->ubuf = buf;508	i->size	= size;509	i->ret	= 0;510 511	do {512		struct bucket_table *tbl;513		struct rhash_head *pos;514		struct btree *b;515 516		ret = flush_buf(i);517		if (ret)518			return ret;519 520		rcu_read_lock();521		i->buf.atomic++;522		tbl = rht_dereference_rcu(c->btree_cache.table.tbl,523					  &c->btree_cache.table);524		if (i->iter < tbl->size) {525			rht_for_each_entry_rcu(b, pos, tbl, i->iter, hash)526				bch2_cached_btree_node_to_text(&i->buf, c, b);527			i->iter++;528		} else {529			done = true;530		}531		--i->buf.atomic;532		rcu_read_unlock();533	} while (!done);534 535	if (i->buf.allocation_failure)536		ret = -ENOMEM;537 538	if (!ret)539		ret = flush_buf(i);540 541	return ret ?: i->ret;542}543 544static const struct file_operations cached_btree_nodes_ops = {545	.owner		= THIS_MODULE,546	.open		= bch2_dump_open,547	.release	= bch2_dump_release,548	.read		= bch2_cached_btree_nodes_read,549};550 551typedef int (*list_cmp_fn)(const struct list_head *l, const struct list_head *r);552 553static void list_sort(struct list_head *head, list_cmp_fn cmp)554{555	struct list_head *pos;556 557	list_for_each(pos, head)558		while (!list_is_last(pos, head) &&559		       cmp(pos, pos->next) > 0) {560			struct list_head *pos2, *next = pos->next;561 562			list_del(next);563			list_for_each(pos2, head)564				if (cmp(next, pos2) < 0)565					goto pos_found;566			BUG();567pos_found:568			list_add_tail(next, pos2);569		}570}571 572static int list_ptr_order_cmp(const struct list_head *l, const struct list_head *r)573{574	return cmp_int(l, r);575}576 577static ssize_t bch2_btree_transactions_read(struct file *file, char __user *buf,578					    size_t size, loff_t *ppos)579{580	struct dump_iter *i = file->private_data;581	struct bch_fs *c = i->c;582	struct btree_trans *trans;583	ssize_t ret = 0;584 585	i->ubuf = buf;586	i->size	= size;587	i->ret	= 0;588restart:589	seqmutex_lock(&c->btree_trans_lock);590	list_sort(&c->btree_trans_list, list_ptr_order_cmp);591 592	list_for_each_entry(trans, &c->btree_trans_list, list) {593		if ((ulong) trans <= i->iter)594			continue;595 596		i->iter = (ulong) trans;597 598		if (!closure_get_not_zero(&trans->ref))599			continue;600 601		u32 seq = seqmutex_unlock(&c->btree_trans_lock);602 603		bch2_btree_trans_to_text(&i->buf, trans);604 605		prt_printf(&i->buf, "backtrace:\n");606		printbuf_indent_add(&i->buf, 2);607		bch2_prt_task_backtrace(&i->buf, trans->locking_wait.task, 0, GFP_KERNEL);608		printbuf_indent_sub(&i->buf, 2);609		prt_newline(&i->buf);610 611		closure_put(&trans->ref);612 613		ret = flush_buf(i);614		if (ret)615			goto unlocked;616 617		if (!seqmutex_relock(&c->btree_trans_lock, seq))618			goto restart;619	}620	seqmutex_unlock(&c->btree_trans_lock);621unlocked:622	if (i->buf.allocation_failure)623		ret = -ENOMEM;624 625	if (!ret)626		ret = flush_buf(i);627 628	return ret ?: i->ret;629}630 631static const struct file_operations btree_transactions_ops = {632	.owner		= THIS_MODULE,633	.open		= bch2_dump_open,634	.release	= bch2_dump_release,635	.read		= bch2_btree_transactions_read,636};637 638static ssize_t bch2_journal_pins_read(struct file *file, char __user *buf,639				      size_t size, loff_t *ppos)640{641	struct dump_iter *i = file->private_data;642	struct bch_fs *c = i->c;643	bool done = false;644	int err;645 646	i->ubuf = buf;647	i->size	= size;648	i->ret	= 0;649 650	while (1) {651		err = flush_buf(i);652		if (err)653			return err;654 655		if (!i->size)656			break;657 658		if (done)659			break;660 661		done = bch2_journal_seq_pins_to_text(&i->buf, &c->journal, &i->iter);662		i->iter++;663	}664 665	if (i->buf.allocation_failure)666		return -ENOMEM;667 668	return i->ret;669}670 671static const struct file_operations journal_pins_ops = {672	.owner		= THIS_MODULE,673	.open		= bch2_dump_open,674	.release	= bch2_dump_release,675	.read		= bch2_journal_pins_read,676};677 678static ssize_t bch2_btree_updates_read(struct file *file, char __user *buf,679				       size_t size, loff_t *ppos)680{681	struct dump_iter *i = file->private_data;682	struct bch_fs *c = i->c;683	int err;684 685	i->ubuf = buf;686	i->size	= size;687	i->ret	= 0;688 689	if (!i->iter) {690		bch2_btree_updates_to_text(&i->buf, c);691		i->iter++;692	}693 694	err = flush_buf(i);695	if (err)696		return err;697 698	if (i->buf.allocation_failure)699		return -ENOMEM;700 701	return i->ret;702}703 704static const struct file_operations btree_updates_ops = {705	.owner		= THIS_MODULE,706	.open		= bch2_dump_open,707	.release	= bch2_dump_release,708	.read		= bch2_btree_updates_read,709};710 711static int btree_transaction_stats_open(struct inode *inode, struct file *file)712{713	struct bch_fs *c = inode->i_private;714	struct dump_iter *i;715 716	i = kzalloc(sizeof(struct dump_iter), GFP_KERNEL);717	if (!i)718		return -ENOMEM;719 720	i->iter = 1;721	i->c    = c;722	i->buf  = PRINTBUF;723	file->private_data = i;724 725	return 0;726}727 728static int btree_transaction_stats_release(struct inode *inode, struct file *file)729{730	struct dump_iter *i = file->private_data;731 732	printbuf_exit(&i->buf);733	kfree(i);734 735	return 0;736}737 738static ssize_t btree_transaction_stats_read(struct file *file, char __user *buf,739					    size_t size, loff_t *ppos)740{741	struct dump_iter        *i = file->private_data;742	struct bch_fs *c = i->c;743	int err;744 745	i->ubuf = buf;746	i->size = size;747	i->ret  = 0;748 749	while (1) {750		struct btree_transaction_stats *s = &c->btree_transaction_stats[i->iter];751 752		err = flush_buf(i);753		if (err)754			return err;755 756		if (!i->size)757			break;758 759		if (i->iter == ARRAY_SIZE(bch2_btree_transaction_fns) ||760		    !bch2_btree_transaction_fns[i->iter])761			break;762 763		prt_printf(&i->buf, "%s:\n", bch2_btree_transaction_fns[i->iter]);764		printbuf_indent_add(&i->buf, 2);765 766		mutex_lock(&s->lock);767 768		prt_printf(&i->buf, "Max mem used: %u\n", s->max_mem);769		prt_printf(&i->buf, "Transaction duration:\n");770 771		printbuf_indent_add(&i->buf, 2);772		bch2_time_stats_to_text(&i->buf, &s->duration);773		printbuf_indent_sub(&i->buf, 2);774 775		if (IS_ENABLED(CONFIG_BCACHEFS_LOCK_TIME_STATS)) {776			prt_printf(&i->buf, "Lock hold times:\n");777 778			printbuf_indent_add(&i->buf, 2);779			bch2_time_stats_to_text(&i->buf, &s->lock_hold_times);780			printbuf_indent_sub(&i->buf, 2);781		}782 783		if (s->max_paths_text) {784			prt_printf(&i->buf, "Maximum allocated btree paths (%u):\n", s->nr_max_paths);785 786			printbuf_indent_add(&i->buf, 2);787			prt_str_indented(&i->buf, s->max_paths_text);788			printbuf_indent_sub(&i->buf, 2);789		}790 791		mutex_unlock(&s->lock);792 793		printbuf_indent_sub(&i->buf, 2);794		prt_newline(&i->buf);795		i->iter++;796	}797 798	if (i->buf.allocation_failure)799		return -ENOMEM;800 801	return i->ret;802}803 804static const struct file_operations btree_transaction_stats_op = {805	.owner		= THIS_MODULE,806	.open		= btree_transaction_stats_open,807	.release	= btree_transaction_stats_release,808	.read		= btree_transaction_stats_read,809};810 811/* walk btree transactions until we find a deadlock and print it */812static void btree_deadlock_to_text(struct printbuf *out, struct bch_fs *c)813{814	struct btree_trans *trans;815	ulong iter = 0;816restart:817	seqmutex_lock(&c->btree_trans_lock);818	list_sort(&c->btree_trans_list, list_ptr_order_cmp);819 820	list_for_each_entry(trans, &c->btree_trans_list, list) {821		if ((ulong) trans <= iter)822			continue;823 824		iter = (ulong) trans;825 826		if (!closure_get_not_zero(&trans->ref))827			continue;828 829		u32 seq = seqmutex_unlock(&c->btree_trans_lock);830 831		bool found = bch2_check_for_deadlock(trans, out) != 0;832 833		closure_put(&trans->ref);834 835		if (found)836			return;837 838		if (!seqmutex_relock(&c->btree_trans_lock, seq))839			goto restart;840	}841	seqmutex_unlock(&c->btree_trans_lock);842}843 844static ssize_t bch2_btree_deadlock_read(struct file *file, char __user *buf,845					    size_t size, loff_t *ppos)846{847	struct dump_iter *i = file->private_data;848	struct bch_fs *c = i->c;849	ssize_t ret = 0;850 851	i->ubuf = buf;852	i->size	= size;853	i->ret	= 0;854 855	if (!i->iter) {856		btree_deadlock_to_text(&i->buf, c);857		i->iter++;858	}859 860	if (i->buf.allocation_failure)861		ret = -ENOMEM;862 863	if (!ret)864		ret = flush_buf(i);865 866	return ret ?: i->ret;867}868 869static const struct file_operations btree_deadlock_ops = {870	.owner		= THIS_MODULE,871	.open		= bch2_dump_open,872	.release	= bch2_dump_release,873	.read		= bch2_btree_deadlock_read,874};875 876void bch2_fs_debug_exit(struct bch_fs *c)877{878	if (!IS_ERR_OR_NULL(c->fs_debug_dir))879		debugfs_remove_recursive(c->fs_debug_dir);880}881 882static void bch2_fs_debug_btree_init(struct bch_fs *c, struct btree_debug *bd)883{884	struct dentry *d;885 886	d = debugfs_create_dir(bch2_btree_id_str(bd->id), c->btree_debug_dir);887 888	debugfs_create_file("keys", 0400, d, bd, &btree_debug_ops);889 890	debugfs_create_file("formats", 0400, d, bd, &btree_format_debug_ops);891 892	debugfs_create_file("bfloat-failed", 0400, d, bd,893			    &bfloat_failed_debug_ops);894}895 896void bch2_fs_debug_init(struct bch_fs *c)897{898	struct btree_debug *bd;899	char name[100];900 901	if (IS_ERR_OR_NULL(bch_debug))902		return;903 904	snprintf(name, sizeof(name), "%pU", c->sb.user_uuid.b);905	c->fs_debug_dir = debugfs_create_dir(name, bch_debug);906	if (IS_ERR_OR_NULL(c->fs_debug_dir))907		return;908 909	debugfs_create_file("cached_btree_nodes", 0400, c->fs_debug_dir,910			    c->btree_debug, &cached_btree_nodes_ops);911 912	debugfs_create_file("btree_transactions", 0400, c->fs_debug_dir,913			    c->btree_debug, &btree_transactions_ops);914 915	debugfs_create_file("journal_pins", 0400, c->fs_debug_dir,916			    c->btree_debug, &journal_pins_ops);917 918	debugfs_create_file("btree_updates", 0400, c->fs_debug_dir,919			    c->btree_debug, &btree_updates_ops);920 921	debugfs_create_file("btree_transaction_stats", 0400, c->fs_debug_dir,922			    c, &btree_transaction_stats_op);923 924	debugfs_create_file("btree_deadlock", 0400, c->fs_debug_dir,925			    c->btree_debug, &btree_deadlock_ops);926 927	c->btree_debug_dir = debugfs_create_dir("btrees", c->fs_debug_dir);928	if (IS_ERR_OR_NULL(c->btree_debug_dir))929		return;930 931	for (bd = c->btree_debug;932	     bd < c->btree_debug + ARRAY_SIZE(c->btree_debug);933	     bd++) {934		bd->id = bd - c->btree_debug;935		bch2_fs_debug_btree_init(c, bd);936	}937}938 939#endif940 941void bch2_debug_exit(void)942{943	if (!IS_ERR_OR_NULL(bch_debug))944		debugfs_remove_recursive(bch_debug);945}946 947int __init bch2_debug_init(void)948{949	bch_debug = debugfs_create_dir("bcachefs", NULL);950	return 0;951}952