diff options
| author | David Woodhouse <David.Woodhouse@intel.com> | 2008-07-11 14:36:25 +0100 | 
|---|---|---|
| committer | David Woodhouse <David.Woodhouse@intel.com> | 2008-07-11 14:36:25 +0100 | 
| commit | a8931ef380c92d121ae74ecfb03b2d63f72eea6f (patch) | |
| tree | 980fb6b019e11e6cb1ece55b7faff184721a8053 /fs/ext4/balloc.c | |
| parent | 90574d0a4d4b73308ae54a2a57a4f3f1fa98e984 (diff) | |
| parent | e5a5816f7875207cb0a0a7032e39a4686c5e10a4 (diff) | |
| download | olio-linux-3.10-a8931ef380c92d121ae74ecfb03b2d63f72eea6f.tar.xz olio-linux-3.10-a8931ef380c92d121ae74ecfb03b2d63f72eea6f.zip  | |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Diffstat (limited to 'fs/ext4/balloc.c')
| -rw-r--r-- | fs/ext4/balloc.c | 86 | 
1 files changed, 72 insertions, 14 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index da994374ec3..9cc80b9cc8d 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -43,6 +43,46 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,  } +static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block, +			ext4_group_t block_group) +{ +	ext4_group_t actual_group; +	ext4_get_group_no_and_offset(sb, block, &actual_group, 0); +	if (actual_group == block_group) +		return 1; +	return 0; +} + +static int ext4_group_used_meta_blocks(struct super_block *sb, +				ext4_group_t block_group) +{ +	ext4_fsblk_t tmp; +	struct ext4_sb_info *sbi = EXT4_SB(sb); +	/* block bitmap, inode bitmap, and inode table blocks */ +	int used_blocks = sbi->s_itb_per_group + 2; + +	if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) { +		struct ext4_group_desc *gdp; +		struct buffer_head *bh; + +		gdp = ext4_get_group_desc(sb, block_group, &bh); +		if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), +					block_group)) +			used_blocks--; + +		if (!ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), +					block_group)) +			used_blocks--; + +		tmp = ext4_inode_table(sb, gdp); +		for (; tmp < ext4_inode_table(sb, gdp) + +				sbi->s_itb_per_group; tmp++) { +			if (!ext4_block_in_group(sb, tmp, block_group)) +				used_blocks -= 1; +		} +	} +	return used_blocks; +}  /* Initializes an uninitialized block bitmap if given, and returns the   * number of blocks free in the group. */  unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh, @@ -105,20 +145,34 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,  	free_blocks = group_blocks - bit_max;  	if (bh) { -		ext4_fsblk_t start; +		ext4_fsblk_t start, tmp; +		int flex_bg = 0;  		for (bit = 0; bit < bit_max; bit++)  			ext4_set_bit(bit, bh->b_data);  		start = ext4_group_first_block_no(sb, block_group); +		if (EXT4_HAS_INCOMPAT_FEATURE(sb, +					      EXT4_FEATURE_INCOMPAT_FLEX_BG)) +			flex_bg = 1; +  		/* Set bits for block and inode bitmaps, and inode table */ -		ext4_set_bit(ext4_block_bitmap(sb, gdp) - start, bh->b_data); -		ext4_set_bit(ext4_inode_bitmap(sb, gdp) - start, bh->b_data); -		for (bit = (ext4_inode_table(sb, gdp) - start), -		     bit_max = bit + sbi->s_itb_per_group; bit < bit_max; bit++) -			ext4_set_bit(bit, bh->b_data); +		tmp = ext4_block_bitmap(sb, gdp); +		if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) +			ext4_set_bit(tmp - start, bh->b_data); +		tmp = ext4_inode_bitmap(sb, gdp); +		if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) +			ext4_set_bit(tmp - start, bh->b_data); + +		tmp = ext4_inode_table(sb, gdp); +		for (; tmp < ext4_inode_table(sb, gdp) + +				sbi->s_itb_per_group; tmp++) { +			if (!flex_bg || +				ext4_block_in_group(sb, tmp, block_group)) +				ext4_set_bit(tmp - start, bh->b_data); +		}  		/*  		 * Also if the number of blocks within the group is  		 * less than the blocksize * 8 ( which is the size @@ -126,8 +180,7 @@ unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,  		 */  		mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);  	} - -	return free_blocks - sbi->s_itb_per_group - 2; +	return free_blocks - ext4_group_used_meta_blocks(sb, block_group);  } @@ -287,11 +340,11 @@ read_block_bitmap(struct super_block *sb, ext4_group_t block_group)  			    (int)block_group, (unsigned long long)bitmap_blk);  		return NULL;  	} -	if (!ext4_valid_block_bitmap(sb, desc, block_group, bh)) { -		put_bh(bh); -		return NULL; -	} - +	ext4_valid_block_bitmap(sb, desc, block_group, bh); +	/* +	 * file system mounted not to panic on error, +	 * continue with corrupt bitmap +	 */  	return bh;  }  /* @@ -1770,7 +1823,12 @@ allocated:  			    "Allocating block in system zone - "  			    "blocks from %llu, length %lu",  			     ret_block, num); -		goto out; +		/* +		 * claim_block marked the blocks we allocated +		 * as in use. So we may want to selectively +		 * mark some of the blocks as free +		 */ +		goto retry_alloc;  	}  	performed_allocation = 1;  |