Use ext4_block_bitmap_csum_set_range() in ext4_mb_mark_context() for fast incremental block bitmap checksum updates. Instead of re-scanning the entire bitmap after every allocation or free, the incremental update computes the CRC delta for the modified bit range in O(log N) time. Add a fast_crc flag that is set when EXT4_MB_BITMAP_MARKED_CHECK is not used. When fast_crc is true, all bits in the range are guaranteed to flip, so the incremental CRC via ext4_block_bitmap_csum_set_range() is correct. Otherwise, fall back to ext4_block_bitmap_csum_set() for a full CRC recalculation, since idempotent operations (mb_set_bits/mb_clear_bits with EXT4_MB_BITMAP_MARKED_CHECK) may leave some bits unchanged. For the BLOCK_UNINIT case, the bitmap was just initialized and there is no valid old checksum, so fast_crc is forced to false to ensure a full CRC recalculation establishes a correct baseline. Signed-off-by: Baokun Li --- fs/ext4/mballoc.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index ff2023c9f52c..77f6309916d1 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -4095,6 +4095,7 @@ ext4_mb_mark_context(handle_t *handle, struct super_block *sb, bool state, struct buffer_head *gdp_bh; int err; unsigned int i, already, changed = len; + bool fast_crc; KUNIT_STATIC_STUB_REDIRECT(ext4_mb_mark_context, handle, sb, state, group, blkoff, len, @@ -4127,12 +4128,28 @@ ext4_mb_mark_context(handle_t *handle, struct super_block *sb, bool state, goto out_err; } + /* + * fast_crc: Use incremental CRC update via crc32c_flip_range(). + * This is only valid when all bits in [blkoff, blkoff+len) are + * guaranteed to be in the opposite state (i.e., every bit will + * actually flip). When EXT4_MB_BITMAP_MARKED_CHECK is set, + * mb_set_bits/mb_clear_bits are idempotent, so some bits may not + * change and incremental CRC would produce incorrect results. + */ + fast_crc = !(flags & EXT4_MB_BITMAP_MARKED_CHECK); + ext4_lock_group(sb, group); if (ext4_has_group_desc_csum(sb) && (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT))) { gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); ext4_free_group_clusters_set(sb, gdp, ext4_free_clusters_after_init(sb, group, gdp)); + /* + * The bitmap was just initialized, so the old checksum + * is invalid for incremental CRC update. Fall back to + * full recalculation. + */ + fast_crc = false; } if (flags & EXT4_MB_BITMAP_MARKED_CHECK) { @@ -4154,7 +4171,10 @@ ext4_mb_mark_context(handle_t *handle, struct super_block *sb, bool state, ext4_free_group_clusters(sb, gdp) + changed); } - ext4_block_bitmap_csum_set(sb, gdp, bitmap_bh); + if (fast_crc) + ext4_block_bitmap_csum_set_range(sb, gdp, blkoff, len); + else + ext4_block_bitmap_csum_set(sb, gdp, bitmap_bh); ext4_group_desc_csum_set(sb, group, gdp); ext4_unlock_group(sb, group); if (ret_changed) -- 2.43.7