To facilitate support for zoned block devices in the extent buffer allocation, a zoned block device chunk is always aligned to a zone of the device. With this, the zone write pointer location simply becomes a hint to allocate new buffers. Signed-off-by: Naohiro Aota <naohiro.aota@xxxxxxx> --- volumes.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/volumes.c b/volumes.c index f6d1b1e9dc7f..64b42643390b 100644 --- a/volumes.c +++ b/volumes.c @@ -399,6 +399,34 @@ int btrfs_scan_one_device(int fd, const char *path, return ret; } +/* zone size is ensured to be power of 2 */ +static u64 btrfs_zone_align(struct btrfs_zone_info *zinfo, u64 val) +{ + if (zinfo && zinfo->zone_size) + return (val + zinfo->zone_size - 1) & ~(zinfo->zone_size - 1); + return val; +} + +static bool check_dev_zone(struct btrfs_zone_info *zinfo, u64 physical, + u64 num_bytes) +{ + u64 zone_size = zinfo->zone_size; + int zone_is_random; + + WARN_ON(!IS_ALIGNED(num_bytes, zone_size)); + zone_is_random = zone_is_random_write(zinfo, physical); + + while (num_bytes) { + if (zone_is_random != zone_is_random_write(zinfo, physical)) + return false; + + physical += zone_size; + num_bytes -= zone_size; + } + + return true; +} + /* * find_free_dev_extent_start - find free space in the specified device * @device: the device which we search the free space in @@ -428,6 +456,7 @@ static int find_free_dev_extent_start(struct btrfs_device *device, struct btrfs_root *root = device->dev_root; struct btrfs_dev_extent *dev_extent; struct btrfs_path *path; + struct btrfs_zone_info *zinfo = &device->zinfo; u64 hole_size; u64 max_hole_start; u64 max_hole_size; @@ -445,6 +474,7 @@ static int find_free_dev_extent_start(struct btrfs_device *device, */ min_search_start = max(root->fs_info->alloc_start, (u64)SZ_1M); search_start = max(search_start, min_search_start); + search_start = btrfs_zone_align(zinfo, search_start); path = btrfs_alloc_path(); if (!path) @@ -497,6 +527,18 @@ static int find_free_dev_extent_start(struct btrfs_device *device, goto next; if (key.offset > search_start) { + if (zinfo && zinfo->zone_size) { + while (key.offset > search_start) { + hole_size = key.offset - search_start; + if (hole_size < num_bytes) + break; + if (check_dev_zone(zinfo, search_start, + num_bytes)) + break; + search_start += zinfo->zone_size; + } + } + hole_size = key.offset - search_start; /* @@ -527,7 +569,8 @@ static int find_free_dev_extent_start(struct btrfs_device *device, extent_end = key.offset + btrfs_dev_extent_length(l, dev_extent); if (extent_end > search_start) - search_start = extent_end; + search_start = btrfs_zone_align(&device->zinfo, + extent_end); next: path->slots[0]++; cond_resched(); @@ -539,6 +582,18 @@ next: * search_end may be smaller than search_start. */ if (search_end > search_start) { + if (zinfo && zinfo->zone_size) { + while (search_end > search_start) { + hole_size = search_end - search_start; + if (hole_size < num_bytes) + break; + if (check_dev_zone(zinfo, search_start, + num_bytes)) + break; + search_start += zinfo->zone_size; + } + } + hole_size = search_end - search_start; if (hole_size > max_hole_size) { @@ -582,6 +637,9 @@ int btrfs_insert_dev_extent(struct btrfs_trans_handle *trans, struct extent_buffer *leaf; struct btrfs_key key; + /* Align to zone for a zoned block device */ + start = btrfs_zone_align(&device->zinfo, start); + path = btrfs_alloc_path(); if (!path) return -ENOMEM; @@ -1065,9 +1123,15 @@ int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, btrfs_super_stripesize(info->super_copy)); } - /* we don't want a chunk larger than 10% of the FS */ - percent_max = div_factor(btrfs_super_total_bytes(info->super_copy), 1); - max_chunk_size = min(percent_max, max_chunk_size); + if (info->fs_devices->hmzoned) { + /* Zoned mode uses zone aligned chunks */ + calc_size = info->fs_devices->zone_size; + max_chunk_size = calc_size * num_stripes; + } else { + /* we don't want a chunk larger than 10% of the FS */ + percent_max = div_factor(btrfs_super_total_bytes(info->super_copy), 1); + max_chunk_size = min(percent_max, max_chunk_size); + } again: if (chunk_bytes_by_type(type, calc_size, num_stripes, sub_stripes) > @@ -1147,7 +1211,9 @@ again: *num_bytes = chunk_bytes_by_type(type, calc_size, num_stripes, sub_stripes); index = 0; + dev_offset = 0; while(index < num_stripes) { + size_t zone_size = device->zinfo.zone_size; struct btrfs_stripe *stripe; BUG_ON(list_empty(&private_devs)); cur = private_devs.next; @@ -1158,11 +1224,16 @@ again: (index == num_stripes - 1)) list_move_tail(&device->dev_list, dev_list); + if (device->zinfo.zone_size) + calc_size = device->zinfo.zone_size; + ret = btrfs_alloc_dev_extent(trans, device, key.offset, calc_size, &dev_offset); if (ret < 0) goto out_chunk_map; + WARN_ON(zone_size && !IS_ALIGNED(dev_offset, zone_size)); + device->bytes_used += calc_size; ret = btrfs_update_device(trans, device); if (ret < 0) -- 2.21.0