112 lines
3.6 KiB
Diff
112 lines
3.6 KiB
Diff
|
From 18d8ff57c3cd9ee31829b19fcd6ca57ed201720a Mon Sep 17 00:00:00 2001
|
||
|
From: Filipe David Borba Manana <fdmanana@gmail.com>
|
||
|
Date: Tue, 3 Sep 2013 12:19:58 +0100
|
||
|
Subject: [PATCH 57/62] Btrfs-progs: fix restore command leaving corrupted
|
||
|
files
|
||
|
|
||
|
When there are files that have parts shared with snapshots, the
|
||
|
restore command was incorrectly restoring them, as it was not
|
||
|
taking into account the offset and number of bytes fields from
|
||
|
the file extent item. Besides leaving the recovered file corrupt,
|
||
|
it was also inneficient as it read and wrote more data than needed
|
||
|
(with each extent copy overwriting portions of the one previously
|
||
|
written).
|
||
|
|
||
|
The following steps show how to reproduce this corruption issue:
|
||
|
|
||
|
$ mkfs.btrfs -f /dev/sdb3
|
||
|
$ mount /dev/sdb3 /mnt/btrfs
|
||
|
$ perl -e '$d = "\x41" . ("\x00" x (1024*1024+349)); open($f,">","/mnt/btrfs/foobar"); print $f $d; close($f);'
|
||
|
$ du -b /mnt/btrfs/foobar
|
||
|
1048926 /mnt/btrfs/foobar
|
||
|
$ md5sum /mnt/btrfs/foobar
|
||
|
f9f778f3a7410c40e4ed104a3a63c3c4 /mnt/btrfs/foobar
|
||
|
|
||
|
$ btrfs subvolume snapshot /mnt/btrfs /mnt/btrfs/my_snap
|
||
|
$ perl -e 'open($f, "+<", "/mnt/btrfs/foobar"); seek($f, 4096, 0); print $f "\xff"; close($f);'
|
||
|
$ md5sum /mnt/btrfs/foobar
|
||
|
b983fcefd4622a03a78936484c40272b /mnt/btrfs/foobar
|
||
|
$ umount /mnt/btrfs
|
||
|
|
||
|
$ btrfs restore /dev/sdb3 /tmp/copy
|
||
|
$ du -b /tmp/copy/foobar
|
||
|
1048926 /tmp/copy/foobar
|
||
|
$ md5sum /tmp/copy/foobar
|
||
|
88db338cbc1c44dfabae083f1ce642d5 /tmp/copy/foobar
|
||
|
$ od -t x1 -j 8192 -N 4 /tmp/copy/foobar
|
||
|
0020000 41 00 00 00
|
||
|
0020004
|
||
|
$ mount /dev/sdb3 /mnt/btrfs
|
||
|
$ od -t x1 -j 8192 -N 4 /mnt/btrfs/foobar
|
||
|
0020000 00 00 00 00
|
||
|
0020004
|
||
|
$ md5sum /mnt/btrfs/foobar
|
||
|
b983fcefd4622a03a78936484c40272b /mnt/btrfs/foobar
|
||
|
|
||
|
Tested this change with zlib, lzo compression and file sizes larger
|
||
|
than 1GiB, and found no regression or other corruption issues (so far
|
||
|
at least).
|
||
|
|
||
|
Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com>
|
||
|
Signed-off-by: David Sterba <dsterba@suse.cz>
|
||
|
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
|
||
|
---
|
||
|
cmds-restore.c | 13 ++++++++-----
|
||
|
1 file changed, 8 insertions(+), 5 deletions(-)
|
||
|
|
||
|
diff --git a/cmds-restore.c b/cmds-restore.c
|
||
|
index e48df40320f6..9688599742d9 100644
|
||
|
--- a/cmds-restore.c
|
||
|
+++ b/cmds-restore.c
|
||
|
@@ -272,6 +272,7 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
|
||
|
u64 bytenr;
|
||
|
u64 ram_size;
|
||
|
u64 disk_size;
|
||
|
+ u64 num_bytes;
|
||
|
u64 length;
|
||
|
u64 size_left;
|
||
|
u64 dev_bytenr;
|
||
|
@@ -288,7 +289,9 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
|
||
|
disk_size = btrfs_file_extent_disk_num_bytes(leaf, fi);
|
||
|
ram_size = btrfs_file_extent_ram_bytes(leaf, fi);
|
||
|
offset = btrfs_file_extent_offset(leaf, fi);
|
||
|
- size_left = disk_size;
|
||
|
+ num_bytes = btrfs_file_extent_num_bytes(leaf, fi);
|
||
|
+ size_left = num_bytes;
|
||
|
+ bytenr += offset;
|
||
|
|
||
|
if (offset)
|
||
|
printf("offset is %Lu\n", offset);
|
||
|
@@ -296,7 +299,7 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
|
||
|
if (disk_size == 0)
|
||
|
return 0;
|
||
|
|
||
|
- inbuf = malloc(disk_size);
|
||
|
+ inbuf = malloc(size_left);
|
||
|
if (!inbuf) {
|
||
|
fprintf(stderr, "No memory\n");
|
||
|
return -1;
|
||
|
@@ -351,8 +354,8 @@ again:
|
||
|
goto again;
|
||
|
|
||
|
if (compress == BTRFS_COMPRESS_NONE) {
|
||
|
- while (total < ram_size) {
|
||
|
- done = pwrite(fd, inbuf+total, ram_size-total,
|
||
|
+ while (total < num_bytes) {
|
||
|
+ done = pwrite(fd, inbuf+total, num_bytes-total,
|
||
|
pos+total);
|
||
|
if (done < 0) {
|
||
|
ret = -1;
|
||
|
@@ -365,7 +368,7 @@ again:
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
- ret = decompress(inbuf, outbuf, disk_size, &ram_size, compress);
|
||
|
+ ret = decompress(inbuf, outbuf, num_bytes, &ram_size, compress);
|
||
|
if (ret) {
|
||
|
num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
|
||
|
bytenr, length);
|
||
|
--
|
||
|
1.8.3.1
|
||
|
|