bcachefs: Print cycle on unrecoverable deadlock
authorKent Overstreet <kent.overstreet@linux.dev>
Sun, 9 Oct 2022 08:29:04 +0000 (04:29 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:42 +0000 (17:09 -0400)
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>
fs/bcachefs/btree_locking.c
fs/bcachefs/debug.c
fs/bcachefs/util.c
fs/bcachefs/util.h

index ad6e364980f3637e1e68450640c22e34b537c3a0..3973e8d7e6da23d09d13289f6cf3e78cc3f2dc79 100644 (file)
@@ -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)
index c7d5583813884de146155fe92da8b588a5004e85..7abc707d2f386ec5ececfa804406275424b19057 100644 (file)
@@ -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);
 
index 477c260de50b375953bb13041b31e19e85729da5..bf529bb137ed71f53f63477f77010d3d0e9a5741 100644 (file)
@@ -265,6 +265,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
index a16f8bb9d4152de988e3b6c1a790f68a86bca9a0..3b0090faef4d70cbf2b9daf4ddf32e332d10e29e 100644 (file)
@@ -383,6 +383,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)