diff options
author | Arne Jansen <sensille@gmx.net> | 2012-08-09 02:16:53 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2012-08-28 16:53:35 -0400 |
commit | 22cd2e7de7b0bd68fb668d23e1564707ca689510 (patch) | |
tree | 115a0c4217ed00d1d879925928dd4e7395a599b2 /fs/btrfs/extent-tree.c | |
parent | b12a3b1ea209d9dec02731fba58c3dbe7d31cfd8 (diff) |
Btrfs: fix race in run_clustered_refs
With commit
commit d1270cd91f308c9d22b2804720c36ccd32dbc35e
Author: Arne Jansen <sensille@gmx.net>
Date: Tue Sep 13 15:16:43 2011 +0200
Btrfs: put back delayed refs that are too new
I added a window where the delayed_ref's head->ref_mod code can diverge
from the sum of the remaining refs, because we release the head->mutex
in the middle. This leads to btrfs_lookup_extent_info returning wrong
numbers. This patch fixes this by adjusting the head's ref_mod with each
delayed ref we run.
Signed-off-by: Arne Jansen <sensille@gmx.net>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 1bb408f737fb..f16411d3c252 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -2318,6 +2318,23 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans, | |||
2318 | ref->in_tree = 0; | 2318 | ref->in_tree = 0; |
2319 | rb_erase(&ref->rb_node, &delayed_refs->root); | 2319 | rb_erase(&ref->rb_node, &delayed_refs->root); |
2320 | delayed_refs->num_entries--; | 2320 | delayed_refs->num_entries--; |
2321 | if (locked_ref) { | ||
2322 | /* | ||
2323 | * when we play the delayed ref, also correct the | ||
2324 | * ref_mod on head | ||
2325 | */ | ||
2326 | switch (ref->action) { | ||
2327 | case BTRFS_ADD_DELAYED_REF: | ||
2328 | case BTRFS_ADD_DELAYED_EXTENT: | ||
2329 | locked_ref->node.ref_mod -= ref->ref_mod; | ||
2330 | break; | ||
2331 | case BTRFS_DROP_DELAYED_REF: | ||
2332 | locked_ref->node.ref_mod += ref->ref_mod; | ||
2333 | break; | ||
2334 | default: | ||
2335 | WARN_ON(1); | ||
2336 | } | ||
2337 | } | ||
2321 | spin_unlock(&delayed_refs->lock); | 2338 | spin_unlock(&delayed_refs->lock); |
2322 | 2339 | ||
2323 | ret = run_one_delayed_ref(trans, root, ref, extent_op, | 2340 | ret = run_one_delayed_ref(trans, root, ref, extent_op, |