Re: [PATCH] btrfs-progs: make btrfs-image restore to support dup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <lufq.fnst@xxxxxxxxxxxxxx>
> ---
>  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 majordomo@xxxxxxxxxxxxxxx
> 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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux