Skip to content

Commit 953fa5c

Browse files
Christoph Hellwigkdave
authored andcommitted
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: Boris Burkov <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent 332581b commit 953fa5c

File tree

1 file changed

+12
-10
lines changed

1 file changed

+12
-10
lines changed

fs/btrfs/inode.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2029,11 +2029,8 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
20292029
leaf = path->nodes[0];
20302030
if (path->slots[0] >= btrfs_header_nritems(leaf)) {
20312031
ret = btrfs_next_leaf(root, path);
2032-
if (ret < 0) {
2033-
if (cow_start != (u64)-1)
2034-
cur_offset = cow_start;
2032+
if (ret < 0)
20352033
goto error;
2036-
}
20372034
if (ret > 0)
20382035
break;
20392036
leaf = path->nodes[0];
@@ -2096,13 +2093,10 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
20962093

20972094
nocow_args.start = cur_offset;
20982095
ret = can_nocow_file_extent(path, &found_key, inode, &nocow_args);
2099-
if (ret < 0) {
2100-
if (cow_start != (u64)-1)
2101-
cur_offset = cow_start;
2096+
if (ret < 0)
21022097
goto error;
2103-
} else if (ret == 0) {
2098+
if (ret == 0)
21042099
goto out_check;
2105-
}
21062100

21072101
ret = 0;
21082102
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,
21332127
if (cow_start != (u64)-1) {
21342128
ret = fallback_to_cow(inode, locked_page,
21352129
cow_start, found_key.offset - 1);
2130+
cow_start = (u64)-1;
21362131
if (ret)
21372132
goto error;
2138-
cow_start = (u64)-1;
21392133
}
21402134

21412135
nocow_end = cur_offset + nocow_args.num_bytes - 1;
@@ -2214,6 +2208,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
22142208
if (cow_start != (u64)-1) {
22152209
cur_offset = end;
22162210
ret = fallback_to_cow(inode, locked_page, cow_start, end);
2211+
cow_start = (u64)-1;
22172212
if (ret)
22182213
goto error;
22192214
}
@@ -2222,6 +2217,13 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
22222217
if (nocow)
22232218
btrfs_dec_nocow_writers(bg);
22242219

2220+
/*
2221+
* If an error happened while a COW region is outstanding, cur_offset
2222+
* needs to be reset to cow_start to ensure the COW region is unlocked
2223+
* as well.
2224+
*/
2225+
if (cow_start != (u64)-1)
2226+
cur_offset = cow_start;
22252227
if (ret && cur_offset < end)
22262228
extent_clear_unlock_delalloc(inode, cur_offset, end,
22272229
locked_page, EXTENT_LOCKED |

0 commit comments

Comments
 (0)