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 "ordered-data.h"
 | 
				
			||||||
#include "transaction.h"
 | 
					#include "transaction.h"
 | 
				
			||||||
#include "block-group.h"
 | 
					#include "block-group.h"
 | 
				
			||||||
 | 
					#include "zoned.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * HOW DOES SPACE RESERVATION WORK
 | 
					 * HOW DOES SPACE RESERVATION WORK
 | 
				
			||||||
| 
						 | 
					@ -724,6 +725,18 @@ static void flush_space(struct btrfs_fs_info *fs_info,
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case ALLOC_CHUNK:
 | 
						case ALLOC_CHUNK:
 | 
				
			||||||
	case ALLOC_CHUNK_FORCE:
 | 
						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);
 | 
							trans = btrfs_join_transaction(root);
 | 
				
			||||||
		if (IS_ERR(trans)) {
 | 
							if (IS_ERR(trans)) {
 | 
				
			||||||
			ret = PTR_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 :
 | 
									(state == ALLOC_CHUNK) ? CHUNK_ALLOC_NO_FORCE :
 | 
				
			||||||
					CHUNK_ALLOC_FORCE);
 | 
										CHUNK_ALLOC_FORCE);
 | 
				
			||||||
		btrfs_end_transaction(trans);
 | 
							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)
 | 
							if (ret > 0 || ret == -ENOSPC)
 | 
				
			||||||
			ret = 0;
 | 
								ret = 0;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2226,3 +2226,56 @@ int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret < 0 ? ret : 1;
 | 
						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,
 | 
					void btrfs_zoned_release_data_reloc_bg(struct btrfs_fs_info *fs_info, u64 logical,
 | 
				
			||||||
				       u64 length);
 | 
									       u64 length);
 | 
				
			||||||
int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info);
 | 
					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 */
 | 
					#else /* CONFIG_BLK_DEV_ZONED */
 | 
				
			||||||
static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
 | 
					static inline int btrfs_get_dev_zone(struct btrfs_device *device, u64 pos,
 | 
				
			||||||
				     struct blk_zone *zone)
 | 
									     struct blk_zone *zone)
 | 
				
			||||||
| 
						 | 
					@ -256,6 +258,14 @@ static inline int btrfs_zone_finish_one_bg(struct btrfs_fs_info *fs_info)
 | 
				
			||||||
	return 1;
 | 
						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
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)
 | 
					static inline bool btrfs_dev_is_sequential(struct btrfs_device *device, u64 pos)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue