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