diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c index 72fc9b3b6dc0..fa6e49a4ba37 100644 --- a/fs/btrfs/block-group.c +++ b/fs/btrfs/block-group.c @@ -1909,7 +1909,7 @@ static bool should_reclaim_block_group(const struct btrfs_block_group *bg, u64 b return true; } -static int btrfs_reclaim_block_group(struct btrfs_block_group *bg) +static int btrfs_reclaim_block_group(struct btrfs_block_group *bg, int *reclaimed) { struct btrfs_fs_info *fs_info = bg->fs_info; struct btrfs_space_info *space_info = bg->space_info; @@ -2036,15 +2036,18 @@ static int btrfs_reclaim_block_group(struct btrfs_block_group *bg) if (space_info->total_bytes < old_total) btrfs_set_periodic_reclaim_ready(space_info, true); spin_unlock(&space_info->lock); + if (!ret) + (*reclaimed)++; return ret; } -static void btrfs_reclaim_block_groups(struct btrfs_fs_info *fs_info) +void btrfs_reclaim_block_groups(struct btrfs_fs_info *fs_info, unsigned int limit) { struct btrfs_block_group *bg; struct btrfs_space_info *space_info; LIST_HEAD(retry_list); + int reclaimed = 0; if (!btrfs_should_reclaim(fs_info)) return; @@ -2080,7 +2083,7 @@ static void btrfs_reclaim_block_groups(struct btrfs_fs_info *fs_info) space_info = bg->space_info; spin_unlock(&fs_info->unused_bgs_lock); - ret = btrfs_reclaim_block_group(bg); + ret = btrfs_reclaim_block_group(bg, &reclaimed); if (ret && !READ_ONCE(space_info->periodic_reclaim)) btrfs_link_bg_list(bg, &retry_list); @@ -2099,6 +2102,8 @@ static void btrfs_reclaim_block_groups(struct btrfs_fs_info *fs_info) if (!mutex_trylock(&fs_info->reclaim_bgs_lock)) goto end; spin_lock(&fs_info->unused_bgs_lock); + if (reclaimed >= limit) + break; } spin_unlock(&fs_info->unused_bgs_lock); mutex_unlock(&fs_info->reclaim_bgs_lock); @@ -2114,7 +2119,7 @@ void btrfs_reclaim_bgs_work(struct work_struct *work) struct btrfs_fs_info *fs_info = container_of(work, struct btrfs_fs_info, reclaim_bgs_work); - btrfs_reclaim_block_groups(fs_info); + btrfs_reclaim_block_groups(fs_info, -1); } void btrfs_reclaim_bgs(struct btrfs_fs_info *fs_info) diff --git a/fs/btrfs/block-group.h b/fs/btrfs/block-group.h index c03e04292900..0504cb357992 100644 --- a/fs/btrfs/block-group.h +++ b/fs/btrfs/block-group.h @@ -350,6 +350,7 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans, struct btrfs_chunk_map *map); void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info); void btrfs_mark_bg_unused(struct btrfs_block_group *bg); +void btrfs_reclaim_block_groups(struct btrfs_fs_info *fs_info, unsigned int limit); void btrfs_reclaim_bgs_work(struct work_struct *work); void btrfs_reclaim_bgs(struct btrfs_fs_info *fs_info); void btrfs_mark_bg_to_reclaim(struct btrfs_block_group *bg); diff --git a/fs/btrfs/space-info.c b/fs/btrfs/space-info.c index 0e5274c3b988..e017bb182c8c 100644 --- a/fs/btrfs/space-info.c +++ b/fs/btrfs/space-info.c @@ -212,6 +212,8 @@ void btrfs_clear_space_info_full(struct btrfs_fs_info *info) #define BTRFS_UNALLOC_BLOCK_GROUP_TARGET (10ULL) +#define BTRFS_ZONED_SYNC_RECLAIM_BATCH (5) + /* * Calculate chunk size depending on volume type (regular or zoned). */ @@ -918,8 +920,8 @@ static void flush_space(struct btrfs_space_info *space_info, u64 num_bytes, if (btrfs_is_zoned(fs_info)) { btrfs_reclaim_sweep(fs_info); btrfs_delete_unused_bgs(fs_info); - btrfs_reclaim_bgs(fs_info); - flush_work(&fs_info->reclaim_bgs_work); + btrfs_reclaim_block_groups(fs_info, + BTRFS_ZONED_SYNC_RECLAIM_BATCH); ASSERT(current->journal_info == NULL); ret = btrfs_commit_current_transaction(root); } else {