18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc. 48c2ecf20Sopenharmony_ci * Copyright (c) 2018 Red Hat, Inc. 58c2ecf20Sopenharmony_ci * All rights reserved. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "xfs.h" 98c2ecf20Sopenharmony_ci#include "xfs_fs.h" 108c2ecf20Sopenharmony_ci#include "xfs_shared.h" 118c2ecf20Sopenharmony_ci#include "xfs_format.h" 128c2ecf20Sopenharmony_ci#include "xfs_trans_resv.h" 138c2ecf20Sopenharmony_ci#include "xfs_bit.h" 148c2ecf20Sopenharmony_ci#include "xfs_sb.h" 158c2ecf20Sopenharmony_ci#include "xfs_mount.h" 168c2ecf20Sopenharmony_ci#include "xfs_btree.h" 178c2ecf20Sopenharmony_ci#include "xfs_alloc_btree.h" 188c2ecf20Sopenharmony_ci#include "xfs_rmap_btree.h" 198c2ecf20Sopenharmony_ci#include "xfs_alloc.h" 208c2ecf20Sopenharmony_ci#include "xfs_ialloc.h" 218c2ecf20Sopenharmony_ci#include "xfs_rmap.h" 228c2ecf20Sopenharmony_ci#include "xfs_ag.h" 238c2ecf20Sopenharmony_ci#include "xfs_ag_resv.h" 248c2ecf20Sopenharmony_ci#include "xfs_health.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int 278c2ecf20Sopenharmony_cixfs_get_aghdr_buf( 288c2ecf20Sopenharmony_ci struct xfs_mount *mp, 298c2ecf20Sopenharmony_ci xfs_daddr_t blkno, 308c2ecf20Sopenharmony_ci size_t numblks, 318c2ecf20Sopenharmony_ci struct xfs_buf **bpp, 328c2ecf20Sopenharmony_ci const struct xfs_buf_ops *ops) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci struct xfs_buf *bp; 358c2ecf20Sopenharmony_ci int error; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci error = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, 0, &bp); 388c2ecf20Sopenharmony_ci if (error) 398c2ecf20Sopenharmony_ci return error; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); 428c2ecf20Sopenharmony_ci bp->b_bn = blkno; 438c2ecf20Sopenharmony_ci bp->b_maps[0].bm_bn = blkno; 448c2ecf20Sopenharmony_ci bp->b_ops = ops; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci *bpp = bp; 478c2ecf20Sopenharmony_ci return 0; 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic inline bool is_log_ag(struct xfs_mount *mp, struct aghdr_init_data *id) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci return mp->m_sb.sb_logstart > 0 && 538c2ecf20Sopenharmony_ci id->agno == XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* 578c2ecf20Sopenharmony_ci * Generic btree root block init function 588c2ecf20Sopenharmony_ci */ 598c2ecf20Sopenharmony_cistatic void 608c2ecf20Sopenharmony_cixfs_btroot_init( 618c2ecf20Sopenharmony_ci struct xfs_mount *mp, 628c2ecf20Sopenharmony_ci struct xfs_buf *bp, 638c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci xfs_btree_init_block(mp, bp, id->type, 0, 0, id->agno); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Finish initializing a free space btree. */ 698c2ecf20Sopenharmony_cistatic void 708c2ecf20Sopenharmony_cixfs_freesp_init_recs( 718c2ecf20Sopenharmony_ci struct xfs_mount *mp, 728c2ecf20Sopenharmony_ci struct xfs_buf *bp, 738c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct xfs_alloc_rec *arec; 768c2ecf20Sopenharmony_ci struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); 798c2ecf20Sopenharmony_ci arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (is_log_ag(mp, id)) { 828c2ecf20Sopenharmony_ci struct xfs_alloc_rec *nrec; 838c2ecf20Sopenharmony_ci xfs_agblock_t start = XFS_FSB_TO_AGBNO(mp, 848c2ecf20Sopenharmony_ci mp->m_sb.sb_logstart); 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci ASSERT(start >= mp->m_ag_prealloc_blocks); 878c2ecf20Sopenharmony_ci if (start != mp->m_ag_prealloc_blocks) { 888c2ecf20Sopenharmony_ci /* 898c2ecf20Sopenharmony_ci * Modify first record to pad stripe align of log 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ci arec->ar_blockcount = cpu_to_be32(start - 928c2ecf20Sopenharmony_ci mp->m_ag_prealloc_blocks); 938c2ecf20Sopenharmony_ci nrec = arec + 1; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* 968c2ecf20Sopenharmony_ci * Insert second record at start of internal log 978c2ecf20Sopenharmony_ci * which then gets trimmed. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_ci nrec->ar_startblock = cpu_to_be32( 1008c2ecf20Sopenharmony_ci be32_to_cpu(arec->ar_startblock) + 1018c2ecf20Sopenharmony_ci be32_to_cpu(arec->ar_blockcount)); 1028c2ecf20Sopenharmony_ci arec = nrec; 1038c2ecf20Sopenharmony_ci be16_add_cpu(&block->bb_numrecs, 1); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci /* 1068c2ecf20Sopenharmony_ci * Change record start to after the internal log 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci be32_add_cpu(&arec->ar_startblock, mp->m_sb.sb_logblocks); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* 1128c2ecf20Sopenharmony_ci * Calculate the record block count and check for the case where 1138c2ecf20Sopenharmony_ci * the log might have consumed all available space in the AG. If 1148c2ecf20Sopenharmony_ci * so, reset the record count to 0 to avoid exposure of an invalid 1158c2ecf20Sopenharmony_ci * record start block. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci arec->ar_blockcount = cpu_to_be32(id->agsize - 1188c2ecf20Sopenharmony_ci be32_to_cpu(arec->ar_startblock)); 1198c2ecf20Sopenharmony_ci if (!arec->ar_blockcount) 1208c2ecf20Sopenharmony_ci block->bb_numrecs = 0; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * Alloc btree root block init functions 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_cistatic void 1278c2ecf20Sopenharmony_cixfs_bnoroot_init( 1288c2ecf20Sopenharmony_ci struct xfs_mount *mp, 1298c2ecf20Sopenharmony_ci struct xfs_buf *bp, 1308c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 1, id->agno); 1338c2ecf20Sopenharmony_ci xfs_freesp_init_recs(mp, bp, id); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic void 1378c2ecf20Sopenharmony_cixfs_cntroot_init( 1388c2ecf20Sopenharmony_ci struct xfs_mount *mp, 1398c2ecf20Sopenharmony_ci struct xfs_buf *bp, 1408c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 1, id->agno); 1438c2ecf20Sopenharmony_ci xfs_freesp_init_recs(mp, bp, id); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/* 1478c2ecf20Sopenharmony_ci * Reverse map root block init 1488c2ecf20Sopenharmony_ci */ 1498c2ecf20Sopenharmony_cistatic void 1508c2ecf20Sopenharmony_cixfs_rmaproot_init( 1518c2ecf20Sopenharmony_ci struct xfs_mount *mp, 1528c2ecf20Sopenharmony_ci struct xfs_buf *bp, 1538c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); 1568c2ecf20Sopenharmony_ci struct xfs_rmap_rec *rrec; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci xfs_btree_init_block(mp, bp, XFS_BTNUM_RMAP, 0, 4, id->agno); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* 1618c2ecf20Sopenharmony_ci * mark the AG header regions as static metadata The BNO 1628c2ecf20Sopenharmony_ci * btree block is the first block after the headers, so 1638c2ecf20Sopenharmony_ci * it's location defines the size of region the static 1648c2ecf20Sopenharmony_ci * metadata consumes. 1658c2ecf20Sopenharmony_ci * 1668c2ecf20Sopenharmony_ci * Note: unlike mkfs, we never have to account for log 1678c2ecf20Sopenharmony_ci * space when growing the data regions 1688c2ecf20Sopenharmony_ci */ 1698c2ecf20Sopenharmony_ci rrec = XFS_RMAP_REC_ADDR(block, 1); 1708c2ecf20Sopenharmony_ci rrec->rm_startblock = 0; 1718c2ecf20Sopenharmony_ci rrec->rm_blockcount = cpu_to_be32(XFS_BNO_BLOCK(mp)); 1728c2ecf20Sopenharmony_ci rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_FS); 1738c2ecf20Sopenharmony_ci rrec->rm_offset = 0; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* account freespace btree root blocks */ 1768c2ecf20Sopenharmony_ci rrec = XFS_RMAP_REC_ADDR(block, 2); 1778c2ecf20Sopenharmony_ci rrec->rm_startblock = cpu_to_be32(XFS_BNO_BLOCK(mp)); 1788c2ecf20Sopenharmony_ci rrec->rm_blockcount = cpu_to_be32(2); 1798c2ecf20Sopenharmony_ci rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG); 1808c2ecf20Sopenharmony_ci rrec->rm_offset = 0; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci /* account inode btree root blocks */ 1838c2ecf20Sopenharmony_ci rrec = XFS_RMAP_REC_ADDR(block, 3); 1848c2ecf20Sopenharmony_ci rrec->rm_startblock = cpu_to_be32(XFS_IBT_BLOCK(mp)); 1858c2ecf20Sopenharmony_ci rrec->rm_blockcount = cpu_to_be32(XFS_RMAP_BLOCK(mp) - 1868c2ecf20Sopenharmony_ci XFS_IBT_BLOCK(mp)); 1878c2ecf20Sopenharmony_ci rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_INOBT); 1888c2ecf20Sopenharmony_ci rrec->rm_offset = 0; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* account for rmap btree root */ 1918c2ecf20Sopenharmony_ci rrec = XFS_RMAP_REC_ADDR(block, 4); 1928c2ecf20Sopenharmony_ci rrec->rm_startblock = cpu_to_be32(XFS_RMAP_BLOCK(mp)); 1938c2ecf20Sopenharmony_ci rrec->rm_blockcount = cpu_to_be32(1); 1948c2ecf20Sopenharmony_ci rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG); 1958c2ecf20Sopenharmony_ci rrec->rm_offset = 0; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* account for refc btree root */ 1988c2ecf20Sopenharmony_ci if (xfs_sb_version_hasreflink(&mp->m_sb)) { 1998c2ecf20Sopenharmony_ci rrec = XFS_RMAP_REC_ADDR(block, 5); 2008c2ecf20Sopenharmony_ci rrec->rm_startblock = cpu_to_be32(xfs_refc_block(mp)); 2018c2ecf20Sopenharmony_ci rrec->rm_blockcount = cpu_to_be32(1); 2028c2ecf20Sopenharmony_ci rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_REFC); 2038c2ecf20Sopenharmony_ci rrec->rm_offset = 0; 2048c2ecf20Sopenharmony_ci be16_add_cpu(&block->bb_numrecs, 1); 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci /* account for the log space */ 2088c2ecf20Sopenharmony_ci if (is_log_ag(mp, id)) { 2098c2ecf20Sopenharmony_ci rrec = XFS_RMAP_REC_ADDR(block, 2108c2ecf20Sopenharmony_ci be16_to_cpu(block->bb_numrecs) + 1); 2118c2ecf20Sopenharmony_ci rrec->rm_startblock = cpu_to_be32( 2128c2ecf20Sopenharmony_ci XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart)); 2138c2ecf20Sopenharmony_ci rrec->rm_blockcount = cpu_to_be32(mp->m_sb.sb_logblocks); 2148c2ecf20Sopenharmony_ci rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_LOG); 2158c2ecf20Sopenharmony_ci rrec->rm_offset = 0; 2168c2ecf20Sopenharmony_ci be16_add_cpu(&block->bb_numrecs, 1); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* 2218c2ecf20Sopenharmony_ci * Initialise new secondary superblocks with the pre-grow geometry, but mark 2228c2ecf20Sopenharmony_ci * them as "in progress" so we know they haven't yet been activated. This will 2238c2ecf20Sopenharmony_ci * get cleared when the update with the new geometry information is done after 2248c2ecf20Sopenharmony_ci * changes to the primary are committed. This isn't strictly necessary, but we 2258c2ecf20Sopenharmony_ci * get it for free with the delayed buffer write lists and it means we can tell 2268c2ecf20Sopenharmony_ci * if a grow operation didn't complete properly after the fact. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistatic void 2298c2ecf20Sopenharmony_cixfs_sbblock_init( 2308c2ecf20Sopenharmony_ci struct xfs_mount *mp, 2318c2ecf20Sopenharmony_ci struct xfs_buf *bp, 2328c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 2338c2ecf20Sopenharmony_ci{ 2348c2ecf20Sopenharmony_ci struct xfs_dsb *dsb = bp->b_addr; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci xfs_sb_to_disk(dsb, &mp->m_sb); 2378c2ecf20Sopenharmony_ci dsb->sb_inprogress = 1; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic void 2418c2ecf20Sopenharmony_cixfs_agfblock_init( 2428c2ecf20Sopenharmony_ci struct xfs_mount *mp, 2438c2ecf20Sopenharmony_ci struct xfs_buf *bp, 2448c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct xfs_agf *agf = bp->b_addr; 2478c2ecf20Sopenharmony_ci xfs_extlen_t tmpsize; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); 2508c2ecf20Sopenharmony_ci agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); 2518c2ecf20Sopenharmony_ci agf->agf_seqno = cpu_to_be32(id->agno); 2528c2ecf20Sopenharmony_ci agf->agf_length = cpu_to_be32(id->agsize); 2538c2ecf20Sopenharmony_ci agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp)); 2548c2ecf20Sopenharmony_ci agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp)); 2558c2ecf20Sopenharmony_ci agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1); 2568c2ecf20Sopenharmony_ci agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1); 2578c2ecf20Sopenharmony_ci if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { 2588c2ecf20Sopenharmony_ci agf->agf_roots[XFS_BTNUM_RMAPi] = 2598c2ecf20Sopenharmony_ci cpu_to_be32(XFS_RMAP_BLOCK(mp)); 2608c2ecf20Sopenharmony_ci agf->agf_levels[XFS_BTNUM_RMAPi] = cpu_to_be32(1); 2618c2ecf20Sopenharmony_ci agf->agf_rmap_blocks = cpu_to_be32(1); 2628c2ecf20Sopenharmony_ci } 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci agf->agf_flfirst = cpu_to_be32(1); 2658c2ecf20Sopenharmony_ci agf->agf_fllast = 0; 2668c2ecf20Sopenharmony_ci agf->agf_flcount = 0; 2678c2ecf20Sopenharmony_ci tmpsize = id->agsize - mp->m_ag_prealloc_blocks; 2688c2ecf20Sopenharmony_ci agf->agf_freeblks = cpu_to_be32(tmpsize); 2698c2ecf20Sopenharmony_ci agf->agf_longest = cpu_to_be32(tmpsize); 2708c2ecf20Sopenharmony_ci if (xfs_sb_version_hascrc(&mp->m_sb)) 2718c2ecf20Sopenharmony_ci uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); 2728c2ecf20Sopenharmony_ci if (xfs_sb_version_hasreflink(&mp->m_sb)) { 2738c2ecf20Sopenharmony_ci agf->agf_refcount_root = cpu_to_be32( 2748c2ecf20Sopenharmony_ci xfs_refc_block(mp)); 2758c2ecf20Sopenharmony_ci agf->agf_refcount_level = cpu_to_be32(1); 2768c2ecf20Sopenharmony_ci agf->agf_refcount_blocks = cpu_to_be32(1); 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (is_log_ag(mp, id)) { 2808c2ecf20Sopenharmony_ci int64_t logblocks = mp->m_sb.sb_logblocks; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci be32_add_cpu(&agf->agf_freeblks, -logblocks); 2838c2ecf20Sopenharmony_ci agf->agf_longest = cpu_to_be32(id->agsize - 2848c2ecf20Sopenharmony_ci XFS_FSB_TO_AGBNO(mp, mp->m_sb.sb_logstart) - logblocks); 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic void 2898c2ecf20Sopenharmony_cixfs_agflblock_init( 2908c2ecf20Sopenharmony_ci struct xfs_mount *mp, 2918c2ecf20Sopenharmony_ci struct xfs_buf *bp, 2928c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp); 2958c2ecf20Sopenharmony_ci __be32 *agfl_bno; 2968c2ecf20Sopenharmony_ci int bucket; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (xfs_sb_version_hascrc(&mp->m_sb)) { 2998c2ecf20Sopenharmony_ci agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC); 3008c2ecf20Sopenharmony_ci agfl->agfl_seqno = cpu_to_be32(id->agno); 3018c2ecf20Sopenharmony_ci uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); 3028c2ecf20Sopenharmony_ci } 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci agfl_bno = xfs_buf_to_agfl_bno(bp); 3058c2ecf20Sopenharmony_ci for (bucket = 0; bucket < xfs_agfl_size(mp); bucket++) 3068c2ecf20Sopenharmony_ci agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK); 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic void 3108c2ecf20Sopenharmony_cixfs_agiblock_init( 3118c2ecf20Sopenharmony_ci struct xfs_mount *mp, 3128c2ecf20Sopenharmony_ci struct xfs_buf *bp, 3138c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 3148c2ecf20Sopenharmony_ci{ 3158c2ecf20Sopenharmony_ci struct xfs_agi *agi = bp->b_addr; 3168c2ecf20Sopenharmony_ci int bucket; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); 3198c2ecf20Sopenharmony_ci agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); 3208c2ecf20Sopenharmony_ci agi->agi_seqno = cpu_to_be32(id->agno); 3218c2ecf20Sopenharmony_ci agi->agi_length = cpu_to_be32(id->agsize); 3228c2ecf20Sopenharmony_ci agi->agi_count = 0; 3238c2ecf20Sopenharmony_ci agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp)); 3248c2ecf20Sopenharmony_ci agi->agi_level = cpu_to_be32(1); 3258c2ecf20Sopenharmony_ci agi->agi_freecount = 0; 3268c2ecf20Sopenharmony_ci agi->agi_newino = cpu_to_be32(NULLAGINO); 3278c2ecf20Sopenharmony_ci agi->agi_dirino = cpu_to_be32(NULLAGINO); 3288c2ecf20Sopenharmony_ci if (xfs_sb_version_hascrc(&mp->m_sb)) 3298c2ecf20Sopenharmony_ci uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); 3308c2ecf20Sopenharmony_ci if (xfs_sb_version_hasfinobt(&mp->m_sb)) { 3318c2ecf20Sopenharmony_ci agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp)); 3328c2ecf20Sopenharmony_ci agi->agi_free_level = cpu_to_be32(1); 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) 3358c2ecf20Sopenharmony_ci agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); 3368c2ecf20Sopenharmony_ci if (xfs_sb_version_hasinobtcounts(&mp->m_sb)) { 3378c2ecf20Sopenharmony_ci agi->agi_iblocks = cpu_to_be32(1); 3388c2ecf20Sopenharmony_ci if (xfs_sb_version_hasfinobt(&mp->m_sb)) 3398c2ecf20Sopenharmony_ci agi->agi_fblocks = cpu_to_be32(1); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_citypedef void (*aghdr_init_work_f)(struct xfs_mount *mp, struct xfs_buf *bp, 3448c2ecf20Sopenharmony_ci struct aghdr_init_data *id); 3458c2ecf20Sopenharmony_cistatic int 3468c2ecf20Sopenharmony_cixfs_ag_init_hdr( 3478c2ecf20Sopenharmony_ci struct xfs_mount *mp, 3488c2ecf20Sopenharmony_ci struct aghdr_init_data *id, 3498c2ecf20Sopenharmony_ci aghdr_init_work_f work, 3508c2ecf20Sopenharmony_ci const struct xfs_buf_ops *ops) 3518c2ecf20Sopenharmony_ci{ 3528c2ecf20Sopenharmony_ci struct xfs_buf *bp; 3538c2ecf20Sopenharmony_ci int error; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci error = xfs_get_aghdr_buf(mp, id->daddr, id->numblks, &bp, ops); 3568c2ecf20Sopenharmony_ci if (error) 3578c2ecf20Sopenharmony_ci return error; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci (*work)(mp, bp, id); 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci xfs_buf_delwri_queue(bp, &id->buffer_list); 3628c2ecf20Sopenharmony_ci xfs_buf_relse(bp); 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistruct xfs_aghdr_grow_data { 3678c2ecf20Sopenharmony_ci xfs_daddr_t daddr; 3688c2ecf20Sopenharmony_ci size_t numblks; 3698c2ecf20Sopenharmony_ci const struct xfs_buf_ops *ops; 3708c2ecf20Sopenharmony_ci aghdr_init_work_f work; 3718c2ecf20Sopenharmony_ci xfs_btnum_t type; 3728c2ecf20Sopenharmony_ci bool need_init; 3738c2ecf20Sopenharmony_ci}; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci/* 3768c2ecf20Sopenharmony_ci * Prepare new AG headers to be written to disk. We use uncached buffers here, 3778c2ecf20Sopenharmony_ci * as it is assumed these new AG headers are currently beyond the currently 3788c2ecf20Sopenharmony_ci * valid filesystem address space. Using cached buffers would trip over EOFS 3798c2ecf20Sopenharmony_ci * corruption detection alogrithms in the buffer cache lookup routines. 3808c2ecf20Sopenharmony_ci * 3818c2ecf20Sopenharmony_ci * This is a non-transactional function, but the prepared buffers are added to a 3828c2ecf20Sopenharmony_ci * delayed write buffer list supplied by the caller so they can submit them to 3838c2ecf20Sopenharmony_ci * disk and wait on them as required. 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_ciint 3868c2ecf20Sopenharmony_cixfs_ag_init_headers( 3878c2ecf20Sopenharmony_ci struct xfs_mount *mp, 3888c2ecf20Sopenharmony_ci struct aghdr_init_data *id) 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct xfs_aghdr_grow_data aghdr_data[] = { 3928c2ecf20Sopenharmony_ci { /* SB */ 3938c2ecf20Sopenharmony_ci .daddr = XFS_AG_DADDR(mp, id->agno, XFS_SB_DADDR), 3948c2ecf20Sopenharmony_ci .numblks = XFS_FSS_TO_BB(mp, 1), 3958c2ecf20Sopenharmony_ci .ops = &xfs_sb_buf_ops, 3968c2ecf20Sopenharmony_ci .work = &xfs_sbblock_init, 3978c2ecf20Sopenharmony_ci .need_init = true 3988c2ecf20Sopenharmony_ci }, 3998c2ecf20Sopenharmony_ci { /* AGF */ 4008c2ecf20Sopenharmony_ci .daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGF_DADDR(mp)), 4018c2ecf20Sopenharmony_ci .numblks = XFS_FSS_TO_BB(mp, 1), 4028c2ecf20Sopenharmony_ci .ops = &xfs_agf_buf_ops, 4038c2ecf20Sopenharmony_ci .work = &xfs_agfblock_init, 4048c2ecf20Sopenharmony_ci .need_init = true 4058c2ecf20Sopenharmony_ci }, 4068c2ecf20Sopenharmony_ci { /* AGFL */ 4078c2ecf20Sopenharmony_ci .daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGFL_DADDR(mp)), 4088c2ecf20Sopenharmony_ci .numblks = XFS_FSS_TO_BB(mp, 1), 4098c2ecf20Sopenharmony_ci .ops = &xfs_agfl_buf_ops, 4108c2ecf20Sopenharmony_ci .work = &xfs_agflblock_init, 4118c2ecf20Sopenharmony_ci .need_init = true 4128c2ecf20Sopenharmony_ci }, 4138c2ecf20Sopenharmony_ci { /* AGI */ 4148c2ecf20Sopenharmony_ci .daddr = XFS_AG_DADDR(mp, id->agno, XFS_AGI_DADDR(mp)), 4158c2ecf20Sopenharmony_ci .numblks = XFS_FSS_TO_BB(mp, 1), 4168c2ecf20Sopenharmony_ci .ops = &xfs_agi_buf_ops, 4178c2ecf20Sopenharmony_ci .work = &xfs_agiblock_init, 4188c2ecf20Sopenharmony_ci .need_init = true 4198c2ecf20Sopenharmony_ci }, 4208c2ecf20Sopenharmony_ci { /* BNO root block */ 4218c2ecf20Sopenharmony_ci .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_BNO_BLOCK(mp)), 4228c2ecf20Sopenharmony_ci .numblks = BTOBB(mp->m_sb.sb_blocksize), 4238c2ecf20Sopenharmony_ci .ops = &xfs_bnobt_buf_ops, 4248c2ecf20Sopenharmony_ci .work = &xfs_bnoroot_init, 4258c2ecf20Sopenharmony_ci .need_init = true 4268c2ecf20Sopenharmony_ci }, 4278c2ecf20Sopenharmony_ci { /* CNT root block */ 4288c2ecf20Sopenharmony_ci .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_CNT_BLOCK(mp)), 4298c2ecf20Sopenharmony_ci .numblks = BTOBB(mp->m_sb.sb_blocksize), 4308c2ecf20Sopenharmony_ci .ops = &xfs_cntbt_buf_ops, 4318c2ecf20Sopenharmony_ci .work = &xfs_cntroot_init, 4328c2ecf20Sopenharmony_ci .need_init = true 4338c2ecf20Sopenharmony_ci }, 4348c2ecf20Sopenharmony_ci { /* INO root block */ 4358c2ecf20Sopenharmony_ci .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_IBT_BLOCK(mp)), 4368c2ecf20Sopenharmony_ci .numblks = BTOBB(mp->m_sb.sb_blocksize), 4378c2ecf20Sopenharmony_ci .ops = &xfs_inobt_buf_ops, 4388c2ecf20Sopenharmony_ci .work = &xfs_btroot_init, 4398c2ecf20Sopenharmony_ci .type = XFS_BTNUM_INO, 4408c2ecf20Sopenharmony_ci .need_init = true 4418c2ecf20Sopenharmony_ci }, 4428c2ecf20Sopenharmony_ci { /* FINO root block */ 4438c2ecf20Sopenharmony_ci .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_FIBT_BLOCK(mp)), 4448c2ecf20Sopenharmony_ci .numblks = BTOBB(mp->m_sb.sb_blocksize), 4458c2ecf20Sopenharmony_ci .ops = &xfs_finobt_buf_ops, 4468c2ecf20Sopenharmony_ci .work = &xfs_btroot_init, 4478c2ecf20Sopenharmony_ci .type = XFS_BTNUM_FINO, 4488c2ecf20Sopenharmony_ci .need_init = xfs_sb_version_hasfinobt(&mp->m_sb) 4498c2ecf20Sopenharmony_ci }, 4508c2ecf20Sopenharmony_ci { /* RMAP root block */ 4518c2ecf20Sopenharmony_ci .daddr = XFS_AGB_TO_DADDR(mp, id->agno, XFS_RMAP_BLOCK(mp)), 4528c2ecf20Sopenharmony_ci .numblks = BTOBB(mp->m_sb.sb_blocksize), 4538c2ecf20Sopenharmony_ci .ops = &xfs_rmapbt_buf_ops, 4548c2ecf20Sopenharmony_ci .work = &xfs_rmaproot_init, 4558c2ecf20Sopenharmony_ci .need_init = xfs_sb_version_hasrmapbt(&mp->m_sb) 4568c2ecf20Sopenharmony_ci }, 4578c2ecf20Sopenharmony_ci { /* REFC root block */ 4588c2ecf20Sopenharmony_ci .daddr = XFS_AGB_TO_DADDR(mp, id->agno, xfs_refc_block(mp)), 4598c2ecf20Sopenharmony_ci .numblks = BTOBB(mp->m_sb.sb_blocksize), 4608c2ecf20Sopenharmony_ci .ops = &xfs_refcountbt_buf_ops, 4618c2ecf20Sopenharmony_ci .work = &xfs_btroot_init, 4628c2ecf20Sopenharmony_ci .type = XFS_BTNUM_REFC, 4638c2ecf20Sopenharmony_ci .need_init = xfs_sb_version_hasreflink(&mp->m_sb) 4648c2ecf20Sopenharmony_ci }, 4658c2ecf20Sopenharmony_ci { /* NULL terminating block */ 4668c2ecf20Sopenharmony_ci .daddr = XFS_BUF_DADDR_NULL, 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci }; 4698c2ecf20Sopenharmony_ci struct xfs_aghdr_grow_data *dp; 4708c2ecf20Sopenharmony_ci int error = 0; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* Account for AG free space in new AG */ 4738c2ecf20Sopenharmony_ci id->nfree += id->agsize - mp->m_ag_prealloc_blocks; 4748c2ecf20Sopenharmony_ci for (dp = &aghdr_data[0]; dp->daddr != XFS_BUF_DADDR_NULL; dp++) { 4758c2ecf20Sopenharmony_ci if (!dp->need_init) 4768c2ecf20Sopenharmony_ci continue; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci id->daddr = dp->daddr; 4798c2ecf20Sopenharmony_ci id->numblks = dp->numblks; 4808c2ecf20Sopenharmony_ci id->type = dp->type; 4818c2ecf20Sopenharmony_ci error = xfs_ag_init_hdr(mp, id, dp->work, dp->ops); 4828c2ecf20Sopenharmony_ci if (error) 4838c2ecf20Sopenharmony_ci break; 4848c2ecf20Sopenharmony_ci } 4858c2ecf20Sopenharmony_ci return error; 4868c2ecf20Sopenharmony_ci} 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci/* 4898c2ecf20Sopenharmony_ci * Extent the AG indicated by the @id by the length passed in 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ciint 4928c2ecf20Sopenharmony_cixfs_ag_extend_space( 4938c2ecf20Sopenharmony_ci struct xfs_mount *mp, 4948c2ecf20Sopenharmony_ci struct xfs_trans *tp, 4958c2ecf20Sopenharmony_ci struct aghdr_init_data *id, 4968c2ecf20Sopenharmony_ci xfs_extlen_t len) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct xfs_buf *bp; 4998c2ecf20Sopenharmony_ci struct xfs_agi *agi; 5008c2ecf20Sopenharmony_ci struct xfs_agf *agf; 5018c2ecf20Sopenharmony_ci int error; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci /* 5048c2ecf20Sopenharmony_ci * Change the agi length. 5058c2ecf20Sopenharmony_ci */ 5068c2ecf20Sopenharmony_ci error = xfs_ialloc_read_agi(mp, tp, id->agno, &bp); 5078c2ecf20Sopenharmony_ci if (error) 5088c2ecf20Sopenharmony_ci return error; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci agi = bp->b_addr; 5118c2ecf20Sopenharmony_ci be32_add_cpu(&agi->agi_length, len); 5128c2ecf20Sopenharmony_ci ASSERT(id->agno == mp->m_sb.sb_agcount - 1 || 5138c2ecf20Sopenharmony_ci be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks); 5148c2ecf20Sopenharmony_ci xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci /* 5178c2ecf20Sopenharmony_ci * Change agf length. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_ci error = xfs_alloc_read_agf(mp, tp, id->agno, 0, &bp); 5208c2ecf20Sopenharmony_ci if (error) 5218c2ecf20Sopenharmony_ci return error; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci agf = bp->b_addr; 5248c2ecf20Sopenharmony_ci be32_add_cpu(&agf->agf_length, len); 5258c2ecf20Sopenharmony_ci ASSERT(agf->agf_length == agi->agi_length); 5268c2ecf20Sopenharmony_ci xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* 5298c2ecf20Sopenharmony_ci * Free the new space. 5308c2ecf20Sopenharmony_ci * 5318c2ecf20Sopenharmony_ci * XFS_RMAP_OINFO_SKIP_UPDATE is used here to tell the rmap btree that 5328c2ecf20Sopenharmony_ci * this doesn't actually exist in the rmap btree. 5338c2ecf20Sopenharmony_ci */ 5348c2ecf20Sopenharmony_ci error = xfs_rmap_free(tp, bp, id->agno, 5358c2ecf20Sopenharmony_ci be32_to_cpu(agf->agf_length) - len, 5368c2ecf20Sopenharmony_ci len, &XFS_RMAP_OINFO_SKIP_UPDATE); 5378c2ecf20Sopenharmony_ci if (error) 5388c2ecf20Sopenharmony_ci return error; 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return xfs_free_extent(tp, XFS_AGB_TO_FSB(mp, id->agno, 5418c2ecf20Sopenharmony_ci be32_to_cpu(agf->agf_length) - len), 5428c2ecf20Sopenharmony_ci len, &XFS_RMAP_OINFO_SKIP_UPDATE, 5438c2ecf20Sopenharmony_ci XFS_AG_RESV_NONE); 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci/* Retrieve AG geometry. */ 5478c2ecf20Sopenharmony_ciint 5488c2ecf20Sopenharmony_cixfs_ag_get_geometry( 5498c2ecf20Sopenharmony_ci struct xfs_mount *mp, 5508c2ecf20Sopenharmony_ci xfs_agnumber_t agno, 5518c2ecf20Sopenharmony_ci struct xfs_ag_geometry *ageo) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci struct xfs_buf *agi_bp; 5548c2ecf20Sopenharmony_ci struct xfs_buf *agf_bp; 5558c2ecf20Sopenharmony_ci struct xfs_agi *agi; 5568c2ecf20Sopenharmony_ci struct xfs_agf *agf; 5578c2ecf20Sopenharmony_ci struct xfs_perag *pag; 5588c2ecf20Sopenharmony_ci unsigned int freeblks; 5598c2ecf20Sopenharmony_ci int error; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci if (agno >= mp->m_sb.sb_agcount) 5628c2ecf20Sopenharmony_ci return -EINVAL; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci /* Lock the AG headers. */ 5658c2ecf20Sopenharmony_ci error = xfs_ialloc_read_agi(mp, NULL, agno, &agi_bp); 5668c2ecf20Sopenharmony_ci if (error) 5678c2ecf20Sopenharmony_ci return error; 5688c2ecf20Sopenharmony_ci error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agf_bp); 5698c2ecf20Sopenharmony_ci if (error) 5708c2ecf20Sopenharmony_ci goto out_agi; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci pag = agi_bp->b_pag; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* Fill out form. */ 5758c2ecf20Sopenharmony_ci memset(ageo, 0, sizeof(*ageo)); 5768c2ecf20Sopenharmony_ci ageo->ag_number = agno; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci agi = agi_bp->b_addr; 5798c2ecf20Sopenharmony_ci ageo->ag_icount = be32_to_cpu(agi->agi_count); 5808c2ecf20Sopenharmony_ci ageo->ag_ifree = be32_to_cpu(agi->agi_freecount); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci agf = agf_bp->b_addr; 5838c2ecf20Sopenharmony_ci ageo->ag_length = be32_to_cpu(agf->agf_length); 5848c2ecf20Sopenharmony_ci freeblks = pag->pagf_freeblks + 5858c2ecf20Sopenharmony_ci pag->pagf_flcount + 5868c2ecf20Sopenharmony_ci pag->pagf_btreeblks - 5878c2ecf20Sopenharmony_ci xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE); 5888c2ecf20Sopenharmony_ci ageo->ag_freeblks = freeblks; 5898c2ecf20Sopenharmony_ci xfs_ag_geom_health(pag, ageo); 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* Release resources. */ 5928c2ecf20Sopenharmony_ci xfs_buf_relse(agf_bp); 5938c2ecf20Sopenharmony_ciout_agi: 5948c2ecf20Sopenharmony_ci xfs_buf_relse(agi_bp); 5958c2ecf20Sopenharmony_ci return error; 5968c2ecf20Sopenharmony_ci} 597