162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc.
462306a36Sopenharmony_ci * Copyright (c) 2018 Red Hat, Inc.
562306a36Sopenharmony_ci * All rights reserved.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include "xfs.h"
962306a36Sopenharmony_ci#include "xfs_fs.h"
1062306a36Sopenharmony_ci#include "xfs_shared.h"
1162306a36Sopenharmony_ci#include "xfs_format.h"
1262306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1362306a36Sopenharmony_ci#include "xfs_bit.h"
1462306a36Sopenharmony_ci#include "xfs_sb.h"
1562306a36Sopenharmony_ci#include "xfs_mount.h"
1662306a36Sopenharmony_ci#include "xfs_btree.h"
1762306a36Sopenharmony_ci#include "xfs_alloc_btree.h"
1862306a36Sopenharmony_ci#include "xfs_rmap_btree.h"
1962306a36Sopenharmony_ci#include "xfs_alloc.h"
2062306a36Sopenharmony_ci#include "xfs_ialloc.h"
2162306a36Sopenharmony_ci#include "xfs_rmap.h"
2262306a36Sopenharmony_ci#include "xfs_ag.h"
2362306a36Sopenharmony_ci#include "xfs_ag_resv.h"
2462306a36Sopenharmony_ci#include "xfs_health.h"
2562306a36Sopenharmony_ci#include "xfs_error.h"
2662306a36Sopenharmony_ci#include "xfs_bmap.h"
2762306a36Sopenharmony_ci#include "xfs_defer.h"
2862306a36Sopenharmony_ci#include "xfs_log_format.h"
2962306a36Sopenharmony_ci#include "xfs_trans.h"
3062306a36Sopenharmony_ci#include "xfs_trace.h"
3162306a36Sopenharmony_ci#include "xfs_inode.h"
3262306a36Sopenharmony_ci#include "xfs_icache.h"
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci/*
3662306a36Sopenharmony_ci * Passive reference counting access wrappers to the perag structures.  If the
3762306a36Sopenharmony_ci * per-ag structure is to be freed, the freeing code is responsible for cleaning
3862306a36Sopenharmony_ci * up objects with passive references before freeing the structure. This is
3962306a36Sopenharmony_ci * things like cached buffers.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_cistruct xfs_perag *
4262306a36Sopenharmony_cixfs_perag_get(
4362306a36Sopenharmony_ci	struct xfs_mount	*mp,
4462306a36Sopenharmony_ci	xfs_agnumber_t		agno)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct xfs_perag	*pag;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	rcu_read_lock();
4962306a36Sopenharmony_ci	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
5062306a36Sopenharmony_ci	if (pag) {
5162306a36Sopenharmony_ci		trace_xfs_perag_get(pag, _RET_IP_);
5262306a36Sopenharmony_ci		ASSERT(atomic_read(&pag->pag_ref) >= 0);
5362306a36Sopenharmony_ci		atomic_inc(&pag->pag_ref);
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci	rcu_read_unlock();
5662306a36Sopenharmony_ci	return pag;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * search from @first to find the next perag with the given tag set.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_cistruct xfs_perag *
6362306a36Sopenharmony_cixfs_perag_get_tag(
6462306a36Sopenharmony_ci	struct xfs_mount	*mp,
6562306a36Sopenharmony_ci	xfs_agnumber_t		first,
6662306a36Sopenharmony_ci	unsigned int		tag)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct xfs_perag	*pag;
6962306a36Sopenharmony_ci	int			found;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	rcu_read_lock();
7262306a36Sopenharmony_ci	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
7362306a36Sopenharmony_ci					(void **)&pag, first, 1, tag);
7462306a36Sopenharmony_ci	if (found <= 0) {
7562306a36Sopenharmony_ci		rcu_read_unlock();
7662306a36Sopenharmony_ci		return NULL;
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci	trace_xfs_perag_get_tag(pag, _RET_IP_);
7962306a36Sopenharmony_ci	atomic_inc(&pag->pag_ref);
8062306a36Sopenharmony_ci	rcu_read_unlock();
8162306a36Sopenharmony_ci	return pag;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/* Get a passive reference to the given perag. */
8562306a36Sopenharmony_cistruct xfs_perag *
8662306a36Sopenharmony_cixfs_perag_hold(
8762306a36Sopenharmony_ci	struct xfs_perag	*pag)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	ASSERT(atomic_read(&pag->pag_ref) > 0 ||
9062306a36Sopenharmony_ci	       atomic_read(&pag->pag_active_ref) > 0);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	trace_xfs_perag_hold(pag, _RET_IP_);
9362306a36Sopenharmony_ci	atomic_inc(&pag->pag_ref);
9462306a36Sopenharmony_ci	return pag;
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_civoid
9862306a36Sopenharmony_cixfs_perag_put(
9962306a36Sopenharmony_ci	struct xfs_perag	*pag)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	trace_xfs_perag_put(pag, _RET_IP_);
10262306a36Sopenharmony_ci	ASSERT(atomic_read(&pag->pag_ref) > 0);
10362306a36Sopenharmony_ci	atomic_dec(&pag->pag_ref);
10462306a36Sopenharmony_ci}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci/*
10762306a36Sopenharmony_ci * Active references for perag structures. This is for short term access to the
10862306a36Sopenharmony_ci * per ag structures for walking trees or accessing state. If an AG is being
10962306a36Sopenharmony_ci * shrunk or is offline, then this will fail to find that AG and return NULL
11062306a36Sopenharmony_ci * instead.
11162306a36Sopenharmony_ci */
11262306a36Sopenharmony_cistruct xfs_perag *
11362306a36Sopenharmony_cixfs_perag_grab(
11462306a36Sopenharmony_ci	struct xfs_mount	*mp,
11562306a36Sopenharmony_ci	xfs_agnumber_t		agno)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct xfs_perag	*pag;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	rcu_read_lock();
12062306a36Sopenharmony_ci	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
12162306a36Sopenharmony_ci	if (pag) {
12262306a36Sopenharmony_ci		trace_xfs_perag_grab(pag, _RET_IP_);
12362306a36Sopenharmony_ci		if (!atomic_inc_not_zero(&pag->pag_active_ref))
12462306a36Sopenharmony_ci			pag = NULL;
12562306a36Sopenharmony_ci	}
12662306a36Sopenharmony_ci	rcu_read_unlock();
12762306a36Sopenharmony_ci	return pag;
12862306a36Sopenharmony_ci}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci/*
13162306a36Sopenharmony_ci * search from @first to find the next perag with the given tag set.
13262306a36Sopenharmony_ci */
13362306a36Sopenharmony_cistruct xfs_perag *
13462306a36Sopenharmony_cixfs_perag_grab_tag(
13562306a36Sopenharmony_ci	struct xfs_mount	*mp,
13662306a36Sopenharmony_ci	xfs_agnumber_t		first,
13762306a36Sopenharmony_ci	int			tag)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct xfs_perag	*pag;
14062306a36Sopenharmony_ci	int			found;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	rcu_read_lock();
14362306a36Sopenharmony_ci	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
14462306a36Sopenharmony_ci					(void **)&pag, first, 1, tag);
14562306a36Sopenharmony_ci	if (found <= 0) {
14662306a36Sopenharmony_ci		rcu_read_unlock();
14762306a36Sopenharmony_ci		return NULL;
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci	trace_xfs_perag_grab_tag(pag, _RET_IP_);
15062306a36Sopenharmony_ci	if (!atomic_inc_not_zero(&pag->pag_active_ref))
15162306a36Sopenharmony_ci		pag = NULL;
15262306a36Sopenharmony_ci	rcu_read_unlock();
15362306a36Sopenharmony_ci	return pag;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_civoid
15762306a36Sopenharmony_cixfs_perag_rele(
15862306a36Sopenharmony_ci	struct xfs_perag	*pag)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	trace_xfs_perag_rele(pag, _RET_IP_);
16162306a36Sopenharmony_ci	if (atomic_dec_and_test(&pag->pag_active_ref))
16262306a36Sopenharmony_ci		wake_up(&pag->pag_active_wq);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/*
16662306a36Sopenharmony_ci * xfs_initialize_perag_data
16762306a36Sopenharmony_ci *
16862306a36Sopenharmony_ci * Read in each per-ag structure so we can count up the number of
16962306a36Sopenharmony_ci * allocated inodes, free inodes and used filesystem blocks as this
17062306a36Sopenharmony_ci * information is no longer persistent in the superblock. Once we have
17162306a36Sopenharmony_ci * this information, write it into the in-core superblock structure.
17262306a36Sopenharmony_ci */
17362306a36Sopenharmony_ciint
17462306a36Sopenharmony_cixfs_initialize_perag_data(
17562306a36Sopenharmony_ci	struct xfs_mount	*mp,
17662306a36Sopenharmony_ci	xfs_agnumber_t		agcount)
17762306a36Sopenharmony_ci{
17862306a36Sopenharmony_ci	xfs_agnumber_t		index;
17962306a36Sopenharmony_ci	struct xfs_perag	*pag;
18062306a36Sopenharmony_ci	struct xfs_sb		*sbp = &mp->m_sb;
18162306a36Sopenharmony_ci	uint64_t		ifree = 0;
18262306a36Sopenharmony_ci	uint64_t		ialloc = 0;
18362306a36Sopenharmony_ci	uint64_t		bfree = 0;
18462306a36Sopenharmony_ci	uint64_t		bfreelst = 0;
18562306a36Sopenharmony_ci	uint64_t		btree = 0;
18662306a36Sopenharmony_ci	uint64_t		fdblocks;
18762306a36Sopenharmony_ci	int			error = 0;
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	for (index = 0; index < agcount; index++) {
19062306a36Sopenharmony_ci		/*
19162306a36Sopenharmony_ci		 * Read the AGF and AGI buffers to populate the per-ag
19262306a36Sopenharmony_ci		 * structures for us.
19362306a36Sopenharmony_ci		 */
19462306a36Sopenharmony_ci		pag = xfs_perag_get(mp, index);
19562306a36Sopenharmony_ci		error = xfs_alloc_read_agf(pag, NULL, 0, NULL);
19662306a36Sopenharmony_ci		if (!error)
19762306a36Sopenharmony_ci			error = xfs_ialloc_read_agi(pag, NULL, NULL);
19862306a36Sopenharmony_ci		if (error) {
19962306a36Sopenharmony_ci			xfs_perag_put(pag);
20062306a36Sopenharmony_ci			return error;
20162306a36Sopenharmony_ci		}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci		ifree += pag->pagi_freecount;
20462306a36Sopenharmony_ci		ialloc += pag->pagi_count;
20562306a36Sopenharmony_ci		bfree += pag->pagf_freeblks;
20662306a36Sopenharmony_ci		bfreelst += pag->pagf_flcount;
20762306a36Sopenharmony_ci		btree += pag->pagf_btreeblks;
20862306a36Sopenharmony_ci		xfs_perag_put(pag);
20962306a36Sopenharmony_ci	}
21062306a36Sopenharmony_ci	fdblocks = bfree + bfreelst + btree;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	/*
21362306a36Sopenharmony_ci	 * If the new summary counts are obviously incorrect, fail the
21462306a36Sopenharmony_ci	 * mount operation because that implies the AGFs are also corrupt.
21562306a36Sopenharmony_ci	 * Clear FS_COUNTERS so that we don't unmount with a dirty log, which
21662306a36Sopenharmony_ci	 * will prevent xfs_repair from fixing anything.
21762306a36Sopenharmony_ci	 */
21862306a36Sopenharmony_ci	if (fdblocks > sbp->sb_dblocks || ifree > ialloc) {
21962306a36Sopenharmony_ci		xfs_alert(mp, "AGF corruption. Please run xfs_repair.");
22062306a36Sopenharmony_ci		error = -EFSCORRUPTED;
22162306a36Sopenharmony_ci		goto out;
22262306a36Sopenharmony_ci	}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	/* Overwrite incore superblock counters with just-read data */
22562306a36Sopenharmony_ci	spin_lock(&mp->m_sb_lock);
22662306a36Sopenharmony_ci	sbp->sb_ifree = ifree;
22762306a36Sopenharmony_ci	sbp->sb_icount = ialloc;
22862306a36Sopenharmony_ci	sbp->sb_fdblocks = fdblocks;
22962306a36Sopenharmony_ci	spin_unlock(&mp->m_sb_lock);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	xfs_reinit_percpu_counters(mp);
23262306a36Sopenharmony_ciout:
23362306a36Sopenharmony_ci	xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
23462306a36Sopenharmony_ci	return error;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ciSTATIC void
23862306a36Sopenharmony_ci__xfs_free_perag(
23962306a36Sopenharmony_ci	struct rcu_head	*head)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	ASSERT(!delayed_work_pending(&pag->pag_blockgc_work));
24462306a36Sopenharmony_ci	kmem_free(pag);
24562306a36Sopenharmony_ci}
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/*
24862306a36Sopenharmony_ci * Free up the per-ag resources associated with the mount structure.
24962306a36Sopenharmony_ci */
25062306a36Sopenharmony_civoid
25162306a36Sopenharmony_cixfs_free_perag(
25262306a36Sopenharmony_ci	struct xfs_mount	*mp)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	struct xfs_perag	*pag;
25562306a36Sopenharmony_ci	xfs_agnumber_t		agno;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
25862306a36Sopenharmony_ci		spin_lock(&mp->m_perag_lock);
25962306a36Sopenharmony_ci		pag = radix_tree_delete(&mp->m_perag_tree, agno);
26062306a36Sopenharmony_ci		spin_unlock(&mp->m_perag_lock);
26162306a36Sopenharmony_ci		ASSERT(pag);
26262306a36Sopenharmony_ci		XFS_IS_CORRUPT(pag->pag_mount, atomic_read(&pag->pag_ref) != 0);
26362306a36Sopenharmony_ci		xfs_defer_drain_free(&pag->pag_intents_drain);
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci		cancel_delayed_work_sync(&pag->pag_blockgc_work);
26662306a36Sopenharmony_ci		xfs_buf_hash_destroy(pag);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci		/* drop the mount's active reference */
26962306a36Sopenharmony_ci		xfs_perag_rele(pag);
27062306a36Sopenharmony_ci		XFS_IS_CORRUPT(pag->pag_mount,
27162306a36Sopenharmony_ci				atomic_read(&pag->pag_active_ref) != 0);
27262306a36Sopenharmony_ci		call_rcu(&pag->rcu_head, __xfs_free_perag);
27362306a36Sopenharmony_ci	}
27462306a36Sopenharmony_ci}
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci/* Find the size of the AG, in blocks. */
27762306a36Sopenharmony_cistatic xfs_agblock_t
27862306a36Sopenharmony_ci__xfs_ag_block_count(
27962306a36Sopenharmony_ci	struct xfs_mount	*mp,
28062306a36Sopenharmony_ci	xfs_agnumber_t		agno,
28162306a36Sopenharmony_ci	xfs_agnumber_t		agcount,
28262306a36Sopenharmony_ci	xfs_rfsblock_t		dblocks)
28362306a36Sopenharmony_ci{
28462306a36Sopenharmony_ci	ASSERT(agno < agcount);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	if (agno < agcount - 1)
28762306a36Sopenharmony_ci		return mp->m_sb.sb_agblocks;
28862306a36Sopenharmony_ci	return dblocks - (agno * mp->m_sb.sb_agblocks);
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cixfs_agblock_t
29262306a36Sopenharmony_cixfs_ag_block_count(
29362306a36Sopenharmony_ci	struct xfs_mount	*mp,
29462306a36Sopenharmony_ci	xfs_agnumber_t		agno)
29562306a36Sopenharmony_ci{
29662306a36Sopenharmony_ci	return __xfs_ag_block_count(mp, agno, mp->m_sb.sb_agcount,
29762306a36Sopenharmony_ci			mp->m_sb.sb_dblocks);
29862306a36Sopenharmony_ci}
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci/* Calculate the first and last possible inode number in an AG. */
30162306a36Sopenharmony_cistatic void
30262306a36Sopenharmony_ci__xfs_agino_range(
30362306a36Sopenharmony_ci	struct xfs_mount	*mp,
30462306a36Sopenharmony_ci	xfs_agblock_t		eoag,
30562306a36Sopenharmony_ci	xfs_agino_t		*first,
30662306a36Sopenharmony_ci	xfs_agino_t		*last)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	xfs_agblock_t		bno;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	/*
31162306a36Sopenharmony_ci	 * Calculate the first inode, which will be in the first
31262306a36Sopenharmony_ci	 * cluster-aligned block after the AGFL.
31362306a36Sopenharmony_ci	 */
31462306a36Sopenharmony_ci	bno = round_up(XFS_AGFL_BLOCK(mp) + 1, M_IGEO(mp)->cluster_align);
31562306a36Sopenharmony_ci	*first = XFS_AGB_TO_AGINO(mp, bno);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/*
31862306a36Sopenharmony_ci	 * Calculate the last inode, which will be at the end of the
31962306a36Sopenharmony_ci	 * last (aligned) cluster that can be allocated in the AG.
32062306a36Sopenharmony_ci	 */
32162306a36Sopenharmony_ci	bno = round_down(eoag, M_IGEO(mp)->cluster_align);
32262306a36Sopenharmony_ci	*last = XFS_AGB_TO_AGINO(mp, bno) - 1;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_civoid
32662306a36Sopenharmony_cixfs_agino_range(
32762306a36Sopenharmony_ci	struct xfs_mount	*mp,
32862306a36Sopenharmony_ci	xfs_agnumber_t		agno,
32962306a36Sopenharmony_ci	xfs_agino_t		*first,
33062306a36Sopenharmony_ci	xfs_agino_t		*last)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ciint
33662306a36Sopenharmony_cixfs_initialize_perag(
33762306a36Sopenharmony_ci	struct xfs_mount	*mp,
33862306a36Sopenharmony_ci	xfs_agnumber_t		agcount,
33962306a36Sopenharmony_ci	xfs_rfsblock_t		dblocks,
34062306a36Sopenharmony_ci	xfs_agnumber_t		*maxagi)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	struct xfs_perag	*pag;
34362306a36Sopenharmony_ci	xfs_agnumber_t		index;
34462306a36Sopenharmony_ci	xfs_agnumber_t		first_initialised = NULLAGNUMBER;
34562306a36Sopenharmony_ci	int			error;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	/*
34862306a36Sopenharmony_ci	 * Walk the current per-ag tree so we don't try to initialise AGs
34962306a36Sopenharmony_ci	 * that already exist (growfs case). Allocate and insert all the
35062306a36Sopenharmony_ci	 * AGs we don't find ready for initialisation.
35162306a36Sopenharmony_ci	 */
35262306a36Sopenharmony_ci	for (index = 0; index < agcount; index++) {
35362306a36Sopenharmony_ci		pag = xfs_perag_get(mp, index);
35462306a36Sopenharmony_ci		if (pag) {
35562306a36Sopenharmony_ci			xfs_perag_put(pag);
35662306a36Sopenharmony_ci			continue;
35762306a36Sopenharmony_ci		}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL);
36062306a36Sopenharmony_ci		if (!pag) {
36162306a36Sopenharmony_ci			error = -ENOMEM;
36262306a36Sopenharmony_ci			goto out_unwind_new_pags;
36362306a36Sopenharmony_ci		}
36462306a36Sopenharmony_ci		pag->pag_agno = index;
36562306a36Sopenharmony_ci		pag->pag_mount = mp;
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		error = radix_tree_preload(GFP_NOFS);
36862306a36Sopenharmony_ci		if (error)
36962306a36Sopenharmony_ci			goto out_free_pag;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci		spin_lock(&mp->m_perag_lock);
37262306a36Sopenharmony_ci		if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
37362306a36Sopenharmony_ci			WARN_ON_ONCE(1);
37462306a36Sopenharmony_ci			spin_unlock(&mp->m_perag_lock);
37562306a36Sopenharmony_ci			radix_tree_preload_end();
37662306a36Sopenharmony_ci			error = -EEXIST;
37762306a36Sopenharmony_ci			goto out_free_pag;
37862306a36Sopenharmony_ci		}
37962306a36Sopenharmony_ci		spin_unlock(&mp->m_perag_lock);
38062306a36Sopenharmony_ci		radix_tree_preload_end();
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci#ifdef __KERNEL__
38362306a36Sopenharmony_ci		/* Place kernel structure only init below this point. */
38462306a36Sopenharmony_ci		spin_lock_init(&pag->pag_ici_lock);
38562306a36Sopenharmony_ci		spin_lock_init(&pag->pagb_lock);
38662306a36Sopenharmony_ci		spin_lock_init(&pag->pag_state_lock);
38762306a36Sopenharmony_ci		INIT_DELAYED_WORK(&pag->pag_blockgc_work, xfs_blockgc_worker);
38862306a36Sopenharmony_ci		INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC);
38962306a36Sopenharmony_ci		xfs_defer_drain_init(&pag->pag_intents_drain);
39062306a36Sopenharmony_ci		init_waitqueue_head(&pag->pagb_wait);
39162306a36Sopenharmony_ci		init_waitqueue_head(&pag->pag_active_wq);
39262306a36Sopenharmony_ci		pag->pagb_count = 0;
39362306a36Sopenharmony_ci		pag->pagb_tree = RB_ROOT;
39462306a36Sopenharmony_ci#endif /* __KERNEL__ */
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		error = xfs_buf_hash_init(pag);
39762306a36Sopenharmony_ci		if (error)
39862306a36Sopenharmony_ci			goto out_remove_pag;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		/* Active ref owned by mount indicates AG is online. */
40162306a36Sopenharmony_ci		atomic_set(&pag->pag_active_ref, 1);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci		/* first new pag is fully initialized */
40462306a36Sopenharmony_ci		if (first_initialised == NULLAGNUMBER)
40562306a36Sopenharmony_ci			first_initialised = index;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci		/*
40862306a36Sopenharmony_ci		 * Pre-calculated geometry
40962306a36Sopenharmony_ci		 */
41062306a36Sopenharmony_ci		pag->block_count = __xfs_ag_block_count(mp, index, agcount,
41162306a36Sopenharmony_ci				dblocks);
41262306a36Sopenharmony_ci		pag->min_block = XFS_AGFL_BLOCK(mp);
41362306a36Sopenharmony_ci		__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
41462306a36Sopenharmony_ci				&pag->agino_max);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	index = xfs_set_inode_alloc(mp, agcount);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	if (maxagi)
42062306a36Sopenharmony_ci		*maxagi = index;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci	mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp);
42362306a36Sopenharmony_ci	return 0;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ciout_remove_pag:
42662306a36Sopenharmony_ci	xfs_defer_drain_free(&pag->pag_intents_drain);
42762306a36Sopenharmony_ci	radix_tree_delete(&mp->m_perag_tree, index);
42862306a36Sopenharmony_ciout_free_pag:
42962306a36Sopenharmony_ci	kmem_free(pag);
43062306a36Sopenharmony_ciout_unwind_new_pags:
43162306a36Sopenharmony_ci	/* unwind any prior newly initialized pags */
43262306a36Sopenharmony_ci	for (index = first_initialised; index < agcount; index++) {
43362306a36Sopenharmony_ci		pag = radix_tree_delete(&mp->m_perag_tree, index);
43462306a36Sopenharmony_ci		if (!pag)
43562306a36Sopenharmony_ci			break;
43662306a36Sopenharmony_ci		xfs_buf_hash_destroy(pag);
43762306a36Sopenharmony_ci		xfs_defer_drain_free(&pag->pag_intents_drain);
43862306a36Sopenharmony_ci		kmem_free(pag);
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci	return error;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic int
44462306a36Sopenharmony_cixfs_get_aghdr_buf(
44562306a36Sopenharmony_ci	struct xfs_mount	*mp,
44662306a36Sopenharmony_ci	xfs_daddr_t		blkno,
44762306a36Sopenharmony_ci	size_t			numblks,
44862306a36Sopenharmony_ci	struct xfs_buf		**bpp,
44962306a36Sopenharmony_ci	const struct xfs_buf_ops *ops)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	struct xfs_buf		*bp;
45262306a36Sopenharmony_ci	int			error;
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	error = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, 0, &bp);
45562306a36Sopenharmony_ci	if (error)
45662306a36Sopenharmony_ci		return error;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	bp->b_maps[0].bm_bn = blkno;
45962306a36Sopenharmony_ci	bp->b_ops = ops;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	*bpp = bp;
46262306a36Sopenharmony_ci	return 0;
46362306a36Sopenharmony_ci}
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci/*
46662306a36Sopenharmony_ci * Generic btree root block init function
46762306a36Sopenharmony_ci */
46862306a36Sopenharmony_cistatic void
46962306a36Sopenharmony_cixfs_btroot_init(
47062306a36Sopenharmony_ci	struct xfs_mount	*mp,
47162306a36Sopenharmony_ci	struct xfs_buf		*bp,
47262306a36Sopenharmony_ci	struct aghdr_init_data	*id)
47362306a36Sopenharmony_ci{
47462306a36Sopenharmony_ci	xfs_btree_init_block(mp, bp, id->type, 0, 0, id->agno);
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci/* Finish initializing a free space btree. */
47862306a36Sopenharmony_cistatic void
47962306a36Sopenharmony_cixfs_freesp_init_recs(
48062306a36Sopenharmony_ci	struct xfs_mount	*mp,
48162306a36Sopenharmony_ci	struct xfs_buf		*bp,
48262306a36Sopenharmony_ci	struct aghdr_init_data	*id)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	struct xfs_alloc_rec	*arec;
48562306a36Sopenharmony_ci	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1);
48862306a36Sopenharmony_ci	arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (xfs_ag_contains_log(mp, id->agno)) {
49162306a36Sopenharmony_ci		struct xfs_alloc_rec	*nrec;
49262306a36Sopenharmony_ci		xfs_agblock_t		start = XFS_FSB_TO_AGBNO(mp,
49362306a36Sopenharmony_ci							mp->m_sb.sb_logstart);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci		ASSERT(start >= mp->m_ag_prealloc_blocks);
49662306a36Sopenharmony_ci		if (start != mp->m_ag_prealloc_blocks) {
49762306a36Sopenharmony_ci			/*
49862306a36Sopenharmony_ci			 * Modify first record to pad stripe align of log and
49962306a36Sopenharmony_ci			 * bump the record count.
50062306a36Sopenharmony_ci			 */
50162306a36Sopenharmony_ci			arec->ar_blockcount = cpu_to_be32(start -
50262306a36Sopenharmony_ci						mp->m_ag_prealloc_blocks);
50362306a36Sopenharmony_ci			be16_add_cpu(&block->bb_numrecs, 1);
50462306a36Sopenharmony_ci			nrec = arec + 1;
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci			/*
50762306a36Sopenharmony_ci			 * Insert second record at start of internal log
50862306a36Sopenharmony_ci			 * which then gets trimmed.
50962306a36Sopenharmony_ci			 */
51062306a36Sopenharmony_ci			nrec->ar_startblock = cpu_to_be32(
51162306a36Sopenharmony_ci					be32_to_cpu(arec->ar_startblock) +
51262306a36Sopenharmony_ci					be32_to_cpu(arec->ar_blockcount));
51362306a36Sopenharmony_ci			arec = nrec;
51462306a36Sopenharmony_ci		}
51562306a36Sopenharmony_ci		/*
51662306a36Sopenharmony_ci		 * Change record start to after the internal log
51762306a36Sopenharmony_ci		 */
51862306a36Sopenharmony_ci		be32_add_cpu(&arec->ar_startblock, mp->m_sb.sb_logblocks);
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	/*
52262306a36Sopenharmony_ci	 * Calculate the block count of this record; if it is nonzero,
52362306a36Sopenharmony_ci	 * increment the record count.
52462306a36Sopenharmony_ci	 */
52562306a36Sopenharmony_ci	arec->ar_blockcount = cpu_to_be32(id->agsize -
52662306a36Sopenharmony_ci					  be32_to_cpu(arec->ar_startblock));
52762306a36Sopenharmony_ci	if (arec->ar_blockcount)
52862306a36Sopenharmony_ci		be16_add_cpu(&block->bb_numrecs, 1);
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci/*
53262306a36Sopenharmony_ci * Alloc btree root block init functions
53362306a36Sopenharmony_ci */
53462306a36Sopenharmony_cistatic void
53562306a36Sopenharmony_cixfs_bnoroot_init(
53662306a36Sopenharmony_ci	struct xfs_mount	*mp,
53762306a36Sopenharmony_ci	struct xfs_buf		*bp,
53862306a36Sopenharmony_ci	struct aghdr_init_data	*id)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 0, id->agno);
54162306a36Sopenharmony_ci	xfs_freesp_init_recs(mp, bp, id);
54262306a36Sopenharmony_ci}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_cistatic void
54562306a36Sopenharmony_cixfs_cntroot_init(
54662306a36Sopenharmony_ci	struct xfs_mount	*mp,
54762306a36Sopenharmony_ci	struct xfs_buf		*bp,
54862306a36Sopenharmony_ci	struct aghdr_init_data	*id)
54962306a36Sopenharmony_ci{
55062306a36Sopenharmony_ci	xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 0, id->agno);
55162306a36Sopenharmony_ci	xfs_freesp_init_recs(mp, bp, id);
55262306a36Sopenharmony_ci}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci/*
55562306a36Sopenharmony_ci * Reverse map root block init
55662306a36Sopenharmony_ci */
55762306a36Sopenharmony_cistatic void
55862306a36Sopenharmony_cixfs_rmaproot_init(
55962306a36Sopenharmony_ci	struct xfs_mount	*mp,
56062306a36Sopenharmony_ci	struct xfs_buf		*bp,
56162306a36Sopenharmony_ci	struct aghdr_init_data	*id)
56262306a36Sopenharmony_ci{
56362306a36Sopenharmony_ci	struct xfs_btree_block	*block = XFS_BUF_TO_BLOCK(bp);
56462306a36Sopenharmony_ci	struct xfs_rmap_rec	*rrec;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	xfs_btree_init_block(mp, bp, XFS_BTNUM_RMAP, 0, 4, id->agno);
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	/*
56962306a36Sopenharmony_ci	 * mark the AG header regions as static metadata The BNO
57062306a36Sopenharmony_ci	 * btree block is the first block after the headers, so
57162306a36Sopenharmony_ci	 * it's location defines the size of region the static
57262306a36Sopenharmony_ci	 * metadata consumes.
57362306a36Sopenharmony_ci	 *
57462306a36Sopenharmony_ci	 * Note: unlike mkfs, we never have to account for log
57562306a36Sopenharmony_ci	 * space when growing the data regions
57662306a36Sopenharmony_ci	 */
57762306a36Sopenharmony_ci	rrec = XFS_RMAP_REC_ADDR(block, 1);
57862306a36Sopenharmony_ci	rrec->rm_startblock = 0;
57962306a36Sopenharmony_ci	rrec->rm_blockcount = cpu_to_be32(XFS_BNO_BLOCK(mp));
58062306a36Sopenharmony_ci	rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_FS);
58162306a36Sopenharmony_ci	rrec->rm_offset = 0;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	/* account freespace btree root blocks */
58462306a36Sopenharmony_ci	rrec = XFS_RMAP_REC_ADDR(block, 2);
58562306a36Sopenharmony_ci	rrec->rm_startblock = cpu_to_be32(XFS_BNO_BLOCK(mp));
58662306a36Sopenharmony_ci	rrec->rm_blockcount = cpu_to_be32(2);
58762306a36Sopenharmony_ci	rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
58862306a36Sopenharmony_ci	rrec->rm_offset = 0;
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	/* account inode btree root blocks */
59162306a36Sopenharmony_ci	rrec = XFS_RMAP_REC_ADDR(block, 3);
59262306a36Sopenharmony_ci	rrec->rm_startblock = cpu_to_be32(XFS_IBT_BLOCK(mp));
59362306a36Sopenharmony_ci	rrec->rm_blockcount = cpu_to_be32(XFS_RMAP_BLOCK(mp) -
59462306a36Sopenharmony_ci					  XFS_IBT_BLOCK(mp));
59562306a36Sopenharmony_ci	rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_INOBT);
59662306a36Sopenharmony_ci	rrec->rm_offset = 0;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	/* account for rmap btree root */
59962306a36Sopenharmony_ci	rrec = XFS_RMAP_REC_ADDR(block, 4);
60062306a36Sopenharmony_ci	rrec->rm_startblock = cpu_to_be32(XFS_RMAP_BLOCK(mp));
60162306a36Sopenharmony_ci	rrec->rm_blockcount = cpu_to_be32(1);
60262306a36Sopenharmony_ci	rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG);
60362306a36Sopenharmony_ci	rrec->rm_offset = 0;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	/* account for refc btree root */
60662306a36Sopenharmony_ci	if (xfs_has_reflink(mp)) {
60762306a36Sopenharmony_ci		rrec = XFS_RMAP_REC_ADDR(block, 5);
60862306a36Sopenharmony_ci		rrec->rm_startblock = cpu_to_be32(xfs_refc_block(mp));
60962306a36Sopenharmony_ci		rrec->rm_blockcount = cpu_to_be32(1);
61062306a36Sopenharmony_ci		rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_REFC);
61162306a36Sopenharmony_ci		rrec->rm_offset = 0;
61262306a36Sopenharmony_ci		be16_add_cpu(&block->bb_numrecs, 1);
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	/* account for the log space */
61662306a36Sopenharmony_ci	if (xfs_ag_contains_log(mp, id->agno)) {
61762306a36Sopenharmony_ci		rrec = XFS_RMAP_REC_ADDR(block,
61862306a36Sopenharmony_ci				be16_to_cpu(block->bb_numrecs) + 1);
61962306a36Sopenharmony_ci		rrec->rm_startblock = cpu_to_be32(
62062306a36Sopenharmony_ci				XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart));
62162306a36Sopenharmony_ci		rrec->rm_blockcount = cpu_to_be32(mp->m_sb.sb_logblocks);
62262306a36Sopenharmony_ci		rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_LOG);
62362306a36Sopenharmony_ci		rrec->rm_offset = 0;
62462306a36Sopenharmony_ci		be16_add_cpu(&block->bb_numrecs, 1);
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci/*
62962306a36Sopenharmony_ci * Initialise new secondary superblocks with the pre-grow geometry, but mark
63062306a36Sopenharmony_ci * them as "in progress" so we know they haven't yet been activated. This will
63162306a36Sopenharmony_ci * get cleared when the update with the new geometry information is done after
63262306a36Sopenharmony_ci * changes to the primary are committed. This isn't strictly necessary, but we
63362306a36Sopenharmony_ci * get it for free with the delayed buffer write lists and it means we can tell
63462306a36Sopenharmony_ci * if a grow operation didn't complete properly after the fact.
63562306a36Sopenharmony_ci */
63662306a36Sopenharmony_cistatic void
63762306a36Sopenharmony_cixfs_sbblock_init(
63862306a36Sopenharmony_ci	struct xfs_mount	*mp,
63962306a36Sopenharmony_ci	struct xfs_buf		*bp,
64062306a36Sopenharmony_ci	struct aghdr_init_data	*id)
64162306a36Sopenharmony_ci{
64262306a36Sopenharmony_ci	struct xfs_dsb		*dsb = bp->b_addr;
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	xfs_sb_to_disk(dsb, &mp->m_sb);
64562306a36Sopenharmony_ci	dsb->sb_inprogress = 1;
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic void
64962306a36Sopenharmony_cixfs_agfblock_init(
65062306a36Sopenharmony_ci	struct xfs_mount	*mp,
65162306a36Sopenharmony_ci	struct xfs_buf		*bp,
65262306a36Sopenharmony_ci	struct aghdr_init_data	*id)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct xfs_agf		*agf = bp->b_addr;
65562306a36Sopenharmony_ci	xfs_extlen_t		tmpsize;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
65862306a36Sopenharmony_ci	agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);
65962306a36Sopenharmony_ci	agf->agf_seqno = cpu_to_be32(id->agno);
66062306a36Sopenharmony_ci	agf->agf_length = cpu_to_be32(id->agsize);
66162306a36Sopenharmony_ci	agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp));
66262306a36Sopenharmony_ci	agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp));
66362306a36Sopenharmony_ci	agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1);
66462306a36Sopenharmony_ci	agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1);
66562306a36Sopenharmony_ci	if (xfs_has_rmapbt(mp)) {
66662306a36Sopenharmony_ci		agf->agf_roots[XFS_BTNUM_RMAPi] =
66762306a36Sopenharmony_ci					cpu_to_be32(XFS_RMAP_BLOCK(mp));
66862306a36Sopenharmony_ci		agf->agf_levels[XFS_BTNUM_RMAPi] = cpu_to_be32(1);
66962306a36Sopenharmony_ci		agf->agf_rmap_blocks = cpu_to_be32(1);
67062306a36Sopenharmony_ci	}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci	agf->agf_flfirst = cpu_to_be32(1);
67362306a36Sopenharmony_ci	agf->agf_fllast = 0;
67462306a36Sopenharmony_ci	agf->agf_flcount = 0;
67562306a36Sopenharmony_ci	tmpsize = id->agsize - mp->m_ag_prealloc_blocks;
67662306a36Sopenharmony_ci	agf->agf_freeblks = cpu_to_be32(tmpsize);
67762306a36Sopenharmony_ci	agf->agf_longest = cpu_to_be32(tmpsize);
67862306a36Sopenharmony_ci	if (xfs_has_crc(mp))
67962306a36Sopenharmony_ci		uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
68062306a36Sopenharmony_ci	if (xfs_has_reflink(mp)) {
68162306a36Sopenharmony_ci		agf->agf_refcount_root = cpu_to_be32(
68262306a36Sopenharmony_ci				xfs_refc_block(mp));
68362306a36Sopenharmony_ci		agf->agf_refcount_level = cpu_to_be32(1);
68462306a36Sopenharmony_ci		agf->agf_refcount_blocks = cpu_to_be32(1);
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	if (xfs_ag_contains_log(mp, id->agno)) {
68862306a36Sopenharmony_ci		int64_t	logblocks = mp->m_sb.sb_logblocks;
68962306a36Sopenharmony_ci
69062306a36Sopenharmony_ci		be32_add_cpu(&agf->agf_freeblks, -logblocks);
69162306a36Sopenharmony_ci		agf->agf_longest = cpu_to_be32(id->agsize -
69262306a36Sopenharmony_ci			XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart) - logblocks);
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_cistatic void
69762306a36Sopenharmony_cixfs_agflblock_init(
69862306a36Sopenharmony_ci	struct xfs_mount	*mp,
69962306a36Sopenharmony_ci	struct xfs_buf		*bp,
70062306a36Sopenharmony_ci	struct aghdr_init_data	*id)
70162306a36Sopenharmony_ci{
70262306a36Sopenharmony_ci	struct xfs_agfl		*agfl = XFS_BUF_TO_AGFL(bp);
70362306a36Sopenharmony_ci	__be32			*agfl_bno;
70462306a36Sopenharmony_ci	int			bucket;
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	if (xfs_has_crc(mp)) {
70762306a36Sopenharmony_ci		agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
70862306a36Sopenharmony_ci		agfl->agfl_seqno = cpu_to_be32(id->agno);
70962306a36Sopenharmony_ci		uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci	agfl_bno = xfs_buf_to_agfl_bno(bp);
71362306a36Sopenharmony_ci	for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++)
71462306a36Sopenharmony_ci		agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK);
71562306a36Sopenharmony_ci}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_cistatic void
71862306a36Sopenharmony_cixfs_agiblock_init(
71962306a36Sopenharmony_ci	struct xfs_mount	*mp,
72062306a36Sopenharmony_ci	struct xfs_buf		*bp,
72162306a36Sopenharmony_ci	struct aghdr_init_data	*id)
72262306a36Sopenharmony_ci{
72362306a36Sopenharmony_ci	struct xfs_agi		*agi = bp->b_addr;
72462306a36Sopenharmony_ci	int			bucket;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
72762306a36Sopenharmony_ci	agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
72862306a36Sopenharmony_ci	agi->agi_seqno = cpu_to_be32(id->agno);
72962306a36Sopenharmony_ci	agi->agi_length = cpu_to_be32(id->agsize);
73062306a36Sopenharmony_ci	agi->agi_count = 0;
73162306a36Sopenharmony_ci	agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp));
73262306a36Sopenharmony_ci	agi->agi_level = cpu_to_be32(1);
73362306a36Sopenharmony_ci	agi->agi_freecount = 0;
73462306a36Sopenharmony_ci	agi->agi_newino = cpu_to_be32(NULLAGINO);
73562306a36Sopenharmony_ci	agi->agi_dirino = cpu_to_be32(NULLAGINO);
73662306a36Sopenharmony_ci	if (xfs_has_crc(mp))
73762306a36Sopenharmony_ci		uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
73862306a36Sopenharmony_ci	if (xfs_has_finobt(mp)) {
73962306a36Sopenharmony_ci		agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp));
74062306a36Sopenharmony_ci		agi->agi_free_level = cpu_to_be32(1);
74162306a36Sopenharmony_ci	}
74262306a36Sopenharmony_ci	for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++)
74362306a36Sopenharmony_ci		agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO);
74462306a36Sopenharmony_ci	if (xfs_has_inobtcounts(mp)) {
74562306a36Sopenharmony_ci		agi->agi_iblocks = cpu_to_be32(1);
74662306a36Sopenharmony_ci		if (xfs_has_finobt(mp))
74762306a36Sopenharmony_ci			agi->agi_fblocks = cpu_to_be32(1);
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_citypedef void (*aghdr_init_work_f)(struct xfs_mount *mp, struct xfs_buf *bp,
75262306a36Sopenharmony_ci				  struct aghdr_init_data *id);
75362306a36Sopenharmony_cistatic int
75462306a36Sopenharmony_cixfs_ag_init_hdr(
75562306a36Sopenharmony_ci	struct xfs_mount	*mp,
75662306a36Sopenharmony_ci	struct aghdr_init_data	*id,
75762306a36Sopenharmony_ci	aghdr_init_work_f	work,
75862306a36Sopenharmony_ci	const struct xfs_buf_ops *ops)
75962306a36Sopenharmony_ci{
76062306a36Sopenharmony_ci	struct xfs_buf		*bp;
76162306a36Sopenharmony_ci	int			error;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci	error = xfs_get_aghdr_buf(mp, id->daddr, id->numblks, &bp, ops);
76462306a36Sopenharmony_ci	if (error)
76562306a36Sopenharmony_ci		return error;
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	(*work)(mp, bp, id);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	xfs_buf_delwri_queue(bp, &id->buffer_list);
77062306a36Sopenharmony_ci	xfs_buf_relse(bp);
77162306a36Sopenharmony_ci	return 0;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistruct xfs_aghdr_grow_data {
77562306a36Sopenharmony_ci	xfs_daddr_t		daddr;
77662306a36Sopenharmony_ci	size_t			numblks;
77762306a36Sopenharmony_ci	const struct xfs_buf_ops *ops;
77862306a36Sopenharmony_ci	aghdr_init_work_f	work;
77962306a36Sopenharmony_ci	xfs_btnum_t		type;
78062306a36Sopenharmony_ci	bool			need_init;
78162306a36Sopenharmony_ci};
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci/*
78462306a36Sopenharmony_ci * Prepare new AG headers to be written to disk. We use uncached buffers here,
78562306a36Sopenharmony_ci * as it is assumed these new AG headers are currently beyond the currently
78662306a36Sopenharmony_ci * valid filesystem address space. Using cached buffers would trip over EOFS
78762306a36Sopenharmony_ci * corruption detection alogrithms in the buffer cache lookup routines.
78862306a36Sopenharmony_ci *
78962306a36Sopenharmony_ci * This is a non-transactional function, but the prepared buffers are added to a
79062306a36Sopenharmony_ci * delayed write buffer list supplied by the caller so they can submit them to
79162306a36Sopenharmony_ci * disk and wait on them as required.
79262306a36Sopenharmony_ci */
79362306a36Sopenharmony_ciint
79462306a36Sopenharmony_cixfs_ag_init_headers(
79562306a36Sopenharmony_ci	struct xfs_mount	*mp,
79662306a36Sopenharmony_ci	struct aghdr_init_data	*id)
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci{
79962306a36Sopenharmony_ci	struct xfs_aghdr_grow_data aghdr_data[] = {
80062306a36Sopenharmony_ci	{ /* SB */
80162306a36Sopenharmony_ci		.daddr = XFS_AG_DADDR(mp, id->agno, XFS_SB_DADDR),
80262306a36Sopenharmony_ci		.numblks = XFS_FSS_TO_BB(mp, 1),
80362306a36Sopenharmony_ci		.ops = &xfs_sb_buf_ops,
80462306a36Sopenharmony_ci		.work = &xfs_sbblock_init,
80562306a36Sopenharmony_ci		.need_init = true
80662306a36Sopenharmony_ci	},
80762306a36Sopenharmony_ci	{ /* AGF */
80862306a36Sopenharmony_ci		.daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGF_DADDR(mp)),
80962306a36Sopenharmony_ci		.numblks = XFS_FSS_TO_BB(mp, 1),
81062306a36Sopenharmony_ci		.ops = &xfs_agf_buf_ops,
81162306a36Sopenharmony_ci		.work = &xfs_agfblock_init,
81262306a36Sopenharmony_ci		.need_init = true
81362306a36Sopenharmony_ci	},
81462306a36Sopenharmony_ci	{ /* AGFL */
81562306a36Sopenharmony_ci		.daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGFL_DADDR(mp)),
81662306a36Sopenharmony_ci		.numblks = XFS_FSS_TO_BB(mp, 1),
81762306a36Sopenharmony_ci		.ops = &xfs_agfl_buf_ops,
81862306a36Sopenharmony_ci		.work = &xfs_agflblock_init,
81962306a36Sopenharmony_ci		.need_init = true
82062306a36Sopenharmony_ci	},
82162306a36Sopenharmony_ci	{ /* AGI */
82262306a36Sopenharmony_ci		.daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGI_DADDR(mp)),
82362306a36Sopenharmony_ci		.numblks = XFS_FSS_TO_BB(mp, 1),
82462306a36Sopenharmony_ci		.ops = &xfs_agi_buf_ops,
82562306a36Sopenharmony_ci		.work = &xfs_agiblock_init,
82662306a36Sopenharmony_ci		.need_init = true
82762306a36Sopenharmony_ci	},
82862306a36Sopenharmony_ci	{ /* BNO root block */
82962306a36Sopenharmony_ci		.daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_BNO_BLOCK(mp)),
83062306a36Sopenharmony_ci		.numblks = BTOBB(mp->m_sb.sb_blocksize),
83162306a36Sopenharmony_ci		.ops = &xfs_bnobt_buf_ops,
83262306a36Sopenharmony_ci		.work = &xfs_bnoroot_init,
83362306a36Sopenharmony_ci		.need_init = true
83462306a36Sopenharmony_ci	},
83562306a36Sopenharmony_ci	{ /* CNT root block */
83662306a36Sopenharmony_ci		.daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_CNT_BLOCK(mp)),
83762306a36Sopenharmony_ci		.numblks = BTOBB(mp->m_sb.sb_blocksize),
83862306a36Sopenharmony_ci		.ops = &xfs_cntbt_buf_ops,
83962306a36Sopenharmony_ci		.work = &xfs_cntroot_init,
84062306a36Sopenharmony_ci		.need_init = true
84162306a36Sopenharmony_ci	},
84262306a36Sopenharmony_ci	{ /* INO root block */
84362306a36Sopenharmony_ci		.daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_IBT_BLOCK(mp)),
84462306a36Sopenharmony_ci		.numblks = BTOBB(mp->m_sb.sb_blocksize),
84562306a36Sopenharmony_ci		.ops = &xfs_inobt_buf_ops,
84662306a36Sopenharmony_ci		.work = &xfs_btroot_init,
84762306a36Sopenharmony_ci		.type = XFS_BTNUM_INO,
84862306a36Sopenharmony_ci		.need_init = true
84962306a36Sopenharmony_ci	},
85062306a36Sopenharmony_ci	{ /* FINO root block */
85162306a36Sopenharmony_ci		.daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_FIBT_BLOCK(mp)),
85262306a36Sopenharmony_ci		.numblks = BTOBB(mp->m_sb.sb_blocksize),
85362306a36Sopenharmony_ci		.ops = &xfs_finobt_buf_ops,
85462306a36Sopenharmony_ci		.work = &xfs_btroot_init,
85562306a36Sopenharmony_ci		.type = XFS_BTNUM_FINO,
85662306a36Sopenharmony_ci		.need_init =  xfs_has_finobt(mp)
85762306a36Sopenharmony_ci	},
85862306a36Sopenharmony_ci	{ /* RMAP root block */
85962306a36Sopenharmony_ci		.daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_RMAP_BLOCK(mp)),
86062306a36Sopenharmony_ci		.numblks = BTOBB(mp->m_sb.sb_blocksize),
86162306a36Sopenharmony_ci		.ops = &xfs_rmapbt_buf_ops,
86262306a36Sopenharmony_ci		.work = &xfs_rmaproot_init,
86362306a36Sopenharmony_ci		.need_init = xfs_has_rmapbt(mp)
86462306a36Sopenharmony_ci	},
86562306a36Sopenharmony_ci	{ /* REFC root block */
86662306a36Sopenharmony_ci		.daddr = XFS_AGB_TO_DADDR(mp, id->agno, xfs_refc_block(mp)),
86762306a36Sopenharmony_ci		.numblks = BTOBB(mp->m_sb.sb_blocksize),
86862306a36Sopenharmony_ci		.ops = &xfs_refcountbt_buf_ops,
86962306a36Sopenharmony_ci		.work = &xfs_btroot_init,
87062306a36Sopenharmony_ci		.type = XFS_BTNUM_REFC,
87162306a36Sopenharmony_ci		.need_init = xfs_has_reflink(mp)
87262306a36Sopenharmony_ci	},
87362306a36Sopenharmony_ci	{ /* NULL terminating block */
87462306a36Sopenharmony_ci		.daddr = XFS_BUF_DADDR_NULL,
87562306a36Sopenharmony_ci	}
87662306a36Sopenharmony_ci	};
87762306a36Sopenharmony_ci	struct  xfs_aghdr_grow_data *dp;
87862306a36Sopenharmony_ci	int			error = 0;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci	/* Account for AG free space in new AG */
88162306a36Sopenharmony_ci	id->nfree += id->agsize - mp->m_ag_prealloc_blocks;
88262306a36Sopenharmony_ci	for (dp = &aghdr_data[0]; dp->daddr != XFS_BUF_DADDR_NULL; dp++) {
88362306a36Sopenharmony_ci		if (!dp->need_init)
88462306a36Sopenharmony_ci			continue;
88562306a36Sopenharmony_ci
88662306a36Sopenharmony_ci		id->daddr = dp->daddr;
88762306a36Sopenharmony_ci		id->numblks = dp->numblks;
88862306a36Sopenharmony_ci		id->type = dp->type;
88962306a36Sopenharmony_ci		error = xfs_ag_init_hdr(mp, id, dp->work, dp->ops);
89062306a36Sopenharmony_ci		if (error)
89162306a36Sopenharmony_ci			break;
89262306a36Sopenharmony_ci	}
89362306a36Sopenharmony_ci	return error;
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ciint
89762306a36Sopenharmony_cixfs_ag_shrink_space(
89862306a36Sopenharmony_ci	struct xfs_perag	*pag,
89962306a36Sopenharmony_ci	struct xfs_trans	**tpp,
90062306a36Sopenharmony_ci	xfs_extlen_t		delta)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	struct xfs_mount	*mp = pag->pag_mount;
90362306a36Sopenharmony_ci	struct xfs_alloc_arg	args = {
90462306a36Sopenharmony_ci		.tp	= *tpp,
90562306a36Sopenharmony_ci		.mp	= mp,
90662306a36Sopenharmony_ci		.pag	= pag,
90762306a36Sopenharmony_ci		.minlen = delta,
90862306a36Sopenharmony_ci		.maxlen = delta,
90962306a36Sopenharmony_ci		.oinfo	= XFS_RMAP_OINFO_SKIP_UPDATE,
91062306a36Sopenharmony_ci		.resv	= XFS_AG_RESV_NONE,
91162306a36Sopenharmony_ci		.prod	= 1
91262306a36Sopenharmony_ci	};
91362306a36Sopenharmony_ci	struct xfs_buf		*agibp, *agfbp;
91462306a36Sopenharmony_ci	struct xfs_agi		*agi;
91562306a36Sopenharmony_ci	struct xfs_agf		*agf;
91662306a36Sopenharmony_ci	xfs_agblock_t		aglen;
91762306a36Sopenharmony_ci	int			error, err2;
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	ASSERT(pag->pag_agno == mp->m_sb.sb_agcount - 1);
92062306a36Sopenharmony_ci	error = xfs_ialloc_read_agi(pag, *tpp, &agibp);
92162306a36Sopenharmony_ci	if (error)
92262306a36Sopenharmony_ci		return error;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	agi = agibp->b_addr;
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	error = xfs_alloc_read_agf(pag, *tpp, 0, &agfbp);
92762306a36Sopenharmony_ci	if (error)
92862306a36Sopenharmony_ci		return error;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	agf = agfbp->b_addr;
93162306a36Sopenharmony_ci	aglen = be32_to_cpu(agi->agi_length);
93262306a36Sopenharmony_ci	/* some extra paranoid checks before we shrink the ag */
93362306a36Sopenharmony_ci	if (XFS_IS_CORRUPT(mp, agf->agf_length != agi->agi_length))
93462306a36Sopenharmony_ci		return -EFSCORRUPTED;
93562306a36Sopenharmony_ci	if (delta >= aglen)
93662306a36Sopenharmony_ci		return -EINVAL;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	/*
93962306a36Sopenharmony_ci	 * Make sure that the last inode cluster cannot overlap with the new
94062306a36Sopenharmony_ci	 * end of the AG, even if it's sparse.
94162306a36Sopenharmony_ci	 */
94262306a36Sopenharmony_ci	error = xfs_ialloc_check_shrink(pag, *tpp, agibp, aglen - delta);
94362306a36Sopenharmony_ci	if (error)
94462306a36Sopenharmony_ci		return error;
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_ci	/*
94762306a36Sopenharmony_ci	 * Disable perag reservations so it doesn't cause the allocation request
94862306a36Sopenharmony_ci	 * to fail. We'll reestablish reservation before we return.
94962306a36Sopenharmony_ci	 */
95062306a36Sopenharmony_ci	error = xfs_ag_resv_free(pag);
95162306a36Sopenharmony_ci	if (error)
95262306a36Sopenharmony_ci		return error;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	/* internal log shouldn't also show up in the free space btrees */
95562306a36Sopenharmony_ci	error = xfs_alloc_vextent_exact_bno(&args,
95662306a36Sopenharmony_ci			XFS_AGB_TO_FSB(mp, pag->pag_agno, aglen - delta));
95762306a36Sopenharmony_ci	if (!error && args.agbno == NULLAGBLOCK)
95862306a36Sopenharmony_ci		error = -ENOSPC;
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	if (error) {
96162306a36Sopenharmony_ci		/*
96262306a36Sopenharmony_ci		 * if extent allocation fails, need to roll the transaction to
96362306a36Sopenharmony_ci		 * ensure that the AGFL fixup has been committed anyway.
96462306a36Sopenharmony_ci		 */
96562306a36Sopenharmony_ci		xfs_trans_bhold(*tpp, agfbp);
96662306a36Sopenharmony_ci		err2 = xfs_trans_roll(tpp);
96762306a36Sopenharmony_ci		if (err2)
96862306a36Sopenharmony_ci			return err2;
96962306a36Sopenharmony_ci		xfs_trans_bjoin(*tpp, agfbp);
97062306a36Sopenharmony_ci		goto resv_init_out;
97162306a36Sopenharmony_ci	}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_ci	/*
97462306a36Sopenharmony_ci	 * if successfully deleted from freespace btrees, need to confirm
97562306a36Sopenharmony_ci	 * per-AG reservation works as expected.
97662306a36Sopenharmony_ci	 */
97762306a36Sopenharmony_ci	be32_add_cpu(&agi->agi_length, -delta);
97862306a36Sopenharmony_ci	be32_add_cpu(&agf->agf_length, -delta);
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	err2 = xfs_ag_resv_init(pag, *tpp);
98162306a36Sopenharmony_ci	if (err2) {
98262306a36Sopenharmony_ci		be32_add_cpu(&agi->agi_length, delta);
98362306a36Sopenharmony_ci		be32_add_cpu(&agf->agf_length, delta);
98462306a36Sopenharmony_ci		if (err2 != -ENOSPC)
98562306a36Sopenharmony_ci			goto resv_err;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci		err2 = __xfs_free_extent_later(*tpp, args.fsbno, delta, NULL,
98862306a36Sopenharmony_ci				XFS_AG_RESV_NONE, true);
98962306a36Sopenharmony_ci		if (err2)
99062306a36Sopenharmony_ci			goto resv_err;
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci		/*
99362306a36Sopenharmony_ci		 * Roll the transaction before trying to re-init the per-ag
99462306a36Sopenharmony_ci		 * reservation. The new transaction is clean so it will cancel
99562306a36Sopenharmony_ci		 * without any side effects.
99662306a36Sopenharmony_ci		 */
99762306a36Sopenharmony_ci		error = xfs_defer_finish(tpp);
99862306a36Sopenharmony_ci		if (error)
99962306a36Sopenharmony_ci			return error;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci		error = -ENOSPC;
100262306a36Sopenharmony_ci		goto resv_init_out;
100362306a36Sopenharmony_ci	}
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/* Update perag geometry */
100662306a36Sopenharmony_ci	pag->block_count -= delta;
100762306a36Sopenharmony_ci	__xfs_agino_range(pag->pag_mount, pag->block_count, &pag->agino_min,
100862306a36Sopenharmony_ci				&pag->agino_max);
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	xfs_ialloc_log_agi(*tpp, agibp, XFS_AGI_LENGTH);
101162306a36Sopenharmony_ci	xfs_alloc_log_agf(*tpp, agfbp, XFS_AGF_LENGTH);
101262306a36Sopenharmony_ci	return 0;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ciresv_init_out:
101562306a36Sopenharmony_ci	err2 = xfs_ag_resv_init(pag, *tpp);
101662306a36Sopenharmony_ci	if (!err2)
101762306a36Sopenharmony_ci		return error;
101862306a36Sopenharmony_ciresv_err:
101962306a36Sopenharmony_ci	xfs_warn(mp, "Error %d reserving per-AG metadata reserve pool.", err2);
102062306a36Sopenharmony_ci	xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
102162306a36Sopenharmony_ci	return err2;
102262306a36Sopenharmony_ci}
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci/*
102562306a36Sopenharmony_ci * Extent the AG indicated by the @id by the length passed in
102662306a36Sopenharmony_ci */
102762306a36Sopenharmony_ciint
102862306a36Sopenharmony_cixfs_ag_extend_space(
102962306a36Sopenharmony_ci	struct xfs_perag	*pag,
103062306a36Sopenharmony_ci	struct xfs_trans	*tp,
103162306a36Sopenharmony_ci	xfs_extlen_t		len)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	struct xfs_buf		*bp;
103462306a36Sopenharmony_ci	struct xfs_agi		*agi;
103562306a36Sopenharmony_ci	struct xfs_agf		*agf;
103662306a36Sopenharmony_ci	int			error;
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	ASSERT(pag->pag_agno == pag->pag_mount->m_sb.sb_agcount - 1);
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	error = xfs_ialloc_read_agi(pag, tp, &bp);
104162306a36Sopenharmony_ci	if (error)
104262306a36Sopenharmony_ci		return error;
104362306a36Sopenharmony_ci
104462306a36Sopenharmony_ci	agi = bp->b_addr;
104562306a36Sopenharmony_ci	be32_add_cpu(&agi->agi_length, len);
104662306a36Sopenharmony_ci	xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH);
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	/*
104962306a36Sopenharmony_ci	 * Change agf length.
105062306a36Sopenharmony_ci	 */
105162306a36Sopenharmony_ci	error = xfs_alloc_read_agf(pag, tp, 0, &bp);
105262306a36Sopenharmony_ci	if (error)
105362306a36Sopenharmony_ci		return error;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	agf = bp->b_addr;
105662306a36Sopenharmony_ci	be32_add_cpu(&agf->agf_length, len);
105762306a36Sopenharmony_ci	ASSERT(agf->agf_length == agi->agi_length);
105862306a36Sopenharmony_ci	xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci	/*
106162306a36Sopenharmony_ci	 * Free the new space.
106262306a36Sopenharmony_ci	 *
106362306a36Sopenharmony_ci	 * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that
106462306a36Sopenharmony_ci	 * this doesn't actually exist in the rmap btree.
106562306a36Sopenharmony_ci	 */
106662306a36Sopenharmony_ci	error = xfs_rmap_free(tp, bp, pag, be32_to_cpu(agf->agf_length) - len,
106762306a36Sopenharmony_ci				len, &XFS_RMAP_OINFO_SKIP_UPDATE);
106862306a36Sopenharmony_ci	if (error)
106962306a36Sopenharmony_ci		return error;
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_ci	error = xfs_free_extent(tp, pag, be32_to_cpu(agf->agf_length) - len,
107262306a36Sopenharmony_ci			len, &XFS_RMAP_OINFO_SKIP_UPDATE, XFS_AG_RESV_NONE);
107362306a36Sopenharmony_ci	if (error)
107462306a36Sopenharmony_ci		return error;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	/* Update perag geometry */
107762306a36Sopenharmony_ci	pag->block_count = be32_to_cpu(agf->agf_length);
107862306a36Sopenharmony_ci	__xfs_agino_range(pag->pag_mount, pag->block_count, &pag->agino_min,
107962306a36Sopenharmony_ci				&pag->agino_max);
108062306a36Sopenharmony_ci	return 0;
108162306a36Sopenharmony_ci}
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci/* Retrieve AG geometry. */
108462306a36Sopenharmony_ciint
108562306a36Sopenharmony_cixfs_ag_get_geometry(
108662306a36Sopenharmony_ci	struct xfs_perag	*pag,
108762306a36Sopenharmony_ci	struct xfs_ag_geometry	*ageo)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	struct xfs_buf		*agi_bp;
109062306a36Sopenharmony_ci	struct xfs_buf		*agf_bp;
109162306a36Sopenharmony_ci	struct xfs_agi		*agi;
109262306a36Sopenharmony_ci	struct xfs_agf		*agf;
109362306a36Sopenharmony_ci	unsigned int		freeblks;
109462306a36Sopenharmony_ci	int			error;
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ci	/* Lock the AG headers. */
109762306a36Sopenharmony_ci	error = xfs_ialloc_read_agi(pag, NULL, &agi_bp);
109862306a36Sopenharmony_ci	if (error)
109962306a36Sopenharmony_ci		return error;
110062306a36Sopenharmony_ci	error = xfs_alloc_read_agf(pag, NULL, 0, &agf_bp);
110162306a36Sopenharmony_ci	if (error)
110262306a36Sopenharmony_ci		goto out_agi;
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	/* Fill out form. */
110562306a36Sopenharmony_ci	memset(ageo, 0, sizeof(*ageo));
110662306a36Sopenharmony_ci	ageo->ag_number = pag->pag_agno;
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	agi = agi_bp->b_addr;
110962306a36Sopenharmony_ci	ageo->ag_icount = be32_to_cpu(agi->agi_count);
111062306a36Sopenharmony_ci	ageo->ag_ifree = be32_to_cpu(agi->agi_freecount);
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci	agf = agf_bp->b_addr;
111362306a36Sopenharmony_ci	ageo->ag_length = be32_to_cpu(agf->agf_length);
111462306a36Sopenharmony_ci	freeblks = pag->pagf_freeblks +
111562306a36Sopenharmony_ci		   pag->pagf_flcount +
111662306a36Sopenharmony_ci		   pag->pagf_btreeblks -
111762306a36Sopenharmony_ci		   xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE);
111862306a36Sopenharmony_ci	ageo->ag_freeblks = freeblks;
111962306a36Sopenharmony_ci	xfs_ag_geom_health(pag, ageo);
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci	/* Release resources. */
112262306a36Sopenharmony_ci	xfs_buf_relse(agf_bp);
112362306a36Sopenharmony_ciout_agi:
112462306a36Sopenharmony_ci	xfs_buf_relse(agi_bp);
112562306a36Sopenharmony_ci	return error;
112662306a36Sopenharmony_ci}
1127