aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ext4/inode.c
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2012-07-22 23:59:40 -0400
committerTheodore Ts'o <tytso@mit.edu>2012-07-22 23:59:40 -0400
commit97795d2a5b8d3c8dc4365d4bd3404191840453ba (patch)
tree75d5871a8ae658b05cdbe3c15d50c95694f8c79f /fs/ext4/inode.c
parent968dee77220768a5f52cf8b21d0bdb73486febef (diff)
ext4: don't let i_reserved_meta_blocks go negative
If we hit a condition where we have allocated metadata blocks that were not appropriately reserved, we risk underflow of ei->i_reserved_meta_blocks. In turn, this can throw sbi->s_dirtyclusters_counter significantly out of whack and undermine the nondelalloc fallback logic in ext4_nonda_switch(). Warn if this occurs and set i_allocated_meta_blocks to avoid this problem. This condition is reproduced by xfstests 270 against ext2 with delalloc enabled: Mar 28 08:58:02 localhost kernel: [ 171.526344] EXT4-fs (loop1): delayed block allocation failed for inode 14 at logical offset 64486 with max blocks 64 with error -28 Mar 28 08:58:02 localhost kernel: [ 171.526346] EXT4-fs (loop1): This should not happen!! Data will be lost 270 ultimately fails with an inconsistent filesystem and requires an fsck to repair. The cause of the error is an underflow in ext4_da_update_reserve_space() due to an unreserved meta block allocation. Signed-off-by: Brian Foster <bfoster@redhat.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> Cc: stable@vger.kernel.org
Diffstat (limited to 'fs/ext4/inode.c')
-rw-r--r--fs/ext4/inode.c9
1 files changed, 9 insertions, 0 deletions
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index a533a18de98e..25f809dc45a3 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -346,6 +346,15 @@ void ext4_da_update_reserve_space(struct inode *inode,
346 used = ei->i_reserved_data_blocks; 346 used = ei->i_reserved_data_blocks;
347 } 347 }
348 348
349 if (unlikely(ei->i_allocated_meta_blocks > ei->i_reserved_meta_blocks)) {
350 ext4_msg(inode->i_sb, KERN_NOTICE, "%s: ino %lu, allocated %d "
351 "with only %d reserved metadata blocks\n", __func__,
352 inode->i_ino, ei->i_allocated_meta_blocks,
353 ei->i_reserved_meta_blocks);
354 WARN_ON(1);
355 ei->i_allocated_meta_blocks = ei->i_reserved_meta_blocks;
356 }
357
349 /* Update per-inode reservations */ 358 /* Update per-inode reservations */
350 ei->i_reserved_data_blocks -= used; 359 ei->i_reserved_data_blocks -= used;
351 ei->i_reserved_meta_blocks -= ei->i_allocated_meta_blocks; 360 ei->i_reserved_meta_blocks -= ei->i_allocated_meta_blocks;