@@ -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)
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 <libaokun@linux.alibaba.com> --- fs/ext4/mballoc.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)