Skip to content

Commit 03c7fc3

Browse files
Kemeng Shitytso
authored andcommitted
ext4: Separate block bitmap and buddy bitmap freeing in ext4_group_add_blocks()
This patch separates block bitmap and buddy bitmap freeing in order to update block bitmap with ext4_mb_mark_context in following patch. The reason why this can be sperated is explained in previous submit. Put the explanation here to simplify the code archeology to ext4_group_add_blocks(): Separated freeing is safe with concurrent allocation as long as: 1. Firstly allocate block in buddy bitmap, and then in block bitmap. 2. Firstly free block in block bitmap, and then buddy bitmap. Then freed block will only be available to allocation when both buddy bitmap and block bitmap are updated by freeing. Allocation obeys rule 1 already, just do sperated freeing with rule 2. Separated freeing has no race with generate_buddy as: Once ext4_mb_load_buddy_gfp is executed successfully, the update-to-date buddy page can be found in sbi->s_buddy_cache and no more buddy initialization of the buddy page will be executed concurrently until buddy page is unloaded. As we always do free in "load buddy, free, unload buddy" sequence, separated freeing has no race with generate_buddy. Signed-off-by: Kemeng Shi <[email protected]> Reviewed-by: "Ritesh Harjani (IBM)" <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Theodore Ts'o <[email protected]>
1 parent 38b8f70 commit 03c7fc3

File tree

1 file changed

+26
-28
lines changed

1 file changed

+26
-28
lines changed

fs/ext4/mballoc.c

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6650,35 +6650,39 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
66506650
ext4_warning(sb, "too many blocks added to group %u",
66516651
block_group);
66526652
err = -EINVAL;
6653-
goto error_return;
6653+
goto error_out;
6654+
}
6655+
6656+
err = ext4_mb_load_buddy(sb, block_group, &e4b);
6657+
if (err)
6658+
goto error_out;
6659+
6660+
if (!ext4_sb_block_valid(sb, NULL, block, count)) {
6661+
ext4_error(sb, "Adding blocks in system zones - "
6662+
"Block = %llu, count = %lu",
6663+
block, count);
6664+
err = -EINVAL;
6665+
goto error_clean;
66546666
}
66556667

66566668
bitmap_bh = ext4_read_block_bitmap(sb, block_group);
66576669
if (IS_ERR(bitmap_bh)) {
66586670
err = PTR_ERR(bitmap_bh);
66596671
bitmap_bh = NULL;
6660-
goto error_return;
6672+
goto error_clean;
66616673
}
66626674

66636675
desc = ext4_get_group_desc(sb, block_group, &gd_bh);
66646676
if (!desc) {
66656677
err = -EIO;
6666-
goto error_return;
6667-
}
6668-
6669-
if (!ext4_sb_block_valid(sb, NULL, block, count)) {
6670-
ext4_error(sb, "Adding blocks in system zones - "
6671-
"Block = %llu, count = %lu",
6672-
block, count);
6673-
err = -EINVAL;
6674-
goto error_return;
6678+
goto error_clean;
66756679
}
66766680

66776681
BUFFER_TRACE(bitmap_bh, "getting write access");
66786682
err = ext4_journal_get_write_access(handle, sb, bitmap_bh,
66796683
EXT4_JTR_NONE);
66806684
if (err)
6681-
goto error_return;
6685+
goto error_clean;
66826686

66836687
/*
66846688
* We are about to modify some metadata. Call the journal APIs
@@ -6688,7 +6692,7 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
66886692
BUFFER_TRACE(gd_bh, "get_write_access");
66896693
err = ext4_journal_get_write_access(handle, sb, gd_bh, EXT4_JTR_NONE);
66906694
if (err)
6691-
goto error_return;
6695+
goto error_clean;
66926696

66936697
for (i = 0, clusters_freed = 0; i < cluster_count; i++) {
66946698
BUFFER_TRACE(bitmap_bh, "clear bit");
@@ -6701,26 +6705,14 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
67016705
}
67026706
}
67036707

6704-
err = ext4_mb_load_buddy(sb, block_group, &e4b);
6705-
if (err)
6706-
goto error_return;
6707-
6708-
/*
6709-
* need to update group_info->bb_free and bitmap
6710-
* with group lock held. generate_buddy look at
6711-
* them with group lock_held
6712-
*/
67136708
ext4_lock_group(sb, block_group);
67146709
mb_clear_bits(bitmap_bh->b_data, bit, cluster_count);
6715-
mb_free_blocks(NULL, &e4b, bit, cluster_count);
67166710
free_clusters_count = clusters_freed +
67176711
ext4_free_group_clusters(sb, desc);
67186712
ext4_free_group_clusters_set(sb, desc, free_clusters_count);
67196713
ext4_block_bitmap_csum_set(sb, desc, bitmap_bh);
67206714
ext4_group_desc_csum_set(sb, block_group, desc);
67216715
ext4_unlock_group(sb, block_group);
6722-
percpu_counter_add(&sbi->s_freeclusters_counter,
6723-
clusters_freed);
67246716

67256717
if (sbi->s_log_groups_per_flex) {
67266718
ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
@@ -6729,8 +6721,6 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
67296721
flex_group)->free_clusters);
67306722
}
67316723

6732-
ext4_mb_unload_buddy(&e4b);
6733-
67346724
/* We dirtied the bitmap block */
67356725
BUFFER_TRACE(bitmap_bh, "dirtied bitmap block");
67366726
err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
@@ -6741,8 +6731,16 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
67416731
if (!err)
67426732
err = ret;
67436733

6744-
error_return:
6734+
ext4_lock_group(sb, block_group);
6735+
mb_free_blocks(NULL, &e4b, bit, cluster_count);
6736+
ext4_unlock_group(sb, block_group);
6737+
percpu_counter_add(&sbi->s_freeclusters_counter,
6738+
clusters_freed);
6739+
6740+
error_clean:
67456741
brelse(bitmap_bh);
6742+
ext4_mb_unload_buddy(&e4b);
6743+
error_out:
67466744
ext4_std_error(sb, err);
67476745
return err;
67486746
}

0 commit comments

Comments
 (0)