diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-05-28 01:55:54 +0200 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-22 23:10:02 +0200 |
commit | f154c3eb429a340d66a06e8f8d2221d28d25ab45 (patch) | |
tree | 5a6e74c7c6518c6415797097f8344524c39e9b2a /fs/bcachefs/btree_iter.h | |
parent | bcachefs: Fix a quota read bug (diff) | |
download | linux-f154c3eb429a340d66a06e8f8d2221d28d25ab45.tar.xz linux-f154c3eb429a340d66a06e8f8d2221d28d25ab45.zip |
bcachefs: trans_for_each_path_safe()
bch2_btree_trans_to_text() is used on btree_trans objects that are owned
by different threads - when printing out deadlock cycles - so we need a
safe version of trans_for_each_path(), else we race with seeing a
btree_path that was just allocated and not fully initialized:
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs/bcachefs/btree_iter.h')
-rw-r--r-- | fs/bcachefs/btree_iter.h | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/fs/bcachefs/btree_iter.h b/fs/bcachefs/btree_iter.h index 0cfb8af3d0e1..9a4dbf358fe5 100644 --- a/fs/bcachefs/btree_iter.h +++ b/fs/bcachefs/btree_iter.h @@ -89,6 +89,35 @@ __trans_next_path(struct btree_trans *trans, unsigned idx) #define trans_for_each_path(_trans, _path) \ trans_for_each_path_from(_trans, _path, 0) +static inline struct btree_path * +__trans_next_path_safe(struct btree_trans *trans, unsigned *idx) +{ + u64 l; + + if (*idx == BTREE_ITER_MAX) + return NULL; + + l = trans->paths_allocated >> *idx; + if (!l) + return NULL; + + *idx += __ffs64(l); + EBUG_ON(*idx >= BTREE_ITER_MAX); + return &trans->paths[*idx]; +} + +/* + * This version is intended to be safe for use on a btree_trans that is owned by + * another thread, for bch2_btree_trans_to_text(); + */ +#define trans_for_each_path_safe_from(_trans, _path, _idx, _start) \ + for (_idx = _start; \ + (_path = __trans_next_path_safe((_trans), &_idx)); \ + _idx++) + +#define trans_for_each_path_safe(_trans, _path, _idx) \ + trans_for_each_path_safe_from(_trans, _path, _idx, 0) + static inline struct btree_path *next_btree_path(struct btree_trans *trans, struct btree_path *path) { unsigned idx = path ? path->sorted_idx + 1 : 0; |