| From e6d806782a687dd59176e8ecb2148ae2d3ccf666 Mon Sep 17 00:00:00 2001 |
| From: Brian Foster <bfoster@redhat.com> |
| Date: Sun, 22 Jul 2012 23:59:40 -0400 |
| Subject: [PATCH] ext4: don't let i_reserved_meta_blocks go negative |
| |
| commit 97795d2a5b8d3c8dc4365d4bd3404191840453ba upstream. |
| |
| 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 |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| --- |
| fs/ext4/inode.c | 9 +++++++++ |
| 1 file changed, 9 insertions(+) |
| |
| diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c |
| index b8965bb679ee..893da43223d4 100644 |
| --- a/fs/ext4/inode.c |
| +++ b/fs/ext4/inode.c |
| @@ -1089,6 +1089,15 @@ void ext4_da_update_reserve_space(struct inode *inode, |
| used = ei->i_reserved_data_blocks; |
| } |
| |
| + if (unlikely(ei->i_allocated_meta_blocks > ei->i_reserved_meta_blocks)) { |
| + ext4_msg(inode->i_sb, KERN_NOTICE, "%s: ino %lu, allocated %d " |
| + "with only %d reserved metadata blocks\n", __func__, |
| + inode->i_ino, ei->i_allocated_meta_blocks, |
| + ei->i_reserved_meta_blocks); |
| + WARN_ON(1); |
| + ei->i_allocated_meta_blocks = ei->i_reserved_meta_blocks; |
| + } |
| + |
| /* Update per-inode reservations */ |
| ei->i_reserved_data_blocks -= used; |
| used += ei->i_allocated_meta_blocks; |
| -- |
| 1.8.5.2 |
| |