diff options
author | Josef Bacik <jbacik@fb.com> | 2016-11-14 14:06:22 -0500 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2016-11-30 07:45:19 -0500 |
commit | f94480bd7be6bb1b0823d1036f3ee4ebe7450172 (patch) | |
tree | 185626f23c4cf4c5be566f9984d2ede1137904e7 /fs/btrfs/file.c | |
parent | 62fe51c1d0100ff07a761cd077872e01f2a2b8ca (diff) |
Btrfs: abort transaction if fill_holes() fails
At this point we will have dropped extent entries from the file, so if we fail
to insert the new hole entries then we are leaving the fs in a corrupt state
(albeit an easily fixed one). Abort the transaciton if this happens so we can
avoid corrupting the fs. Thanks,
Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs/file.c')
-rw-r--r-- | fs/btrfs/file.c | 19 |
1 files changed, 17 insertions, 2 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index f5288fa0aad0..3c1f4be36f16 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -2232,9 +2232,15 @@ static int fill_holes(struct btrfs_trans_handle *trans, struct inode *inode, | |||
2232 | key.offset = offset; | 2232 | key.offset = offset; |
2233 | 2233 | ||
2234 | ret = btrfs_search_slot(trans, root, &key, path, 0, 1); | 2234 | ret = btrfs_search_slot(trans, root, &key, path, 0, 1); |
2235 | if (ret < 0) | 2235 | if (ret <= 0) { |
2236 | /* | ||
2237 | * We should have dropped this offset, so if we find it then | ||
2238 | * something has gone horribly wrong. | ||
2239 | */ | ||
2240 | if (ret == 0) | ||
2241 | ret = -EINVAL; | ||
2236 | return ret; | 2242 | return ret; |
2237 | BUG_ON(!ret); | 2243 | } |
2238 | 2244 | ||
2239 | leaf = path->nodes[0]; | 2245 | leaf = path->nodes[0]; |
2240 | if (hole_mergeable(inode, leaf, path->slots[0]-1, offset, end)) { | 2246 | if (hole_mergeable(inode, leaf, path->slots[0]-1, offset, end)) { |
@@ -2537,6 +2543,13 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) | |||
2537 | ret = fill_holes(trans, inode, path, cur_offset, | 2543 | ret = fill_holes(trans, inode, path, cur_offset, |
2538 | drop_end); | 2544 | drop_end); |
2539 | if (ret) { | 2545 | if (ret) { |
2546 | /* | ||
2547 | * If we failed then we didn't insert our hole | ||
2548 | * entries for the area we dropped, so now the | ||
2549 | * fs is corrupted, so we must abort the | ||
2550 | * transaction. | ||
2551 | */ | ||
2552 | btrfs_abort_transaction(trans, ret); | ||
2540 | err = ret; | 2553 | err = ret; |
2541 | break; | 2554 | break; |
2542 | } | 2555 | } |
@@ -2601,6 +2614,8 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) | |||
2601 | if (cur_offset < ino_size && cur_offset < drop_end) { | 2614 | if (cur_offset < ino_size && cur_offset < drop_end) { |
2602 | ret = fill_holes(trans, inode, path, cur_offset, drop_end); | 2615 | ret = fill_holes(trans, inode, path, cur_offset, drop_end); |
2603 | if (ret) { | 2616 | if (ret) { |
2617 | /* Same comment as above. */ | ||
2618 | btrfs_abort_transaction(trans, ret); | ||
2604 | err = ret; | 2619 | err = ret; |
2605 | goto out_trans; | 2620 | goto out_trans; |
2606 | } | 2621 | } |