Re: [RFC]Ext4: journal credits reservation fixes for DIO, fallocate and delalloc writepages

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



在 2008-07-28一的 21:41 +0530,Aneesh Kumar K.V写道:
> On Fri, Jul 25, 2008 at 12:26:42PM -0700, Mingming Cao wrote:
> > 
> 
> ......
> 
> > > >   */
> > > >  int ext4_ext_calc_credits_for_insert(struct inode *inode,
> > > >  						struct ext4_ext_path *path)
> > > > @@ -1930,9 +1931,6 @@ int ext4_ext_calc_credits_for_insert(str
> > > >  	 */
> > > >  	needed += (depth * 2) + (depth * 2);
> > > > 
> > > > -	/* any allocation modifies superblock */
> > > > -	needed += 1;
> > > > -
> > > 
> > > 
> > > Why are we dropping the super block modification credit ? An insert of
> > > an extent can result in super block modification also. If the goal is to
> > > use ext4_writepages_trans_blocks everywhere then this change is correct.
> > > But i see  many place not using ext4_writepages_trans_blocks.
> > > 
> > ext4_writepages_trans_blocks() will take care of the credits need for
> > updating superblock, for just once.ext4_ext_calc_credits_for_insert()
> > calculate the credits needed for inserting a single extent, You could
> > see in ext4_writepages_trans_blocks(), it will multiple it will the
> > total numberof blocks. If we account for superblock credit in
> > ext4_ext_calc_credits_for_insert(),  then super block updates for
> > multiple extents allocation will be overaccounted, and have to remove
> > that later in ext4_writepages_trans_blocks()
> 
> 
> 
> ext4_ext_calc_credit for insert was not doing it currently with 
> path != NULL.  I attaching a patch which reflect some of the changes
> I suggested.
> 
> 
Acked. this fixed another bug in existing code.
> > 
> > Other places calling  ext4_ext_calc_credits_for_insert() (mostly
> > migrate.c and defrag,c) are updated to add extra 4 credits, including
> > superblock, inode block and quota blocks.
> 
> 
> I guess it should not be +4 but should be +2 + 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
> 

Yes.  
> > 
> > > You also need to update the function comment saying that super block
> > > update is not accounted.Also it doesn't account for block bitmap,
> > > group descriptor and inode block update.
> > > 
> > 
> > Credits for block bitmap and group descriptors are accounted in
> > ext4_ext_calc_credits_for_insert()
> > 
> > inode block update is only accounted once per writepages, so it's
> > accounted in
> > ext4_writepages_trans_blocks()/ext4_ext_writepages_trans_blocks()
> > 
> 
> ....
> 
> > > >   *
> > > > @@ -1142,13 +1133,13 @@ int ext4_get_block(struct inode *inode, 
> > > >  	handle_t *handle = ext4_journal_current_handle();
> > > >  	int ret = 0, started = 0;
> > > >  	unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
> > > > +	int dio_credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb);
> > > 
> > > Again this should be
> > > 	int dio_credits = ext4_writeblocks_trans(inode, DIO_MAX_BLOCKS);
> > > 
> > No. DIO case is different than writepages(). When get_block() is called
> > from DIO path, the get_block()  is called in a loop, and the credit is
> > reserved inside the loop. Each time get_block(),will return a single
> > extent, so we should use   EXT4_DATA_TRANS_BLOCKS(inode->i_sb) which is
> > calculate a single chunk of allocation credits.
> 
> 
> That is true only for extent format. With noextents we need something
> like below
> 

Not really, even with non extent format block allocation, ext4_get_block() will only allocate/map a chunk of contiguous blocks (i.e. an extent), so it will not hit the worse case.

> if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
> 	dio_credits = ext4_writeblocks_trans_credits_old(inode, max_blocks);
> else {
> 	/*
> 	 * For extent format get_block return only one extent
> 	 */
> 	dio_credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb);
> }
> 
> 

...

> 
> > > 
> > > > -	int bpp = ext4_journal_blocks_per_page(inode);
> > > > -	int indirects = (EXT4_NDIR_BLOCKS % bpp) ? 5 : 3;
> > > > +	int indirects = (EXT4_NDIR_BLOCKS % num) ? 5 : 3;
> > > >  	int ret;
> > > > 
> > > > -	if (EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL)
> > > > -		return ext4_ext_writepage_trans_blocks(inode, bpp);
> > > > -
> > > >  	if (ext4_should_journal_data(inode))
> > > > -		ret = 3 * (bpp + indirects) + 2;
> > > > +		ret = 3 * (num + indirects) + 2;
> > > >  	else
> > > > -		ret = 2 * (bpp + indirects) + 2;
> > > > +		ret = 2 * (num + indirects) + 2;
> > > 
> > > 
> > > With non journalled moded we should just decrease num. I guess the above
> > > should be
> > > 	if (ext4_should_journal_data(inode))
> > > 		ret = 3 * (num + indirects) + 2;
> > > 	else
> > > 		ret = 3 * (num + indirects) + 2 - num;
> > > 
> > > 
> > > 
> > 
> > Well, I think in the journalled mode we need to journal the content of
> > the indirect/double indirect blocks also, no?
> > 
> 
> With non journalled mode we still need to journal the indirect, dindirect
> and tindirect block so this should be
> 

yes, changes of indirect blocks are also logged in all journalling
mode. 



Mingming
> Attaching the patch for easy review
> 
> 
> 
> diff --git a/fs/ext4/defrag.c b/fs/ext4/defrag.c
> index 7c819fd..46e9600 100644
> --- a/fs/ext4/defrag.c
> +++ b/fs/ext4/defrag.c
> @@ -1385,8 +1385,9 @@ ext4_defrag_alloc_blocks(handle_t *handle, struct inode *org_inode,
>  	struct buffer_head *bh = NULL;
>  	int err, i, credits = 0;
> 
> -	credits = ext4_ext_calc_credits_for_single_extent(dest_inode, dest_path)
> -		  + 4;
> +	credits = ext4_ext_calc_credits_for_single_extent(dest_inode,
> +			dest_path) + 2 +
> +			2 * EXT4_QUOTA_TRANS_BLOCKS(dest_inode->i_sb);
>  	err = ext4_ext_journal_restart(handle,
>  				credits + EXT4_TRANS_META_BLOCKS);
>  	if (err)
> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
> index 77f4f94..969b1e6 100644
> --- a/fs/ext4/extents.c
> +++ b/fs/ext4/extents.c
> @@ -1898,6 +1898,9 @@ static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
>   * for old tree and new tree, for every level we need to reserve
>   * credits to log the bitmap and block group descriptors
>   *
> + * This doesn't take into account credit needed for the update of
> + * super block + inode block + quota files
> + *
>   */
>  int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
>  						struct ext4_ext_path *path)
> @@ -1909,7 +1912,8 @@ int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
>  		depth = ext_depth(inode);
>  		if (le16_to_cpu(path[depth].p_hdr->eh_entries)
>  				< le16_to_cpu(path[depth].p_hdr->eh_max))
> -			return 1;
> +			/* 1 group desc + 1 block bitmap for allocated blocks */
> +			return 2;
>  	}
> 
>  	/*
> @@ -1919,7 +1923,7 @@ int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
>  	 */
>  	depth = 5;
> 
> -	/* allocation of new data block(s) */
> +	/* 1 group desc + 1 block bitmap for allocated blocks */
>  	needed = 2;
> 
>  	/*
> @@ -2059,9 +2063,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
>  			correct_index = 1;
>  			credits += (ext_depth(inode)) + 1;
>  		}
> -#ifdef CONFIG_QUOTA
>  		credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
> -#endif
> 
>  		err = ext4_ext_journal_restart(handle, credits);
>  		if (err)
> @@ -3023,9 +3025,7 @@ int  ext4_ext_writeblocks_trans_credits(struct inode *inode, int nrblocks)
>  	else
>  		needed = nrblocks * needed  + 2;
> 
> -#ifdef CONFIG_QUOTA
>  	needed += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
> -#endif
> 
>  	return needed;
>  }
> @@ -3092,7 +3092,7 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len)
>  	/*
>  	 * credits to insert 1 extent into extent tree
>  	 */
> -	credits =  EXT4_DATA_TRANS_BLOCKS(inode->i_sb);
> +	credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb);
>  	mutex_lock(&inode->i_mutex);
>  retry:
>  	while (ret >= 0 && ret < max_blocks) {
> diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
> index 5a394c8..d2832a1 100644
> --- a/fs/ext4/inode.c
> +++ b/fs/ext4/inode.c
> @@ -1126,18 +1126,29 @@ int ext4_get_blocks_wrap(handle_t *handle, struct inode *inode, sector_t block,
>  	up_write((&EXT4_I(inode)->i_data_sem));
>  	return retval;
>  }
> +static int ext4_writeblocks_trans_credits_old(struct inode *, int);
>  int ext4_get_block(struct inode *inode, sector_t iblock,
>  			struct buffer_head *bh_result, int create)
>  {
>  	handle_t *handle = ext4_journal_current_handle();
>  	int ret = 0, started = 0;
>  	unsigned max_blocks = bh_result->b_size >> inode->i_blkbits;
> -	int dio_credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb);
> +	int dio_credits;
> 
>  	if (create && !handle) {
>  		/* Direct IO write... */
>  		if (max_blocks > DIO_MAX_BLOCKS)
>  			max_blocks = DIO_MAX_BLOCKS;
> +		if (!(EXT4_I(inode)->i_flags & EXT4_EXTENTS_FL))
> +			dio_credits = ext4_writeblocks_trans_credits_old(inode,
> +							max_blocks);
> +		else {
> +			/*
> +			 * For extent format get_block return only one extent
> +			 */
> +			dio_credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb);
> +		}
> +
>  		handle = ext4_journal_start(inode, dio_credits);
>  		if (IS_ERR(handle)) {
>  			ret = PTR_ERR(handle);
> @@ -4310,14 +4321,18 @@ static int ext4_writeblocks_trans_credits_old(struct inode *inode, int nrblocks)
> 
>  	if (ext4_should_journal_data(inode))
>  		ret = 3 * (nrblocks + indirects) + 2;
> -	else
> -		ret = 2 * (nrblocks + indirects) + 2;
> +	else {
> +		/*
> +		 * We still need to journal update for the
> +		 * indirect, dindirect, and tindirect blocks
> +		 * only data blocks are not journalled
> +		 */
> +		ret = 3 * (nrblocks + indirects) + 2 - nrblocks;
> +	}
> 
> -#ifdef CONFIG_QUOTA
>  	/* We know that structure was already allocated during DQUOT_INIT so
>  	 * we will be updating only the data blocks + inodes */
> -	ret += 2*EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
> -#endif
> +	ret += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
> 
>  	return ret;
>  }
> diff --git a/fs/ext4/migrate.c b/fs/ext4/migrate.c
> index 3456094..72488ab 100644
> --- a/fs/ext4/migrate.c
> +++ b/fs/ext4/migrate.c
> @@ -55,7 +55,8 @@ static int finish_range(handle_t *handle, struct inode *inode,
>  	 *
>  	 * extra 4 credits for: 1 superblock, 1 inode block, 2 quotas
>  	 */
> -	needed = ext4_ext_calc_credits_for_single_extent(inode, path) + 4;
> +	needed = ext4_ext_calc_credits_for_single_extent(inode, path) + 2 +
> +				2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);;
> 
>  	/*
>  	 * Make sure the credit we accumalated is not really high
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux