We need to check if an affected AG is empty or not during FS shrink, this is a helper could be used for this purpose. Maybe it's better to isolate AG related routines to a dedicated file: xfs_ag.c? Signed-off-by: Jie Liu <jeff.liu@xxxxxxxxxx> --- fs/xfs/xfs_fsops.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 92 insertions(+), 0 deletions(-) diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index 029ab6d..6623d9a 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -614,6 +614,98 @@ xfs_growfs_log( } /* + * Get the reserved blocks of metadatas per AG which are includes: + * Superblock (1 sector) + * AG free block info (1 sector) + * AG inode B+tree info (1 sector) + * AG internal free list (1 sector) + * Root of inode B+tree (1 block) + * Root of free space B+tree, key is block number (1 block) + * Root of free space B+tree, key is block count (1 block) + * Free list (4 blocks) + * The reserved block number of the aboves can be fetched via: + * XFS_PREALLOC_BLOCKS(mp). + * + * The left blocks are used for Primary AG only. + * - Inodes (64 inodes) + */ +static xfs_extlen_t +xfs_ag_metadata_blocks( + xfs_mount_t *mp, + xfs_agnumber_t agno) +{ + xfs_extlen_t mdblocks; + + mdblocks = XFS_PREALLOC_BLOCKS(mp); + /* + * For primary AG, we need to figure out how many blocks are + * reserved for those 64 inodes which are used for the root + * of inodes B+tree. + */ + if (agno == 0) + mdblocks += (64 / mp->m_sb.sb_inopblock); + + return mdblocks; +} + +/* + * An empty AG means that there has no data/inodes allocated + * at it except those metadata blocks, and the agi_count should + * be ZERO. + */ +static int +xfs_ag_is_empty( + xfs_mount_t *mp, + xfs_agnumber_t agno, + bool *empty) +{ + xfs_extlen_t agblocks; + xfs_extlen_t agfblocks; + xfs_extlen_t agmblocks; + xfs_extlen_t agicount; + xfs_agf_t *agf; + xfs_agi_t *agi; + xfs_buf_t *bp; + int error = 0; + + bp = xfs_buf_get(mp->m_ddev_targp, + XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), + XFS_FSS_TO_BB(mp, 1), 0); + if (!bp) { + error = XFS_ERROR(ENOMEM); + goto error0; + } + agf = XFS_BUF_TO_AGF(bp); + agmblocks = xfs_ag_metadata_blocks(mp, agno); + /* + * The latest AG might has different size to others. + */ + if (agno == mp->m_sb.sb_agcount - 1) + agblocks = (be32_to_cpu(agf->agf_length) - agmblocks); + else + agblocks = mp->m_sb.sb_agblocks - agmblocks; + agfblocks = be32_to_cpu(agf->agf_freeblks); + xfs_buf_relse(bp); + + bp = xfs_buf_get(mp->m_ddev_targp, + XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), + XFS_FSS_TO_BB(mp, 1), 0); + if (!bp) { + error = XFS_ERROR(ENOMEM); + goto error0; + } + agi = XFS_BUF_TO_AGI(bp); + agicount = be32_to_cpu(agi->agi_count); + xfs_buf_relse(bp); + + *empty = ((agblocks == agfblocks && agicount == 0) ? + true : false); + +error0: + return error; +} + +/* * exported through ioctl XFS_IOC_FSCOUNTS */ -- 1.7.4.1 _______________________________________________ xfs mailing list xfs@xxxxxxxxxxx http://oss.sgi.com/mailman/listinfo/xfs