Re: [PATCH 1/2] xfs: allow inode allocations in post-growfs disk space

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

 



On Wed, Jul 02, 2014 at 11:54:06PM -0500, Eric Sandeen wrote:
> Today, if we perform an xfs_growfs which adds allocation groups,
> mp->m_maxagi is not properly updated when the growfs is complete.
> 
> Therefore inodes will continue to be allocated only in the
> AGs which existed prior to the growfs, and the new space
> won't be utilized.
> 
> This is because of this path in xfs_growfs_data_private():
> 
> xfs_growfs_data_private
> 	xfs_initialize_perag(mp, nagcount, &nagimax);
> 	 	if (mp->m_flags & XFS_MOUNT_32BITINODES)
> 			index = xfs_set_inode32(mp);
>  		else
> 			index = xfs_set_inode64(mp);
> 
> 	 	if (maxagi)
>  			*maxagi = index;
> 
> where xfs_set_inode* iterates over the (old) agcount in
> mp->m_sb.sb_agblocks, which has not yet been updated
> in the growfs path.  So "index" will be returned based on
> the old agcount, not the new one, and new AGs are not available
> for inode allocation.
> 
> Fix this by explicitly passing the proper AG count (which 
> xfs_initialize_perag() already has) down another level,
> so that xfs_set_inode* can make the proper decision about
> acceptable AGs for inode allocation in the potentially
> newly-added AGs.
> 
> This has been broken since 3.7, when these two
> xfs_set_inode* functions were added in commit 2d2194f.
> Prior to that, we looped over "agcount" not sb_agblocks
> in these calculations.
> 
> Signed-off-by: Eric Sandeen <sandeen@xxxxxxxxxx>
> ---
> 
> tested for regression with the -g growfs group, but this
> shows that we need another testcase for growfs.
> 
> 
> diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
> index 993cb19..b291ada 100644
> --- a/fs/xfs/xfs_mount.c
> +++ b/fs/xfs/xfs_mount.c
> @@ -250,9 +250,9 @@ xfs_initialize_perag(
>  		mp->m_flags &= ~XFS_MOUNT_32BITINODES;
>  
>  	if (mp->m_flags & XFS_MOUNT_32BITINODES)
> -		index = xfs_set_inode32(mp);
> +		index = xfs_set_inode32(mp, agcount);
>  	else
> -		index = xfs_set_inode64(mp);
> +		index = xfs_set_inode64(mp, agcount);
>  
>  	if (maxagi)
>  		*maxagi = index;
> diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
> index 87e8b01..ccc564d 100644
> --- a/fs/xfs/xfs_super.c
> +++ b/fs/xfs/xfs_super.c
> @@ -597,8 +597,13 @@ xfs_max_file_offset(
>  	return (((__uint64_t)pagefactor) << bitshift) - 1;
>  }
>  
> +/*
> + * xfs_set_inode32() and xfs_set_inode64() are passed an agcount
> + * because in the growfs case, mp->m_sb.sb_agcount is not updated
> + * yet to the potentially higher ag count.
> + */
>  xfs_agnumber_t
> -xfs_set_inode32(struct xfs_mount *mp)
> +xfs_set_inode32(struct xfs_mount *mp, xfs_agnumber_t agcount)
>  {
>  	xfs_agnumber_t	index = 0;
>  	xfs_agnumber_t	maxagi = 0;
> @@ -620,10 +625,10 @@ xfs_set_inode32(struct xfs_mount *mp)
>  		do_div(icount, sbp->sb_agblocks);
>  		max_metadata = icount;
>  	} else {
> -		max_metadata = sbp->sb_agcount;
> +		max_metadata = agcount;

The fix looks pretty good to me, but what about the 'if' branch of this
logic here? We calculate max_metadata based on sb_dblocks, which also
isn't updated until the growfs tp commit. That appears to be a similar
bug in that we wouldn't set pagf_metadata on the new AGs where
appropriate, which I think means data allocation could steal the new
inode space sooner than anticipated.

I wonder if this is better moved after the superblock is updated?

Brian

>  	}
>  
> -	for (index = 0; index < sbp->sb_agcount; index++) {
> +	for (index = 0; index < agcount; index++) {
>  		ino = XFS_AGINO_TO_INO(mp, index, agino);
>  
>  		if (ino > XFS_MAXINUMBER_32) {
> @@ -648,11 +653,11 @@ xfs_set_inode32(struct xfs_mount *mp)
>  }
>  
>  xfs_agnumber_t
> -xfs_set_inode64(struct xfs_mount *mp)
> +xfs_set_inode64(struct xfs_mount *mp, xfs_agnumber_t agcount)
>  {
>  	xfs_agnumber_t index = 0;
>  
> -	for (index = 0; index < mp->m_sb.sb_agcount; index++) {
> +	for (index = 0; index < agcount; index++) {
>  		struct xfs_perag	*pag;
>  
>  		pag = xfs_perag_get(mp, index);
> @@ -1193,6 +1198,7 @@ xfs_fs_remount(
>  	char			*options)
>  {
>  	struct xfs_mount	*mp = XFS_M(sb);
> +	xfs_sb_t		*sbp = &mp->m_sb;
>  	substring_t		args[MAX_OPT_ARGS];
>  	char			*p;
>  	int			error;
> @@ -1212,10 +1218,10 @@ xfs_fs_remount(
>  			mp->m_flags &= ~XFS_MOUNT_BARRIER;
>  			break;
>  		case Opt_inode64:
> -			mp->m_maxagi = xfs_set_inode64(mp);
> +			mp->m_maxagi = xfs_set_inode64(mp, sbp->sb_agcount);
>  			break;
>  		case Opt_inode32:
> -			mp->m_maxagi = xfs_set_inode32(mp);
> +			mp->m_maxagi = xfs_set_inode32(mp, sbp->sb_agcount);
>  			break;
>  		default:
>  			/*
> diff --git a/fs/xfs/xfs_super.h b/fs/xfs/xfs_super.h
> index bbe3d15..b4cfe21 100644
> --- a/fs/xfs/xfs_super.h
> +++ b/fs/xfs/xfs_super.h
> @@ -76,8 +76,8 @@ extern __uint64_t xfs_max_file_offset(unsigned int);
>  
>  extern void xfs_flush_inodes(struct xfs_mount *mp);
>  extern void xfs_blkdev_issue_flush(struct xfs_buftarg *);
> -extern xfs_agnumber_t xfs_set_inode32(struct xfs_mount *);
> -extern xfs_agnumber_t xfs_set_inode64(struct xfs_mount *);
> +extern xfs_agnumber_t xfs_set_inode32(struct xfs_mount *, xfs_agnumber_t agcount);
> +extern xfs_agnumber_t xfs_set_inode64(struct xfs_mount *, xfs_agnumber_t agcount);
>  
>  extern const struct export_operations xfs_export_operations;
>  extern const struct xattr_handler *xfs_xattr_handlers[];
> 
> 
> _______________________________________________
> xfs mailing list
> xfs@xxxxxxxxxxx
> http://oss.sgi.com/mailman/listinfo/xfs

_______________________________________________
xfs mailing list
xfs@xxxxxxxxxxx
http://oss.sgi.com/mailman/listinfo/xfs




[Index of Archives]     [Linux XFS Devel]     [Linux Filesystem Development]     [Filesystem Testing]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux