From 18e92841e87bc548fcb91530115a66e72eecb10c Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Sat, 22 Jun 2024 20:59:09 -0400 Subject: [PATCH] bcachefs: Make btree_deadlock_to_text() clearer btree_deadlock_to_text() searches the list of btree transactions to find a deadlock - when it finds one it's done; it's not like other *_read() functions that's printing each object. Factor out btree_deadlock_to_text() to make this clearer. Signed-off-by: Kent Overstreet --- fs/bcachefs/debug.c | 66 ++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/fs/bcachefs/debug.c b/fs/bcachefs/debug.c index 8ec2d44e4956..ecfdb21ebade 100644 --- a/fs/bcachefs/debug.c +++ b/fs/bcachefs/debug.c @@ -802,48 +802,54 @@ static const struct file_operations btree_transaction_stats_op = { .read = btree_transaction_stats_read, }; +/* walk btree transactions until we find a deadlock and print it */ +static void btree_deadlock_to_text(struct printbuf *out, struct bch_fs *c) +{ + struct btree_trans *trans; + pid_t iter = 0; +restart: + seqmutex_lock(&c->btree_trans_lock); + list_for_each_entry(trans, &c->btree_trans_list, list) { + struct task_struct *task = READ_ONCE(trans->locking_wait.task); + + if (!task || task->pid <= iter) + continue; + + iter = task->pid; + + closure_get(&trans->ref); + + u32 seq = seqmutex_unlock(&c->btree_trans_lock); + + bool found = bch2_check_for_deadlock(trans, out) != 0; + + closure_put(&trans->ref); + + if (found) + return; + + if (!seqmutex_relock(&c->btree_trans_lock, seq)) + goto restart; + } + seqmutex_unlock(&c->btree_trans_lock); +} + static ssize_t bch2_btree_deadlock_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { struct dump_iter *i = file->private_data; struct bch_fs *c = i->c; - struct btree_trans *trans; ssize_t ret = 0; i->ubuf = buf; i->size = size; i->ret = 0; - if (i->iter) - goto out; -restart: - seqmutex_lock(&c->btree_trans_lock); - list_for_each_entry(trans, &c->btree_trans_list, list) { - struct task_struct *task = READ_ONCE(trans->locking_wait.task); - - if (!task || task->pid <= i->iter) - continue; - - closure_get(&trans->ref); - u32 seq = seqmutex_unlock(&c->btree_trans_lock); - - ret = flush_buf(i); - if (ret) { - closure_put(&trans->ref); - goto out; - } - - bch2_check_for_deadlock(trans, &i->buf); - - i->iter = task->pid; - - closure_put(&trans->ref); - - if (!seqmutex_relock(&c->btree_trans_lock, seq)) - goto restart; + if (!i->iter) { + btree_deadlock_to_text(&i->buf, c); + i->iter++; } - seqmutex_unlock(&c->btree_trans_lock); -out: + if (i->buf.allocation_failure) ret = -ENOMEM;