1 Ext4: Fix delalloc release block reservation for truncate
3 From: Mingming Cao <cmm@us.ibm.com>
5 Ext4 will release the reserved blocks for delayed allocations when
6 inode is truncated/unlinked. If there is no reserved block at all, we
7 shouldn't need to do so. But current code still tries to release the
8 reserved blocks regardless whether the counters's value is 0.
9 Continue to do that causes the later calculation to go wrong and a
10 kernel BUG_ON() caught that. This doesn't happen for extent-based
11 files, as the calculation for 0 reserved blocks was right for extent
14 This patch fixed the kernel BUG() due to above reason. It adds checks
15 for 0 to avoid unnecessary release and fix calculation for non extent
18 Signed-off-by: Mingming Cao <cmm@us.ibm.com>
19 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
22 fs/ext4/inode.c | 21 +++++++++++++++++++++
23 1 file changed, 21 insertions(+)
25 Index: linux-2.6.27-rc3/fs/ext4/inode.c
26 ===================================================================
27 --- linux-2.6.27-rc3.orig/fs/ext4/inode.c 2008-08-19 15:56:49.000000000 -0700
28 +++ linux-2.6.27-rc3/fs/ext4/inode.c 2008-08-19 15:57:12.000000000 -0700
29 @@ -1005,6 +1005,9 @@ static int ext4_indirect_calc_metadata_a
31 static int ext4_calc_metadata_amount(struct inode *inode, int blocks)
36 if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
37 return ext4_ext_calc_metadata_amount(inode, blocks);
39 @@ -1559,7 +1562,25 @@ static void ext4_da_release_space(struct
40 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
41 int total, mdb, mdb_free, release;
44 + return; /* Nothing to release, exit */
46 spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
48 + if (!EXT4_I(inode)->i_reserved_data_blocks) {
50 + * if there is no reserved blocks, but we try to free some
51 + * then the counter is messed up somewhere.
52 + * but since this function is called from invalidate
53 + * page, it's harmless to return without any action
55 + printk(KERN_INFO "ext4 delalloc try to release %d reserved "
56 + "blocks for inode %lu, but there is no reserved "
57 + "data blocks\n", to_free, inode->i_ino);
58 + spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
62 /* recalculate the number of metablocks still need to be reserved */
63 total = EXT4_I(inode)->i_reserved_data_blocks - to_free;
64 mdb = ext4_calc_metadata_amount(inode, total);