btrfs-progs: restore: Do proper mirror iteration in copy_one_extent()
The old code of copy_one_extent() is a mess: - The main loop is implemented using goto - @mirror_num is reset to 1 for each loop - @mirror num check against @num_copies is wrong for decompression error This patch will fix this mess by: - Use read_extent_data() read_extent_data() has all the good wrapping of btrfs_map_block() and length check. This removes a lot of complexity. - Add extra file extent offset check To prevent underflow for memory allocation - Do proper mirror_num check for decompression error Issue: #221 Signed-off-by: Qu Wenruo <wqu@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
2efe160bc7
commit
41ff76b833
|
@ -346,8 +346,6 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
|
||||||
struct extent_buffer *leaf,
|
struct extent_buffer *leaf,
|
||||||
struct btrfs_file_extent_item *fi, u64 pos)
|
struct btrfs_file_extent_item *fi, u64 pos)
|
||||||
{
|
{
|
||||||
struct btrfs_multi_bio *multi = NULL;
|
|
||||||
struct btrfs_device *device;
|
|
||||||
char *inbuf, *outbuf = NULL;
|
char *inbuf, *outbuf = NULL;
|
||||||
ssize_t done, total = 0;
|
ssize_t done, total = 0;
|
||||||
u64 bytenr;
|
u64 bytenr;
|
||||||
|
@ -356,12 +354,10 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
|
||||||
u64 num_bytes;
|
u64 num_bytes;
|
||||||
u64 length;
|
u64 length;
|
||||||
u64 size_left;
|
u64 size_left;
|
||||||
u64 dev_bytenr;
|
|
||||||
u64 offset;
|
u64 offset;
|
||||||
u64 count = 0;
|
u64 cur;
|
||||||
int compress;
|
int compress;
|
||||||
int ret;
|
int ret;
|
||||||
int dev_fd;
|
|
||||||
int mirror_num = 1;
|
int mirror_num = 1;
|
||||||
int num_copies;
|
int num_copies;
|
||||||
|
|
||||||
|
@ -372,14 +368,26 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
|
||||||
offset = btrfs_file_extent_offset(leaf, fi);
|
offset = btrfs_file_extent_offset(leaf, fi);
|
||||||
num_bytes = btrfs_file_extent_num_bytes(leaf, fi);
|
num_bytes = btrfs_file_extent_num_bytes(leaf, fi);
|
||||||
size_left = disk_size;
|
size_left = disk_size;
|
||||||
if (compress == BTRFS_COMPRESS_NONE)
|
/* Hole, early exit */
|
||||||
|
if (disk_size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Invalid file extent */
|
||||||
|
if ((compress == BTRFS_COMPRESS_NONE && offset >= disk_size) ||
|
||||||
|
offset > ram_size) {
|
||||||
|
error(
|
||||||
|
"invalid data extent offset, offset %llu disk_size %llu ram_size %llu",
|
||||||
|
offset, disk_size, ram_size);
|
||||||
|
return -EUCLEAN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compress == BTRFS_COMPRESS_NONE && offset < disk_size) {
|
||||||
bytenr += offset;
|
bytenr += offset;
|
||||||
|
size_left -= offset;
|
||||||
|
}
|
||||||
|
|
||||||
if (verbose && offset)
|
if (verbose && offset)
|
||||||
printf("offset is %Lu\n", offset);
|
printf("offset is %Lu\n", offset);
|
||||||
/* we found a hole */
|
|
||||||
if (disk_size == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
inbuf = malloc(size_left);
|
inbuf = malloc(size_left);
|
||||||
if (!inbuf) {
|
if (!inbuf) {
|
||||||
|
@ -395,48 +403,28 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
num_copies = btrfs_num_copies(root->fs_info, bytenr, disk_size - offset);
|
||||||
again:
|
again:
|
||||||
length = size_left;
|
cur = bytenr;
|
||||||
ret = btrfs_map_block(root->fs_info, READ, bytenr, &length, &multi,
|
while (cur < bytenr + size_left) {
|
||||||
mirror_num, NULL);
|
length = bytenr + size_left - cur;
|
||||||
if (ret) {
|
ret = read_extent_data(root->fs_info, inbuf + cur - bytenr, cur,
|
||||||
error("cannot map block logical %llu length %llu: %d",
|
&length, mirror_num);
|
||||||
(unsigned long long)bytenr,
|
if (ret < 0) {
|
||||||
(unsigned long long)length, ret);
|
mirror_num++;
|
||||||
goto out;
|
if (mirror_num > num_copies) {
|
||||||
}
|
ret = -1;
|
||||||
device = multi->stripes[0].dev;
|
error("exhausted mirros trying to read (%d > %d)",
|
||||||
dev_fd = device->fd;
|
|
||||||
device->total_ios++;
|
|
||||||
dev_bytenr = multi->stripes[0].physical;
|
|
||||||
free(multi);
|
|
||||||
|
|
||||||
if (size_left < length)
|
|
||||||
length = size_left;
|
|
||||||
|
|
||||||
done = pread(dev_fd, inbuf+count, length, dev_bytenr);
|
|
||||||
/* Need both checks, or we miss negative values due to u64 conversion */
|
|
||||||
if (done < 0 || done < length) {
|
|
||||||
num_copies = btrfs_num_copies(root->fs_info, bytenr, length);
|
|
||||||
mirror_num++;
|
|
||||||
/* mirror_num is 1-indexed, so num_copies is a valid mirror. */
|
|
||||||
if (mirror_num > num_copies) {
|
|
||||||
ret = -1;
|
|
||||||
error("exhausted mirrors trying to read (%d > %d)",
|
|
||||||
mirror_num, num_copies);
|
mirror_num, num_copies);
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "trying another mirror\n");
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Trying another mirror\n");
|
cur += length;
|
||||||
goto again;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mirror_num = 1;
|
|
||||||
size_left -= length;
|
|
||||||
count += length;
|
|
||||||
bytenr += length;
|
|
||||||
if (size_left)
|
|
||||||
goto again;
|
|
||||||
|
|
||||||
if (compress == BTRFS_COMPRESS_NONE) {
|
if (compress == BTRFS_COMPRESS_NONE) {
|
||||||
while (total < num_bytes) {
|
while (total < num_bytes) {
|
||||||
done = pwrite(fd, inbuf+total, num_bytes-total,
|
done = pwrite(fd, inbuf+total, num_bytes-total,
|
||||||
|
@ -454,13 +442,13 @@ again:
|
||||||
|
|
||||||
ret = decompress(root, inbuf, outbuf, disk_size, &ram_size, compress);
|
ret = decompress(root, inbuf, outbuf, disk_size, &ram_size, compress);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
num_copies = btrfs_num_copies(root->fs_info, bytenr, length);
|
|
||||||
mirror_num++;
|
mirror_num++;
|
||||||
if (mirror_num >= num_copies) {
|
if (mirror_num > num_copies) {
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
fprintf(stderr, "Trying another mirror\n");
|
fprintf(stderr,
|
||||||
|
"trying another mirror due to decompression error\n");
|
||||||
goto again;
|
goto again;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue