@@ -1867,6 +1867,35 @@ int btrfs_sync_zone_write_pointer(struct btrfs_device *tgt_dev, u64 logical,
return btrfs_zoned_issue_zeroout(tgt_dev, physical_pos, length);
}
+/*
+ * Number of active zones reserved for one metadata block group and one
+ * system block group.
+ */
+static int reserved_zones(struct btrfs_fs_info *fs_info)
+{
+ const u64 flags[] = {BTRFS_BLOCK_GROUP_METADATA, BTRFS_BLOCK_GROUP_SYSTEM};
+ int reserved = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(flags); i++) {
+ u64 profile = btrfs_get_alloc_profile(fs_info, flags[i]);
+
+ switch (profile) {
+ case 0: /* single */
+ reserved += 1;
+ break;
+ case BTRFS_BLOCK_GROUP_DUP:
+ reserved += 2;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ }
+
+ return reserved;
+}
+
/*
* Activate block group and underlying device zones
*
@@ -1880,6 +1909,8 @@ bool btrfs_zone_activate(struct btrfs_block_group *block_group)
struct btrfs_space_info *space_info = block_group->space_info;
struct map_lookup *map;
struct btrfs_device *device;
+ const int reserved = (block_group->flags & BTRFS_BLOCK_GROUP_DATA) ?
+ reserved_zones(fs_info) : 0;
u64 physical;
bool ret;
int i;
@@ -1909,6 +1940,15 @@ bool btrfs_zone_activate(struct btrfs_block_group *block_group)
if (device->zone_info->max_active_zones == 0)
continue;
+ /*
+ * For the data block group, leave active zones for one
+ * metadata block group and one system block group.
+ */
+ if (atomic_read(&device->zone_info->active_zones_left) <= reserved) {
+ ret = false;
+ goto out_unlock;
+ }
+
if (!btrfs_dev_set_active_zone(device, physical)) {
/* Cannot activate the zone */
ret = false;
@@ -2103,6 +2143,8 @@ bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, u64 flags)
{
struct btrfs_fs_info *fs_info = fs_devices->fs_info;
struct btrfs_device *device;
+ const int reserved = (flags & BTRFS_BLOCK_GROUP_DATA) ?
+ reserved_zones(fs_info) : 0;
bool ret = false;
if (!btrfs_is_zoned(fs_info))
@@ -2123,10 +2165,10 @@ bool btrfs_can_activate_zone(struct btrfs_fs_devices *fs_devices, u64 flags)
switch (flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) {
case 0: /* single */
- ret = (atomic_read(&zinfo->active_zones_left) >= 1);
+ ret = (atomic_read(&zinfo->active_zones_left) >= (1 + reserved));
break;
case BTRFS_BLOCK_GROUP_DUP:
- ret = (atomic_read(&zinfo->active_zones_left) >= 2);
+ ret = (atomic_read(&zinfo->active_zones_left) >= (2 + reserved));
break;
}
if (ret)
Ensure a metadata and system block group can be activated on write time, by leaving a certain number of active zones when trying to activate a data block group. Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com> --- fs/btrfs/zoned.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-)