summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2015-01-14 14:40:21 -0500
committerJosef Bacik <jbacik@fb.com>2015-02-09 14:53:14 -0500
commit1b7126f93722064eff6ee0792694a598a37bef30 (patch)
treec83bf8c8e415314510447734ebbe9fcca69348a0
parentcc73e60d952af55f4aac5266711456d5a774c207 (diff)
Btrfs-progs: read super properly in btrfs-image
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 <jbacik@fb.com>
-rw-r--r--btrfs-image.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/btrfs-image.c b/btrfs-image.c
index f6347f36..4bcaf6c2 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);