summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2013-03-12 13:38:09 -0400
committerDavid Sterba <dsterba@suse.cz>2013-03-18 18:14:10 +0100
commit9969ea479db454fac29971016219b03ec2f02b9c (patch)
treeff305d5d057094e583efe3dacd8765166074f07e
parent331295de0596cb2f16dca494814cf9c231d50353 (diff)
Btrfs-progs: try other mirrors if decompression fails
This will make the restore program fall back on other mirrors if it fails to decompress an extent for whatever reason. Thanks, Signed-off-by: Josef Bacik <josef@redhat.com>
-rw-r--r--cmds-restore.c46
1 files changed, 25 insertions, 21 deletions
diff --git a/cmds-restore.c b/cmds-restore.c
index 467e5ef3..1d246919 100644
--- a/cmds-restore.c
+++ b/cmds-restore.c
@@ -65,7 +65,7 @@ static int decompress(char *inbuf, char *outbuf, u64 compress_len,
ret = inflate(&strm, Z_NO_FLUSH);
if (ret != Z_STREAM_END) {
(void)inflateEnd(&strm);
- fprintf(stderr, "ret is %d\n", ret);
+ fprintf(stderr, "failed to inflate: %d\n", ret);
return -1;
}
@@ -198,6 +198,8 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
int compress;
int ret;
int dev_fd;
+ int mirror_num = 0;
+ int num_copies;
compress = btrfs_file_extent_compression(leaf, fi);
bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
@@ -226,12 +228,10 @@ static int copy_one_extent(struct btrfs_root *root, int fd,
again:
length = size_left;
ret = btrfs_map_block(&root->fs_info->mapping_tree, READ,
- bytenr, &length, &multi, 0, NULL);
+ bytenr, &length, &multi, mirror_num, NULL);
if (ret) {
- free(inbuf);
- free(outbuf);
fprintf(stderr, "Error mapping block %d\n", ret);
- return ret;
+ goto out;
}
device = multi->stripes[0].dev;
dev_fd = device->fd;
@@ -245,10 +245,9 @@ again:
done = pread(dev_fd, inbuf+count, length, dev_bytenr);
if (done < length) {
- free(inbuf);
- free(outbuf);
+ ret = -1;
fprintf(stderr, "Short read %d\n", errno);
- return -1;
+ goto out;
}
count += length;
@@ -256,41 +255,46 @@ again:
if (size_left)
goto again;
-
if (compress == BTRFS_COMPRESS_NONE) {
while (total < ram_size) {
done = pwrite(fd, inbuf+total, ram_size-total,
pos+total);
if (done < 0) {
- free(inbuf);
+ ret = -1;
fprintf(stderr, "Error writing: %d %s\n", errno, strerror(errno));
- return -1;
+ goto out;
}
total += done;
}
- free(inbuf);
- return 0;
+ ret = 0;
+ goto out;
}
ret = decompress(inbuf, outbuf, disk_size, ram_size);
- free(inbuf);
if (ret) {
- free(outbuf);
- return ret;
+ num_copies = btrfs_num_copies(&root->fs_info->mapping_tree,
+ bytenr, length);
+ mirror_num++;
+ if (mirror_num >= num_copies) {
+ ret = -1;
+ goto out;
+ }
+ fprintf(stderr, "Trying another mirror\n");
+ goto again;
}
while (total < ram_size) {
done = pwrite(fd, outbuf+total, ram_size-total, pos+total);
if (done < 0) {
- free(outbuf);
- fprintf(stderr, "Error writing: %d %s\n", errno, strerror(errno));
- return -1;
+ ret = -1;
+ goto out;
}
total += done;
}
+out:
+ free(inbuf);
free(outbuf);
-
- return 0;
+ return ret;
}
static int ask_to_continue(const char *file)