When btrfs-image makes a metadump it'll map all the blocks from their logical
address to their physical.  This works out fine with the exception of the super
block, which is the physical offset.  Normally this just works, but if the user
has balanced their fs it'll either crash btrfs-image or it'll copy some
completely arbitrary data.  This forces btrfs-image to read the super directly
from the disk.  Thanks,

Signed-off-by: Josef Bacik <jba...@fb.com>
---
 btrfs-image.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/btrfs-image.c b/btrfs-image.c
index f6347f3..4bcaf6c 100644
--- a/btrfs-image.c
+++ b/btrfs-image.c
@@ -868,6 +868,15 @@ static int read_data_extent(struct metadump_struct *md,
        return 0;
 }
 
+static int get_dev_fd(struct btrfs_root *root)
+{
+       struct btrfs_device *dev;
+
+       dev = list_first_entry(&root->fs_info->fs_devices->devices,
+                              struct btrfs_device, dev_list);
+       return dev->fd;
+}
+
 static int flush_pending(struct metadump_struct *md, int done)
 {
        struct async_work *async = NULL;
@@ -904,6 +913,24 @@ static int flush_pending(struct metadump_struct *md, int 
done)
                        }
                }
 
+               /*
+                * Balance can make the mapping not cover the super block, so
+                * just copy directly from one of the devices.
+                */
+               if (start == BTRFS_SUPER_INFO_OFFSET) {
+                       int fd = get_dev_fd(md->root);
+
+                       ret = pread64(fd, async->buffer, size, start);
+                       if (ret < size) {
+                               free(async->buffer);
+                               free(async);
+                               fprintf(stderr, "Error reading superblock\n");
+                               return -EIO;
+                       }
+                       size = 0;
+                       ret = 0;
+               }
+
                while (!md->data && size > 0) {
                        u64 this_read = min(blocksize, size);
                        eb = read_tree_block(md->root, start, this_read, 0);
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to