btrfs-progs: image: Don't modify the chunk and device tree if the source dump is single device

Btrfs-image -r doesn't always create exactly the same fs of the original
fs, this is because btrfs-image can create dump from multi-device, and
restore it to single device.

Thus we need some special modification to chunk and device tree. This
behavior is mostly to handle the old behavior where we always restore
the metadata into SINGLE profile no matter what.

However this is not needed if the source fs only has one device, in that
case, we can use all the metadata as is, no need to modify the fs at
all, resulting an exact copy of metadata.

This patch will do extra check when doing restore, to avoid modify the
restored fs if the source is also single device.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2020-05-27 18:28:09 +08:00 committed by David Sterba
parent 23bee6a7b5
commit 73dd4e3c87

View File

@ -103,6 +103,7 @@ struct mdrestore_struct {
struct rb_root physical_tree;
struct list_head list;
struct list_head overlapping_chunks;
struct btrfs_super_block *original_super;
size_t num_items;
u32 nodesize;
u64 devid;
@ -1085,6 +1086,12 @@ static int update_super(struct mdrestore_struct *mdres, u8 *buffer)
u8 *ptr, *write_ptr;
int old_num_stripes;
/* No need to fix, use all data as is */
if (btrfs_super_num_devices(mdres->original_super) == 1) {
new_array_size = btrfs_super_sys_array_size(super);
goto finish;
}
write_ptr = ptr = super->sys_chunk_array;
array_size = btrfs_super_sys_array_size(super);
@ -1135,6 +1142,7 @@ static int update_super(struct mdrestore_struct *mdres, u8 *buffer)
cur += btrfs_chunk_item_size(old_num_stripes);
}
finish:
if (mdres->clear_space_cache)
btrfs_set_super_cache_generation(super, 0);
@ -1203,6 +1211,8 @@ static int fixup_chunk_tree_block(struct mdrestore_struct *mdres,
u64 bytenr = async->start;
int i;
if (btrfs_super_num_devices(mdres->original_super) == 1)
return 0;
if (size_left % mdres->nodesize)
return 0;
@ -1373,6 +1383,8 @@ static void *restore_worker(void *data)
if (!mdres->multi_devices) {
if (async->start == BTRFS_SUPER_INFO_OFFSET) {
memcpy(mdres->original_super, outbuf,
BTRFS_SUPER_INFO_SIZE);
if (mdres->old_restore) {
update_super_old(outbuf);
} else {
@ -1474,6 +1486,7 @@ static void mdrestore_destroy(struct mdrestore_struct *mdres, int num_threads)
pthread_cond_destroy(&mdres->cond);
pthread_mutex_destroy(&mdres->mutex);
free(mdres->original_super);
}
static int mdrestore_init(struct mdrestore_struct *mdres,
@ -1500,6 +1513,10 @@ static int mdrestore_init(struct mdrestore_struct *mdres,
mdres->last_physical_offset = 0;
mdres->alloced_chunks = 0;
mdres->original_super = malloc(BTRFS_SUPER_INFO_SIZE);
if (!mdres->original_super)
return -ENOMEM;
if (!num_threads)
return 0;
@ -2606,7 +2623,8 @@ static int restore_metadump(const char *input, FILE *out, int old_restore,
}
ret = wait_for_worker(&mdrestore);
if (!ret && !multi_devices && !old_restore) {
if (!ret && !multi_devices && !old_restore &&
btrfs_super_num_devices(mdrestore.original_super) != 1) {
struct btrfs_root *root;
struct stat st;