From: Qu Wenruo Date: Wed, 4 Feb 2026 02:54:07 +0000 (+1030) Subject: btrfs: update per-profile available estimation X-Git-Tag: v7.1-rc1~231^2~109 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c84053d9f7f758c79320716caa098cafc70a74da;p=thirdparty%2Fkernel%2Flinux.git btrfs: update per-profile available estimation This involves the following timing: - Chunk allocation - Chunk removal - After Mount - New device - Device removal - Device shrink - Device enlarge And since the function btrfs_update_per_profile_avail() will not return an error, this won't cause new error handling path. Although when btrfs_update_per_profile_avail() failed (only ENOSPC possible) it will mark the per-profile available estimation as unreliable, so later btrfs_get_per_profile_avail() will return false and require the caller to have a fallback solution. The function btrfs_update_per_profile_avail() will be executed with chunk_mutex hold, thus it will slightly slow down those involved functions, but not a lot. As all the core workload is just various u64 calculations inside a loop, without any tree search, the overhead should be acceptable even for all supported 9 profiles. For 4 disks (which exercises all 9 profiles), the execution time of that function will still be less than 10 us. Reviewed-by: Filipe Manana Signed-off-by: Qu Wenruo Signed-off-by: David Sterba --- diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 9eb07f48cf827..62e02cc1efc93 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -2340,6 +2340,7 @@ int btrfs_rm_device(struct btrfs_fs_info *fs_info, mutex_lock(&fs_info->chunk_mutex); list_del_init(&device->dev_alloc_list); device->fs_devices->rw_devices--; + btrfs_update_per_profile_avail(fs_info); mutex_unlock(&fs_info->chunk_mutex); } @@ -2451,6 +2452,7 @@ error_undo: list_add(&device->dev_alloc_list, &fs_devices->alloc_list); device->fs_devices->rw_devices++; + btrfs_update_per_profile_avail(fs_info); mutex_unlock(&fs_info->chunk_mutex); } return ret; @@ -2938,6 +2940,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path */ btrfs_clear_space_info_full(fs_info); + btrfs_update_per_profile_avail(fs_info); mutex_unlock(&fs_info->chunk_mutex); /* Add sysfs device entry */ @@ -2948,6 +2951,7 @@ int btrfs_init_new_device(struct btrfs_fs_info *fs_info, const char *device_path if (seeding_dev) { mutex_lock(&fs_info->chunk_mutex); ret = init_first_rw_device(trans); + btrfs_update_per_profile_avail(fs_info); mutex_unlock(&fs_info->chunk_mutex); if (unlikely(ret)) { btrfs_abort_transaction(trans, ret); @@ -3030,6 +3034,7 @@ error_sysfs: orig_super_total_bytes); btrfs_set_super_num_devices(fs_info->super_copy, orig_super_num_devices); + btrfs_update_per_profile_avail(fs_info); mutex_unlock(&fs_info->chunk_mutex); mutex_unlock(&fs_info->fs_devices->device_list_mutex); error_trans: @@ -3122,6 +3127,7 @@ int btrfs_grow_device(struct btrfs_trans_handle *trans, if (list_empty(&device->post_commit_list)) list_add_tail(&device->post_commit_list, &trans->transaction->dev_update_list); + btrfs_update_per_profile_avail(fs_info); mutex_unlock(&fs_info->chunk_mutex); btrfs_reserve_chunk_metadata(trans, false); @@ -3498,6 +3504,7 @@ int btrfs_remove_chunk(struct btrfs_trans_handle *trans, u64 chunk_offset) } } + btrfs_update_per_profile_avail(fs_info); mutex_unlock(&fs_info->chunk_mutex); trans->removing_chunk = false; @@ -5201,6 +5208,7 @@ int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) atomic64_sub(free_diff, &fs_info->free_chunk_space); } + btrfs_update_per_profile_avail(fs_info); /* * Once the device's size has been set to the new size, ensure all * in-memory chunks are synced to disk so that the loop below sees them @@ -5316,6 +5324,7 @@ again: WARN_ON(diff > old_total); btrfs_set_super_total_bytes(super_copy, round_down(old_total - diff, fs_info->sectorsize)); + btrfs_update_per_profile_avail(fs_info); mutex_unlock(&fs_info->chunk_mutex); btrfs_reserve_chunk_metadata(trans, false); @@ -6028,6 +6037,8 @@ static struct btrfs_block_group *create_chunk(struct btrfs_trans_handle *trans, check_raid56_incompat_flag(info, type); check_raid1c34_incompat_flag(info, type); + btrfs_update_per_profile_avail(info); + return block_group; } @@ -8603,7 +8614,14 @@ int btrfs_verify_dev_extents(struct btrfs_fs_info *fs_info) } /* Ensure all chunks have corresponding dev extents */ - return verify_chunk_dev_extent_mapping(fs_info); + ret = verify_chunk_dev_extent_mapping(fs_info); + if (ret < 0) + return ret; + + mutex_lock(&fs_info->chunk_mutex); + btrfs_update_per_profile_avail(fs_info); + mutex_unlock(&fs_info->chunk_mutex); + return 0; } /*