mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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: afba2bc036 ("btrfs: zoned: implement active zone tracking")
Signed-off-by: Naohiro Aota <naohiro.aota@wdc.com>
Signed-off-by: David Sterba <dsterba@suse.com>
			
			
This commit is contained in:
		
							parent
							
								
									79417d040f
								
							
						
					
					
						commit
						b093151391
					
				
					 3 changed files with 93 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue