Commit b0931513 authored by Naohiro Aota's avatar Naohiro Aota Committed by David Sterba
Browse files

btrfs: zoned: activate metadata block group on flush_space



For metadata space on zoned filesystem, reaching ALLOC_CHUNK{,_FORCE}
means we don't have enough space left in the active_total_bytes. Before
allocating a new chunk, we can try to activate an existing block group
in this case.

Also, allocating a chunk is not enough to grant a ticket for metadata
space on zoned filesystem we need to activate the block group to
increase the active_total_bytes.

btrfs_zoned_activate_one_bg() implements the activation feature. It will
activate a block group by (maybe) finishing a block group. It will give up
activating a block group if it cannot finish any block group.

CC: stable@vger.kernel.org # 5.16+
Fixes: afba2bc0 ("btrfs: zoned: implement active zone tracking")
Signed-off-by: default avatarNaohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent 79417d04
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include "ordered-data.h"
#include "transaction.h"
#include "block-group.h"
#include "zoned.h"

/*
 * HOW DOES SPACE RESERVATION WORK
@@ -724,6 +725,18 @@ static void flush_space(struct btrfs_fs_info *fs_info,
		break;
	case ALLOC_CHUNK:
	case ALLOC_CHUNK_FORCE:
		/*
		 * For metadata space on zoned filesystem, reaching here means we
		 * don't have enough space left in active_total_bytes. Try to
		 * activate a block group first, because we may have inactive
		 * block group already allocated.
		 */
		ret = btrfs_zoned_activate_one_bg(fs_info, space_info, false);
		if (ret < 0)
			break;
		else if (ret == 1)
			break;

		trans = btrfs_join_transaction(root);
		if (IS_ERR(trans)) {
			ret = PTR_ERR(trans);
@@ -734,6 +747,23 @@ static void flush_space(struct btrfs_fs_info *fs_info,
				(state == ALLOC_CHUNK) ? CHUNK_ALLOC_NO_FORCE :
					CHUNK_ALLOC_FORCE);
		btrfs_end_transaction(trans);

		/*
		 * For metadata space on zoned filesystem, allocating a new chunk
		 * is not enough. We still need to activate the block * group.
		 * Active the newly allocated block group by (maybe) finishing
		 * a block group.
		 */
		if (ret == 1) {
			ret = btrfs_zoned_activate_one_bg(fs_info, space_info, true);
			/*
			 * Revert to the original ret regardless we could finish
			 * one block group or not.
			 */
			if (ret >= 0)
				ret = 1;
		}

		if (ret > 0 || ret == -ENOSPC)
			ret = 0;
		break;
+53 −0
Original line number Diff line number Diff line
@@ -2226,3 +2226,56 @@ int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)

	return ret < 0 ? ret : 1;
}

int btrfs_zoned_activate_one_bg(struct btrfs_fs_info *fs_info,
				struct btrfs_space_info *space_info,
				bool do_finish)
{
	struct btrfs_block_group *bg;
	int index;

	if (!btrfs_is_zoned(fs_info) || (space_info->flags & BTRFS_BLOCK_GROUP_DATA))
		return 0;

	/* No more block groups to activate */
	if (space_info->active_total_bytes == space_info->total_bytes)
		return 0;

	for (;;) {
		int ret;
		bool need_finish = false;

		down_read(&space_info->groups_sem);
		for (index = 0; index < BTRFS_NR_RAID_TYPES; index++) {
			list_for_each_entry(bg, &space_info->block_groups[index],
					    list) {
				if (!spin_trylock(&bg->lock))
					continue;
				if (btrfs_zoned_bg_is_full(bg) || bg->zone_is_active) {
					spin_unlock(&bg->lock);
					continue;
				}
				spin_unlock(&bg->lock);

				if (btrfs_zone_activate(bg)) {
					up_read(&space_info->groups_sem);
					return 1;
				}

				need_finish = true;
			}
		}
		up_read(&space_info->groups_sem);

		if (!do_finish || !need_finish)
			break;

		ret = btrfs_zone_finish_one_bg(fs_info);
		if (ret == 0)
			break;
		if (ret < 0)
			return ret;
	}

	return 0;
}
+10 −0
Original line number Diff line number Diff line
@@ -81,6 +81,8 @@ bool btrfs_zoned_should_reclaim(struct btrfs_fs_info *fs_info);
void btrfs_zoned_release_data_reloc_bg(struct btrfs_fs_info *fs_info, u64 logical,
				       u64 length);
int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info);
int btrfs_zoned_activate_one_bg(struct btrfs_fs_info *fs_info,
				struct btrfs_space_info *space_info, bool do_finish);
#else /* CONFIG_BLK_DEV_ZONED */
static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
				     struct blk_zone *zone)
@@ -256,6 +258,14 @@ static inline int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)
	return 1;
}

static inline int btrfs_zoned_activate_one_bg(struct btrfs_fs_info *fs_info,
					      struct btrfs_space_info *space_info,
					      bool do_finish)
{
	/* Consider all the block groups are active */
	return 0;
}

#endif

static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)