lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20090503170836.GA18865@duck.suse.cz>
Date:	Sun, 3 May 2009 19:08:36 +0200
From:	Jan Kara <jack@...e.cz>
To:	Theodore Ts'o <tytso@....edu>
Cc:	Ext4 Developers List <linux-ext4@...r.kernel.org>,
	Jan Kara <jack@...e.cz>
Subject: Re: [PATCH v2] ext4: Avoid races caused by on-line resizing and
	SMP memory reordering

On Fri 01-05-09 09:55:59, Theodore Ts'o wrote:
> Ext4's on-line resizing adds a new block group and then, only at the
> last step adjusts s_groups_count.  However, it's possible on SMP
> systems that another CPU could see the updated the s_group_count and
> not see the newly initialized data structures for the just-added block
> group.  For this reason, it's important to insert a SMP read barrier
> after reading s_groups_count and before reading any (for example) the
> new block group descriptors allowed by the increased value of
> s_groups_count.
> 
> Unfortunately, we rather blatently violate this locking protocol
> documented in fs/ext4/resize.c.  Fortunately, (1) on-line resizes
> happen relatively rarely, and (2) it seems rare that the filesystem
> code will immediately try to use just-added block group before any
> memory ordering issues resolve themselves.  So apparently problems
> here are relatively hard to hit, since ext3 has been vulnerable to the
> same issue for years with no one apparently complaining.
> 
> Signed-off-by: "Theodore Ts'o" <tytso@....edu>
> ---
> 
> Here's an updated version which uses a helper function to make sure we
> in the future we don't miss a place where smp_rmb() is needed.
  Yeah, it looks nice. Maybe the code looks even better like this ;).

Acked-by: Jan Kara <jack@...e.cz>

									Honza
 
>  fs/ext4/balloc.c  |   15 +++++++--------
>  fs/ext4/ext4.h    |   12 ++++++++++++
>  fs/ext4/ialloc.c  |   40 +++++++++++++++++++---------------------
>  fs/ext4/inode.c   |    7 ++++---
>  fs/ext4/mballoc.c |   45 ++++++++++++++++++++++++---------------------
>  fs/ext4/super.c   |    3 +--
>  6 files changed, 67 insertions(+), 55 deletions(-)
> 
> diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c
> index 53c72ad..a5ba039 100644
> --- a/fs/ext4/balloc.c
> +++ b/fs/ext4/balloc.c
> @@ -88,6 +88,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
>  		 ext4_group_t block_group, struct ext4_group_desc *gdp)
>  {
>  	int bit, bit_max;
> +	ext4_group_t ngroups = ext4_get_groups_count(sb);
>  	unsigned free_blocks, group_blocks;
>  	struct ext4_sb_info *sbi = EXT4_SB(sb);
>  
> @@ -123,7 +124,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
>  		bit_max += ext4_bg_num_gdb(sb, block_group);
>  	}
>  
> -	if (block_group == sbi->s_groups_count - 1) {
> +	if (block_group == ngroups - 1) {
>  		/*
>  		 * Even though mke2fs always initialize first and last group
>  		 * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
> @@ -131,7 +132,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
>  		 */
>  		group_blocks = ext4_blocks_count(sbi->s_es) -
>  			le32_to_cpu(sbi->s_es->s_first_data_block) -
> -			(EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1));
> +			(EXT4_BLOCKS_PER_GROUP(sb) * (ngroups - 1));
>  	} else {
>  		group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
>  	}
> @@ -205,18 +206,18 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
>  {
>  	unsigned int group_desc;
>  	unsigned int offset;
> +	ext4_group_t ngroups = ext4_get_groups_count(sb);
>  	struct ext4_group_desc *desc;
>  	struct ext4_sb_info *sbi = EXT4_SB(sb);
>  
> -	if (block_group >= sbi->s_groups_count) {
> +	if (block_group >= ngroups) {
>  		ext4_error(sb, "ext4_get_group_desc",
>  			   "block_group >= groups_count - "
>  			   "block_group = %u, groups_count = %u",
> -			   block_group, sbi->s_groups_count);
> +			   block_group, ngroups);
>  
>  		return NULL;
>  	}
> -	smp_rmb();
>  
>  	group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
>  	offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
> @@ -665,7 +666,7 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
>  	ext4_fsblk_t desc_count;
>  	struct ext4_group_desc *gdp;
>  	ext4_group_t i;
> -	ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
> +	ext4_group_t ngroups = ext4_get_groups_count(sb);
>  #ifdef EXT4FS_DEBUG
>  	struct ext4_super_block *es;
>  	ext4_fsblk_t bitmap_count;
> @@ -677,7 +678,6 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
>  	bitmap_count = 0;
>  	gdp = NULL;
>  
> -	smp_rmb();
>  	for (i = 0; i < ngroups; i++) {
>  		gdp = ext4_get_group_desc(sb, i, NULL);
>  		if (!gdp)
> @@ -700,7 +700,6 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
>  	return bitmap_count;
>  #else
>  	desc_count = 0;
> -	smp_rmb();
>  	for (i = 0; i < ngroups; i++) {
>  		gdp = ext4_get_group_desc(sb, i, NULL);
>  		if (!gdp)
> diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
> index d0f15ef..02ec44b 100644
> --- a/fs/ext4/ext4.h
> +++ b/fs/ext4/ext4.h
> @@ -1228,6 +1228,18 @@ struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
>  	 return grp_info[indexv][indexh];
>  }
>  
> +/*
> + * Reading s_groups_count requires using smp_rmb() afterwards.  See
> + * the locking protocol documented in the comments of ext4_group_add()
> + * in resize.c
> + */
> +static inline ext4_group_t ext4_get_groups_count(struct super_block *sb)
> +{
> +	ext4_group_t	ngroups = EXT4_SB(sb)->s_groups_count;
> +
> +	smp_rmb();
> +	return ngroups;
> +}
>  
>  static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi,
>  					     ext4_group_t block_group)
> diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
> index f18e0a0..55ba419 100644
> --- a/fs/ext4/ialloc.c
> +++ b/fs/ext4/ialloc.c
> @@ -316,7 +316,7 @@ error_return:
>  static int find_group_dir(struct super_block *sb, struct inode *parent,
>  				ext4_group_t *best_group)
>  {
> -	ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
> +	ext4_group_t ngroups = ext4_get_groups_count(sb);
>  	unsigned int freei, avefreei;
>  	struct ext4_group_desc *desc, *best_desc = NULL;
>  	ext4_group_t group;
> @@ -353,7 +353,7 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
>  	struct flex_groups *flex_group = sbi->s_flex_groups;
>  	ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
>  	ext4_group_t parent_fbg_group = ext4_flex_group(sbi, parent_group);
> -	ext4_group_t ngroups = sbi->s_groups_count;
> +	ext4_group_t ngroups = ext4_get_groups_count(sb);
>  	int flex_size = ext4_flex_bg_size(sbi);
>  	ext4_group_t best_flex = parent_fbg_group;
>  	int blocks_per_flex = sbi->s_blocks_per_group * flex_size;
> @@ -362,7 +362,7 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
>  	ext4_group_t n_fbg_groups;
>  	ext4_group_t i;
>  
> -	n_fbg_groups = (sbi->s_groups_count + flex_size - 1) >>
> +	n_fbg_groups = (ngroups + flex_size - 1) >>
>  		sbi->s_log_groups_per_flex;
>  
>  find_close_to_parent:
> @@ -478,20 +478,21 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
>  {
>  	ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
>  	struct ext4_sb_info *sbi = EXT4_SB(sb);
> -	ext4_group_t ngroups = sbi->s_groups_count;
> +	ext4_group_t real_ngroups = ext4_get_groups_count(sb);
>  	int inodes_per_group = EXT4_INODES_PER_GROUP(sb);
>  	unsigned int freei, avefreei;
>  	ext4_fsblk_t freeb, avefreeb;
>  	unsigned int ndirs;
>  	int max_dirs, min_inodes;
>  	ext4_grpblk_t min_blocks;
> -	ext4_group_t i, grp, g;
> +	ext4_group_t i, grp, g, ngroups;
>  	struct ext4_group_desc *desc;
>  	struct orlov_stats stats;
>  	int flex_size = ext4_flex_bg_size(sbi);
>  
> +	ngroups = real_ngroups;
>  	if (flex_size > 1) {
> -		ngroups = (ngroups + flex_size - 1) >>
> +		ngroups = (real_ngroups + flex_size - 1) >>
>  			sbi->s_log_groups_per_flex;
>  		parent_group >>= sbi->s_log_groups_per_flex;
>  	}
> @@ -543,7 +544,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
>  		 */
>  		grp *= flex_size;
>  		for (i = 0; i < flex_size; i++) {
> -			if (grp+i >= sbi->s_groups_count)
> +			if (grp+i >= real_ngroups)
>  				break;
>  			desc = ext4_get_group_desc(sb, grp+i, NULL);
>  			if (desc && ext4_free_inodes_count(sb, desc)) {
> @@ -583,7 +584,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent,
>  	}
>  
>  fallback:
> -	ngroups = sbi->s_groups_count;
> +	ngroups = real_ngroups;
>  	avefreei = freei / ngroups;
>  fallback_retry:
>  	parent_group = EXT4_I(parent)->i_block_group;
> @@ -613,9 +614,8 @@ static int find_group_other(struct super_block *sb, struct inode *parent,
>  			    ext4_group_t *group, int mode)
>  {
>  	ext4_group_t parent_group = EXT4_I(parent)->i_block_group;
> -	ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
> +	ext4_group_t i, last, ngroups = ext4_get_groups_count(sb);
>  	struct ext4_group_desc *desc;
> -	ext4_group_t i, last;
>  	int flex_size = ext4_flex_bg_size(EXT4_SB(sb));
>  
>  	/*
> @@ -799,11 +799,10 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
>  	struct super_block *sb;
>  	struct buffer_head *inode_bitmap_bh = NULL;
>  	struct buffer_head *group_desc_bh;
> -	ext4_group_t group = 0;
> +	ext4_group_t ngroups, group = 0;
>  	unsigned long ino = 0;
>  	struct inode *inode;
>  	struct ext4_group_desc *gdp = NULL;
> -	struct ext4_super_block *es;
>  	struct ext4_inode_info *ei;
>  	struct ext4_sb_info *sbi;
>  	int ret2, err = 0;
> @@ -818,15 +817,14 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
>  		return ERR_PTR(-EPERM);
>  
>  	sb = dir->i_sb;
> +	ngroups = ext4_get_groups_count(sb);
>  	trace_mark(ext4_request_inode, "dev %s dir %lu mode %d", sb->s_id,
>  		   dir->i_ino, mode);
>  	inode = new_inode(sb);
>  	if (!inode)
>  		return ERR_PTR(-ENOMEM);
>  	ei = EXT4_I(inode);
> -
>  	sbi = EXT4_SB(sb);
> -	es = sbi->s_es;
>  
>  	if (sbi->s_log_groups_per_flex && test_opt(sb, OLDALLOC)) {
>  		ret2 = find_group_flex(sb, dir, &group);
> @@ -856,7 +854,7 @@ got_group:
>  	if (ret2 == -1)
>  		goto out;
>  
> -	for (i = 0; i < sbi->s_groups_count; i++) {
> +	for (i = 0; i < ngroups; i++) {
>  		err = -EIO;
>  
>  		gdp = ext4_get_group_desc(sb, group, &group_desc_bh);
> @@ -917,7 +915,7 @@ repeat_in_this_group:
>  		 * group descriptor metadata has not yet been updated.
>  		 * So we just go onto the next blockgroup.
>  		 */
> -		if (++group == sbi->s_groups_count)
> +		if (++group == ngroups)
>  			group = 0;
>  	}
>  	err = -ENOSPC;
> @@ -1158,7 +1156,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
>  {
>  	unsigned long desc_count;
>  	struct ext4_group_desc *gdp;
> -	ext4_group_t i;
> +	ext4_group_t i, ngroups = ext4_get_groups_count(sb);
>  #ifdef EXT4FS_DEBUG
>  	struct ext4_super_block *es;
>  	unsigned long bitmap_count, x;
> @@ -1168,7 +1166,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
>  	desc_count = 0;
>  	bitmap_count = 0;
>  	gdp = NULL;
> -	for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
> +	for (i = 0; i < ngroups; i++) {
>  		gdp = ext4_get_group_desc(sb, i, NULL);
>  		if (!gdp)
>  			continue;
> @@ -1190,7 +1188,7 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
>  	return desc_count;
>  #else
>  	desc_count = 0;
> -	for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
> +	for (i = 0; i < ngroups; i++) {
>  		gdp = ext4_get_group_desc(sb, i, NULL);
>  		if (!gdp)
>  			continue;
> @@ -1205,9 +1203,9 @@ unsigned long ext4_count_free_inodes(struct super_block *sb)
>  unsigned long ext4_count_dirs(struct super_block * sb)
>  {
>  	unsigned long count = 0;
> -	ext4_group_t i;
> +	ext4_group_t i, ngroups = ext4_get_groups_count(sb);
>  
> -	for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
> +	for (i = 0; i < ngroups; i++) {
>  		struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
>  		if (!gdp)
>  			continue;
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index b891045..3e90965 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -4916,7 +4916,8 @@ static int ext4_index_trans_blocks(struct inode *inode, int nrblocks, int chunk)
>   */
>  int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk)
>  {
> -	int groups, gdpblocks;
> +	ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb);
> +	int gdpblocks;
>  	int idxblocks;
>  	int ret = 0;
>  
> @@ -4943,8 +4944,8 @@ int ext4_meta_trans_blocks(struct inode *inode, int nrblocks, int chunk)
>  		groups += nrblocks;
>  
>  	gdpblocks = groups;
> -	if (groups > EXT4_SB(inode->i_sb)->s_groups_count)
> -		groups = EXT4_SB(inode->i_sb)->s_groups_count;
> +	if (groups > ngroups)
> +		groups = ngroups;
>  	if (groups > EXT4_SB(inode->i_sb)->s_gdb_count)
>  		gdpblocks = EXT4_SB(inode->i_sb)->s_gdb_count;
>  
> diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
> index f871677..c3af9e6 100644
> --- a/fs/ext4/mballoc.c
> +++ b/fs/ext4/mballoc.c
> @@ -739,6 +739,7 @@ static void ext4_mb_generate_buddy(struct super_block *sb,
>  
>  static int ext4_mb_init_cache(struct page *page, char *incore)
>  {
> +	ext4_group_t ngroups;
>  	int blocksize;
>  	int blocks_per_page;
>  	int groups_per_page;
> @@ -757,6 +758,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
>  
>  	inode = page->mapping->host;
>  	sb = inode->i_sb;
> +	ngroups = ext4_get_groups_count(sb);
>  	blocksize = 1 << inode->i_blkbits;
>  	blocks_per_page = PAGE_CACHE_SIZE / blocksize;
>  
> @@ -780,7 +782,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
>  	for (i = 0; i < groups_per_page; i++) {
>  		struct ext4_group_desc *desc;
>  
> -		if (first_group + i >= EXT4_SB(sb)->s_groups_count)
> +		if (first_group + i >= ngroups)
>  			break;
>  
>  		err = -EIO;
> @@ -852,7 +854,7 @@ static int ext4_mb_init_cache(struct page *page, char *incore)
>  		struct ext4_group_info *grinfo;
>  
>  		group = (first_block + i) >> 1;
> -		if (group >= EXT4_SB(sb)->s_groups_count)
> +		if (group >= ngroups)
>  			break;
>  
>  		/*
> @@ -1788,6 +1790,7 @@ int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group)
>  	int block, pnum;
>  	int blocks_per_page;
>  	int groups_per_page;
> +	ext4_group_t ngroups = ext4_get_groups_count(sb);
>  	ext4_group_t first_group;
>  	struct ext4_group_info *grp;
>  
> @@ -1807,7 +1810,7 @@ int ext4_mb_get_buddy_cache_lock(struct super_block *sb, ext4_group_t group)
>  	/* read all groups the page covers into the cache */
>  	for (i = 0; i < groups_per_page; i++) {
>  
> -		if ((first_group + i) >= EXT4_SB(sb)->s_groups_count)
> +		if ((first_group + i) >= ngroups)
>  			break;
>  		grp = ext4_get_group_info(sb, first_group + i);
>  		/* take all groups write allocation
> @@ -1945,8 +1948,7 @@ err:
>  static noinline_for_stack int
>  ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
>  {
> -	ext4_group_t group;
> -	ext4_group_t i;
> +	ext4_group_t ngroups, group, i;
>  	int cr;
>  	int err = 0;
>  	int bsbits;
> @@ -1957,6 +1959,7 @@ ext4_mb_regular_allocator(struct ext4_allocation_context *ac)
>  
>  	sb = ac->ac_sb;
>  	sbi = EXT4_SB(sb);
> +	ngroups = ext4_get_groups_count(sb);
>  	BUG_ON(ac->ac_status == AC_STATUS_FOUND);
>  
>  	/* first, try the goal */
> @@ -2017,11 +2020,11 @@ repeat:
>  		 */
>  		group = ac->ac_g_ex.fe_group;
>  
> -		for (i = 0; i < EXT4_SB(sb)->s_groups_count; group++, i++) {
> +		for (i = 0; i < ngroups; group++, i++) {
>  			struct ext4_group_info *grp;
>  			struct ext4_group_desc *desc;
>  
> -			if (group == EXT4_SB(sb)->s_groups_count)
> +			if (group == ngroups)
>  				group = 0;
>  
>  			/* quick check to skip empty groups */
> @@ -2315,12 +2318,10 @@ static struct file_operations ext4_mb_seq_history_fops = {
>  static void *ext4_mb_seq_groups_start(struct seq_file *seq, loff_t *pos)
>  {
>  	struct super_block *sb = seq->private;
> -	struct ext4_sb_info *sbi = EXT4_SB(sb);
>  	ext4_group_t group;
>  
> -	if (*pos < 0 || *pos >= sbi->s_groups_count)
> +	if (*pos < 0 || *pos >= ext4_get_groups_count(sb))
>  		return NULL;
> -
>  	group = *pos + 1;
>  	return (void *) ((unsigned long) group);
>  }
> @@ -2328,11 +2329,10 @@ static void *ext4_mb_seq_groups_start(struct seq_file *seq, loff_t *pos)
>  static void *ext4_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos)
>  {
>  	struct super_block *sb = seq->private;
> -	struct ext4_sb_info *sbi = EXT4_SB(sb);
>  	ext4_group_t group;
>  
>  	++*pos;
> -	if (*pos < 0 || *pos >= sbi->s_groups_count)
> +	if (*pos < 0 || *pos >= ext4_get_groups_count(sb))
>  		return NULL;
>  	group = *pos + 1;
>  	return (void *) ((unsigned long) group);
> @@ -2587,6 +2587,7 @@ void ext4_mb_update_group_info(struct ext4_group_info *grp, ext4_grpblk_t add)
>  
>  static int ext4_mb_init_backend(struct super_block *sb)
>  {
> +	ext4_group_t ngroups = ext4_get_groups_count(sb);
>  	ext4_group_t i;
>  	int metalen;
>  	struct ext4_sb_info *sbi = EXT4_SB(sb);
> @@ -2598,7 +2599,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
>  	struct ext4_group_desc *desc;
>  
>  	/* This is the number of blocks used by GDT */
> -	num_meta_group_infos = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) -
> +	num_meta_group_infos = (ngroups + EXT4_DESC_PER_BLOCK(sb) -
>  				1) >> EXT4_DESC_PER_BLOCK_BITS(sb);
>  
>  	/*
> @@ -2644,7 +2645,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
>  	for (i = 0; i < num_meta_group_infos; i++) {
>  		if ((i + 1) == num_meta_group_infos)
>  			metalen = sizeof(*meta_group_info) *
> -				(sbi->s_groups_count -
> +				(ngroups -
>  					(i << EXT4_DESC_PER_BLOCK_BITS(sb)));
>  		meta_group_info = kmalloc(metalen, GFP_KERNEL);
>  		if (meta_group_info == NULL) {
> @@ -2655,7 +2656,7 @@ static int ext4_mb_init_backend(struct super_block *sb)
>  		sbi->s_group_info[i] = meta_group_info;
>  	}
>  
> -	for (i = 0; i < sbi->s_groups_count; i++) {
> +	for (i = 0; i < ngroups; i++) {
>  		desc = ext4_get_group_desc(sb, i, NULL);
>  		if (desc == NULL) {
>  			printk(KERN_ERR
> @@ -2781,13 +2782,14 @@ static void ext4_mb_cleanup_pa(struct ext4_group_info *grp)
>  
>  int ext4_mb_release(struct super_block *sb)
>  {
> +	ext4_group_t ngroups = ext4_get_groups_count(sb);
>  	ext4_group_t i;
>  	int num_meta_group_infos;
>  	struct ext4_group_info *grinfo;
>  	struct ext4_sb_info *sbi = EXT4_SB(sb);
>  
>  	if (sbi->s_group_info) {
> -		for (i = 0; i < sbi->s_groups_count; i++) {
> +		for (i = 0; i < ngroups; i++) {
>  			grinfo = ext4_get_group_info(sb, i);
>  #ifdef DOUBLE_CHECK
>  			kfree(grinfo->bb_bitmap);
> @@ -2797,7 +2799,7 @@ int ext4_mb_release(struct super_block *sb)
>  			ext4_unlock_group(sb, i);
>  			kfree(grinfo);
>  		}
> -		num_meta_group_infos = (sbi->s_groups_count +
> +		num_meta_group_infos = (ngroups +
>  				EXT4_DESC_PER_BLOCK(sb) - 1) >>
>  			EXT4_DESC_PER_BLOCK_BITS(sb);
>  		for (i = 0; i < num_meta_group_infos; i++)
> @@ -4121,7 +4123,7 @@ static void ext4_mb_return_to_preallocation(struct inode *inode,
>  static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
>  {
>  	struct super_block *sb = ac->ac_sb;
> -	ext4_group_t i;
> +	ext4_group_t ngroups, i;
>  
>  	printk(KERN_ERR "EXT4-fs: Can't allocate:"
>  			" Allocation context details:\n");
> @@ -4145,7 +4147,8 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
>  	printk(KERN_ERR "EXT4-fs: %lu scanned, %d found\n", ac->ac_ex_scanned,
>  		ac->ac_found);
>  	printk(KERN_ERR "EXT4-fs: groups: \n");
> -	for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
> +	ngroups = ext4_get_groups_count(sb);
> +	for (i = 0; i < ngroups; i++) {
>  		struct ext4_group_info *grp = ext4_get_group_info(sb, i);
>  		struct ext4_prealloc_space *pa;
>  		ext4_grpblk_t start;
> @@ -4469,13 +4472,13 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
>  
>  static int ext4_mb_discard_preallocations(struct super_block *sb, int needed)
>  {
> -	ext4_group_t i;
> +	ext4_group_t i, ngroups = ext4_get_groups_count(sb);
>  	int ret;
>  	int freed = 0;
>  
>  	trace_mark(ext4_mb_discard_preallocations, "dev %s needed %d",
>  		   sb->s_id, needed);
> -	for (i = 0; i < EXT4_SB(sb)->s_groups_count && needed > 0; i++) {
> +	for (i = 0; i < ngroups && needed > 0; i++) {
>  		ret = ext4_mb_discard_group_preallocations(sb, i, needed);
>  		freed += ret;
>  		needed -= ret;
> diff --git a/fs/ext4/super.c b/fs/ext4/super.c
> index 241a81e..bcdbb6d 100644
> --- a/fs/ext4/super.c
> +++ b/fs/ext4/super.c
> @@ -3539,9 +3539,8 @@ static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf)
>  	if (test_opt(sb, MINIX_DF)) {
>  		sbi->s_overhead_last = 0;
>  	} else if (sbi->s_blocks_last != ext4_blocks_count(es)) {
> -		ext4_group_t ngroups = sbi->s_groups_count, i;
> +		ext4_group_t i, ngroups = ext4_get_groups_count(sb);
>  		ext4_fsblk_t overhead = 0;
> -		smp_rmb();
>  
>  		/*
>  		 * Compute the overhead (FS structures).  This is constant
> -- 
> 1.6.0.4
> 
-- 
Jan Kara <jack@...e.cz>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ