summaryrefslogtreecommitdiffstats
path: root/fs/bcachefs/btree_locking.c
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-12-12 20:08:29 -0500
committerKent Overstreet <kent.overstreet@linux.dev>2024-01-01 11:47:44 -0500
commitfea153a84557c982542527143950dbef434731c2 (patch)
tree7fc53a84018c9d7ed237cfcd9e342da3cbd1d25f /fs/bcachefs/btree_locking.c
parent6474b706108bac9e531a71ddeb8150f8fa17163c (diff)
downloadlinux-stable-fea153a84557c982542527143950dbef434731c2.tar.gz
linux-stable-fea153a84557c982542527143950dbef434731c2.tar.bz2
linux-stable-fea153a84557c982542527143950dbef434731c2.zip
bcachefs: rcu protect trans->paths
Upcoming patches are going to be changing trans->paths to a reallocatable buffer. We need to guard against use after free when it's used by other threads; this introduces RCU protection to those paths and changes them to check for trans->paths == NULL Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/btree_locking.c')
-rw-r--r--fs/bcachefs/btree_locking.c31
1 files changed, 24 insertions, 7 deletions
diff --git a/fs/bcachefs/btree_locking.c b/fs/bcachefs/btree_locking.c
index e4a436bfaeee..d68e1211029d 100644
--- a/fs/bcachefs/btree_locking.c
+++ b/fs/bcachefs/btree_locking.c
@@ -281,9 +281,8 @@ int bch2_check_for_deadlock(struct btree_trans *trans, struct printbuf *cycle)
struct lock_graph g;
struct trans_waiting_for_lock *top;
struct btree_bkey_cached_common *b;
- struct btree_path *path;
- unsigned path_idx;
- int ret;
+ btree_path_idx_t path_idx;
+ int ret = 0;
g.nr = 0;
@@ -296,13 +295,26 @@ int bch2_check_for_deadlock(struct btree_trans *trans, struct printbuf *cycle)
}
lock_graph_down(&g, trans);
+
+ /* trans->paths is rcu protected vs. freeing */
+ rcu_read_lock();
+ if (cycle)
+ cycle->atomic++;
next:
if (!g.nr)
- return 0;
+ goto out;
top = &g.g[g.nr - 1];
- trans_for_each_path_from(top->trans, path, path_idx, top->path_idx) {
+ struct btree_path *paths = rcu_dereference(top->trans->paths);
+ if (!paths)
+ goto up;
+
+ unsigned long *paths_allocated = trans_paths_allocated(paths);
+
+ trans_for_each_path_idx_from(paths_allocated, *trans_paths_nr(paths),
+ path_idx, top->path_idx) {
+ struct btree_path *path = paths + path_idx;
if (!path->nodes_locked)
continue;
@@ -368,18 +380,23 @@ next:
ret = lock_graph_descend(&g, trans, cycle);
if (ret)
- return ret;
+ goto out;
goto next;
}
raw_spin_unlock(&b->lock.wait_lock);
}
}
-
+up:
if (g.nr > 1 && cycle)
print_chain(cycle, &g);
lock_graph_up(&g);
goto next;
+out:
+ if (cycle)
+ --cycle->atomic;
+ rcu_read_unlock();
+ return ret;
}
int bch2_six_check_for_deadlock(struct six_lock *lock, void *p)