btrfs-progs: rewrite btrfs_alloc_data_chunk() using create_chunk()

btrfs_alloc_data_chunk() and create_chunk() have the most part in common.
Let's rewrite btrfs_alloc_data_chunk() using create_chunk().

There are two differences between btrfs_alloc_data_chunk() and
create_chunk(). create_chunk() uses find_next_chunk() to decide the
logical address of the chunk, and it uses btrfs_alloc_dev_extent() to
decide the physical address of a device extent. On the other hand,
btrfs_alloc_data_chunk() uses *start for both logical and physical
addresses.

To support the btrfs_alloc_data_chunk()'s use case, we use ctl->start
and ctl->dev_offset. If these values are set (non-zero), use the
specified values as the address. It is safe to use 0 to indicate the
value is not set here. Because both lower addresses of logical

  (0..BTRFS_FIRST_CHUNK_TREE_OBJECT_ID) and physical
  (0..BTRFS_BLOCK_RESERVED_1M_FOR_SUPER) are reserved.

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Naohiro Aota 2021-04-06 17:05:49 +09:00 committed by David Sterba
parent 1e344dc8cf
commit 13a6cff8b6
1 changed files with 43 additions and 93 deletions

View File

@ -161,6 +161,7 @@ struct alloc_chunk_ctl {
u64 max_chunk_size;
int stripe_len;
int total_devs;
u64 dev_offset;
};
struct stripe {
@ -1058,6 +1059,7 @@ static void init_alloc_chunk_ctl(struct btrfs_fs_info *info,
ctl->max_chunk_size = 4 * ctl->calc_size;
ctl->stripe_len = BTRFS_STRIPE_LEN;
ctl->total_devs = btrfs_super_num_devices(info->super_copy);
ctl->dev_offset = 0;
switch (info->fs_devices->chunk_alloc_policy) {
case BTRFS_CHUNK_ALLOC_REGULAR:
@ -1137,9 +1139,14 @@ static int create_chunk(struct btrfs_trans_handle *trans,
struct btrfs_key key;
u64 offset;
ret = find_next_chunk(info, &offset);
if (ret)
return ret;
if (!ctl->start) {
ret = find_next_chunk(info, &offset);
if (ret)
return ret;
} else {
offset = ctl->start;
}
key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
key.type = BTRFS_CHUNK_ITEM_KEY;
key.offset = offset;
@ -1170,10 +1177,18 @@ static int create_chunk(struct btrfs_trans_handle *trans,
(index == ctl->num_stripes - 1))
list_move(&device->dev_list, dev_list);
ret = btrfs_alloc_dev_extent(trans, device, key.offset,
ctl->calc_size, &dev_offset);
if (ret < 0)
goto out_chunk_map;
if (!ctl->dev_offset) {
ret = btrfs_alloc_dev_extent(trans, device, key.offset,
ctl->calc_size, &dev_offset);
if (ret < 0)
goto out_chunk_map;
} else {
dev_offset = ctl->dev_offset;
ret = btrfs_insert_dev_extent(trans, device, key.offset,
ctl->calc_size,
ctl->dev_offset);
BUG_ON(ret);
}
device->bytes_used += ctl->calc_size;
ret = btrfs_update_device(trans, device);
@ -1330,23 +1345,10 @@ again:
int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans,
struct btrfs_fs_info *info, u64 *start, u64 num_bytes)
{
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 = 1;
int ret;
int index;
int stripe_len = BTRFS_STRIPE_LEN;
struct btrfs_key key;
struct list_head private_devs;
struct btrfs_device *device;
struct alloc_chunk_ctl ctl;
if (*start != round_down(*start, info->sectorsize)) {
error("DATA chunk start not sectorsize aligned: %llu",
@ -1354,78 +1356,26 @@ int btrfs_alloc_data_chunk(struct btrfs_trans_handle *trans,
return -EINVAL;
}
key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID;
key.type = BTRFS_CHUNK_ITEM_KEY;
key.offset = *start;
dev_offset = *start;
ctl.start = *start;
ctl.type = BTRFS_BLOCK_GROUP_DATA;
ctl.num_stripes = 1;
ctl.max_stripes = 1;
ctl.min_stripes = 1;
ctl.sub_stripes = 1;
ctl.calc_size = num_bytes;
ctl.min_stripe_size = num_bytes;
ctl.num_bytes = num_bytes;
ctl.max_chunk_size = num_bytes;
ctl.stripe_len = BTRFS_STRIPE_LEN;
ctl.total_devs = btrfs_super_num_devices(info->super_copy);
ctl.dev_offset = *start;
chunk = kmalloc(btrfs_chunk_item_size(num_stripes), GFP_NOFS);
if (!chunk)
return -ENOMEM;
INIT_LIST_HEAD(&private_devs);
/* Build a list containing one device */
device = list_entry(dev_list->next, struct btrfs_device, dev_list);
list_move(&device->dev_list, &private_devs);
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_insert_dev_extent(trans, device, key.offset, calc_size,
dev_offset);
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, BTRFS_BLOCK_GROUP_DATA);
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 = BTRFS_BLOCK_GROUP_DATA;
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);
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;
return create_chunk(trans, info, &ctl, &private_devs);
}
int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len)