diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-07-18 02:35:38 +0300 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-23 00:09:36 +0300 |
commit | e941ae7d3afc68127adef917a2b779dabe83fdfe (patch) | |
tree | 577edab610a98f574dbfc9cc9bf2622959affe95 /fs/bcachefs/btree_iter.h | |
parent | 445d184af25abd70575539f7d7b2c8e25b8c49c8 (diff) | |
download | linux-e941ae7d3afc68127adef917a2b779dabe83fdfe.tar.xz |
bcachefs: Add a counter for btree_trans restarts
This will help us improve nested transactions - we need to add
assertions that whenever an inner transaction handles a restart, it
still returns -EINTR to the outer transaction.
This also adds nested_lockrestart_do() and nested_commit_do() which use
the new counters to correctly return -EINTR when the transaction was
restarted.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'fs/bcachefs/btree_iter.h')
-rw-r--r-- | fs/bcachefs/btree_iter.h | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/fs/bcachefs/btree_iter.h b/fs/bcachefs/btree_iter.h index 209b89dd1d2b..c2f5afc9eeb9 100644 --- a/fs/bcachefs/btree_iter.h +++ b/fs/bcachefs/btree_iter.h @@ -203,10 +203,18 @@ void bch2_path_put(struct btree_trans *, struct btree_path *, bool); bool bch2_trans_relock(struct btree_trans *); void bch2_trans_unlock(struct btree_trans *); +static inline int trans_was_restarted(struct btree_trans *trans, u32 restart_count) +{ + return restart_count != trans->restart_count ? -EINTR : 0; +} + +void bch2_trans_verify_not_restarted(struct btree_trans *, u32); + __always_inline static inline int btree_trans_restart(struct btree_trans *trans) { trans->restarted = true; + trans->restart_count++; bch2_trans_unlock(trans); return -EINTR; } @@ -321,7 +329,7 @@ static inline void set_btree_iter_dontneed(struct btree_iter *iter) } void *bch2_trans_kmalloc(struct btree_trans *, size_t); -void bch2_trans_begin(struct btree_trans *); +u32 bch2_trans_begin(struct btree_trans *); static inline struct btree * __btree_iter_peek_node_and_restart(struct btree_trans *trans, struct btree_iter *iter) @@ -394,6 +402,42 @@ __bch2_btree_iter_peek_and_restart(struct btree_trans *trans, return k; } +#define lockrestart_do(_trans, _do) \ +({ \ + int _ret; \ + \ + do { \ + bch2_trans_begin(_trans); \ + _ret = (_do); \ + } while (_ret == -EINTR); \ + \ + _ret; \ +}) + +/* + * nested_lockrestart_do(), nested_commit_do(): + * + * These are like lockrestart_do() and commit_do(), with two differences: + * + * - We don't call bch2_trans_begin() unless we had a transaction restart + * - We return -EINTR if we succeeded after a transaction restart + */ +#define nested_lockrestart_do(_trans, _do) \ +({ \ + u32 _restart_count, _orig_restart_count; \ + int _ret; \ + \ + _restart_count = _orig_restart_count = (_trans)->restart_count; \ + \ + while ((_ret = (_do)) == -EINTR) \ + _restart_count = bch2_trans_begin(_trans); \ + \ + if (!_ret) \ + bch2_trans_verify_not_restarted(_trans, _restart_count);\ + \ + _ret ?: trans_was_restarted(_trans, _orig_restart_count); \ +}) + #define for_each_btree_key2(_trans, _iter, _btree_id, \ _start, _flags, _k, _do) \ ({ \ |