ext4: fix reserved space counter leakage

When ext4_insert_delayed block receives and recovers from an error from
ext4_es_insert_delayed_block(), e.g., ENOMEM, it does not release the
space it has reserved for that block insertion as it should. One effect
of this bug is that s_dirtyclusters_counter is not decremented and
remains incorrectly elevated until the file system has been unmounted.
This can result in premature ENOSPC returns and apparent loss of free
space.

Another effect of this bug is that
/sys/fs/ext4/<dev>/delayed_allocation_blocks can remain non-zero even
after syncfs has been executed on the filesystem.

Besides, add check for s_dirtyclusters_counter when inode is going to be
evicted and freed. s_dirtyclusters_counter can still keep non-zero until
inode is written back in .evict_inode(), and thus the check is delayed
to .destroy_inode().

Fixes: 51865fda28e5 ("ext4: let ext4 maintain extent status tree")
Cc: stable@kernel.org
Suggested-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Signed-off-by: Jeffle Xu <jefflexu@linux.alibaba.com>
Reviewed-by: Eric Whitney <enwlinux@gmail.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Link: https://lore.kernel.org/r/20210823061358.84473-1-jefflexu@linux.alibaba.com

authored by Jeffle Xu and committed by Theodore Ts'o 6fed8395 a2c2f082

+11
+5
fs/ext4/inode.c
··· 1628 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 1629 int ret; 1630 bool allocated = false; 1631 1632 /* 1633 * If the cluster containing lblk is shared with a delayed, ··· 1645 ret = ext4_da_reserve_space(inode); 1646 if (ret != 0) /* ENOSPC */ 1647 goto errout; 1648 } else { /* bigalloc */ 1649 if (!ext4_es_scan_clu(inode, &ext4_es_is_delonly, lblk)) { 1650 if (!ext4_es_scan_clu(inode, ··· 1658 ret = ext4_da_reserve_space(inode); 1659 if (ret != 0) /* ENOSPC */ 1660 goto errout; 1661 } else { 1662 allocated = true; 1663 } ··· 1669 } 1670 1671 ret = ext4_es_insert_delayed_block(inode, lblk, allocated); 1672 1673 errout: 1674 return ret;
··· 1628 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 1629 int ret; 1630 bool allocated = false; 1631 + bool reserved = false; 1632 1633 /* 1634 * If the cluster containing lblk is shared with a delayed, ··· 1644 ret = ext4_da_reserve_space(inode); 1645 if (ret != 0) /* ENOSPC */ 1646 goto errout; 1647 + reserved = true; 1648 } else { /* bigalloc */ 1649 if (!ext4_es_scan_clu(inode, &ext4_es_is_delonly, lblk)) { 1650 if (!ext4_es_scan_clu(inode, ··· 1656 ret = ext4_da_reserve_space(inode); 1657 if (ret != 0) /* ENOSPC */ 1658 goto errout; 1659 + reserved = true; 1660 } else { 1661 allocated = true; 1662 } ··· 1666 } 1667 1668 ret = ext4_es_insert_delayed_block(inode, lblk, allocated); 1669 + if (ret && reserved) 1670 + ext4_da_release_space(inode, 1); 1671 1672 errout: 1673 return ret;
+6
fs/ext4/super.c
··· 1352 true); 1353 dump_stack(); 1354 } 1355 } 1356 1357 static void init_once(void *foo)
··· 1352 true); 1353 dump_stack(); 1354 } 1355 + 1356 + if (EXT4_I(inode)->i_reserved_data_blocks) 1357 + ext4_msg(inode->i_sb, KERN_ERR, 1358 + "Inode %lu (%p): i_reserved_data_blocks (%u) not cleared!", 1359 + inode->i_ino, EXT4_I(inode), 1360 + EXT4_I(inode)->i_reserved_data_blocks); 1361 } 1362 1363 static void init_once(void *foo)