[PATCH] ext4: fix quota accounting WARN in bigalloc punch hole
From: Qiliang Yuan
Date: Thu May 28 2026 - 06:28:45 EST
When doing direct I/O write on a bigalloc filesystem, the allocated
extent might not cover entire clusters at its boundaries, leaving
delayed blocks in those boundary clusters. In ext4_es_insert_extent(),
__revise_pending() inserts new pending reservations for those boundary
clusters, and the return value (pending=true) was added to resv_used,
causing ext4_da_update_reserve_space() to incorrectly release the
quota reservations for those boundary clusters.
Later when PUNCH_HOLE removes the DIO-allocated blocks, the
extent removal path detects the pending reservation via
ext4_is_pending() and calls ext4_rereserve_cluster(). This tries
to reclaim quota from dq_dqb.dqb_curspace back to dqb_rsvspace,
but since the quota was already incorrectly released, dqb_curspace
is insufficient, triggering:
WARNING at dquot_reclaim_space_nodirty+0x77c/0x8c0
The subsequent delalloc writeback then fires a second WARN from
dquot_claim_space_nodirty() for the same reason: dqb_rsvspace was
depleted by the earlier incorrect release.
__es_remove_extent() -> get_rsvd() already correctly excludes
boundary clusters that still contain delayed blocks from resv_used.
Adding pending to resv_used double-counts those boundary clusters,
erroneously releasing reservations that are still needed.
Remove the pending variable and the resv_used += pending addition.
Fixes: c543e2429640 ("ext4: update delalloc data reserve spcae in ext4_es_insert_extent()")
Reported-by: Zijing Yin <yzjaurora@xxxxxxxxx>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221570
Signed-off-by: Qiliang Yuan <realwujing@xxxxxxxxx>
---
fs/ext4/extents_status.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/fs/ext4/extents_status.c b/fs/ext4/extents_status.c
index 6e4a191e82191..fefe0bb8ac4d1 100644
--- a/fs/ext4/extents_status.c
+++ b/fs/ext4/extents_status.c
@@ -909,7 +909,7 @@ void ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
struct extent_status newes;
ext4_lblk_t end = lblk + len - 1;
int err1 = 0, err2 = 0, err3 = 0;
- int resv_used = 0, pending = 0;
+ int resv_used = 0;
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
struct extent_status *es1 = NULL;
struct extent_status *es2 = NULL;
@@ -977,7 +977,6 @@ void ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
__free_pending(pr);
pr = NULL;
}
- pending = err3;
}
ext4_es_inc_seq(inode);
error:
@@ -998,7 +997,6 @@ void ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk,
* any previously delayed allocated clusters instead of claim them
* again.
*/
- resv_used += pending;
if (resv_used)
ext4_da_update_reserve_space(inode, resv_used,
delalloc_reserve_used);
---
base-commit: eb3f4b7426cfd2b79d65b7d37155480b32259a11
change-id: 20260528-fix-ext4-bigalloc-punch-hole-quota-v2-2adca315d1ba
Best regards,
--
Qiliang Yuan <realwujing@xxxxxxxxx>