diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-01-20 21:35:07 +0100 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 23:09:43 +0200 |
commit | 80df5b8cacceb25962621ccf4cf555413bdfbdbb (patch) | |
tree | f50218611c78d65e45ed7c63a22ef03a5eed6f08 /fs/bcachefs/btree_locking.c | |
parent | bcachefs: Fix lock_graph_remove_non_waiters() (diff) | |
download | linux-80df5b8cacceb25962621ccf4cf555413bdfbdbb.tar.xz linux-80df5b8cacceb25962621ccf4cf555413bdfbdbb.zip |
fixup bcachefs: Deadlock cycle detector
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/btree_locking.c')
-rw-r--r-- | fs/bcachefs/btree_locking.c | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/fs/bcachefs/btree_locking.c b/fs/bcachefs/btree_locking.c index 922cfc7f5450..76a532f98c72 100644 --- a/fs/bcachefs/btree_locking.c +++ b/fs/bcachefs/btree_locking.c @@ -99,6 +99,12 @@ static void lock_graph_up(struct lock_graph *g) closure_put(&g->g[--g->nr].trans->ref); } +static noinline void lock_graph_pop_all(struct lock_graph *g) +{ + while (g->nr) + lock_graph_up(g); +} + static void lock_graph_down(struct lock_graph *g, struct btree_trans *trans) { closure_get(&trans->ref); @@ -274,8 +280,26 @@ next: b = &READ_ONCE(path->l[top->level].b)->c; - if (unlikely(IS_ERR_OR_NULL(b))) { - BUG_ON(!lock_graph_remove_non_waiters(&g)); + if (IS_ERR_OR_NULL(b)) { + /* + * If we get here, it means we raced with the + * other thread updating its btree_path + * structures - which means it can't be blocked + * waiting on a lock: + */ + if (!lock_graph_remove_non_waiters(&g)) { + /* + * If lock_graph_remove_non_waiters() + * didn't do anything, it must be + * because we're being called by debugfs + * checking for lock cycles, which + * invokes us on btree_transactions that + * aren't actually waiting on anything. + * Just bail out: + */ + lock_graph_pop_all(&g); + } + goto next; } |