diff options
author | Jan Schmidt <list.btrfs@jan-o-sch.net> | 2012-06-22 08:51:15 -0400 |
---|---|---|
committer | Jan Schmidt <list.btrfs@jan-o-sch.net> | 2012-06-27 10:34:40 -0400 |
commit | d42244a0d36ad0939c5f173ebf15841a0678899c (patch) | |
tree | 3bd49c2f50a0786230f882756c8ee683c73ed9e0 /fs | |
parent | 19956c7e94a7a58d6df8c4db5ae62f9109a7c663 (diff) |
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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.c | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index b98f8604f4f6..8206b3900587 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -5119,6 +5119,18 @@ again: | |||
5119 | 5119 | ||
5120 | if (!path->skip_locking) { | 5120 | if (!path->skip_locking) { |
5121 | ret = btrfs_try_tree_read_lock(next); | 5121 | ret = btrfs_try_tree_read_lock(next); |
5122 | if (!ret && time_seq) { | ||
5123 | /* | ||
5124 | * If we don't get the lock, we may be racing | ||
5125 | * with push_leaf_left, holding that lock while | ||
5126 | * itself waiting for the leaf we've currently | ||
5127 | * locked. To solve this situation, we give up | ||
5128 | * on our lock and cycle. | ||
5129 | */ | ||
5130 | btrfs_release_path(path); | ||
5131 | cond_resched(); | ||
5132 | goto again; | ||
5133 | } | ||
5122 | if (!ret) { | 5134 | if (!ret) { |
5123 | btrfs_set_path_blocking(path); | 5135 | btrfs_set_path_blocking(path); |
5124 | btrfs_tree_read_lock(next); | 5136 | btrfs_tree_read_lock(next); |