Skip to content

Commit 2672a26

Browse files
adam900710kdave
authored andcommitted
btrfs: use per-profile available space in calc_available_free_space()
For the following disk layout, can_overcommit() can cause false confidence in available space: devid 1 unallocated: 1GiB devid 2 unallocated: 50GiB metadata type: RAID1 As can_overcommit() simply uses unallocated space with factor to calculate the allocatable metadata chunk size, resulting 25.5GiB available space. But in reality we can only allocate one 1GiB RAID1 chunk, the remaining 49GiB on devid 2 will never be utilized to fulfill a RAID1 chunk. This leads to various ENOSPC related transaction abort and flips the fs read-only. Now use per-profile available space in calc_available_free_space(), and only when that failed we fall back to the old factor based estimation. And for zoned devices or for the very low chance of temporary memory allocation failure, we will still fallback to factor based estimation. But I hope in reality it's very rare. Reviewed-by: Filipe Manana <[email protected]> Signed-off-by: Qu Wenruo <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent c84053d commit 2672a26

1 file changed

Lines changed: 15 additions & 12 deletions

File tree

fs/btrfs/space-info.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ static u64 calc_available_free_space(const struct btrfs_space_info *space_info,
444444
enum btrfs_reserve_flush_enum flush)
445445
{
446446
struct btrfs_fs_info *fs_info = space_info->fs_info;
447+
bool has_per_profile;
447448
u64 profile;
448449
u64 avail;
449450
u64 data_chunk_size;
@@ -454,19 +455,21 @@ static u64 calc_available_free_space(const struct btrfs_space_info *space_info,
454455
else
455456
profile = btrfs_metadata_alloc_profile(fs_info);
456457

457-
avail = atomic64_read(&fs_info->free_chunk_space);
458-
459-
/*
460-
* If we have dup, raid1 or raid10 then only half of the free
461-
* space is actually usable. For raid56, the space info used
462-
* doesn't include the parity drive, so we don't have to
463-
* change the math
464-
*/
465-
factor = btrfs_bg_type_to_factor(profile);
466-
avail = div_u64(avail, factor);
467-
if (avail == 0)
468-
return 0;
458+
has_per_profile = btrfs_get_per_profile_avail(fs_info, profile, &avail);
459+
if (!has_per_profile) {
460+
avail = atomic64_read(&fs_info->free_chunk_space);
469461

462+
/*
463+
* If we have dup, raid1 or raid10 then only half of the free
464+
* space is actually usable. For raid56, the space info used
465+
* doesn't include the parity drive, so we don't have to
466+
* change the math
467+
*/
468+
factor = btrfs_bg_type_to_factor(profile);
469+
avail = div_u64(avail, factor);
470+
if (avail == 0)
471+
return 0;
472+
}
470473
data_chunk_size = calc_effective_data_chunk_size(fs_info);
471474

472475
/*

0 commit comments

Comments
 (0)