mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-25 21:24:08 +08: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
@ -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 New Issue
Block a user