Commit ef824bfb authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4

Pull ext4 bug fixes from Ted Ts'o:
 "The following are all bug fixes and regressions.  The most notable are
  the ones which cause problems for ext4 on RAID --- a performance
  problem when mounting very large filesystems, and a kernel OOPS when
  doing an rm -rf on large directory hierarchies on fast devices."

* tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: fix kernel BUG on large-scale rm -rf commands
  ext4: fix long mount times on very big file systems
  ext4: don't call ext4_error while block group is locked
  ext4: avoid kmemcheck complaint from reading uninitialized memory
  ext4: make sure the journal sb is written in ext4_clear_journal_err()
parents d807ff83 89a4e48f
...@@ -280,14 +280,18 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, ...@@ -280,14 +280,18 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
return desc; return desc;
} }
static int ext4_valid_block_bitmap(struct super_block *sb, /*
* Return the block number which was discovered to be invalid, or 0 if
* the block bitmap is valid.
*/
static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb,
struct ext4_group_desc *desc, struct ext4_group_desc *desc,
unsigned int block_group, unsigned int block_group,
struct buffer_head *bh) struct buffer_head *bh)
{ {
ext4_grpblk_t offset; ext4_grpblk_t offset;
ext4_grpblk_t next_zero_bit; ext4_grpblk_t next_zero_bit;
ext4_fsblk_t bitmap_blk; ext4_fsblk_t blk;
ext4_fsblk_t group_first_block; ext4_fsblk_t group_first_block;
if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
...@@ -297,37 +301,33 @@ static int ext4_valid_block_bitmap(struct super_block *sb, ...@@ -297,37 +301,33 @@ static int ext4_valid_block_bitmap(struct super_block *sb,
* or it has to also read the block group where the bitmaps * or it has to also read the block group where the bitmaps
* are located to verify they are set. * are located to verify they are set.
*/ */
return 1; return 0;
} }
group_first_block = ext4_group_first_block_no(sb, block_group); group_first_block = ext4_group_first_block_no(sb, block_group);
/* check whether block bitmap block number is set */ /* check whether block bitmap block number is set */
bitmap_blk = ext4_block_bitmap(sb, desc); blk = ext4_block_bitmap(sb, desc);
offset = bitmap_blk - group_first_block; offset = blk - group_first_block;
if (!ext4_test_bit(offset, bh->b_data)) if (!ext4_test_bit(offset, bh->b_data))
/* bad block bitmap */ /* bad block bitmap */
goto err_out; return blk;
/* check whether the inode bitmap block number is set */ /* check whether the inode bitmap block number is set */
bitmap_blk = ext4_inode_bitmap(sb, desc); blk = ext4_inode_bitmap(sb, desc);
offset = bitmap_blk - group_first_block; offset = blk - group_first_block;
if (!ext4_test_bit(offset, bh->b_data)) if (!ext4_test_bit(offset, bh->b_data))
/* bad block bitmap */ /* bad block bitmap */
goto err_out; return blk;
/* check whether the inode table block number is set */ /* check whether the inode table block number is set */
bitmap_blk = ext4_inode_table(sb, desc); blk = ext4_inode_table(sb, desc);
offset = bitmap_blk - group_first_block; offset = blk - group_first_block;
next_zero_bit = ext4_find_next_zero_bit(bh->b_data, next_zero_bit = ext4_find_next_zero_bit(bh->b_data,
offset + EXT4_SB(sb)->s_itb_per_group, offset + EXT4_SB(sb)->s_itb_per_group,
offset); offset);
if (next_zero_bit >= offset + EXT4_SB(sb)->s_itb_per_group) if (next_zero_bit < offset + EXT4_SB(sb)->s_itb_per_group)
/* good bitmap for inode tables */ /* bad bitmap for inode tables */
return 1; return blk;
err_out:
ext4_error(sb, "Invalid block bitmap - block_group = %d, block = %llu",
block_group, bitmap_blk);
return 0; return 0;
} }
...@@ -336,13 +336,25 @@ void ext4_validate_block_bitmap(struct super_block *sb, ...@@ -336,13 +336,25 @@ void ext4_validate_block_bitmap(struct super_block *sb,
unsigned int block_group, unsigned int block_group,
struct buffer_head *bh) struct buffer_head *bh)
{ {
ext4_fsblk_t blk;
if (buffer_verified(bh)) if (buffer_verified(bh))
return; return;
ext4_lock_group(sb, block_group); ext4_lock_group(sb, block_group);
if (ext4_valid_block_bitmap(sb, desc, block_group, bh) && blk = ext4_valid_block_bitmap(sb, desc, block_group, bh);
ext4_block_bitmap_csum_verify(sb, block_group, desc, bh, if (unlikely(blk != 0)) {
EXT4_BLOCKS_PER_GROUP(sb) / 8)) ext4_unlock_group(sb, block_group);
ext4_error(sb, "bg %u: block %llu: invalid block bitmap",
block_group, blk);
return;
}
if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group,
desc, bh, EXT4_BLOCKS_PER_GROUP(sb) / 8))) {
ext4_unlock_group(sb, block_group);
ext4_error(sb, "bg %u: bad block bitmap checksum", block_group);
return;
}
set_buffer_verified(bh); set_buffer_verified(bh);
ext4_unlock_group(sb, block_group); ext4_unlock_group(sb, block_group);
} }
......
...@@ -79,7 +79,6 @@ int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, ...@@ -79,7 +79,6 @@ int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
if (provided == calculated) if (provided == calculated)
return 1; return 1;
ext4_error(sb, "Bad block bitmap checksum: block_group = %u", group);
return 0; return 0;
} }
......
...@@ -2662,6 +2662,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, ...@@ -2662,6 +2662,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
} }
path[0].p_depth = depth; path[0].p_depth = depth;
path[0].p_hdr = ext_inode_hdr(inode); path[0].p_hdr = ext_inode_hdr(inode);
i = 0;
if (ext4_ext_check(inode, path[0].p_hdr, depth)) { if (ext4_ext_check(inode, path[0].p_hdr, depth)) {
err = -EIO; err = -EIO;
......
...@@ -948,6 +948,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb) ...@@ -948,6 +948,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
ei->i_reserved_meta_blocks = 0; ei->i_reserved_meta_blocks = 0;
ei->i_allocated_meta_blocks = 0; ei->i_allocated_meta_blocks = 0;
ei->i_da_metadata_calc_len = 0; ei->i_da_metadata_calc_len = 0;
ei->i_da_metadata_calc_last_lblock = 0;
spin_lock_init(&(ei->i_block_reservation_lock)); spin_lock_init(&(ei->i_block_reservation_lock));
#ifdef CONFIG_QUOTA #ifdef CONFIG_QUOTA
ei->i_reserved_quota = 0; ei->i_reserved_quota = 0;
...@@ -3108,6 +3109,10 @@ static int count_overhead(struct super_block *sb, ext4_group_t grp, ...@@ -3108,6 +3109,10 @@ static int count_overhead(struct super_block *sb, ext4_group_t grp,
ext4_group_t i, ngroups = ext4_get_groups_count(sb); ext4_group_t i, ngroups = ext4_get_groups_count(sb);
int s, j, count = 0; int s, j, count = 0;
if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_BIGALLOC))
return (ext4_bg_has_super(sb, grp) + ext4_bg_num_gdb(sb, grp) +
sbi->s_itb_per_group + 2);
first_block = le32_to_cpu(sbi->s_es->s_first_data_block) + first_block = le32_to_cpu(sbi->s_es->s_first_data_block) +
(grp * EXT4_BLOCKS_PER_GROUP(sb)); (grp * EXT4_BLOCKS_PER_GROUP(sb));
last_block = first_block + EXT4_BLOCKS_PER_GROUP(sb) - 1; last_block = first_block + EXT4_BLOCKS_PER_GROUP(sb) - 1;
...@@ -4419,6 +4424,7 @@ static void ext4_clear_journal_err(struct super_block *sb, ...@@ -4419,6 +4424,7 @@ static void ext4_clear_journal_err(struct super_block *sb,
ext4_commit_super(sb, 1); ext4_commit_super(sb, 1);
jbd2_journal_clear_err(journal); jbd2_journal_clear_err(journal);
jbd2_journal_update_sb_errno(journal);
} }
} }
......
...@@ -1377,7 +1377,7 @@ static void jbd2_mark_journal_empty(journal_t *journal) ...@@ -1377,7 +1377,7 @@ static void jbd2_mark_journal_empty(journal_t *journal)
* Update a journal's errno. Write updated superblock to disk waiting for IO * Update a journal's errno. Write updated superblock to disk waiting for IO
* to complete. * to complete.
*/ */
static void jbd2_journal_update_sb_errno(journal_t *journal) void jbd2_journal_update_sb_errno(journal_t *journal)
{ {
journal_superblock_t *sb = journal->j_superblock; journal_superblock_t *sb = journal->j_superblock;
...@@ -1390,6 +1390,7 @@ static void jbd2_journal_update_sb_errno(journal_t *journal) ...@@ -1390,6 +1390,7 @@ static void jbd2_journal_update_sb_errno(journal_t *journal)
jbd2_write_superblock(journal, WRITE_SYNC); jbd2_write_superblock(journal, WRITE_SYNC);
} }
EXPORT_SYMBOL(jbd2_journal_update_sb_errno);
/* /*
* Read the superblock for a given journal, performing initial * Read the superblock for a given journal, performing initial
......
...@@ -1125,6 +1125,7 @@ extern int jbd2_journal_destroy (journal_t *); ...@@ -1125,6 +1125,7 @@ extern int jbd2_journal_destroy (journal_t *);
extern int jbd2_journal_recover (journal_t *journal); extern int jbd2_journal_recover (journal_t *journal);
extern int jbd2_journal_wipe (journal_t *, int); extern int jbd2_journal_wipe (journal_t *, int);
extern int jbd2_journal_skip_recovery (journal_t *); extern int jbd2_journal_skip_recovery (journal_t *);
extern void jbd2_journal_update_sb_errno(journal_t *);
extern void jbd2_journal_update_sb_log_tail (journal_t *, tid_t, extern void jbd2_journal_update_sb_log_tail (journal_t *, tid_t,
unsigned long, int); unsigned long, int);
extern void __jbd2_journal_abort_hard (journal_t *); extern void __jbd2_journal_abort_hard (journal_t *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment