Commit 16874b2c 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 bugfixes from Ted Ts'o:
 "Fix a regression when trying to compile ext4 on older versions gcc.

  Fix a number of miscellaneous bugs for punch hole as well as a
  long-standing potential double buffer head release when failing a
  block allocation for an indirect-mapped file"

* tag 'ext4_for_linus_stable' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4:
  ext4: Fix hole punching for files with indirect blocks
  ext4: Fix block zeroing when punching holes in indirect block files
  ext4: decrement free clusters/inodes counters when block group declared bad
  fs/mbcache: replace __builtin_log2() with ilog2()
  ext4: Fix buffer double free in ext4_alloc_branch()
parents 4c834452 a93cd4cf
...@@ -194,7 +194,16 @@ static void ext4_init_block_bitmap(struct super_block *sb, ...@@ -194,7 +194,16 @@ static void ext4_init_block_bitmap(struct super_block *sb,
if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
ext4_error(sb, "Checksum bad for group %u", block_group); ext4_error(sb, "Checksum bad for group %u", block_group);
grp = ext4_get_group_info(sb, block_group); grp = ext4_get_group_info(sb, block_group);
if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
percpu_counter_sub(&sbi->s_freeclusters_counter,
grp->bb_free);
set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
int count;
count = ext4_free_inodes_count(sb, gdp);
percpu_counter_sub(&sbi->s_freeinodes_counter,
count);
}
set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
return; return;
} }
...@@ -359,6 +368,7 @@ static void ext4_validate_block_bitmap(struct super_block *sb, ...@@ -359,6 +368,7 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
{ {
ext4_fsblk_t blk; ext4_fsblk_t blk;
struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); struct ext4_group_info *grp = ext4_get_group_info(sb, block_group);
struct ext4_sb_info *sbi = EXT4_SB(sb);
if (buffer_verified(bh)) if (buffer_verified(bh))
return; return;
...@@ -369,6 +379,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb, ...@@ -369,6 +379,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
ext4_unlock_group(sb, block_group); ext4_unlock_group(sb, block_group);
ext4_error(sb, "bg %u: block %llu: invalid block bitmap", ext4_error(sb, "bg %u: block %llu: invalid block bitmap",
block_group, blk); block_group, blk);
if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
percpu_counter_sub(&sbi->s_freeclusters_counter,
grp->bb_free);
set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
return; return;
} }
...@@ -376,6 +389,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb, ...@@ -376,6 +389,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
desc, bh))) { desc, bh))) {
ext4_unlock_group(sb, block_group); ext4_unlock_group(sb, block_group);
ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); ext4_error(sb, "bg %u: bad block bitmap checksum", block_group);
if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
percpu_counter_sub(&sbi->s_freeclusters_counter,
grp->bb_free);
set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
return; return;
} }
......
...@@ -71,6 +71,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb, ...@@ -71,6 +71,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
struct ext4_group_desc *gdp) struct ext4_group_desc *gdp)
{ {
struct ext4_group_info *grp; struct ext4_group_info *grp;
struct ext4_sb_info *sbi = EXT4_SB(sb);
J_ASSERT_BH(bh, buffer_locked(bh)); J_ASSERT_BH(bh, buffer_locked(bh));
/* If checksum is bad mark all blocks and inodes use to prevent /* If checksum is bad mark all blocks and inodes use to prevent
...@@ -78,7 +79,16 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb, ...@@ -78,7 +79,16 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
ext4_error(sb, "Checksum bad for group %u", block_group); ext4_error(sb, "Checksum bad for group %u", block_group);
grp = ext4_get_group_info(sb, block_group); grp = ext4_get_group_info(sb, block_group);
if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
percpu_counter_sub(&sbi->s_freeclusters_counter,
grp->bb_free);
set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
int count;
count = ext4_free_inodes_count(sb, gdp);
percpu_counter_sub(&sbi->s_freeinodes_counter,
count);
}
set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
return 0; return 0;
} }
...@@ -116,6 +126,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) ...@@ -116,6 +126,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
ext4_fsblk_t bitmap_blk; ext4_fsblk_t bitmap_blk;
struct ext4_group_info *grp; struct ext4_group_info *grp;
struct ext4_sb_info *sbi = EXT4_SB(sb);
desc = ext4_get_group_desc(sb, block_group, NULL); desc = ext4_get_group_desc(sb, block_group, NULL);
if (!desc) if (!desc)
...@@ -185,6 +196,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) ...@@ -185,6 +196,12 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
ext4_error(sb, "Corrupt inode bitmap - block_group = %u, " ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
"inode_bitmap = %llu", block_group, bitmap_blk); "inode_bitmap = %llu", block_group, bitmap_blk);
grp = ext4_get_group_info(sb, block_group); grp = ext4_get_group_info(sb, block_group);
if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
int count;
count = ext4_free_inodes_count(sb, desc);
percpu_counter_sub(&sbi->s_freeinodes_counter,
count);
}
set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
return NULL; return NULL;
} }
...@@ -321,6 +338,12 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) ...@@ -321,6 +338,12 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
fatal = err; fatal = err;
} else { } else {
ext4_error(sb, "bit already cleared for inode %lu", ino); ext4_error(sb, "bit already cleared for inode %lu", ino);
if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) {
int count;
count = ext4_free_inodes_count(sb, gdp);
percpu_counter_sub(&sbi->s_freeinodes_counter,
count);
}
set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state);
} }
......
...@@ -389,7 +389,13 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode, ...@@ -389,7 +389,13 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
return 0; return 0;
failed: failed:
for (; i >= 0; i--) { for (; i >= 0; i--) {
if (i != indirect_blks && branch[i].bh) /*
* We want to ext4_forget() only freshly allocated indirect
* blocks. Buffer for new_blocks[i-1] is at branch[i].bh and
* buffer at branch[0].bh is indirect block / inode already
* existing before ext4_alloc_branch() was called.
*/
if (i > 0 && i != indirect_blks && branch[i].bh)
ext4_forget(handle, 1, inode, branch[i].bh, ext4_forget(handle, 1, inode, branch[i].bh,
branch[i].bh->b_blocknr); branch[i].bh->b_blocknr);
ext4_free_blocks(handle, inode, NULL, new_blocks[i], ext4_free_blocks(handle, inode, NULL, new_blocks[i],
...@@ -1310,16 +1316,24 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode, ...@@ -1310,16 +1316,24 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode,
blk = *i_data; blk = *i_data;
if (level > 0) { if (level > 0) {
ext4_lblk_t first2; ext4_lblk_t first2;
ext4_lblk_t count2;
bh = sb_bread(inode->i_sb, le32_to_cpu(blk)); bh = sb_bread(inode->i_sb, le32_to_cpu(blk));
if (!bh) { if (!bh) {
EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk), EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk),
"Read failure"); "Read failure");
return -EIO; return -EIO;
} }
first2 = (first > offset) ? first - offset : 0; if (first > offset) {
first2 = first - offset;
count2 = count;
} else {
first2 = 0;
count2 = count - (offset - first);
}
ret = free_hole_blocks(handle, inode, bh, ret = free_hole_blocks(handle, inode, bh,
(__le32 *)bh->b_data, level - 1, (__le32 *)bh->b_data, level - 1,
first2, count - offset, first2, count2,
inode->i_sb->s_blocksize >> 2); inode->i_sb->s_blocksize >> 2);
if (ret) { if (ret) {
brelse(bh); brelse(bh);
...@@ -1329,8 +1343,8 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode, ...@@ -1329,8 +1343,8 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode,
if (level == 0 || if (level == 0 ||
(bh && all_zeroes((__le32 *)bh->b_data, (bh && all_zeroes((__le32 *)bh->b_data,
(__le32 *)bh->b_data + addr_per_block))) { (__le32 *)bh->b_data + addr_per_block))) {
ext4_free_data(handle, inode, parent_bh, &blk, &blk+1); ext4_free_data(handle, inode, parent_bh,
*i_data = 0; i_data, i_data + 1);
} }
brelse(bh); brelse(bh);
bh = NULL; bh = NULL;
......
...@@ -722,6 +722,7 @@ void ext4_mb_generate_buddy(struct super_block *sb, ...@@ -722,6 +722,7 @@ void ext4_mb_generate_buddy(struct super_block *sb,
void *buddy, void *bitmap, ext4_group_t group) void *buddy, void *bitmap, ext4_group_t group)
{ {
struct ext4_group_info *grp = ext4_get_group_info(sb, group); struct ext4_group_info *grp = ext4_get_group_info(sb, group);
struct ext4_sb_info *sbi = EXT4_SB(sb);
ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb); ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb);
ext4_grpblk_t i = 0; ext4_grpblk_t i = 0;
ext4_grpblk_t first; ext4_grpblk_t first;
...@@ -759,6 +760,9 @@ void ext4_mb_generate_buddy(struct super_block *sb, ...@@ -759,6 +760,9 @@ void ext4_mb_generate_buddy(struct super_block *sb,
* corrupt and update bb_free using bitmap value * corrupt and update bb_free using bitmap value
*/ */
grp->bb_free = free; grp->bb_free = free;
if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp))
percpu_counter_sub(&sbi->s_freeclusters_counter,
grp->bb_free);
set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state);
} }
mb_set_largest_free_order(sb, grp); mb_set_largest_free_order(sb, grp);
...@@ -1431,6 +1435,7 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, ...@@ -1431,6 +1435,7 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
right_is_free = !mb_test_bit(last + 1, e4b->bd_bitmap); right_is_free = !mb_test_bit(last + 1, e4b->bd_bitmap);
if (unlikely(block != -1)) { if (unlikely(block != -1)) {
struct ext4_sb_info *sbi = EXT4_SB(sb);
ext4_fsblk_t blocknr; ext4_fsblk_t blocknr;
blocknr = ext4_group_first_block_no(sb, e4b->bd_group); blocknr = ext4_group_first_block_no(sb, e4b->bd_group);
...@@ -1441,6 +1446,9 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, ...@@ -1441,6 +1446,9 @@ static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b,
"freeing already freed block " "freeing already freed block "
"(bit %u); block bitmap corrupt.", "(bit %u); block bitmap corrupt.",
block); block);
if (!EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))
percpu_counter_sub(&sbi->s_freeclusters_counter,
e4b->bd_info->bb_free);
/* Mark the block group as corrupt. */ /* Mark the block group as corrupt. */
set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
&e4b->bd_info->bb_state); &e4b->bd_info->bb_state);
......
...@@ -73,6 +73,7 @@ ...@@ -73,6 +73,7 @@
#include <linux/mbcache.h> #include <linux/mbcache.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/blockgroup_lock.h> #include <linux/blockgroup_lock.h>
#include <linux/log2.h>
#ifdef MB_CACHE_DEBUG #ifdef MB_CACHE_DEBUG
# define mb_debug(f...) do { \ # define mb_debug(f...) do { \
...@@ -93,7 +94,7 @@ ...@@ -93,7 +94,7 @@
#define MB_CACHE_WRITER ((unsigned short)~0U >> 1) #define MB_CACHE_WRITER ((unsigned short)~0U >> 1)
#define MB_CACHE_ENTRY_LOCK_BITS __builtin_log2(NR_BG_LOCKS) #define MB_CACHE_ENTRY_LOCK_BITS ilog2(NR_BG_LOCKS)
#define MB_CACHE_ENTRY_LOCK_INDEX(ce) \ #define MB_CACHE_ENTRY_LOCK_INDEX(ce) \
(hash_long((unsigned long)ce, MB_CACHE_ENTRY_LOCK_BITS)) (hash_long((unsigned long)ce, MB_CACHE_ENTRY_LOCK_BITS))
......
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