Commit 953fa5ce authored by Christoph Hellwig's avatar Christoph Hellwig Committed by David Sterba

btrfs: fix error handling when in a COW window in run_delalloc_nocow

When run_delalloc_nocow has cow_start set to a value other than (u64)-1,
it has delayed COW writeback pending behind cur_offset.  When an error
occurs in such a window, the range going back to cow_start and not just
cur_offset needs to be unlocked, but only two error cases handle this
correctly  Move the code to handle unlock the COW range to the common
error handling label and document the logic.

To make things even more complicated, cow_file_range as called by
fallback_to_cow will unlock the range it is operating on when it fails as
well, so we need to reset cow_start right after caling fallback_to_cow
instead of only when it succeeded.
Reviewed-by: default avatarBoris Burkov <boris@bur.io>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 332581bd
...@@ -2029,11 +2029,8 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, ...@@ -2029,11 +2029,8 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
leaf = path->nodes[0]; leaf = path->nodes[0];
if (path->slots[0] >= btrfs_header_nritems(leaf)) { if (path->slots[0] >= btrfs_header_nritems(leaf)) {
ret = btrfs_next_leaf(root, path); ret = btrfs_next_leaf(root, path);
if (ret < 0) { if (ret < 0)
if (cow_start != (u64)-1)
cur_offset = cow_start;
goto error; goto error;
}
if (ret > 0) if (ret > 0)
break; break;
leaf = path->nodes[0]; leaf = path->nodes[0];
...@@ -2096,13 +2093,10 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, ...@@ -2096,13 +2093,10 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
nocow_args.start = cur_offset; nocow_args.start = cur_offset;
ret = can_nocow_file_extent(path, &found_key, inode, &nocow_args); ret = can_nocow_file_extent(path, &found_key, inode, &nocow_args);
if (ret < 0) { if (ret < 0)
if (cow_start != (u64)-1)
cur_offset = cow_start;
goto error; goto error;
} else if (ret == 0) { if (ret == 0)
goto out_check; goto out_check;
}
ret = 0; ret = 0;
bg = btrfs_inc_nocow_writers(fs_info, nocow_args.disk_bytenr); bg = btrfs_inc_nocow_writers(fs_info, nocow_args.disk_bytenr);
...@@ -2133,9 +2127,9 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, ...@@ -2133,9 +2127,9 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
if (cow_start != (u64)-1) { if (cow_start != (u64)-1) {
ret = fallback_to_cow(inode, locked_page, ret = fallback_to_cow(inode, locked_page,
cow_start, found_key.offset - 1); cow_start, found_key.offset - 1);
cow_start = (u64)-1;
if (ret) if (ret)
goto error; goto error;
cow_start = (u64)-1;
} }
nocow_end = cur_offset + nocow_args.num_bytes - 1; nocow_end = cur_offset + nocow_args.num_bytes - 1;
...@@ -2214,6 +2208,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, ...@@ -2214,6 +2208,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
if (cow_start != (u64)-1) { if (cow_start != (u64)-1) {
cur_offset = end; cur_offset = end;
ret = fallback_to_cow(inode, locked_page, cow_start, end); ret = fallback_to_cow(inode, locked_page, cow_start, end);
cow_start = (u64)-1;
if (ret) if (ret)
goto error; goto error;
} }
...@@ -2222,6 +2217,13 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, ...@@ -2222,6 +2217,13 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
if (nocow) if (nocow)
btrfs_dec_nocow_writers(bg); btrfs_dec_nocow_writers(bg);
/*
* If an error happened while a COW region is outstanding, cur_offset
* needs to be reset to cow_start to ensure the COW region is unlocked
* as well.
*/
if (cow_start != (u64)-1)
cur_offset = cow_start;
if (ret && cur_offset < end) if (ret && cur_offset < end)
extent_clear_unlock_delalloc(inode, cur_offset, end, extent_clear_unlock_delalloc(inode, cur_offset, end,
locked_page, EXTENT_LOCKED | locked_page, EXTENT_LOCKED |
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment