Skip to content

Commit

Permalink
btrfs: zoned: load zone capacity information from devices
Browse files Browse the repository at this point in the history
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: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
Naohiro Aota authored and David Sterba committed Oct 26, 2021
1 parent c22a357 commit 8eae532
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 1 deletion.
1 change: 1 addition & 0 deletions fs/btrfs/block-group.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ struct btrfs_block_group {
*/
u64 alloc_offset;
u64 zone_unusable;
u64 zone_capacity;
u64 meta_write_pointer;
};

Expand Down
24 changes: 23 additions & 1 deletion fs/btrfs/zoned.c
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
int i;
unsigned int nofs_flag;
u64 *alloc_offsets = NULL;
u64 *caps = NULL;
u64 last_alloc = 0;
u32 num_sequential = 0, num_conventional = 0;

Expand Down Expand Up @@ -1069,6 +1070,12 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
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++) {
bool is_sequential;
struct blk_zone zone;
Expand Down Expand Up @@ -1131,6 +1138,8 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
goto out;
}

caps[i] = (zone.capacity << SECTOR_SHIFT);

switch (zone.cond) {
case BLK_ZONE_COND_OFFLINE:
case BLK_ZONE_COND_READONLY:
Expand All @@ -1144,7 +1153,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
alloc_offsets[i] = 0;
break;
case BLK_ZONE_COND_FULL:
alloc_offsets[i] = fs_info->zone_size;
alloc_offsets[i] = caps[i];
break;
default:
/* Partially used zone */
Expand All @@ -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
* locks to avoid deadlock.
*/

/* Zone capacity is always zone size in emulation */
cache->zone_capacity = cache->length;
if (new) {
cache->alloc_offset = 0;
goto out;
Expand All @@ -1195,6 +1207,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
goto out;
}
cache->alloc_offset = alloc_offsets[0];
cache->zone_capacity = caps[0];
break;
case BTRFS_BLOCK_GROUP_DUP:
case BTRFS_BLOCK_GROUP_RAID1:
Expand All @@ -1218,6 +1231,14 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
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 */
if (!ret && num_conventional && last_alloc > cache->alloc_offset) {
btrfs_err(fs_info,
Expand All @@ -1229,6 +1250,7 @@ int btrfs_load_block_group_zone_info(struct btrfs_block_group *cache, bool new)
if (!ret)
cache->meta_write_pointer = cache->alloc_offset + cache->start;

kfree(caps);
kfree(alloc_offsets);
free_extent_map(em);

Expand Down

0 comments on commit 8eae532

Please sign in to comment.