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 | |
| 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>
| -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, |
