Btrfs: resolve tree mod log locking issue in btrfs_next_leaf
With the tree mod log, we may end up with two roots (the current root and a rewinded version of it) both pointing to two leaves, l1 and l2, of which l2 had already been cow-ed in the current transaction. If we don't rewind any tree blocks, we cannot have two roots both pointing to an already cowed tree block. Now there is btrfs_next_leaf, which has a leaf locked and wants a lock on the next (right) leaf. And there is push_leaf_left, which has a (cowed!) leaf locked and wants a lock on the previous (left) leaf. In order to solve this dead lock situation, we use try_lock in btrfs_next_leaf (only in case it's called with a tree mod log time_seq paramter) and if we fail to get a lock on the next leaf, we give up our lock on the current leaf and retry from the very beginning. Signed-off-by: Jan Schmidt <list.btrfs@jan-o-sch.net>
This commit is contained in:
parent
19956c7e94
commit
d42244a0d3
|
@ -5119,6 +5119,18 @@ again:
|
|||
|
||||
if (!path->skip_locking) {
|
||||
ret = btrfs_try_tree_read_lock(next);
|
||||
if (!ret && time_seq) {
|
||||
/*
|
||||
* If we don't get the lock, we may be racing
|
||||
* with push_leaf_left, holding that lock while
|
||||
* itself waiting for the leaf we've currently
|
||||
* locked. To solve this situation, we give up
|
||||
* on our lock and cycle.
|
||||
*/
|
||||
btrfs_release_path(path);
|
||||
cond_resched();
|
||||
goto again;
|
||||
}
|
||||
if (!ret) {
|
||||
btrfs_set_path_blocking(path);
|
||||
btrfs_tree_read_lock(next);
|
||||
|
|
Loading…
Reference in New Issue