aboutsummaryrefslogtreecommitdiffstats
path: root/btrfs-image.c
diff options
context:
space:
mode:
authorLu Fengqi <lufq.fnst@cn.fujitsu.com>2016-05-26 17:43:00 +0800
committerDavid Sterba <dsterba@suse.com>2016-06-01 14:56:56 +0200
commit9088ab6a10679eccb70255d0bf5c7e31fbbb8c97 (patch)
tree71132b4fd1cff0796aa7bb7f671fd97a6df5a9d0 /btrfs-image.c
parent0993ae5a73d5d0709b543faa0c528931a0f7fc36 (diff)
downloadbtrfs-progs-9088ab6a10679eccb70255d0bf5c7e31fbbb8c97.tar.gz
btrfs-progs-9088ab6a10679eccb70255d0bf5c7e31fbbb8c97.tar.xz
btrfs-progs-9088ab6a10679eccb70255d0bf5c7e31fbbb8c97.zip
btrfs-progs: make btrfs-image restore to support dup
Previously btrfs-image restore would set the chunk items to have 1 stripe, even if the chunk is dup. If you use btrfsck on the restored file system, some dev_extent will not find any relative chunk stripe, and the bytes-used of dev_item will not equal to the dev_extents's total_bytes. This patch store a additional physical just for the dup case when build the in-memory chunk-tree. Currently btrfsck on the restored file system, only single and dup is no problem. raid* support should be added in the future. Signed-off-by: Lu Fengqi <lufq.fnst@cn.fujitsu.com> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'btrfs-image.c')
-rw-r--r--btrfs-image.c145
1 files changed, 99 insertions, 46 deletions
diff --git a/btrfs-image.c b/btrfs-image.c
index 8a1b799..660b0aa 100644
--- a/btrfs-image.c
+++ b/btrfs-image.c
@@ -68,6 +68,13 @@ struct meta_cluster {
struct fs_chunk {
u64 logical;
u64 physical;
+ /*
+ * physical_dup only store additonal physical for BTRFS_BLOCK_GROUP_DUP
+ * currently restore only support single and DUP
+ * TODO: modify this structure and the function related to this
+ * structure for support RAID*
+ */
+ u64 physical_dup;
u64 bytes;
struct rb_node l;
struct rb_node p;
@@ -290,7 +297,8 @@ static struct rb_node *tree_search(struct rb_root *root,
return NULL;
}
-static u64 logical_to_physical(struct mdrestore_struct *mdres, u64 logical, u64 *size)
+static u64 logical_to_physical(struct mdrestore_struct *mdres, u64 logical,
+ u64 *size, u64 *physical_dup)
{
struct fs_chunk *fs_chunk;
struct rb_node *entry;
@@ -312,6 +320,14 @@ static u64 logical_to_physical(struct mdrestore_struct *mdres, u64 logical, u64
BUG();
offset = search.logical - fs_chunk->logical;
+ if (physical_dup) {
+ /* Only in dup case, physical_dup is not equal to 0 */
+ if (fs_chunk->physical_dup)
+ *physical_dup = fs_chunk->physical_dup + offset;
+ else
+ *physical_dup = 0;
+ }
+
*size = min(*size, fs_chunk->bytes + fs_chunk->logical - logical);
return fs_chunk->physical + offset;
}
@@ -1451,20 +1467,26 @@ static int update_super(struct mdrestore_struct *mdres, u8 *buffer)
cur += sizeof(*disk_key);
if (key.type == BTRFS_CHUNK_ITEM_KEY) {
- u64 physical, size = 0;
+ u64 type, physical, physical_dup, size = 0;
chunk = (struct btrfs_chunk *)ptr;
old_num_stripes = btrfs_stack_chunk_num_stripes(chunk);
chunk = (struct btrfs_chunk *)write_ptr;
memmove(write_ptr, ptr, sizeof(*chunk));
- btrfs_set_stack_chunk_num_stripes(chunk, 1);
btrfs_set_stack_chunk_sub_stripes(chunk, 0);
- btrfs_set_stack_chunk_type(chunk,
- BTRFS_BLOCK_GROUP_SYSTEM);
+ type = btrfs_stack_chunk_type(chunk);
+ if (type & BTRFS_BLOCK_GROUP_DUP) {
+ new_array_size += sizeof(struct btrfs_stripe);
+ write_ptr += sizeof(struct btrfs_stripe);
+ } else {
+ btrfs_set_stack_chunk_num_stripes(chunk, 1);
+ btrfs_set_stack_chunk_type(chunk,
+ BTRFS_BLOCK_GROUP_SYSTEM);
+ }
chunk->stripe.devid = super->dev_item.devid;
physical = logical_to_physical(mdres, key.offset,
- &size);
+ &size, &physical_dup);
if (size != (u64)-1)
btrfs_set_stack_stripe_offset(&chunk->stripe,
physical);
@@ -1573,41 +1595,47 @@ static int fixup_chunk_tree_block(struct mdrestore_struct *mdres,
goto next;
for (i = 0; i < btrfs_header_nritems(eb); i++) {
- struct btrfs_chunk chunk;
+ struct btrfs_chunk *chunk;
struct btrfs_key key;
- u64 type, physical, size = (u64)-1;
+ u64 type, physical, physical_dup, size = (u64)-1;
btrfs_item_key_to_cpu(eb, &key, i);
if (key.type != BTRFS_CHUNK_ITEM_KEY)
continue;
- truncate_item(eb, i, sizeof(chunk));
- read_extent_buffer(eb, &chunk,
- btrfs_item_ptr_offset(eb, i),
- sizeof(chunk));
size = 0;
physical = logical_to_physical(mdres, key.offset,
- &size);
+ &size, &physical_dup);
+
+ if (!physical_dup)
+ truncate_item(eb, i, sizeof(*chunk));
+ chunk = btrfs_item_ptr(eb, i, struct btrfs_chunk);
+
/* Zero out the RAID profile */
- type = btrfs_stack_chunk_type(&chunk);
+ type = btrfs_chunk_type(eb, chunk);
type &= (BTRFS_BLOCK_GROUP_DATA |
BTRFS_BLOCK_GROUP_SYSTEM |
BTRFS_BLOCK_GROUP_METADATA |
BTRFS_BLOCK_GROUP_DUP);
- btrfs_set_stack_chunk_type(&chunk, type);
+ btrfs_set_chunk_type(eb, chunk, type);
- btrfs_set_stack_chunk_num_stripes(&chunk, 1);
- btrfs_set_stack_chunk_sub_stripes(&chunk, 0);
- btrfs_set_stack_stripe_devid(&chunk.stripe, mdres->devid);
+ if (!physical_dup)
+ btrfs_set_chunk_num_stripes(eb, chunk, 1);
+ btrfs_set_chunk_sub_stripes(eb, chunk, 0);
+ btrfs_set_stripe_devid_nr(eb, chunk, 0, mdres->devid);
if (size != (u64)-1)
- btrfs_set_stack_stripe_offset(&chunk.stripe,
- physical);
- memcpy(chunk.stripe.dev_uuid, mdres->uuid,
- BTRFS_UUID_SIZE);
- write_extent_buffer(eb, &chunk,
- btrfs_item_ptr_offset(eb, i),
- sizeof(chunk));
+ btrfs_set_stripe_offset_nr(eb, chunk, 0,
+ physical);
+ /* update stripe 2 offset */
+ if (physical_dup)
+ btrfs_set_stripe_offset_nr(eb, chunk, 1,
+ physical_dup);
+
+ write_extent_buffer(eb, mdres->uuid,
+ (unsigned long)btrfs_stripe_dev_uuid_nr(
+ chunk, 0),
+ BTRFS_UUID_SIZE);
}
memcpy(buffer, eb->data, eb->len);
csum_block(buffer, eb->len);
@@ -1680,7 +1708,7 @@ static void *restore_worker(void *data)
}
while (1) {
- u64 bytenr;
+ u64 bytenr, physical_dup;
off_t offset = 0;
int err = 0;
@@ -1730,29 +1758,40 @@ static void *restore_worker(void *data)
if (!mdres->fixup_offset) {
while (size) {
u64 chunk_size = size;
+ physical_dup = 0;
if (!mdres->multi_devices && !mdres->old_restore)
bytenr = logical_to_physical(mdres,
- async->start + offset,
- &chunk_size);
+ async->start + offset,
+ &chunk_size,
+ &physical_dup);
else
bytenr = async->start + offset;
ret = pwrite64(outfd, outbuf+offset, chunk_size,
bytenr);
- if (ret != chunk_size) {
- if (ret < 0) {
- fprintf(stderr, "Error writing to "
- "device %d\n", errno);
- err = errno;
- break;
- } else {
- fprintf(stderr, "Short write\n");
- err = -EIO;
- break;
- }
- }
+ if (ret != chunk_size)
+ goto error;
+
+ if (physical_dup)
+ ret = pwrite64(outfd, outbuf+offset,
+ chunk_size,
+ physical_dup);
+ if (ret != chunk_size)
+ goto error;
+
size -= chunk_size;
offset += chunk_size;
+ continue;
+
+error:
+ if (ret < 0) {
+ fprintf(stderr, "Error writing to device %d\n",
+ errno);
+ err = errno;
+ } else {
+ fprintf(stderr, "Short write\n");
+ err = -EIO;
+ }
}
} else if (async->start != BTRFS_SUPER_INFO_OFFSET) {
ret = write_data_to_disk(mdres->info, outbuf, async->start, size, 0);
@@ -2017,9 +2056,10 @@ static int read_chunk_block(struct mdrestore_struct *mdres, u8 *buffer,
}
for (i = 0; i < btrfs_header_nritems(eb); i++) {
- struct btrfs_chunk chunk;
+ struct btrfs_chunk *chunk;
struct fs_chunk *fs_chunk;
struct btrfs_key key;
+ u64 type;
if (btrfs_header_level(eb)) {
u64 blockptr = btrfs_node_blockptr(eb, i);
@@ -2043,12 +2083,11 @@ static int read_chunk_block(struct mdrestore_struct *mdres, u8 *buffer,
break;
}
memset(fs_chunk, 0, sizeof(*fs_chunk));
- read_extent_buffer(eb, &chunk, btrfs_item_ptr_offset(eb, i),
- sizeof(chunk));
+ chunk = btrfs_item_ptr(eb, i, struct btrfs_chunk);
fs_chunk->logical = key.offset;
- fs_chunk->physical = btrfs_stack_stripe_offset(&chunk.stripe);
- fs_chunk->bytes = btrfs_stack_chunk_length(&chunk);
+ fs_chunk->physical = btrfs_stripe_offset_nr(eb, chunk, 0);
+ fs_chunk->bytes = btrfs_chunk_length(eb, chunk);
INIT_LIST_HEAD(&fs_chunk->list);
if (tree_search(&mdres->physical_tree, &fs_chunk->p,
physical_cmp, 1) != NULL)
@@ -2056,11 +2095,25 @@ static int read_chunk_block(struct mdrestore_struct *mdres, u8 *buffer,
else
tree_insert(&mdres->physical_tree, &fs_chunk->p,
physical_cmp);
- if (fs_chunk->physical + fs_chunk->bytes >
+
+ type = btrfs_chunk_type(eb, chunk);
+ if (type & BTRFS_BLOCK_GROUP_DUP) {
+ fs_chunk->physical_dup =
+ btrfs_stripe_offset_nr(eb, chunk, 1);
+ }
+
+ if (fs_chunk->physical_dup + fs_chunk->bytes >
+ mdres->last_physical_offset)
+ mdres->last_physical_offset = fs_chunk->physical_dup +
+ fs_chunk->bytes;
+ else if (fs_chunk->physical + fs_chunk->bytes >
mdres->last_physical_offset)
mdres->last_physical_offset = fs_chunk->physical +
fs_chunk->bytes;
mdres->alloced_chunks += fs_chunk->bytes;
+ /* in dup case, fs_chunk->bytes should add twice */
+ if (fs_chunk->physical_dup)
+ mdres->alloced_chunks += fs_chunk->bytes;
tree_insert(&mdres->chunk_tree, &fs_chunk->l, chunk_cmp);
}
out: