Commit fddb564f authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

Merge tag 'xfs-perag-conv-5.20' of...

Merge tag 'xfs-perag-conv-5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs

 into xfs-5.20-mergeA

xfs: per-ag conversions for 5.20

This series drives the perag down into the AGI, AGF and AGFL access
routines and unifies the perag structure initialisation with the
high level AG header read functions. This largely replaces the
xfs_mount/agno pair that is passed to all these functions with a
perag, and in most places we already have a perag ready to pass in.
There are a few places where perags need to be grabbed before
reading the AG header buffers - some of these will need to be driven
to higher layers to ensure we can run operations on AGs without
getting stuck part way through waiting on a perag reference.

The latter section of this patchset moves some of the AG geometry
information from the xfs_mount to the xfs_perag, and starts
converting code that requires geometry validation to use a perag
instead of a mount and having to extract the AGNO from the object
location. This also allows us to store the AG size in the perag and
then we can stop having to compare the agno against sb_agcount to
determine if the AG is the last AG and so has a runt size.  This
greatly simplifies some of the type validity checking we do and
substantially reduces the CPU overhead of type validity checking. It
also cuts over 1.2kB out of the binary size.

Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>

* tag 'xfs-perag-conv-5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/linux-xfs:
  xfs: make is_log_ag() a first class helper
  xfs: replace xfs_ag_block_count() with perag accesses
  xfs: Pre-calculate per-AG agino geometry
  xfs: Pre-calculate per-AG agbno geometry
  xfs: pass perag to xfs_alloc_read_agfl
  xfs: pass perag to xfs_alloc_put_freelist
  xfs: pass perag to xfs_alloc_get_freelist
  xfs: pass perag to xfs_read_agf
  xfs: pass perag to xfs_read_agi
  xfs: pass perag to xfs_alloc_read_agf()
  xfs: kill xfs_alloc_pagf_init()
  xfs: pass perag to xfs_ialloc_read_agi()
  xfs: kill xfs_ialloc_pagi_init()
  xfs: make last AG grow/shrink perag centric
parents dd81dc05 36029dee
Loading
Loading
Loading
Loading
+112 −51
Original line number Diff line number Diff line
@@ -120,18 +120,18 @@ xfs_initialize_perag_data(

	for (index = 0; index < agcount; index++) {
		/*
		 * read the agf, then the agi. This gets us
		 * all the information we need and populates the
		 * per-ag structures for us.
		 * Read the AGF and AGI buffers to populate the per-ag
		 * structures for us.
		 */
		error = xfs_alloc_pagf_init(mp, NULL, index, 0);
		if (error)
		pag = xfs_perag_get(mp, index);
		error = xfs_alloc_read_agf(pag, NULL, 0, NULL);
		if (!error)
			error = xfs_ialloc_read_agi(pag, NULL, NULL);
		if (error) {
			xfs_perag_put(pag);
			return error;
		}

		error = xfs_ialloc_pagi_init(mp, NULL, index);
		if (error)
			return error;
		pag = xfs_perag_get(mp, index);
		ifree += pag->pagi_freecount;
		ialloc += pag->pagi_count;
		bfree += pag->pagf_freeblks;
@@ -201,10 +201,70 @@ xfs_free_perag(
	}
}

/* Find the size of the AG, in blocks. */
static xfs_agblock_t
__xfs_ag_block_count(
	struct xfs_mount	*mp,
	xfs_agnumber_t		agno,
	xfs_agnumber_t		agcount,
	xfs_rfsblock_t		dblocks)
{
	ASSERT(agno < agcount);

	if (agno < agcount - 1)
		return mp->m_sb.sb_agblocks;
	return dblocks - (agno * mp->m_sb.sb_agblocks);
}

xfs_agblock_t
xfs_ag_block_count(
	struct xfs_mount	*mp,
	xfs_agnumber_t		agno)
{
	return __xfs_ag_block_count(mp, agno, mp->m_sb.sb_agcount,
			mp->m_sb.sb_dblocks);
}

/* Calculate the first and last possible inode number in an AG. */
static void
__xfs_agino_range(
	struct xfs_mount	*mp,
	xfs_agblock_t		eoag,
	xfs_agino_t		*first,
	xfs_agino_t		*last)
{
	xfs_agblock_t		bno;

	/*
	 * Calculate the first inode, which will be in the first
	 * cluster-aligned block after the AGFL.
	 */
	bno = round_up(XFS_AGFL_BLOCK(mp) + 1, M_IGEO(mp)->cluster_align);
	*first = XFS_AGB_TO_AGINO(mp, bno);

	/*
	 * Calculate the last inode, which will be at the end of the
	 * last (aligned) cluster that can be allocated in the AG.
	 */
	bno = round_down(eoag, M_IGEO(mp)->cluster_align);
	*last = XFS_AGB_TO_AGINO(mp, bno) - 1;
}

void
xfs_agino_range(
	struct xfs_mount	*mp,
	xfs_agnumber_t		agno,
	xfs_agino_t		*first,
	xfs_agino_t		*last)
{
	return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
}

int
xfs_initialize_perag(
	struct xfs_mount	*mp,
	xfs_agnumber_t		agcount,
	xfs_rfsblock_t		dblocks,
	xfs_agnumber_t		*maxagi)
{
	struct xfs_perag	*pag;
@@ -270,6 +330,15 @@ xfs_initialize_perag(
		/* first new pag is fully initialized */
		if (first_initialised == NULLAGNUMBER)
			first_initialised = index;

		/*
		 * Pre-calculated geometry
		 */
		pag->block_count = __xfs_ag_block_count(mp, index, agcount,
				dblocks);
		pag->min_block = XFS_AGFL_BLOCK(mp);
		__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
				&pag->agino_max);
	}

	index = xfs_set_inode_alloc(mp, agcount);
@@ -321,12 +390,6 @@ xfs_get_aghdr_buf(
	return 0;
}

static inline bool is_log_ag(struct xfs_mount *mp, struct aghdr_init_data *id)
{
	return mp->m_sb.sb_logstart > 0 &&
	       id->agno == XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart);
}

/*
 * Generic btree root block init function
 */
@@ -352,7 +415,7 @@ xfs_freesp_init_recs(
	arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
	arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks);

	if (is_log_ag(mp, id)) {
	if (xfs_ag_contains_log(mp, id->agno)) {
		struct xfs_alloc_rec	*nrec;
		xfs_agblock_t		start = XFS_FSB_TO_AGBNO(mp,
							mp->m_sb.sb_logstart);
@@ -479,7 +542,7 @@ xfs_rmaproot_init(
	}

	/* account for the log space */
	if (is_log_ag(mp, id)) {
	if (xfs_ag_contains_log(mp, id->agno)) {
		rrec = XFS_RMAP_REC_ADDR(block,
				be16_to_cpu(block->bb_numrecs) + 1);
		rrec->rm_startblock = cpu_to_be32(
@@ -550,7 +613,7 @@ xfs_agfblock_init(
		agf->agf_refcount_blocks = cpu_to_be32(1);
	}

	if (is_log_ag(mp, id)) {
	if (xfs_ag_contains_log(mp, id->agno)) {
		int64_t	logblocks = mp->m_sb.sb_logblocks;

		be32_add_cpu(&agf->agf_freeblks, -logblocks);
@@ -761,11 +824,11 @@ xfs_ag_init_headers(

int
xfs_ag_shrink_space(
	struct xfs_mount	*mp,
	struct xfs_perag	*pag,
	struct xfs_trans	**tpp,
	xfs_agnumber_t		agno,
	xfs_extlen_t		delta)
{
	struct xfs_mount	*mp = pag->pag_mount;
	struct xfs_alloc_arg	args = {
		.tp	= *tpp,
		.mp	= mp,
@@ -782,14 +845,14 @@ xfs_ag_shrink_space(
	xfs_agblock_t		aglen;
	int			error, err2;

	ASSERT(agno == mp->m_sb.sb_agcount - 1);
	error = xfs_ialloc_read_agi(mp, *tpp, agno, &agibp);
	ASSERT(pag->pag_agno == mp->m_sb.sb_agcount - 1);
	error = xfs_ialloc_read_agi(pag, *tpp, &agibp);
	if (error)
		return error;

	agi = agibp->b_addr;

	error = xfs_alloc_read_agf(mp, *tpp, agno, 0, &agfbp);
	error = xfs_alloc_read_agf(pag, *tpp, 0, &agfbp);
	if (error)
		return error;

@@ -801,13 +864,14 @@ xfs_ag_shrink_space(
	if (delta >= aglen)
		return -EINVAL;

	args.fsbno = XFS_AGB_TO_FSB(mp, agno, aglen - delta);
	args.fsbno = XFS_AGB_TO_FSB(mp, pag->pag_agno, aglen - delta);

	/*
	 * Make sure that the last inode cluster cannot overlap with the new
	 * end of the AG, even if it's sparse.
	 */
	error = xfs_ialloc_check_shrink(*tpp, agno, agibp, aglen - delta);
	error = xfs_ialloc_check_shrink(*tpp, pag->pag_agno, agibp,
			aglen - delta);
	if (error)
		return error;

@@ -815,7 +879,7 @@ xfs_ag_shrink_space(
	 * Disable perag reservations so it doesn't cause the allocation request
	 * to fail. We'll reestablish reservation before we return.
	 */
	error = xfs_ag_resv_free(agibp->b_pag);
	error = xfs_ag_resv_free(pag);
	if (error)
		return error;

@@ -844,7 +908,7 @@ xfs_ag_shrink_space(
	be32_add_cpu(&agi->agi_length, -delta);
	be32_add_cpu(&agf->agf_length, -delta);

	err2 = xfs_ag_resv_init(agibp->b_pag, *tpp);
	err2 = xfs_ag_resv_init(pag, *tpp);
	if (err2) {
		be32_add_cpu(&agi->agi_length, delta);
		be32_add_cpu(&agf->agf_length, delta);
@@ -868,8 +932,9 @@ xfs_ag_shrink_space(
	xfs_ialloc_log_agi(*tpp, agibp, XFS_AGI_LENGTH);
	xfs_alloc_log_agf(*tpp, agfbp, XFS_AGF_LENGTH);
	return 0;

resv_init_out:
	err2 = xfs_ag_resv_init(agibp->b_pag, *tpp);
	err2 = xfs_ag_resv_init(pag, *tpp);
	if (!err2)
		return error;
resv_err:
@@ -883,9 +948,8 @@ xfs_ag_shrink_space(
 */
int
xfs_ag_extend_space(
	struct xfs_mount	*mp,
	struct xfs_perag	*pag,
	struct xfs_trans	*tp,
	struct aghdr_init_data	*id,
	xfs_extlen_t		len)
{
	struct xfs_buf		*bp;
@@ -893,23 +957,20 @@ xfs_ag_extend_space(
	struct xfs_agf		*agf;
	int			error;

	/*
	 * Change the agi length.
	 */
	error = xfs_ialloc_read_agi(mp, tp, id->agno, &bp);
	ASSERT(pag->pag_agno == pag->pag_mount->m_sb.sb_agcount - 1);

	error = xfs_ialloc_read_agi(pag, tp, &bp);
	if (error)
		return error;

	agi = bp->b_addr;
	be32_add_cpu(&agi->agi_length, len);
	ASSERT(id->agno == mp->m_sb.sb_agcount - 1 ||
	       be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks);
	xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH);

	/*
	 * Change agf length.
	 */
	error = xfs_alloc_read_agf(mp, tp, id->agno, 0, &bp);
	error = xfs_alloc_read_agf(pag, tp, 0, &bp);
	if (error)
		return error;

@@ -924,49 +985,49 @@ xfs_ag_extend_space(
	 * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that
	 * this doesn't actually exist in the rmap btree.
	 */
	error = xfs_rmap_free(tp, bp, bp->b_pag,
				be32_to_cpu(agf->agf_length) - len,
	error = xfs_rmap_free(tp, bp, pag, be32_to_cpu(agf->agf_length) - len,
				len, &XFS_RMAP_OINFO_SKIP_UPDATE);
	if (error)
		return error;

	return  xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, id->agno,
	error = xfs_free_extent(tp, XFS_AGB_TO_FSB(pag->pag_mount, pag->pag_agno,
					be32_to_cpu(agf->agf_length) - len),
				len, &XFS_RMAP_OINFO_SKIP_UPDATE,
				XFS_AG_RESV_NONE);
	if (error)
		return error;

	/* Update perag geometry */
	pag->block_count = be32_to_cpu(agf->agf_length);
	__xfs_agino_range(pag->pag_mount, pag->block_count, &pag->agino_min,
				&pag->agino_max);
	return 0;
}

/* Retrieve AG geometry. */
int
xfs_ag_get_geometry(
	struct xfs_mount	*mp,
	xfs_agnumber_t		agno,
	struct xfs_perag	*pag,
	struct xfs_ag_geometry	*ageo)
{
	struct xfs_buf		*agi_bp;
	struct xfs_buf		*agf_bp;
	struct xfs_agi		*agi;
	struct xfs_agf		*agf;
	struct xfs_perag	*pag;
	unsigned int		freeblks;
	int			error;

	if (agno >= mp->m_sb.sb_agcount)
		return -EINVAL;

	/* Lock the AG headers. */
	error = xfs_ialloc_read_agi(mp, NULL, agno, &agi_bp);
	error = xfs_ialloc_read_agi(pag, NULL, &agi_bp);
	if (error)
		return error;
	error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agf_bp);
	error = xfs_alloc_read_agf(pag, NULL, 0, &agf_bp);
	if (error)
		goto out_agi;

	pag = agi_bp->b_pag;

	/* Fill out form. */
	memset(ageo, 0, sizeof(*ageo));
	ageo->ag_number = agno;
	ageo->ag_number = pag->pag_agno;

	agi = agi_bp->b_addr;
	ageo->ag_icount = be32_to_cpu(agi->agi_count);
+62 −7
Original line number Diff line number Diff line
@@ -67,6 +67,12 @@ struct xfs_perag {
	/* for rcu-safe freeing */
	struct rcu_head	rcu_head;

	/* Precalculated geometry info */
	xfs_agblock_t		block_count;
	xfs_agblock_t		min_block;
	xfs_agino_t		agino_min;
	xfs_agino_t		agino_max;

#ifdef __KERNEL__
	/* -- kernel only structures below this line -- */

@@ -107,7 +113,7 @@ struct xfs_perag {
};

int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
			xfs_agnumber_t *maxagi);
			xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi);
int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
void xfs_free_perag(struct xfs_mount *mp);

@@ -116,6 +122,56 @@ struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *mp, xfs_agnumber_t agno,
		unsigned int tag);
void xfs_perag_put(struct xfs_perag *pag);

/*
 * Per-ag geometry infomation and validation
 */
xfs_agblock_t xfs_ag_block_count(struct xfs_mount *mp, xfs_agnumber_t agno);
void xfs_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno,
		xfs_agino_t *first, xfs_agino_t *last);

static inline bool
xfs_verify_agbno(struct xfs_perag *pag, xfs_agblock_t agbno)
{
	if (agbno >= pag->block_count)
		return false;
	if (agbno <= pag->min_block)
		return false;
	return true;
}

/*
 * Verify that an AG inode number pointer neither points outside the AG
 * nor points at static metadata.
 */
static inline bool
xfs_verify_agino(struct xfs_perag *pag, xfs_agino_t agino)
{
	if (agino < pag->agino_min)
		return false;
	if (agino > pag->agino_max)
		return false;
	return true;
}

/*
 * Verify that an AG inode number pointer neither points outside the AG
 * nor points at static metadata, or is NULLAGINO.
 */
static inline bool
xfs_verify_agino_or_null(struct xfs_perag *pag, xfs_agino_t agino)
{
	if (agino == NULLAGINO)
		return true;
	return xfs_verify_agino(pag, agino);
}

static inline bool
xfs_ag_contains_log(struct xfs_mount *mp, xfs_agnumber_t agno)
{
	return mp->m_sb.sb_logstart > 0 &&
	       agno == XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart);
}

/*
 * Perag iteration APIs
 */
@@ -168,11 +224,10 @@ struct aghdr_init_data {
};

int xfs_ag_init_headers(struct xfs_mount *mp, struct aghdr_init_data *id);
int xfs_ag_shrink_space(struct xfs_mount *mp, struct xfs_trans **tpp,
			xfs_agnumber_t agno, xfs_extlen_t delta);
int xfs_ag_extend_space(struct xfs_mount *mp, struct xfs_trans *tp,
			struct aghdr_init_data *id, xfs_extlen_t len);
int xfs_ag_get_geometry(struct xfs_mount *mp, xfs_agnumber_t agno,
			struct xfs_ag_geometry *ageo);
int xfs_ag_shrink_space(struct xfs_perag *pag, struct xfs_trans **tpp,
			xfs_extlen_t delta);
int xfs_ag_extend_space(struct xfs_perag *pag, struct xfs_trans *tp,
			xfs_extlen_t len);
int xfs_ag_get_geometry(struct xfs_perag *pag, struct xfs_ag_geometry *ageo);

#endif /* __LIBXFS_AG_H */
+1 −1
Original line number Diff line number Diff line
@@ -322,7 +322,7 @@ xfs_ag_resv_init(
	 * address.
	 */
	if (has_resv) {
		error2 = xfs_alloc_pagf_init(mp, tp, pag->pag_agno, 0);
		error2 = xfs_alloc_read_agf(pag, tp, 0, NULL);
		if (error2)
			return error2;

+63 −80
Original line number Diff line number Diff line
@@ -248,7 +248,7 @@ xfs_alloc_get_rec(
	int			*stat)	/* output: success/failure */
{
	struct xfs_mount	*mp = cur->bc_mp;
	xfs_agnumber_t		agno = cur->bc_ag.pag->pag_agno;
	struct xfs_perag	*pag = cur->bc_ag.pag;
	union xfs_btree_rec	*rec;
	int			error;

@@ -263,11 +263,11 @@ xfs_alloc_get_rec(
		goto out_bad_rec;

	/* check for valid extent range, including overflow */
	if (!xfs_verify_agbno(mp, agno, *bno))
	if (!xfs_verify_agbno(pag, *bno))
		goto out_bad_rec;
	if (*bno > *bno + *len)
		goto out_bad_rec;
	if (!xfs_verify_agbno(mp, agno, *bno + *len - 1))
	if (!xfs_verify_agbno(pag, *bno + *len - 1))
		goto out_bad_rec;

	return 0;
@@ -275,7 +275,8 @@ xfs_alloc_get_rec(
out_bad_rec:
	xfs_warn(mp,
		"%s Freespace BTree record corruption in AG %d detected!",
		cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size", agno);
		cur->bc_btnum == XFS_BTNUM_BNO ? "Block" : "Size",
		pag->pag_agno);
	xfs_warn(mp,
		"start block 0x%x block count 0x%x", *bno, *len);
	return -EFSCORRUPTED;
@@ -703,20 +704,19 @@ const struct xfs_buf_ops xfs_agfl_buf_ops = {
/*
 * Read in the allocation group free block array.
 */
int					/* error */
int
xfs_alloc_read_agfl(
	xfs_mount_t	*mp,		/* mount point structure */
	xfs_trans_t	*tp,		/* transaction pointer */
	xfs_agnumber_t	agno,		/* allocation group number */
	struct xfs_buf	**bpp)		/* buffer for the ag free block array */
	struct xfs_perag	*pag,
	struct xfs_trans	*tp,
	struct xfs_buf		**bpp)
{
	struct xfs_buf	*bp;		/* return value */
	struct xfs_mount	*mp = pag->pag_mount;
	struct xfs_buf		*bp;
	int			error;

	ASSERT(agno != NULLAGNUMBER);
	error = xfs_trans_read_buf(
			mp, tp, mp->m_ddev_targp,
			XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)),
			XFS_AG_DADDR(mp, pag->pag_agno, XFS_AGFL_DADDR(mp)),
			XFS_FSS_TO_BB(mp, 1), 0, &bp, &xfs_agfl_buf_ops);
	if (error)
		return error;
@@ -1075,7 +1075,8 @@ xfs_alloc_ag_vextent_small(
	    be32_to_cpu(agf->agf_flcount) <= args->minleft)
		goto out;

	error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0);
	error = xfs_alloc_get_freelist(args->pag, args->tp, args->agbp,
			&fbno, 0);
	if (error)
		goto error;
	if (fbno == NULLAGBLOCK)
@@ -2609,7 +2610,7 @@ xfs_alloc_fix_freelist(
	ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);

	if (!pag->pagf_init) {
		error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp);
		error = xfs_alloc_read_agf(pag, tp, flags, &agbp);
		if (error) {
			/* Couldn't lock the AGF so skip this AG. */
			if (error == -EAGAIN)
@@ -2639,7 +2640,7 @@ xfs_alloc_fix_freelist(
	 * Can fail if we're not blocking on locks, and it's held.
	 */
	if (!agbp) {
		error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp);
		error = xfs_alloc_read_agf(pag, tp, flags, &agbp);
		if (error) {
			/* Couldn't lock the AGF so skip this AG. */
			if (error == -EAGAIN)
@@ -2697,7 +2698,7 @@ xfs_alloc_fix_freelist(
	else
		targs.oinfo = XFS_RMAP_OINFO_AG;
	while (!(flags & XFS_ALLOC_FLAG_NOSHRINK) && pag->pagf_flcount > need) {
		error = xfs_alloc_get_freelist(tp, agbp, &bno, 0);
		error = xfs_alloc_get_freelist(pag, tp, agbp, &bno, 0);
		if (error)
			goto out_agbp_relse;

@@ -2712,7 +2713,7 @@ xfs_alloc_fix_freelist(
	targs.alignment = targs.minlen = targs.prod = 1;
	targs.type = XFS_ALLOCTYPE_THIS_AG;
	targs.pag = pag;
	error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp);
	error = xfs_alloc_read_agfl(pag, tp, &agflbp);
	if (error)
		goto out_agbp_relse;

@@ -2741,7 +2742,7 @@ xfs_alloc_fix_freelist(
		 * Put each allocated block on the list.
		 */
		for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) {
			error = xfs_alloc_put_freelist(tp, agbp,
			error = xfs_alloc_put_freelist(pag, tp, agbp,
							agflbp, bno, 0);
			if (error)
				goto out_agflbp_relse;
@@ -2767,6 +2768,7 @@ xfs_alloc_fix_freelist(
 */
int
xfs_alloc_get_freelist(
	struct xfs_perag	*pag,
	struct xfs_trans	*tp,
	struct xfs_buf		*agbp,
	xfs_agblock_t		*bnop,
@@ -2779,7 +2781,6 @@ xfs_alloc_get_freelist(
	int			error;
	uint32_t		logflags;
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_perag	*pag;

	/*
	 * Freelist is empty, give up.
@@ -2791,8 +2792,7 @@ xfs_alloc_get_freelist(
	/*
	 * Read the array of free blocks.
	 */
	error = xfs_alloc_read_agfl(mp, tp, be32_to_cpu(agf->agf_seqno),
				    &agflbp);
	error = xfs_alloc_read_agfl(pag, tp, &agflbp);
	if (error)
		return error;

@@ -2807,7 +2807,6 @@ xfs_alloc_get_freelist(
	if (be32_to_cpu(agf->agf_flfirst) == xfs_agfl_size(mp))
		agf->agf_flfirst = 0;

	pag = agbp->b_pag;
	ASSERT(!pag->pagf_agflreset);
	be32_add_cpu(&agf->agf_flcount, -1);
	pag->pagf_flcount--;
@@ -2867,30 +2866,12 @@ xfs_alloc_log_agf(
	xfs_trans_log_buf(tp, bp, (uint)first, (uint)last);
}

/*
 * Interface for inode allocation to force the pag data to be initialized.
 */
int					/* error */
xfs_alloc_pagf_init(
	xfs_mount_t		*mp,	/* file system mount structure */
	xfs_trans_t		*tp,	/* transaction pointer */
	xfs_agnumber_t		agno,	/* allocation group number */
	int			flags)	/* XFS_ALLOC_FLAGS_... */
{
	struct xfs_buf		*bp;
	int			error;

	error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp);
	if (!error)
		xfs_trans_brelse(tp, bp);
	return error;
}

/*
 * Put the block on the freelist for the allocation group.
 */
int
xfs_alloc_put_freelist(
	struct xfs_perag	*pag,
	struct xfs_trans	*tp,
	struct xfs_buf		*agbp,
	struct xfs_buf		*agflbp,
@@ -2899,21 +2880,22 @@ xfs_alloc_put_freelist(
{
	struct xfs_mount	*mp = tp->t_mountp;
	struct xfs_agf		*agf = agbp->b_addr;
	struct xfs_perag	*pag;
	__be32			*blockp;
	int			error;
	uint32_t		logflags;
	__be32			*agfl_bno;
	int			startoff;

	if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp,
			be32_to_cpu(agf->agf_seqno), &agflbp)))
	if (!agflbp) {
		error = xfs_alloc_read_agfl(pag, tp, &agflbp);
		if (error)
			return error;
	}

	be32_add_cpu(&agf->agf_fllast, 1);
	if (be32_to_cpu(agf->agf_fllast) == xfs_agfl_size(mp))
		agf->agf_fllast = 0;

	pag = agbp->b_pag;
	ASSERT(!pag->pagf_agflreset);
	be32_add_cpu(&agf->agf_flcount, 1);
	pag->pagf_flcount++;
@@ -3070,61 +3052,57 @@ const struct xfs_buf_ops xfs_agf_buf_ops = {
/*
 * Read in the allocation group header (free/alloc section).
 */
int					/* error */
int
xfs_read_agf(
	struct xfs_mount	*mp,	/* mount point structure */
	struct xfs_trans	*tp,	/* transaction pointer */
	xfs_agnumber_t		agno,	/* allocation group number */
	int			flags,	/* XFS_BUF_ */
	struct xfs_buf		**bpp)	/* buffer for the ag freelist header */
	struct xfs_perag	*pag,
	struct xfs_trans	*tp,
	int			flags,
	struct xfs_buf		**agfbpp)
{
	struct xfs_mount	*mp = pag->pag_mount;
	int			error;

	trace_xfs_read_agf(mp, agno);
	trace_xfs_read_agf(pag->pag_mount, pag->pag_agno);

	ASSERT(agno != NULLAGNUMBER);
	error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp,
			XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)),
			XFS_FSS_TO_BB(mp, 1), flags, bpp, &xfs_agf_buf_ops);
			XFS_AG_DADDR(mp, pag->pag_agno, XFS_AGF_DADDR(mp)),
			XFS_FSS_TO_BB(mp, 1), flags, agfbpp, &xfs_agf_buf_ops);
	if (error)
		return error;

	ASSERT(!(*bpp)->b_error);
	xfs_buf_set_ref(*bpp, XFS_AGF_REF);
	xfs_buf_set_ref(*agfbpp, XFS_AGF_REF);
	return 0;
}

/*
 * Read in the allocation group header (free/alloc section).
 * Read in the allocation group header (free/alloc section) and initialise the
 * perag structure if necessary. If the caller provides @agfbpp, then return the
 * locked buffer to the caller, otherwise free it.
 */
int					/* error */
int
xfs_alloc_read_agf(
	struct xfs_mount	*mp,	/* mount point structure */
	struct xfs_trans	*tp,	/* transaction pointer */
	xfs_agnumber_t		agno,	/* allocation group number */
	int			flags,	/* XFS_ALLOC_FLAG_... */
	struct xfs_buf		**bpp)	/* buffer for the ag freelist header */
{
	struct xfs_agf		*agf;		/* ag freelist header */
	struct xfs_perag	*pag;		/* per allocation group data */
	struct xfs_perag	*pag,
	struct xfs_trans	*tp,
	int			flags,
	struct xfs_buf		**agfbpp)
{
	struct xfs_buf		*agfbp;
	struct xfs_agf		*agf;
	int			error;
	int			allocbt_blks;

	trace_xfs_alloc_read_agf(mp, agno);
	trace_xfs_alloc_read_agf(pag->pag_mount, pag->pag_agno);

	/* We don't support trylock when freeing. */
	ASSERT((flags & (XFS_ALLOC_FLAG_FREEING | XFS_ALLOC_FLAG_TRYLOCK)) !=
			(XFS_ALLOC_FLAG_FREEING | XFS_ALLOC_FLAG_TRYLOCK));
	ASSERT(agno != NULLAGNUMBER);
	error = xfs_read_agf(mp, tp, agno,
	error = xfs_read_agf(pag, tp,
			(flags & XFS_ALLOC_FLAG_TRYLOCK) ? XBF_TRYLOCK : 0,
			bpp);
			&agfbp);
	if (error)
		return error;
	ASSERT(!(*bpp)->b_error);

	agf = (*bpp)->b_addr;
	pag = (*bpp)->b_pag;
	agf = agfbp->b_addr;
	if (!pag->pagf_init) {
		pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks);
		pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks);
@@ -3138,7 +3116,7 @@ xfs_alloc_read_agf(
			be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAPi]);
		pag->pagf_refcount_level = be32_to_cpu(agf->agf_refcount_level);
		pag->pagf_init = 1;
		pag->pagf_agflreset = xfs_agfl_needs_reset(mp, agf);
		pag->pagf_agflreset = xfs_agfl_needs_reset(pag->pag_mount, agf);

		/*
		 * Update the in-core allocbt counter. Filter out the rmapbt
@@ -3148,13 +3126,14 @@ xfs_alloc_read_agf(
		 * counter only tracks non-root blocks.
		 */
		allocbt_blks = pag->pagf_btreeblks;
		if (xfs_has_rmapbt(mp))
		if (xfs_has_rmapbt(pag->pag_mount))
			allocbt_blks -= be32_to_cpu(agf->agf_rmap_blocks) - 1;
		if (allocbt_blks > 0)
			atomic64_add(allocbt_blks, &mp->m_allocbt_blks);
			atomic64_add(allocbt_blks,
					&pag->pag_mount->m_allocbt_blks);
	}
#ifdef DEBUG
	else if (!xfs_is_shutdown(mp)) {
	else if (!xfs_is_shutdown(pag->pag_mount)) {
		ASSERT(pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks));
		ASSERT(pag->pagf_btreeblks == be32_to_cpu(agf->agf_btreeblks));
		ASSERT(pag->pagf_flcount == be32_to_cpu(agf->agf_flcount));
@@ -3165,6 +3144,10 @@ xfs_alloc_read_agf(
		       be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]));
	}
#endif
	if (agfbpp)
		*agfbpp = agfbp;
	else
		xfs_trans_brelse(tp, agfbp);
	return 0;
}

+11 −47
Original line number Diff line number Diff line
@@ -95,6 +95,11 @@ xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_perag *pag,
		xfs_extlen_t need, xfs_extlen_t reserved);
unsigned int xfs_alloc_min_freelist(struct xfs_mount *mp,
		struct xfs_perag *pag);
int xfs_alloc_get_freelist(struct xfs_perag *pag, struct xfs_trans *tp,
		struct xfs_buf *agfbp, xfs_agblock_t *bnop, int	 btreeblk);
int xfs_alloc_put_freelist(struct xfs_perag *pag, struct xfs_trans *tp,
		struct xfs_buf *agfbp, struct xfs_buf *agflbp,
		xfs_agblock_t bno, int btreeblk);

/*
 * Compute and fill in value of m_alloc_maxlevels.
@@ -103,17 +108,6 @@ void
xfs_alloc_compute_maxlevels(
	struct xfs_mount	*mp);	/* file system mount structure */

/*
 * Get a block from the freelist.
 * Returns with the buffer for the block gotten.
 */
int				/* error */
xfs_alloc_get_freelist(
	struct xfs_trans *tp,	/* transaction pointer */
	struct xfs_buf	*agbp,	/* buffer containing the agf structure */
	xfs_agblock_t	*bnop,	/* block address retrieved from freelist */
	int		btreeblk); /* destination is a AGF btree */

/*
 * Log the given fields from the agf structure.
 */
@@ -123,38 +117,6 @@ xfs_alloc_log_agf(
	struct xfs_buf	*bp,	/* buffer for a.g. freelist header */
	uint32_t	fields);/* mask of fields to be logged (XFS_AGF_...) */

/*
 * Interface for inode allocation to force the pag data to be initialized.
 */
int				/* error */
xfs_alloc_pagf_init(
	struct xfs_mount *mp,	/* file system mount structure */
	struct xfs_trans *tp,	/* transaction pointer */
	xfs_agnumber_t	agno,	/* allocation group number */
	int		flags);	/* XFS_ALLOC_FLAGS_... */

/*
 * Put the block on the freelist for the allocation group.
 */
int				/* error */
xfs_alloc_put_freelist(
	struct xfs_trans *tp,	/* transaction pointer */
	struct xfs_buf	*agbp,	/* buffer for a.g. freelist header */
	struct xfs_buf	*agflbp,/* buffer for a.g. free block array */
	xfs_agblock_t	bno,	/* block being freed */
	int		btreeblk); /* owner was a AGF btree */

/*
 * Read in the allocation group header (free/alloc section).
 */
int					/* error  */
xfs_alloc_read_agf(
	struct xfs_mount *mp,		/* mount point structure */
	struct xfs_trans *tp,		/* transaction pointer */
	xfs_agnumber_t	agno,		/* allocation group number */
	int		flags,		/* XFS_ALLOC_FLAG_... */
	struct xfs_buf	**bpp);		/* buffer for the ag freelist header */

/*
 * Allocate an extent (variable-size).
 */
@@ -206,10 +168,12 @@ xfs_alloc_get_rec(
	xfs_extlen_t		*len,	/* output: length of extent */
	int			*stat);	/* output: success/failure */

int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp,
			xfs_agnumber_t agno, int flags, struct xfs_buf **bpp);
int xfs_alloc_read_agfl(struct xfs_mount *mp, struct xfs_trans *tp,
			xfs_agnumber_t agno, struct xfs_buf **bpp);
int xfs_read_agf(struct xfs_perag *pag, struct xfs_trans *tp, int flags,
		struct xfs_buf **agfbpp);
int xfs_alloc_read_agf(struct xfs_perag *pag, struct xfs_trans *tp, int flags,
		struct xfs_buf **agfbpp);
int xfs_alloc_read_agfl(struct xfs_perag *pag, struct xfs_trans *tp,
		struct xfs_buf **bpp);
int xfs_free_agfl_block(struct xfs_trans *, xfs_agnumber_t, xfs_agblock_t,
			struct xfs_buf *, struct xfs_owner_info *);
int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags);
Loading