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. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.22 (GNU/Linux) iQIcBAABCAAGBQJTsKRpAAoJENNvdpvBGATwf3YQAJoGNvrxd6BPpB0bSTLRdh+k 0IDShwB9PpSJulIHx8xIOpFIvpk5T0E1Ho+UqUnpMImRiqueYbFfOPca4lYsRBqW r9TNmm0O8Bf8K0j8YUaV2P8BGNJuiCzv7YcCbSHt1/eP6/InyfJWA17hYD6oxBPF ZrrcZemDH863KhYIF55sbx9UvBLz515ifd4kHN9pSVbV3pJT5/zPiRk/wujQZTrX v0z5pe5i8GfYoBMmdCNak3a1YoXdf+FUdID+pvGWtfzs8AG8nS7jb8C1zkfgUWtC zau9yBnFHKlBdmoPrFJIpvDT/2rBRks6g6uM2Jsc+YS+zHCXi0xJR1EaPIqkRJbf vWHNSogzOKetyFZFML1Dg1cjXVEnPusOsyhvcXTFwb3n/YY1NBFdLiVgNbTzQ7aU X7P4M+ca2yib2rQos5Ltipk4ju9eT4d5qsf+QSaaryYeUHg+8sNaqd82y42eita1 Dgg7IpyKWdNo+lBHEtDSV5Gli4oRrXddj7Yvrib7nobf+FTi4cpbbu0PfY5qXfDV vKrsvIiJcPJYsvi+USH3fvv2m6UaZd+gDo/RObV06tSNTZWqGzalSeviaJZ+cfEP v05ODGLUNvg+thhvBsYAGNeaV/SOYztmNA6v0qfI+OwscH8ycGeb6R98Kil/hd97 P3i12fhP7tkffNTNPM/E =X4vY -----END PGP SIGNATURE----- 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()
This commit is contained in:
commit
16874b2cb8
|
@ -194,7 +194,16 @@ static void ext4_init_block_bitmap(struct super_block *sb,
|
|||
if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
|
||||
ext4_error(sb, "Checksum bad for group %u", 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);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@ -359,6 +368,7 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
|
|||
{
|
||||
ext4_fsblk_t blk;
|
||||
struct ext4_group_info *grp = ext4_get_group_info(sb, block_group);
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
|
||||
if (buffer_verified(bh))
|
||||
return;
|
||||
|
@ -369,6 +379,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
|
|||
ext4_unlock_group(sb, block_group);
|
||||
ext4_error(sb, "bg %u: block %llu: invalid block bitmap",
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
@ -376,6 +389,9 @@ static void ext4_validate_block_bitmap(struct super_block *sb,
|
|||
desc, bh))) {
|
||||
ext4_unlock_group(sb, 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);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,7 @@ static unsigned ext4_init_inode_bitmap(struct super_block *sb,
|
|||
struct ext4_group_desc *gdp)
|
||||
{
|
||||
struct ext4_group_info *grp;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
J_ASSERT_BH(bh, buffer_locked(bh));
|
||||
|
||||
/* 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,
|
|||
if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
|
||||
ext4_error(sb, "Checksum bad for group %u", 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);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
@ -116,6 +126,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
|
|||
struct buffer_head *bh = NULL;
|
||||
ext4_fsblk_t bitmap_blk;
|
||||
struct ext4_group_info *grp;
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
|
||||
desc = ext4_get_group_desc(sb, block_group, NULL);
|
||||
if (!desc)
|
||||
|
@ -185,6 +196,12 @@ verify:
|
|||
ext4_error(sb, "Corrupt inode bitmap - block_group = %u, "
|
||||
"inode_bitmap = %llu", block_group, bitmap_blk);
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -321,6 +338,12 @@ out:
|
|||
fatal = err;
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -389,7 +389,13 @@ static int ext4_alloc_branch(handle_t *handle, struct inode *inode,
|
|||
return 0;
|
||||
failed:
|
||||
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,
|
||||
branch[i].bh->b_blocknr);
|
||||
ext4_free_blocks(handle, inode, NULL, new_blocks[i],
|
||||
|
@ -1310,16 +1316,24 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode,
|
|||
blk = *i_data;
|
||||
if (level > 0) {
|
||||
ext4_lblk_t first2;
|
||||
ext4_lblk_t count2;
|
||||
|
||||
bh = sb_bread(inode->i_sb, le32_to_cpu(blk));
|
||||
if (!bh) {
|
||||
EXT4_ERROR_INODE_BLOCK(inode, le32_to_cpu(blk),
|
||||
"Read failure");
|
||||
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,
|
||||
(__le32 *)bh->b_data, level - 1,
|
||||
first2, count - offset,
|
||||
first2, count2,
|
||||
inode->i_sb->s_blocksize >> 2);
|
||||
if (ret) {
|
||||
brelse(bh);
|
||||
|
@ -1329,8 +1343,8 @@ static int free_hole_blocks(handle_t *handle, struct inode *inode,
|
|||
if (level == 0 ||
|
||||
(bh && all_zeroes((__le32 *)bh->b_data,
|
||||
(__le32 *)bh->b_data + addr_per_block))) {
|
||||
ext4_free_data(handle, inode, parent_bh, &blk, &blk+1);
|
||||
*i_data = 0;
|
||||
ext4_free_data(handle, inode, parent_bh,
|
||||
i_data, i_data + 1);
|
||||
}
|
||||
brelse(bh);
|
||||
bh = NULL;
|
||||
|
|
|
@ -722,6 +722,7 @@ void ext4_mb_generate_buddy(struct super_block *sb,
|
|||
void *buddy, void *bitmap, ext4_group_t 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 i = 0;
|
||||
ext4_grpblk_t first;
|
||||
|
@ -759,6 +760,9 @@ void ext4_mb_generate_buddy(struct super_block *sb,
|
|||
* corrupt and update bb_free using bitmap value
|
||||
*/
|
||||
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);
|
||||
}
|
||||
mb_set_largest_free_order(sb, grp);
|
||||
|
@ -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);
|
||||
|
||||
if (unlikely(block != -1)) {
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
ext4_fsblk_t blocknr;
|
||||
|
||||
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,
|
|||
"freeing already freed block "
|
||||
"(bit %u); block bitmap corrupt.",
|
||||
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. */
|
||||
set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT,
|
||||
&e4b->bd_info->bb_state);
|
||||
|
|
|
@ -73,6 +73,7 @@
|
|||
#include <linux/mbcache.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/blockgroup_lock.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
#ifdef MB_CACHE_DEBUG
|
||||
# define mb_debug(f...) do { \
|
||||
|
@ -93,7 +94,7 @@
|
|||
|
||||
#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) \
|
||||
(hash_long((unsigned long)ce, MB_CACHE_ENTRY_LOCK_BITS))
|
||||
|
||||
|
|
Loading…
Reference in New Issue