On Thu, May 26, 2016 at 05:43:00PM +0800, Lu Fengqi wrote:
> 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 <[email protected]>
> ---
>  btrfs-image.c | 143 
> +++++++++++++++++++++++++++++++++++++++-------------------
>  1 file changed, 97 insertions(+), 46 deletions(-)
> 
> diff --git a/btrfs-image.c b/btrfs-image.c
> index 8a1b799..d121951 100644
> --- a/btrfs-image.c
> +++ b/btrfs-image.c
> @@ -68,6 +68,12 @@ 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*

What does it do in case of RAID? Can we do runtime checks and report
potential problems? btrfs-image on multiple device was always somehow
tricky so I'll merge the patch.

> +      */
> +     u64 physical_dup;
>       u64 bytes;
>       struct rb_node l;
>       struct rb_node p;
> @@ -290,7 +296,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 +319,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 +1466,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 +1594,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 +1707,7 @@ static void *restore_worker(void *data)
>       }
>  
>       while (1) {
> -             u64 bytenr;
> +             u64 bytenr, physical_dup;
>               off_t offset = 0;
>               int err = 0;
>  
> @@ -1732,27 +1759,37 @@ static void *restore_worker(void *data)
>                               u64 chunk_size = size;
>                               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 +2054,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 +2081,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 +2093,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:
> -- 
> 2.5.5
> 
> 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to [email protected]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to