On 2018年02月02日 17:20, Su Yue wrote: > > > On 02/02/2018 04:19 PM, Qu Wenruo wrote: >> We used to have two chunk allocators, btrfs_alloc_chunk() and >> btrfs_alloc_data_chunk(), the former is the more generic one, while the >> later is only used in mkfs and convert, to allocate SINGLE data chunk. >> >> Although btrfs_alloc_data_chunk() has some special hacks to cooperate >> with convert, it's quite simple to integrity it into the generic chunk >> allocator. >> >> So merge them into one btrfs_alloc_chunk(), with extra @convert >> parameter and necessary comment, to make code less duplicated and less >> thing to maintain. >> >> Signed-off-by: Qu Wenruo <w...@suse.com> >> --- >> convert/main.c | 6 +- >> extent-tree.c | 2 +- >> mkfs/main.c | 8 +-- >> volumes.c | 219 >> ++++++++++++++++++++++----------------------------------- [snip] >> diff --git a/volumes.c b/volumes.c >> index 677d085de96c..9ee4650351c3 100644 >> --- a/volumes.c >> +++ b/volumes.c >> @@ -836,9 +836,23 @@ error: >> - 2 * sizeof(struct btrfs_chunk)) \ >> / sizeof(struct btrfs_stripe) + 1) >> +/* >> + * Alloc a chunk, will insert dev extents, chunk item. >> + * NOTE: This function will not insert block group item nor mark newly >> + * allocated chunk available for later allocation. >> + * Block group item and free space update is handled by >> btrfs_make_block_group() >> + * >> + * @start: return value of allocated chunk start bytenr. >> + * @num_bytes: return value of allocated chunk size >> + * @type: chunk type (including both profile and type) >> + * @convert: if the chunk is allocated for convert case. >> + * If @convert is true, chunk allocator will skip device extent >> + * search, but use *start and *num_bytes as chunk >> start/num_bytes >> + * and devive offset, to build a 1:1 chunk mapping for convert. >> + */ >> int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, >> struct btrfs_fs_info *info, u64 *start, >> - u64 *num_bytes, u64 type) >> + u64 *num_bytes, u64 type, bool convert) >> { >> u64 dev_offset; >> struct btrfs_root *extent_root = info->extent_root; >> @@ -868,10 +882,38 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle >> *trans, >> struct btrfs_key key; >> u64 offset; >> - if (list_empty(dev_list)) { >> + if (list_empty(dev_list)) >> return -ENOSPC; >> + >> + if (convert) { >> + /* For convert, profile must be SINGLE */ >> + if (type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { > Maybe BTRFS_RAID_SINGLE?
Here we're using type and raid index is not introduced yet, so what we're doing is correct. Thanks, Qu > > Thanks, > Su > >> + error("convert only suports SINGLE profile"); >> + return -EINVAL; >> + } >> + if (!IS_ALIGNED(*start, info->sectorsize)) { >> + error("chunk start not aligned, start=%llu sectorsize=%u", >> + *start, info->sectorsize); >> + return -EINVAL; >> + } >> + if (!IS_ALIGNED(*num_bytes, info->sectorsize)) { >> + error("chunk size not aligned, size=%llu sectorsize=%u", >> + *num_bytes, info->sectorsize); >> + return -EINVAL; >> + } >> + calc_size = *num_bytes; >> + offset = *start; >> + /* >> + * For convert, we use 1:1 chunk mapping specified by @start and >> + * @num_bytes, so there is no need to go through dev_extent >> + * searching. >> + */ >> + goto alloc_chunk; >> } >> + /* >> + * Chunk size calculation part. >> + */ >> if (type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { >> if (type & BTRFS_BLOCK_GROUP_SYSTEM) { >> calc_size = SZ_8M; >> @@ -942,6 +984,9 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle >> *trans, >> percent_max = >> div_factor(btrfs_super_total_bytes(info->super_copy), 1); >> max_chunk_size = min(percent_max, max_chunk_size); >> + /* >> + * Reserve space from each device. >> + */ >> again: >> if (chunk_bytes_by_type(type, calc_size, num_stripes, >> sub_stripes) > >> max_chunk_size) { >> @@ -972,7 +1017,8 @@ again: >> return ret; >> cur = cur->next; >> if (avail >= min_free) { >> - list_move_tail(&device->dev_list, &private_devs); >> + list_move_tail(&device->dev_list, >> + &private_devs); >> index++; >> if (type & BTRFS_BLOCK_GROUP_DUP) >> index++; >> @@ -999,9 +1045,16 @@ again: >> } >> return -ENOSPC; >> } >> - ret = find_next_chunk(info, &offset); >> - if (ret) >> - return ret; >> + >> + /* >> + * Fill chunk mapping and chunk stripes >> + */ >> +alloc_chunk: >> + if (!convert) { >> + ret = find_next_chunk(info, &offset); >> + if (ret) >> + return ret; >> + } >> key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; >> key.type = BTRFS_CHUNK_ITEM_KEY; >> key.offset = offset; >> @@ -1022,17 +1075,31 @@ again: >> index = 0; >> while(index < num_stripes) { >> struct btrfs_stripe *stripe; >> - BUG_ON(list_empty(&private_devs)); >> - cur = private_devs.next; >> - device = list_entry(cur, struct btrfs_device, dev_list); >> - /* loop over this device again if we're doing a dup group */ >> - if (!(type & BTRFS_BLOCK_GROUP_DUP) || >> - (index == num_stripes - 1)) >> - list_move_tail(&device->dev_list, dev_list); >> + if (!convert) { >> + if (list_empty(&private_devs)) >> + return -ENODEV; >> + cur = private_devs.next; >> + device = list_entry(cur, struct btrfs_device, dev_list); >> + if (!(type & BTRFS_BLOCK_GROUP_DUP) || >> + (index == num_stripes - 1)) { >> + /* >> + * loop over this device again if we're doing a >> + * dup group >> + */ >> + list_move_tail(&device->dev_list, dev_list); >> + } >> + } else { >> + /* Only SINGLE is accepted in convert case */ >> + BUG_ON(num_stripes > 1); >> + device = list_entry(dev_list->next, struct btrfs_device, >> + dev_list); >> + key.offset = *start; >> + dev_offset = *start; >> + } >> ret = btrfs_alloc_dev_extent(trans, device, key.offset, >> - calc_size, &dev_offset, 0); >> + calc_size, &dev_offset, convert); >> if (ret < 0) >> goto out_chunk_map; >> @@ -1049,7 +1116,7 @@ again: >> memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE); >> index++; >> } >> - BUG_ON(!list_empty(&private_devs)); >> + BUG_ON(!convert && !list_empty(&private_devs)); >> /* key was set above */ >> btrfs_set_stack_chunk_length(chunk, *num_bytes); >> @@ -1069,6 +1136,9 @@ again: >> map->num_stripes = num_stripes; >> map->sub_stripes = sub_stripes; >> + /* >> + * Insert chunk item and chunk mapping. >> + */ >> ret = btrfs_insert_item(trans, chunk_root, &key, chunk, >> btrfs_chunk_item_size(num_stripes)); >> BUG_ON(ret); >> @@ -1098,125 +1168,6 @@ out_chunk: >> return ret; >> } >> -/* >> - * Alloc a DATA chunk with SINGLE profile. >> - * >> - * If 'convert' is set, it will alloc a chunk with 1:1 mapping >> - * (btrfs logical bytenr == on-disk bytenr) >> - * For that case, caller must make sure the chunk and dev_extent are not >> - * occupied. >> - */ >> -int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans, >> - struct btrfs_fs_info *info, u64 *start, >> - u64 num_bytes, u64 type, int convert) >> -{ >> - u64 dev_offset; >> - struct btrfs_root *extent_root = info->extent_root; >> - struct btrfs_root *chunk_root = info->chunk_root; >> - struct btrfs_stripe *stripes; >> - struct btrfs_device *device = NULL; >> - struct btrfs_chunk *chunk; >> - struct list_head *dev_list = &info->fs_devices->devices; >> - struct list_head *cur; >> - struct map_lookup *map; >> - u64 calc_size = SZ_8M; >> - int num_stripes = 1; >> - int sub_stripes = 0; >> - int ret; >> - int index; >> - int stripe_len = BTRFS_STRIPE_LEN; >> - struct btrfs_key key; >> - >> - key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; >> - key.type = BTRFS_CHUNK_ITEM_KEY; >> - if (convert) { >> - if (*start != round_down(*start, info->sectorsize)) { >> - error("DATA chunk start not sectorsize aligned: %llu", >> - (unsigned long long)*start); >> - return -EINVAL; >> - } >> - key.offset = *start; >> - dev_offset = *start; >> - } else { >> - u64 tmp; >> - >> - ret = find_next_chunk(info, &tmp); >> - key.offset = tmp; >> - if (ret) >> - return ret; >> - } >> - >> - chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS); >> - if (!chunk) >> - return -ENOMEM; >> - >> - map = kmalloc(btrfs_map_lookup_size(num_stripes), GFP_NOFS); >> - if (!map) { >> - kfree(chunk); >> - return -ENOMEM; >> - } >> - >> - stripes = &chunk->stripe; >> - calc_size = num_bytes; >> - >> - index = 0; >> - cur = dev_list->next; >> - device = list_entry(cur, struct btrfs_device, dev_list); >> - >> - while (index < num_stripes) { >> - struct btrfs_stripe *stripe; >> - >> - ret = btrfs_alloc_dev_extent(trans, device, key.offset, >> - calc_size, &dev_offset, convert); >> - BUG_ON(ret); >> - >> - device->bytes_used += calc_size; >> - ret = btrfs_update_device(trans, device); >> - BUG_ON(ret); >> - >> - map->stripes[index].dev = device; >> - map->stripes[index].physical = dev_offset; >> - stripe = stripes + index; >> - btrfs_set_stack_stripe_devid(stripe, device->devid); >> - btrfs_set_stack_stripe_offset(stripe, dev_offset); >> - memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE); >> - index++; >> - } >> - >> - /* key was set above */ >> - btrfs_set_stack_chunk_length(chunk, num_bytes); >> - btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid); >> - btrfs_set_stack_chunk_stripe_len(chunk, stripe_len); >> - btrfs_set_stack_chunk_type(chunk, type); >> - btrfs_set_stack_chunk_num_stripes(chunk, num_stripes); >> - btrfs_set_stack_chunk_io_align(chunk, stripe_len); >> - btrfs_set_stack_chunk_io_width(chunk, stripe_len); >> - btrfs_set_stack_chunk_sector_size(chunk, info->sectorsize); >> - btrfs_set_stack_chunk_sub_stripes(chunk, sub_stripes); >> - map->sector_size = info->sectorsize; >> - map->stripe_len = stripe_len; >> - map->io_align = stripe_len; >> - map->io_width = stripe_len; >> - map->type = type; >> - map->num_stripes = num_stripes; >> - map->sub_stripes = sub_stripes; >> - >> - ret = btrfs_insert_item(trans, chunk_root, &key, chunk, >> - btrfs_chunk_item_size(num_stripes)); >> - BUG_ON(ret); >> - if (!convert) >> - *start = key.offset; >> - >> - map->ce.start = key.offset; >> - map->ce.size = num_bytes; >> - >> - ret = insert_cache_extent(&info->mapping_tree.cache_tree, &map->ce); >> - BUG_ON(ret); >> - >> - kfree(chunk); >> - return ret; >> -} >> - >> int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 >> len) >> { >> struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; >> diff --git a/volumes.h b/volumes.h >> index 11572e78c04f..7bbdf615d31a 100644 >> --- a/volumes.h >> +++ b/volumes.h >> @@ -208,10 +208,7 @@ int btrfs_read_sys_array(struct btrfs_fs_info >> *fs_info); >> int btrfs_read_chunk_tree(struct btrfs_fs_info *fs_info); >> int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, >> struct btrfs_fs_info *fs_info, u64 *start, >> - u64 *num_bytes, u64 type); >> -int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans, >> - struct btrfs_fs_info *fs_info, u64 *start, >> - u64 num_bytes, u64 type, int convert); >> + u64 *num_bytes, u64 type, bool convert); >> int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, >> int flags); >> int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); >> > >
signature.asc
Description: OpenPGP digital signature