diff options
Diffstat (limited to 'fs/ext4/balloc.c')
| -rw-r--r-- | fs/ext4/balloc.c | 46 | 
1 files changed, 44 insertions, 2 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 094269488183..1f72f977c6db 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -305,6 +305,36 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,  	return desc;  } +static ext4_fsblk_t ext4_valid_block_bitmap_padding(struct super_block *sb, +						    ext4_group_t block_group, +						    struct buffer_head *bh) +{ +	ext4_grpblk_t next_zero_bit; +	unsigned long bitmap_size = sb->s_blocksize * 8; +	unsigned int offset = num_clusters_in_group(sb, block_group); + +	if (bitmap_size <= offset) +		return 0; + +	next_zero_bit = ext4_find_next_zero_bit(bh->b_data, bitmap_size, offset); + +	return (next_zero_bit < bitmap_size ? next_zero_bit : 0); +} + +struct ext4_group_info *ext4_get_group_info(struct super_block *sb, +					    ext4_group_t group) +{ +	struct ext4_group_info **grp_info; +	long indexv, indexh; + +	if (unlikely(group >= EXT4_SB(sb)->s_groups_count)) +		return NULL; +	indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb)); +	indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1); +	grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv); +	return grp_info[indexh]; +} +  /*   * Return the block number which was discovered to be invalid, or 0 if   * the block bitmap is valid. @@ -379,7 +409,7 @@ static int ext4_validate_block_bitmap(struct super_block *sb,  	if (buffer_verified(bh))  		return 0; -	if (EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) +	if (!grp || EXT4_MB_GRP_BBITMAP_CORRUPT(grp))  		return -EFSCORRUPTED;  	ext4_lock_group(sb, block_group); @@ -402,6 +432,15 @@ static int ext4_validate_block_bitmap(struct super_block *sb,  					EXT4_GROUP_INFO_BBITMAP_CORRUPT);  		return -EFSCORRUPTED;  	} +	blk = ext4_valid_block_bitmap_padding(sb, block_group, bh); +	if (unlikely(blk != 0)) { +		ext4_unlock_group(sb, block_group); +		ext4_error(sb, "bg %u: block %llu: padding at end of block bitmap is not set", +			   block_group, blk); +		ext4_mark_group_bitmap_corrupted(sb, block_group, +						 EXT4_GROUP_INFO_BBITMAP_CORRUPT); +		return -EFSCORRUPTED; +	}  	set_buffer_verified(bh);  verified:  	ext4_unlock_group(sb, block_group); @@ -845,7 +884,10 @@ static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,  	if (!ext4_bg_has_super(sb, group))  		return 0; -	return EXT4_SB(sb)->s_gdb_count; +	if (ext4_has_feature_meta_bg(sb)) +		return le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg); +	else +		return EXT4_SB(sb)->s_gdb_count;  }  /**  | 
