Btrfs-progs: try other mirrors if decompression fails
authorJosef Bacik <josef@redhat.com>
Tue, 12 Mar 2013 17:38:09 +0000 (13:38 -0400)
committerDavid Sterba <dsterba@suse.cz>
Mon, 18 Mar 2013 17:14:10 +0000 (18:14 +0100)
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>
cmds-restore.c

index 467e5ef..1d24691 100644 (file)
@@ -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)