summaryrefslogtreecommitdiff
path: root/extent_io.c
diff options
context:
space:
mode:
authorLiu Bo <bo.li.liu@oracle.com>2013-06-22 13:32:45 +0800
committerChris Mason <chris.mason@fusionio.com>2013-07-03 14:16:10 -0400
commit095e21af458b9c40fc90b3f6901e4c7f2c6d0dd5 (patch)
treed55d3799068194806c8a05f6af89aee5667c2ad7 /extent_io.c
parentaa88c0ac37cddd4690c7fb427018276788618621 (diff)
Btrfs-progs: enhance btrfs-image to restore image onto multiple disks
This adds a 'btrfs-image -m' option, which let us restore an image that is built from a btrfs of multiple disks onto several disks altogether. This aims to address the following case, $ mkfs.btrfs -m raid0 sda sdb $ btrfs-image sda image.file $ btrfs-image -r image.file sdc --------- so we can only restore metadata onto sdc, and another thing is we can only mount sdc with degraded mode as we don't provide informations of another disk. And, it's built as RAID0 and we have only one disk, so after mount sdc we'll get into readonly mode. This is just annoying for people(like me) who're trying to restore image but turn to find they cannot make it work. So this'll make your life easier, just tap $ btrfs-image -m image.file sdc sdd --------- then you get everything about metadata done, the same offset with that of the originals(of course, you need offer enough disk size, at least the disk size of the original disks). Besides, this also works with raid5 and raid6 metadata image. Signed-off-by: Liu Bo <bo.li.liu@oracle.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'extent_io.c')
-rw-r--r--extent_io.c87
1 files changed, 87 insertions, 0 deletions
diff --git a/extent_io.c b/extent_io.c
index 5093aeb2..592acd61 100644
--- a/extent_io.c
+++ b/extent_io.c
@@ -747,6 +747,93 @@ int read_data_from_disk(struct btrfs_fs_info *info, void *buf, u64 offset,
return 0;
}
+int write_data_to_disk(struct btrfs_fs_info *info, void *buf, u64 offset,
+ u64 bytes, int mirror)
+{
+ struct btrfs_multi_bio *multi = NULL;
+ struct btrfs_device *device;
+ u64 bytes_left = bytes;
+ u64 this_len;
+ u64 total_write = 0;
+ u64 *raid_map = NULL;
+ u64 dev_bytenr;
+ int dev_nr;
+ int ret = 0;
+
+ while (bytes_left > 0) {
+ this_len = bytes_left;
+ dev_nr = 0;
+
+ ret = btrfs_map_block(&info->mapping_tree, WRITE, offset,
+ &this_len, &multi, mirror, &raid_map);
+ if (ret) {
+ fprintf(stderr, "Couldn't map the block %Lu\n",
+ offset);
+ return -EIO;
+ }
+
+ if (raid_map) {
+ struct extent_buffer *eb;
+ u64 stripe_len = this_len;
+
+ this_len = min(this_len, bytes_left);
+ this_len = min(this_len, (u64)info->tree_root->leafsize);
+
+ eb = malloc(sizeof(struct extent_buffer) + this_len);
+ BUG_ON(!eb);
+
+ memset(eb, 0, sizeof(struct extent_buffer) + this_len);
+ eb->start = offset;
+ eb->len = this_len;
+
+ memcpy(eb->data, buf + total_write, this_len);
+ ret = write_raid56_with_parity(info, eb, multi,
+ stripe_len, raid_map);
+ BUG_ON(ret);
+
+ free(eb);
+ kfree(raid_map);
+ raid_map = NULL;
+ } else while (dev_nr < multi->num_stripes) {
+ device = multi->stripes[dev_nr].dev;
+ if (device->fd == 0) {
+ kfree(multi);
+ return -EIO;
+ }
+
+ dev_bytenr = multi->stripes[dev_nr].physical;
+ this_len = min(this_len, bytes_left);
+ dev_nr++;
+
+ ret = pwrite(device->fd, buf + total_write, this_len, dev_bytenr);
+ if (ret != this_len) {
+ if (ret < 0) {
+ fprintf(stderr, "Error writing to "
+ "device %d\n", errno);
+ ret = errno;
+ kfree(multi);
+ return ret;
+ } else {
+ fprintf(stderr, "Short write\n");
+ kfree(multi);
+ return -EIO;
+ }
+ }
+ }
+
+ BUG_ON(bytes_left < this_len);
+
+ bytes_left -= this_len;
+ offset += this_len;
+ total_write += this_len;
+
+ kfree(multi);
+ multi = NULL;
+ }
+ return 0;
+}
+
+
int set_extent_buffer_uptodate(struct extent_buffer *eb)
{
eb->flags |= EXTENT_UPTODATE;