aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorFilipe David Borba Manana <fdmanana@gmail.com>2014-01-27 20:38:06 -0500
committerChris Mason <clm@fb.com>2014-01-29 10:06:25 -0500
commitbf54f412f0624786ac8a115110b5203430a9eebb (patch)
tree601f2590ec4d426938e015ebd476c24a1d522eb6 /fs
parentbca1a290033d20981e11f81ae4207e4d0fa5b1e6 (diff)
Btrfs: fix send file hole detection leading to data corruption
There was a case where file hole detection was incorrect and it would cause an incremental send to override a section of a file with zeroes. This happened in the case where between the last leaf we processed which contained a file extent item for our current inode and the leaf we're currently are at (and has a file extent item for our current inode) there are only leafs containing exclusively file extent items for our current inode, and none of them was updated since the previous send operation. The file hole detection code would incorrectly consider the file range covered by these leafs as a hole. A test case for xfstests follows soon. Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com> Signed-off-by: Josef Bacik <jbacik@fb.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/send.c15
1 files changed, 15 insertions, 0 deletions
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 4d31f72bdf41..85259cba784a 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -4489,6 +4489,21 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
4489 extent_end = key->offset + 4489 extent_end = key->offset +
4490 btrfs_file_extent_num_bytes(path->nodes[0], fi); 4490 btrfs_file_extent_num_bytes(path->nodes[0], fi);
4491 } 4491 }
4492
4493 if (path->slots[0] == 0 &&
4494 sctx->cur_inode_last_extent < key->offset) {
4495 /*
4496 * We might have skipped entire leafs that contained only
4497 * file extent items for our current inode. These leafs have
4498 * a generation number smaller (older) than the one in the
4499 * current leaf and the leaf our last extent came from, and
4500 * are located between these 2 leafs.
4501 */
4502 ret = get_last_extent(sctx, key->offset - 1);
4503 if (ret)
4504 return ret;
4505 }
4506
4492 if (sctx->cur_inode_last_extent < key->offset) 4507 if (sctx->cur_inode_last_extent < key->offset)
4493 ret = send_hole(sctx, key->offset); 4508 ret = send_hole(sctx, key->offset);
4494 sctx->cur_inode_last_extent = extent_end; 4509 sctx->cur_inode_last_extent = extent_end;