ext4: Fix delalloc release block reservation for truncate

Ext4 will release the reserved blocks for delayed allocations when
inode is truncated/unlinked. If there is no reserved block at all, we
shouldn't need to do so. But current code still tries to release the
reserved blocks regardless whether the counters's value is 0.
Continue to do that causes the later calculation to go wrong and a
kernel BUG_ON() caught that. This doesn't happen for extent-based
files, as the calculation for 0 reserved blocks was right for extent
based file.

This patch fixed the kernel BUG() due to above reason. It adds checks
for 0 to avoid unnecessary release and fix calculation for non-extent
files.

Signed-off-by: Mingming Cao <cmm@us.ibm.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>

authored by Mingming Cao and committed by Theodore Ts'o cd213226 b4df2030

+21
+21
fs/ext4/inode.c
··· 1005 1005 */ 1006 1006 static int ext4_calc_metadata_amount(struct inode *inode, int blocks) 1007 1007 { 1008 + if (!blocks) 1009 + return 0; 1010 + 1008 1011 if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) 1009 1012 return ext4_ext_calc_metadata_amount(inode, blocks); 1010 1013 ··· 1562 1559 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 1563 1560 int total, mdb, mdb_free, release; 1564 1561 1562 + if (!to_free) 1563 + return; /* Nothing to release, exit */ 1564 + 1565 1565 spin_lock(&EXT4_I(inode)->i_block_reservation_lock); 1566 + 1567 + if (!EXT4_I(inode)->i_reserved_data_blocks) { 1568 + /* 1569 + * if there is no reserved blocks, but we try to free some 1570 + * then the counter is messed up somewhere. 1571 + * but since this function is called from invalidate 1572 + * page, it's harmless to return without any action 1573 + */ 1574 + printk(KERN_INFO "ext4 delalloc try to release %d reserved " 1575 + "blocks for inode %lu, but there is no reserved " 1576 + "data blocks\n", to_free, inode->i_ino); 1577 + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); 1578 + return; 1579 + } 1580 + 1566 1581 /* recalculate the number of metablocks still need to be reserved */ 1567 1582 total = EXT4_I(inode)->i_reserved_data_blocks - to_free; 1568 1583 mdb = ext4_calc_metadata_amount(inode, total);