Commit 8eae532b authored by Naohiro Aota's avatar Naohiro Aota Committed by David Sterba

btrfs: zoned: load zone capacity information from devices

The ZNS specification introduces the concept of a Zone Capacity.  A zone
capacity is an additional per-zone attribute that indicates the number of
usable logical blocks within each zone, starting from the first logical
block of each zone. It is always smaller or equal to the zone size.

With the SINGLE profile, we can set a block group's "capacity" as the same
as the underlying zone's Zone Capacity. We will limit the allocation not
to exceed in a following commit.
Reviewed-by: default avatarJohannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: default avatarNaohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent c22a3572
...@@ -202,6 +202,7 @@ struct btrfs_block_group { ...@@ -202,6 +202,7 @@ struct btrfs_block_group {
*/ */
u64 alloc_offset; u64 alloc_offset;
u64 zone_unusable; u64 zone_unusable;
u64 zone_capacity;
u64 meta_write_pointer; u64 meta_write_pointer;
}; };
......
...@@ -1039,6 +1039,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ...@@ -1039,6 +1039,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
int i; int i;
unsigned int nofs_flag; unsigned int nofs_flag;
u64 *alloc_offsets = NULL; u64 *alloc_offsets = NULL;
u64 *caps = NULL;
u64 last_alloc = 0; u64 last_alloc = 0;
u32 num_sequential = 0, num_conventional = 0; u32 num_sequential = 0, num_conventional = 0;
...@@ -1069,6 +1070,12 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ...@@ -1069,6 +1070,12 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
return -ENOMEM; return -ENOMEM;
} }
caps = kcalloc(map->num_stripes, sizeof(*caps), GFP_NOFS);
if (!caps) {
ret = -ENOMEM;
goto out;
}
for (i = 0; i < map->num_stripes; i++) { for (i = 0; i < map->num_stripes; i++) {
bool is_sequential; bool is_sequential;
struct blk_zone zone; struct blk_zone zone;
...@@ -1131,6 +1138,8 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ...@@ -1131,6 +1138,8 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
goto out; goto out;
} }
caps[i] = (zone.capacity << SECTOR_SHIFT);
switch (zone.cond) { switch (zone.cond) {
case BLK_ZONE_COND_OFFLINE: case BLK_ZONE_COND_OFFLINE:
case BLK_ZONE_COND_READONLY: case BLK_ZONE_COND_READONLY:
...@@ -1144,7 +1153,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ...@@ -1144,7 +1153,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
alloc_offsets[i] = 0; alloc_offsets[i] = 0;
break; break;
case BLK_ZONE_COND_FULL: case BLK_ZONE_COND_FULL:
alloc_offsets[i] = fs_info->zone_size; alloc_offsets[i] = caps[i];
break; break;
default: default:
/* Partially used zone */ /* Partially used zone */
...@@ -1169,6 +1178,9 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ...@@ -1169,6 +1178,9 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
* calculate_alloc_pointer() which takes extent buffer * calculate_alloc_pointer() which takes extent buffer
* locks to avoid deadlock. * locks to avoid deadlock.
*/ */
/* Zone capacity is always zone size in emulation */
cache->zone_capacity = cache->length;
if (new) { if (new) {
cache->alloc_offset = 0; cache->alloc_offset = 0;
goto out; goto out;
...@@ -1195,6 +1207,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ...@@ -1195,6 +1207,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
goto out; goto out;
} }
cache->alloc_offset = alloc_offsets[0]; cache->alloc_offset = alloc_offsets[0];
cache->zone_capacity = caps[0];
break; break;
case BTRFS_BLOCK_GROUP_DUP: case BTRFS_BLOCK_GROUP_DUP:
case BTRFS_BLOCK_GROUP_RAID1: case BTRFS_BLOCK_GROUP_RAID1:
...@@ -1218,6 +1231,14 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ...@@ -1218,6 +1231,14 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
ret = -EIO; ret = -EIO;
} }
if (cache->alloc_offset > cache->zone_capacity) {
btrfs_err(fs_info,
"zoned: invalid write pointer %llu (larger than zone capacity %llu) in block group %llu",
cache->alloc_offset, cache->zone_capacity,
cache->start);
ret = -EIO;
}
/* An extent is allocated after the write pointer */ /* An extent is allocated after the write pointer */
if (!ret && num_conventional && last_alloc > cache->alloc_offset) { if (!ret && num_conventional && last_alloc > cache->alloc_offset) {
btrfs_err(fs_info, btrfs_err(fs_info,
...@@ -1229,6 +1250,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new) ...@@ -1229,6 +1250,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
if (!ret) if (!ret)
cache->meta_write_pointer = cache->alloc_offset + cache->start; cache->meta_write_pointer = cache->alloc_offset + cache->start;
kfree(caps);
kfree(alloc_offsets); kfree(alloc_offsets);
free_extent_map(em); free_extent_map(em);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment