summaryrefslogtreecommitdiff
path: root/btrfs-image.c
diff options
context:
space:
mode:
Diffstat (limited to 'btrfs-image.c')
-rw-r--r--btrfs-image.c150
1 files changed, 131 insertions, 19 deletions
diff --git a/btrfs-image.c b/btrfs-image.c
index feb4a620..3c78388a 100644
--- a/btrfs-image.c
+++ b/btrfs-image.c
@@ -133,6 +133,7 @@ struct mdrestore_struct {
size_t num_items;
u32 leafsize;
u64 devid;
+ u64 alloced_chunks;
u64 last_physical_offset;
u8 uuid[BTRFS_UUID_SIZE];
u8 fsid[BTRFS_FSID_SIZE];
@@ -1856,6 +1857,7 @@ static int mdrestore_init(struct mdrestore_struct *mdres,
mdres->multi_devices = multi_devices;
mdres->clear_space_cache = 0;
mdres->last_physical_offset = 0;
+ mdres->alloced_chunks = 0;
if (!num_threads)
return 0;
@@ -2087,6 +2089,7 @@ static int read_chunk_block(struct mdrestore_struct *mdres, u8 *buffer,
mdres->last_physical_offset)
mdres->last_physical_offset = fs_chunk->physical +
fs_chunk->bytes;
+ mdres->alloced_chunks += fs_chunk->bytes;
tree_insert(&mdres->chunk_tree, &fs_chunk->l, chunk_cmp);
}
out:
@@ -2372,9 +2375,107 @@ static void remap_overlapping_chunks(struct mdrestore_struct *mdres)
}
}
-static int __restore_metadump(const char *input, FILE *out, int old_restore,
- int num_threads, int fixup_offset,
- const char *target, int multi_devices)
+static int fixup_devices(struct btrfs_fs_info *fs_info,
+ struct mdrestore_struct *mdres, off_t dev_size)
+{
+ struct btrfs_trans_handle *trans;
+ struct btrfs_dev_item *dev_item;
+ struct btrfs_path *path;
+ struct extent_buffer *leaf;
+ struct btrfs_root *root = fs_info->chunk_root;
+ struct btrfs_key key;
+ u64 devid, cur_devid;
+ int ret;
+
+ path = btrfs_alloc_path();
+ if (!path) {
+ fprintf(stderr, "Error alloc'ing path\n");
+ return -ENOMEM;
+ }
+
+ trans = btrfs_start_transaction(fs_info->tree_root, 1);
+ if (IS_ERR(trans)) {
+ fprintf(stderr, "Error starting transaction %ld\n",
+ PTR_ERR(trans));
+ btrfs_free_path(path);
+ return PTR_ERR(trans);
+ }
+
+ dev_item = &fs_info->super_copy->dev_item;
+
+ devid = btrfs_stack_device_id(dev_item);
+
+ btrfs_set_stack_device_total_bytes(dev_item, dev_size);
+ btrfs_set_stack_device_bytes_used(dev_item, mdres->alloced_chunks);
+
+ key.objectid = BTRFS_DEV_ITEMS_OBJECTID;
+ key.type = BTRFS_DEV_ITEM_KEY;
+ key.offset = 0;
+
+again:
+ ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+ if (ret < 0) {
+ fprintf(stderr, "search failed %d\n", ret);
+ exit(1);
+ }
+
+ while (1) {
+ leaf = path->nodes[0];
+ if (path->slots[0] >= btrfs_header_nritems(leaf)) {
+ ret = btrfs_next_leaf(root, path);
+ if (ret < 0) {
+ fprintf(stderr, "Error going to next leaf "
+ "%d\n", ret);
+ exit(1);
+ }
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
+ leaf = path->nodes[0];
+ }
+
+ btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+ if (key.type > BTRFS_DEV_ITEM_KEY)
+ break;
+ if (key.type != BTRFS_DEV_ITEM_KEY) {
+ path->slots[0]++;
+ continue;
+ }
+
+ dev_item = btrfs_item_ptr(leaf, path->slots[0],
+ struct btrfs_dev_item);
+ cur_devid = btrfs_device_id(leaf, dev_item);
+ if (devid != cur_devid) {
+ ret = btrfs_del_item(trans, root, path);
+ if (ret) {
+ fprintf(stderr, "Error deleting item %d\n",
+ ret);
+ exit(1);
+ }
+ btrfs_release_path(path);
+ goto again;
+ }
+
+ btrfs_set_device_total_bytes(leaf, dev_item, dev_size);
+ btrfs_set_device_bytes_used(leaf, dev_item,
+ mdres->alloced_chunks);
+ btrfs_mark_buffer_dirty(leaf);
+ path->slots[0]++;
+ }
+
+ btrfs_free_path(path);
+ ret = btrfs_commit_transaction(trans, fs_info->tree_root);
+ if (ret) {
+ fprintf(stderr, "Commit failed %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int restore_metadump(const char *input, FILE *out, int old_restore,
+ int num_threads, int fixup_offset,
+ const char *target, int multi_devices)
{
struct meta_cluster *cluster = NULL;
struct meta_cluster_header *header;
@@ -2454,6 +2555,30 @@ static int __restore_metadump(const char *input, FILE *out, int old_restore,
}
}
ret = wait_for_worker(&mdrestore);
+
+ if (!ret && !multi_devices && !old_restore) {
+ struct stat st;
+
+ info = open_ctree_fs_info(target, 0, 0,
+ OPEN_CTREE_PARTIAL |
+ OPEN_CTREE_WRITES);
+ if (!info) {
+ fprintf(stderr, "unable to open %s\n", target);
+ ret = -EIO;
+ goto out;
+ }
+
+ if (stat(target, &st)) {
+ fprintf(stderr, "statting %s failed\n", target);
+ close_ctree(info->chunk_root);
+ return 1;
+ }
+
+ ret = fixup_devices(info, &mdrestore, st.st_size);
+ close_ctree(info->chunk_root);
+ if (ret)
+ goto out;
+ }
out:
mdrestore_destroy(&mdrestore, num_threads);
failed_cluster:
@@ -2467,19 +2592,6 @@ failed_open:
return ret;
}
-static int restore_metadump(const char *input, FILE *out, int old_restore,
- int num_threads, int multi_devices)
-{
- return __restore_metadump(input, out, old_restore, num_threads, 0, NULL,
- multi_devices);
-}
-
-static int fixup_metadump(const char *input, FILE *out, int num_threads,
- const char *target)
-{
- return __restore_metadump(input, out, 0, num_threads, 1, target, 1);
-}
-
static int update_disk_super_on_device(struct btrfs_fs_info *info,
const char *other_dev, u64 cur_devid)
{
@@ -2705,7 +2817,7 @@ int main(int argc, char *argv[])
compress_level, sanitize, walk_trees);
} else {
ret = restore_metadump(source, out, old_restore, num_threads,
- multi_devices);
+ 0, target, multi_devices);
}
if (ret) {
printk("%s failed (%s)\n", (create) ? "create" : "restore",
@@ -2752,14 +2864,14 @@ int main(int argc, char *argv[])
close_ctree(info->chunk_root);
/* fix metadata block to map correct chunk */
- ret = fixup_metadump(source, out, 1, target);
+ ret = restore_metadump(source, out, 0, num_threads, 1,
+ target, 1);
if (ret) {
fprintf(stderr, "fix metadump failed (error=%d)\n",
ret);
exit(1);
}
}
-
out:
if (out == stdout) {
fflush(out);