diff options
author | Chris Mason <chris.mason@oracle.com> | 2009-03-25 09:55:11 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-03-25 09:55:11 -0400 |
commit | 1a81af4d1d9c60d4313309f937a1fc5567205a87 (patch) | |
tree | 535b65b3948d34f0948613afc6ebdfe693683f33 | |
parent | af4176b49c5ee15a9c9b10720c92456b28e7aac7 (diff) | |
download | linux-3.10-1a81af4d1d9c60d4313309f937a1fc5567205a87.tar.gz linux-3.10-1a81af4d1d9c60d4313309f937a1fc5567205a87.tar.bz2 linux-3.10-1a81af4d1d9c60d4313309f937a1fc5567205a87.zip |
Btrfs: make sure btrfs_update_delayed_ref doesn't increase ref_mod
btrfs_update_delayed_ref is optimized to add and remove different
references in one pass through the delayed ref tree. It is a zero
sum on the total number of refs on a given extent.
But, the code was recording an extra ref in the head node. This
never made it down to the disk but was used when deciding if it was
safe to free the extent while dropping snapshots.
The fix used here is to make sure the ref_mod count is unchanged
on the head ref when btrfs_update_delayed_ref is called.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/delayed-ref.c | 10 | ||||
-rw-r--r-- | fs/btrfs/delayed-ref.h | 1 |
2 files changed, 8 insertions, 3 deletions
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c index 759fa247ced..cbf7dc8ae3e 100644 --- a/fs/btrfs/delayed-ref.c +++ b/fs/btrfs/delayed-ref.c @@ -450,8 +450,12 @@ static noinline int __btrfs_add_delayed_ref(struct btrfs_trans_handle *trans, * the head node stores the sum of all the mods, so dropping a ref * should drop the sum in the head node by one. */ - if (parent == (u64)-1 && action == BTRFS_DROP_DELAYED_REF) - count_mod = -1; + if (parent == (u64)-1) { + if (action == BTRFS_DROP_DELAYED_REF) + count_mod = -1; + else if (action == BTRFS_UPDATE_DELAYED_HEAD) + count_mod = 0; + } /* * BTRFS_ADD_DELAYED_EXTENT means that we need to update @@ -647,7 +651,7 @@ int btrfs_update_delayed_ref(struct btrfs_trans_handle *trans, */ ret = __btrfs_add_delayed_ref(trans, &head_ref->node, bytenr, num_bytes, (u64)-1, 0, 0, 0, - BTRFS_ADD_DELAYED_REF, 0); + BTRFS_UPDATE_DELAYED_HEAD, 0); BUG_ON(ret); ret = __btrfs_add_delayed_ref(trans, &ref->node, bytenr, num_bytes, diff --git a/fs/btrfs/delayed-ref.h b/fs/btrfs/delayed-ref.h index 57153fcc347..3bec2ff0b15 100644 --- a/fs/btrfs/delayed-ref.h +++ b/fs/btrfs/delayed-ref.h @@ -22,6 +22,7 @@ #define BTRFS_ADD_DELAYED_REF 1 /* add one backref to the tree */ #define BTRFS_DROP_DELAYED_REF 2 /* delete one backref from the tree */ #define BTRFS_ADD_DELAYED_EXTENT 3 /* record a full extent allocation */ +#define BTRFS_UPDATE_DELAYED_HEAD 4 /* not changing ref count on head ref */ struct btrfs_delayed_ref_node { struct rb_node rb_node; |