summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2022-10-09 04:29:04 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-02-03 21:48:41 -0500
commita77b909d94e56cbee3d3053774e36d7c6a803091 (patch)
tree420fea8a4367bffcfbe397d95d5b06852ccfa107
parent60f4e072404863e411b69d15697086052a0b52d2 (diff)
bcachefs: Print cycle on unrecoverable deadlock
Some lock operations can't fail; a cycle of nofail locks is impossible to recover from. So we want to get rid of these nofail locking operations, but as this is tricky it'll be done incrementally. If such a cycle happens, this patch prints out which codepaths are involved so we know what to work on next. Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/btree_locking.c24
-rw-r--r--fs/bcachefs/debug.c22
-rw-r--r--fs/bcachefs/util.c20
-rw-r--r--fs/bcachefs/util.h1
4 files changed, 45 insertions, 22 deletions
diff --git a/fs/bcachefs/btree_locking.c b/fs/bcachefs/btree_locking.c
index f0bbd0317719..fac338edceda 100644
--- a/fs/bcachefs/btree_locking.c
+++ b/fs/bcachefs/btree_locking.c
@@ -138,7 +138,29 @@ static noinline int break_cycle(struct lock_graph *g)
return abort_lock(g, i);
}
- BUG();
+ {
+ struct bch_fs *c = g->g->trans->c;
+ struct printbuf buf = PRINTBUF;
+
+ bch_err(c, "cycle of nofail locks");
+
+ for (i = g->g; i < g->g + g->nr; i++) {
+ struct btree_trans *trans = i->trans;
+
+ bch2_btree_trans_to_text(&buf, trans);
+
+ prt_printf(&buf, "backtrace:");
+ prt_newline(&buf);
+ printbuf_indent_add(&buf, 2);
+ bch2_prt_backtrace(&buf, trans->locking_wait.task);
+ printbuf_indent_sub(&buf, 2);
+ prt_newline(&buf);
+ }
+
+ bch2_print_string_as_lines(KERN_ERR, buf.buf);
+ printbuf_exit(&buf);
+ BUG();
+ }
}
static void lock_graph_pop(struct lock_graph *g)
diff --git a/fs/bcachefs/debug.c b/fs/bcachefs/debug.c
index c7d558381388..7abc707d2f38 100644
--- a/fs/bcachefs/debug.c
+++ b/fs/bcachefs/debug.c
@@ -501,26 +501,6 @@ static const struct file_operations cached_btree_nodes_ops = {
};
#ifdef CONFIG_BCACHEFS_DEBUG_TRANSACTIONS
-static int prt_backtrace(struct printbuf *out, struct task_struct *task)
-{
- unsigned long entries[32];
- unsigned i, nr_entries;
- int ret;
-
- ret = down_read_killable(&task->signal->exec_update_lock);
- if (ret)
- return ret;
-
- nr_entries = stack_trace_save_tsk(task, entries, ARRAY_SIZE(entries), 0);
- for (i = 0; i < nr_entries; i++) {
- prt_printf(out, "[<0>] %pB", (void *)entries[i]);
- prt_newline(out);
- }
-
- up_read(&task->signal->exec_update_lock);
- return 0;
-}
-
static ssize_t bch2_btree_transactions_read(struct file *file, char __user *buf,
size_t size, loff_t *ppos)
{
@@ -547,7 +527,7 @@ static ssize_t bch2_btree_transactions_read(struct file *file, char __user *buf,
prt_printf(&i->buf, "backtrace:");
prt_newline(&i->buf);
printbuf_indent_add(&i->buf, 2);
- prt_backtrace(&i->buf, trans->locking_wait.task);
+ bch2_prt_backtrace(&i->buf, trans->locking_wait.task);
printbuf_indent_sub(&i->buf, 2);
prt_newline(&i->buf);
diff --git a/fs/bcachefs/util.c b/fs/bcachefs/util.c
index 4df504d0bea6..0ecd9d46fbed 100644
--- a/fs/bcachefs/util.c
+++ b/fs/bcachefs/util.c
@@ -511,6 +511,26 @@ void bch2_print_string_as_lines(const char *prefix, const char *lines)
console_unlock();
}
+int bch2_prt_backtrace(struct printbuf *out, struct task_struct *task)
+{
+ unsigned long entries[32];
+ unsigned i, nr_entries;
+ int ret;
+
+ ret = down_read_killable(&task->signal->exec_update_lock);
+ if (ret)
+ return ret;
+
+ nr_entries = stack_trace_save_tsk(task, entries, ARRAY_SIZE(entries), 0);
+ for (i = 0; i < nr_entries; i++) {
+ prt_printf(out, "[<0>] %pB", (void *)entries[i]);
+ prt_newline(out);
+ }
+
+ up_read(&task->signal->exec_update_lock);
+ return 0;
+}
+
/* time stats: */
#ifndef CONFIG_BCACHEFS_NO_LATENCY_ACCT
diff --git a/fs/bcachefs/util.h b/fs/bcachefs/util.h
index af5e24adb14c..b9b53b09f20c 100644
--- a/fs/bcachefs/util.h
+++ b/fs/bcachefs/util.h
@@ -530,6 +530,7 @@ u64 bch2_read_flag_list(char *, const char * const[]);
void bch2_prt_u64_binary(struct printbuf *, u64, unsigned);
void bch2_print_string_as_lines(const char *prefix, const char *lines);
+int bch2_prt_backtrace(struct printbuf *, struct task_struct *);
#define NR_QUANTILES 15
#define QUANTILE_IDX(i) inorder_to_eytzinger0(i, NR_QUANTILES)