More commit description fixups
[ext4-patch-queue.git] / fix-delalloc-release-block-reservation-for-truncate
blob9755a1fbf7a781bfb7a63bcd86ac7a9477bb90d2
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
12 based file.
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
16 files.
18 Signed-off-by: Mingming Cao <cmm@us.ibm.com>
19 Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
20 ---
21 ---
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
30   */
31  static int ext4_calc_metadata_amount(struct inode *inode, int blocks)
32  {
33 +       if (!blocks)
34 +               return 0;
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;
43 +       if (!to_free)
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) {
49 +               /*
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
54 +                */
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);
59 +               return;
60 +       }
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);