diff mbox series

[RFC,07/17] ext4: use fast incremental CRC update in ext4_mb_mark_context()

Message ID 20260508121539.4174601-8-libaokun@linux.alibaba.com
State Changes Requested
Headers show
Series ext4/lib-crc: LBS performance part 1 - incremental CRC32c for bitmap checksums | expand

Commit Message

Baokun Li May 8, 2026, 12:15 p.m. UTC
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(-)
diff mbox series

Patch

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)