aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorMingming Cao <cmm@us.ibm.com>2008-08-19 22:16:59 -0400
committerTheodore Ts'o <tytso@mit.edu>2008-08-19 22:16:59 -0400
commitcd21322616c3af265d39bf15321d436e667a5dd1 (patch)
tree2e293b838191785a0ecf3b19f204731c73589139 /fs
parentb4df2030858bde986cb6ff2e4b45945f84649e32 (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/inode.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index 2d54c822c4c3..5e17d5f22a7e 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -1005,6 +1005,9 @@ static int ext4_indirect_calc_metadata_amount(struct inode *inode, int blocks)
1005 */ 1005 */
1006static int ext4_calc_metadata_amount(struct inode *inode, int blocks) 1006static int ext4_calc_metadata_amount(struct inode *inode, int blocks)
1007{ 1007{
1008 if (!blocks)
1009 return 0;
1010
1008 if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL) 1011 if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
1009 return ext4_ext_calc_metadata_amount(inode, blocks); 1012 return ext4_ext_calc_metadata_amount(inode, blocks);
1010 1013
@@ -1559,7 +1562,25 @@ static void ext4_da_release_space(struct inode *inode, int to_free)
1559 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); 1562 struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
1560 int total, mdb, mdb_free, release; 1563 int total, mdb, mdb_free, release;
1561 1564
1565 if (!to_free)
1566 return; /* Nothing to release, exit */
1567
1562 spin_lock(&EXT4_I(inode)->i_block_reservation_lock); 1568 spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
1569
1570 if (!EXT4_I(inode)->i_reserved_data_blocks) {
1571 /*
1572 * if there is no reserved blocks, but we try to free some
1573 * then the counter is messed up somewhere.
1574 * but since this function is called from invalidate
1575 * page, it's harmless to return without any action
1576 */
1577 printk(KERN_INFO "ext4 delalloc try to release %d reserved "
1578 "blocks for inode %lu, but there is no reserved "
1579 "data blocks\n", to_free, inode->i_ino);
1580 spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
1581 return;
1582 }
1583
1563 /* recalculate the number of metablocks still need to be reserved */ 1584 /* recalculate the number of metablocks still need to be reserved */
1564 total = EXT4_I(inode)->i_reserved_data_blocks - to_free; 1585 total = EXT4_I(inode)->i_reserved_data_blocks - to_free;
1565 mdb = ext4_calc_metadata_amount(inode, total); 1586 mdb = ext4_calc_metadata_amount(inode, total);