diff options
Diffstat (limited to 'fs/ext4/balloc.c')
| -rw-r--r-- | fs/ext4/balloc.c | 14 | 
1 files changed, 11 insertions, 3 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 5f993a411251..8fd0b3cdab4c 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -270,6 +270,7 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,  	ext4_group_t ngroups = ext4_get_groups_count(sb);  	struct ext4_group_desc *desc;  	struct ext4_sb_info *sbi = EXT4_SB(sb); +	struct buffer_head *bh_p;  	if (block_group >= ngroups) {  		ext4_error(sb, "block_group >= groups_count - block_group = %u," @@ -280,7 +281,14 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,  	group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);  	offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); -	if (!sbi->s_group_desc[group_desc]) { +	bh_p = sbi_array_rcu_deref(sbi, s_group_desc, group_desc); +	/* +	 * sbi_array_rcu_deref returns with rcu unlocked, this is ok since +	 * the pointer being dereferenced won't be dereferenced again. By +	 * looking at the usage in add_new_gdb() the value isn't modified, +	 * just the pointer, and so it remains valid. +	 */ +	if (!bh_p) {  		ext4_error(sb, "Group descriptor not loaded - "  			   "block_group = %u, group_desc = %u, desc = %u",  			   block_group, group_desc, offset); @@ -288,10 +296,10 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,  	}  	desc = (struct ext4_group_desc *)( -		(__u8 *)sbi->s_group_desc[group_desc]->b_data + +		(__u8 *)bh_p->b_data +  		offset * EXT4_DESC_SIZE(sb));  	if (bh) -		*bh = sbi->s_group_desc[group_desc]; +		*bh = bh_p;  	return desc;  }  |