diff options
author | Qu Wenruo <quwenruo@cn.fujitsu.com> | 2014-08-08 01:06:20 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-08-21 10:55:27 -0400 |
commit | 51f395ad4058883e4273b02fdebe98072dbdc0d2 (patch) | |
tree | 34f6012ce23157db296f2cd668f809b46a4b6d17 /fs | |
parent | 62e2390e1ad78f956e96a6a831761adc6f2bf58a (diff) |
btrfs: Use right extent length when inserting overlap extent map.
When current btrfs finds that a new extent map is going to be insereted
but failed with -EEXIST, it will try again to insert the extent map
but with the length of sectorsize.
This is OK if we don't enable 'no-holes' feature since all extent space
is continuous, we will not go into the not found->insert routine.
But if we enable 'no-holes' feature, it will make things out of control.
e.g. in 4K sectorsize, we pass the following args to btrfs_get_extent():
btrfs_get_extent() args: start: 27874 len 4100
28672 27874 28672 27874+4100 32768
|-----------------------|
|---------hole--------------------|---------data----------|
1) not found and insert
Since no extent map containing the range, btrfs_get_extent() will go
into the not_found and insert routine, which will try to insert the
extent map (27874, 27847 + 4100).
2) first overlap
But it overlaps with (28672, 32768) extent, so -EEXIST will be returned
by add_extent_mapping().
3) retry but still overlap
After catching the -EEXIST, then btrfs_get_extent() will try insert it
again but with 4K length, which still overlaps, so -EEXIST will be
returned.
This makes the following patch fail to punch hole.
d77815461f047e561f77a07754ae923ade597d4e btrfs: Avoid trucating page or punching hole in a already existed hole.
This patch will use the right length, which is the (exsisting->start -
em->start) to insert, making the above patch works in 'no-holes' mode.
Also, some small code style problems in above patch is fixed too.
Reported-by: Filipe David Manana <fdmanana@gmail.com>
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Reviewed-by: Filipe David Manana <fdmanana@suse.com>
Tested-by: Filipe David Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/file.c | 4 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 7 |
2 files changed, 5 insertions, 6 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 77e33534c7d6..f15c13f97018 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -2215,7 +2215,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) | |||
2215 | goto out_only_mutex; | 2215 | goto out_only_mutex; |
2216 | } | 2216 | } |
2217 | 2217 | ||
2218 | lockstart = round_up(offset , BTRFS_I(inode)->root->sectorsize); | 2218 | lockstart = round_up(offset, BTRFS_I(inode)->root->sectorsize); |
2219 | lockend = round_down(offset + len, | 2219 | lockend = round_down(offset + len, |
2220 | BTRFS_I(inode)->root->sectorsize) - 1; | 2220 | BTRFS_I(inode)->root->sectorsize) - 1; |
2221 | same_page = ((offset >> PAGE_CACHE_SHIFT) == | 2221 | same_page = ((offset >> PAGE_CACHE_SHIFT) == |
@@ -2276,7 +2276,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) | |||
2276 | tail_start + tail_len, 0, 1); | 2276 | tail_start + tail_len, 0, 1); |
2277 | if (ret) | 2277 | if (ret) |
2278 | goto out_only_mutex; | 2278 | goto out_only_mutex; |
2279 | } | 2279 | } |
2280 | } | 2280 | } |
2281 | } | 2281 | } |
2282 | 2282 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 2ac260d41ccd..ae98df67950f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -6146,14 +6146,14 @@ out_fail: | |||
6146 | static int merge_extent_mapping(struct extent_map_tree *em_tree, | 6146 | static int merge_extent_mapping(struct extent_map_tree *em_tree, |
6147 | struct extent_map *existing, | 6147 | struct extent_map *existing, |
6148 | struct extent_map *em, | 6148 | struct extent_map *em, |
6149 | u64 map_start, u64 map_len) | 6149 | u64 map_start) |
6150 | { | 6150 | { |
6151 | u64 start_diff; | 6151 | u64 start_diff; |
6152 | 6152 | ||
6153 | BUG_ON(map_start < em->start || map_start >= extent_map_end(em)); | 6153 | BUG_ON(map_start < em->start || map_start >= extent_map_end(em)); |
6154 | start_diff = map_start - em->start; | 6154 | start_diff = map_start - em->start; |
6155 | em->start = map_start; | 6155 | em->start = map_start; |
6156 | em->len = map_len; | 6156 | em->len = existing->start - em->start; |
6157 | if (em->block_start < EXTENT_MAP_LAST_BYTE && | 6157 | if (em->block_start < EXTENT_MAP_LAST_BYTE && |
6158 | !test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { | 6158 | !test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { |
6159 | em->block_start += start_diff; | 6159 | em->block_start += start_diff; |
@@ -6441,8 +6441,7 @@ insert: | |||
6441 | em->len); | 6441 | em->len); |
6442 | if (existing) { | 6442 | if (existing) { |
6443 | err = merge_extent_mapping(em_tree, existing, | 6443 | err = merge_extent_mapping(em_tree, existing, |
6444 | em, start, | 6444 | em, start); |
6445 | root->sectorsize); | ||
6446 | free_extent_map(existing); | 6445 | free_extent_map(existing); |
6447 | if (err) { | 6446 | if (err) { |
6448 | free_extent_map(em); | 6447 | free_extent_map(em); |