From 621c2bcb87548ff6fe7ec1116f9b27ed87fbeb48 Mon Sep 17 00:00:00 2001 From: Matthias Goergens Date: Wed, 5 Aug 2026 19:39:20 +0800 Subject: [PATCH] ocfs2: fix cached cluster count after suballocator reclaim When reclaiming a suballocator block group, first reduce the on-disk cluster count by cl_cpg. The current code then subtracts that new count (fe->i_clusters) from the old cached count (OCFS2_I(alloc_inode)->ip_clusters). For an allocator with N block groups, that leaves the cache at N * cl_cpg - (N * cl_cpg - cl_cpg) = cl_cpg i.e. ip_clusters -= (fe->i_clusters - cl_cpg) leaves ip_clusters equal to cl_cpg regardless of N. This happens to be correct when reclaiming from two block groups, but undercounts the clusters from three block groups onwards. The incorrect cache value is also used immediately to update i_blocks. Assign the updated on-disk count to the cache, matching the allocation and inode refresh paths. In a QEMU test using a clean 256 MiB OCFS2 image and a 10,000-file create/delete workload, the first buggy reclaim left the on-disk (fe->i_clusters) and cached (ip_clusters) counts at 2048 and 512 clusters respectively; later reclaims underflowed the cache. With this change, the cache matched the on-disk count across all four reclaims: 2048, 1536, 1024, and 512 clusters. Link: https://lore.kernel.org/20260805113920.385959-1-matthias.goergens@gmail.com Fixes: 4a54331616b3 ("ocfs2: give ocfs2 the ability to reclaim suballocator free bg") Signed-off-by: Matthias Goergens Reviewed-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Cc: Junxiao Bi Cc: Changwei Ge Cc: Jun Piao Cc: Heming Zhao Cc: Signed-off-by: Andrew Morton --- fs/ocfs2/suballoc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index a4a2b87a45fe..20c3aec6b987 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -2759,7 +2759,7 @@ static int _ocfs2_reclaim_suballoc_to_main(handle_t *handle, fe->i_clusters = cpu_to_le32(tmp_used - le16_to_cpu(cl->cl_cpg)); spin_lock(&OCFS2_I(alloc_inode)->ip_lock); - OCFS2_I(alloc_inode)->ip_clusters -= le32_to_cpu(fe->i_clusters); + OCFS2_I(alloc_inode)->ip_clusters = le32_to_cpu(fe->i_clusters); fe->i_size = cpu_to_le64(ocfs2_clusters_to_bytes(alloc_inode->i_sb, le32_to_cpu(fe->i_clusters))); spin_unlock(&OCFS2_I(alloc_inode)->ip_lock);