11da177e4SLinus Torvalds /* 27b718769SNathan Scott * Copyright (c) 2000-2005 Silicon Graphics, Inc. 37b718769SNathan Scott * All Rights Reserved. 41da177e4SLinus Torvalds * 57b718769SNathan Scott * This program is free software; you can redistribute it and/or 67b718769SNathan Scott * modify it under the terms of the GNU General Public License as 71da177e4SLinus Torvalds * published by the Free Software Foundation. 81da177e4SLinus Torvalds * 97b718769SNathan Scott * This program is distributed in the hope that it would be useful, 107b718769SNathan Scott * but WITHOUT ANY WARRANTY; without even the implied warranty of 117b718769SNathan Scott * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 127b718769SNathan Scott * GNU General Public License for more details. 131da177e4SLinus Torvalds * 147b718769SNathan Scott * You should have received a copy of the GNU General Public License 157b718769SNathan Scott * along with this program; if not, write the Free Software Foundation, 167b718769SNathan Scott * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 171da177e4SLinus Torvalds */ 181da177e4SLinus Torvalds #include "xfs.h" 19a844f451SNathan Scott #include "xfs_fs.h" 2070a9883cSDave Chinner #include "xfs_shared.h" 21239880efSDave Chinner #include "xfs_format.h" 22a4fbe6abSDave Chinner #include "xfs_log_format.h" 23239880efSDave Chinner #include "xfs_trans_resv.h" 241da177e4SLinus Torvalds #include "xfs_sb.h" 251da177e4SLinus Torvalds #include "xfs_mount.h" 263ab78df2SDarrick J. Wong #include "xfs_defer.h" 278f66193cSDave Chinner #include "xfs_da_format.h" 288f66193cSDave Chinner #include "xfs_da_btree.h" 29a844f451SNathan Scott #include "xfs_inode.h" 30239880efSDave Chinner #include "xfs_trans.h" 31a844f451SNathan Scott #include "xfs_inode_item.h" 321da177e4SLinus Torvalds #include "xfs_error.h" 33a4fbe6abSDave Chinner #include "xfs_btree.h" 34a4fbe6abSDave Chinner #include "xfs_alloc_btree.h" 351da177e4SLinus Torvalds #include "xfs_alloc.h" 36e70d829fSDarrick J. Wong #include "xfs_rmap_btree.h" 371da177e4SLinus Torvalds #include "xfs_ialloc.h" 381da177e4SLinus Torvalds #include "xfs_fsops.h" 391da177e4SLinus Torvalds #include "xfs_itable.h" 401da177e4SLinus Torvalds #include "xfs_trans_space.h" 411da177e4SLinus Torvalds #include "xfs_rtalloc.h" 420b1b213fSChristoph Hellwig #include "xfs_trace.h" 43239880efSDave Chinner #include "xfs_log.h" 44a4fbe6abSDave Chinner #include "xfs_filestream.h" 45340785ccSDarrick J. Wong #include "xfs_rmap.h" 4684d69619SDarrick J. Wong #include "xfs_ag_resv.h" 471da177e4SLinus Torvalds 481da177e4SLinus Torvalds /* 491da177e4SLinus Torvalds * File system operations 501da177e4SLinus Torvalds */ 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds int 531da177e4SLinus Torvalds xfs_fs_geometry( 541da177e4SLinus Torvalds xfs_mount_t *mp, 551da177e4SLinus Torvalds xfs_fsop_geom_t *geo, 561da177e4SLinus Torvalds int new_version) 571da177e4SLinus Torvalds { 58c4d0c3b0SDan Rosenberg 59c4d0c3b0SDan Rosenberg memset(geo, 0, sizeof(*geo)); 60c4d0c3b0SDan Rosenberg 611da177e4SLinus Torvalds geo->blocksize = mp->m_sb.sb_blocksize; 621da177e4SLinus Torvalds geo->rtextsize = mp->m_sb.sb_rextsize; 631da177e4SLinus Torvalds geo->agblocks = mp->m_sb.sb_agblocks; 641da177e4SLinus Torvalds geo->agcount = mp->m_sb.sb_agcount; 651da177e4SLinus Torvalds geo->logblocks = mp->m_sb.sb_logblocks; 661da177e4SLinus Torvalds geo->sectsize = mp->m_sb.sb_sectsize; 671da177e4SLinus Torvalds geo->inodesize = mp->m_sb.sb_inodesize; 681da177e4SLinus Torvalds geo->imaxpct = mp->m_sb.sb_imax_pct; 691da177e4SLinus Torvalds geo->datablocks = mp->m_sb.sb_dblocks; 701da177e4SLinus Torvalds geo->rtblocks = mp->m_sb.sb_rblocks; 711da177e4SLinus Torvalds geo->rtextents = mp->m_sb.sb_rextents; 721da177e4SLinus Torvalds geo->logstart = mp->m_sb.sb_logstart; 731da177e4SLinus Torvalds ASSERT(sizeof(geo->uuid)==sizeof(mp->m_sb.sb_uuid)); 741da177e4SLinus Torvalds memcpy(geo->uuid, &mp->m_sb.sb_uuid, sizeof(mp->m_sb.sb_uuid)); 751da177e4SLinus Torvalds if (new_version >= 2) { 761da177e4SLinus Torvalds geo->sunit = mp->m_sb.sb_unit; 771da177e4SLinus Torvalds geo->swidth = mp->m_sb.sb_width; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds if (new_version >= 3) { 801da177e4SLinus Torvalds geo->version = XFS_FSOP_GEOM_VERSION; 81263997a6SDave Chinner geo->flags = XFS_FSOP_GEOM_FLAGS_NLINK | 825d074a4fSDave Chinner XFS_FSOP_GEOM_FLAGS_DIRV2 | 8362118709SEric Sandeen (xfs_sb_version_hasattr(&mp->m_sb) ? 841da177e4SLinus Torvalds XFS_FSOP_GEOM_FLAGS_ATTR : 0) | 8562118709SEric Sandeen (xfs_sb_version_hasquota(&mp->m_sb) ? 861da177e4SLinus Torvalds XFS_FSOP_GEOM_FLAGS_QUOTA : 0) | 8762118709SEric Sandeen (xfs_sb_version_hasalign(&mp->m_sb) ? 881da177e4SLinus Torvalds XFS_FSOP_GEOM_FLAGS_IALIGN : 0) | 8962118709SEric Sandeen (xfs_sb_version_hasdalign(&mp->m_sb) ? 901da177e4SLinus Torvalds XFS_FSOP_GEOM_FLAGS_DALIGN : 0) | 9162118709SEric Sandeen (xfs_sb_version_hasextflgbit(&mp->m_sb) ? 921da177e4SLinus Torvalds XFS_FSOP_GEOM_FLAGS_EXTFLG : 0) | 9362118709SEric Sandeen (xfs_sb_version_hassector(&mp->m_sb) ? 94d8cc890dSNathan Scott XFS_FSOP_GEOM_FLAGS_SECTOR : 0) | 95189f4bf2SBarry Naujok (xfs_sb_version_hasasciici(&mp->m_sb) ? 96189f4bf2SBarry Naujok XFS_FSOP_GEOM_FLAGS_DIRV2CI : 0) | 9792821e2bSDavid Chinner (xfs_sb_version_haslazysbcount(&mp->m_sb) ? 9892821e2bSDavid Chinner XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) | 9962118709SEric Sandeen (xfs_sb_version_hasattr2(&mp->m_sb) ? 10069a58a43SEric Sandeen XFS_FSOP_GEOM_FLAGS_ATTR2 : 0) | 10169a58a43SEric Sandeen (xfs_sb_version_hasprojid32bit(&mp->m_sb) ? 10274137fffSDave Chinner XFS_FSOP_GEOM_FLAGS_PROJID32 : 0) | 10374137fffSDave Chinner (xfs_sb_version_hascrc(&mp->m_sb) ? 1042900a579SMark Tinguely XFS_FSOP_GEOM_FLAGS_V5SB : 0) | 1052900a579SMark Tinguely (xfs_sb_version_hasftype(&mp->m_sb) ? 1060c153c1eSBrian Foster XFS_FSOP_GEOM_FLAGS_FTYPE : 0) | 1070c153c1eSBrian Foster (xfs_sb_version_hasfinobt(&mp->m_sb) ? 108502a4e72SBrian Foster XFS_FSOP_GEOM_FLAGS_FINOBT : 0) | 109502a4e72SBrian Foster (xfs_sb_version_hassparseinodes(&mp->m_sb) ? 1105d650e90SDarrick J. Wong XFS_FSOP_GEOM_FLAGS_SPINODES : 0) | 1115d650e90SDarrick J. Wong (xfs_sb_version_hasrmapbt(&mp->m_sb) ? 112f0ec1b8eSDarrick J. Wong XFS_FSOP_GEOM_FLAGS_RMAPBT : 0) | 113f0ec1b8eSDarrick J. Wong (xfs_sb_version_hasreflink(&mp->m_sb) ? 114f0ec1b8eSDarrick J. Wong XFS_FSOP_GEOM_FLAGS_REFLINK : 0); 11562118709SEric Sandeen geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ? 1161da177e4SLinus Torvalds mp->m_sb.sb_logsectsize : BBSIZE; 1171da177e4SLinus Torvalds geo->rtsectsize = mp->m_sb.sb_blocksize; 1188f66193cSDave Chinner geo->dirblocksize = mp->m_dir_geo->blksize; 1191da177e4SLinus Torvalds } 1201da177e4SLinus Torvalds if (new_version >= 4) { 1211da177e4SLinus Torvalds geo->flags |= 12262118709SEric Sandeen (xfs_sb_version_haslogv2(&mp->m_sb) ? 1231da177e4SLinus Torvalds XFS_FSOP_GEOM_FLAGS_LOGV2 : 0); 1241da177e4SLinus Torvalds geo->logsunit = mp->m_sb.sb_logsunit; 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds return 0; 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds 129fd23683cSDave Chinner static struct xfs_buf * 130fd23683cSDave Chinner xfs_growfs_get_hdr_buf( 131fd23683cSDave Chinner struct xfs_mount *mp, 132fd23683cSDave Chinner xfs_daddr_t blkno, 133fd23683cSDave Chinner size_t numblks, 1341813dd64SDave Chinner int flags, 1351813dd64SDave Chinner const struct xfs_buf_ops *ops) 136fd23683cSDave Chinner { 137fd23683cSDave Chinner struct xfs_buf *bp; 138fd23683cSDave Chinner 139fd23683cSDave Chinner bp = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, flags); 140fd23683cSDave Chinner if (!bp) 141fd23683cSDave Chinner return NULL; 142fd23683cSDave Chinner 143fd23683cSDave Chinner xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); 144fd23683cSDave Chinner bp->b_bn = blkno; 145fd23683cSDave Chinner bp->b_maps[0].bm_bn = blkno; 1461813dd64SDave Chinner bp->b_ops = ops; 147fd23683cSDave Chinner 148fd23683cSDave Chinner return bp; 149fd23683cSDave Chinner } 150fd23683cSDave Chinner 1511da177e4SLinus Torvalds static int 1521da177e4SLinus Torvalds xfs_growfs_data_private( 1531da177e4SLinus Torvalds xfs_mount_t *mp, /* mount point for filesystem */ 1541da177e4SLinus Torvalds xfs_growfs_data_t *in) /* growfs data input struct */ 1551da177e4SLinus Torvalds { 1561da177e4SLinus Torvalds xfs_agf_t *agf; 157de497688SDave Chinner struct xfs_agfl *agfl; 1581da177e4SLinus Torvalds xfs_agi_t *agi; 1591da177e4SLinus Torvalds xfs_agnumber_t agno; 1601da177e4SLinus Torvalds xfs_extlen_t agsize; 1611da177e4SLinus Torvalds xfs_extlen_t tmpsize; 1621da177e4SLinus Torvalds xfs_alloc_rec_t *arec; 1631da177e4SLinus Torvalds xfs_buf_t *bp; 1641da177e4SLinus Torvalds int bucket; 1651da177e4SLinus Torvalds int dpct; 16659e5a0e8SEric Sandeen int error, saved_error = 0; 1671da177e4SLinus Torvalds xfs_agnumber_t nagcount; 1681da177e4SLinus Torvalds xfs_agnumber_t nagimax = 0; 1691da177e4SLinus Torvalds xfs_rfsblock_t nb, nb_mod; 1701da177e4SLinus Torvalds xfs_rfsblock_t new; 1711da177e4SLinus Torvalds xfs_rfsblock_t nfree; 1721da177e4SLinus Torvalds xfs_agnumber_t oagcount; 1731da177e4SLinus Torvalds int pct; 1741da177e4SLinus Torvalds xfs_trans_t *tp; 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds nb = in->newblocks; 1771da177e4SLinus Torvalds pct = in->imaxpct; 1781da177e4SLinus Torvalds if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100) 1792451337dSDave Chinner return -EINVAL; 1804cc929eeSNathan Scott if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb))) 1814cc929eeSNathan Scott return error; 1821da177e4SLinus Torvalds dpct = pct - mp->m_sb.sb_imax_pct; 183ba372674SDave Chinner error = xfs_buf_read_uncached(mp->m_ddev_targp, 1841da177e4SLinus Torvalds XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1), 185ba372674SDave Chinner XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL); 186ba372674SDave Chinner if (error) 187eab4e633SDave Chinner return error; 1881da177e4SLinus Torvalds xfs_buf_relse(bp); 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds new = nb; /* use new as a temporary here */ 1911da177e4SLinus Torvalds nb_mod = do_div(new, mp->m_sb.sb_agblocks); 1921da177e4SLinus Torvalds nagcount = new + (nb_mod != 0); 1931da177e4SLinus Torvalds if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) { 1941da177e4SLinus Torvalds nagcount--; 195e6da7c9fSEric Sandeen nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks; 1961da177e4SLinus Torvalds if (nb < mp->m_sb.sb_dblocks) 1972451337dSDave Chinner return -EINVAL; 1981da177e4SLinus Torvalds } 1991da177e4SLinus Torvalds new = nb - mp->m_sb.sb_dblocks; 2001da177e4SLinus Torvalds oagcount = mp->m_sb.sb_agcount; 2011c1c6ebcSDave Chinner 2021c1c6ebcSDave Chinner /* allocate the new per-ag structures */ 2031da177e4SLinus Torvalds if (nagcount > oagcount) { 2041c1c6ebcSDave Chinner error = xfs_initialize_perag(mp, nagcount, &nagimax); 2051c1c6ebcSDave Chinner if (error) 2061c1c6ebcSDave Chinner return error; 2071da177e4SLinus Torvalds } 2081c1c6ebcSDave Chinner 209253f4911SChristoph Hellwig error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, 210253f4911SChristoph Hellwig XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp); 211253f4911SChristoph Hellwig if (error) 2121da177e4SLinus Torvalds return error; 2131da177e4SLinus Torvalds 2141c1c6ebcSDave Chinner /* 2151c1c6ebcSDave Chinner * Write new AG headers to disk. Non-transactional, but written 2161c1c6ebcSDave Chinner * synchronously so they are completed prior to the growfs transaction 2171c1c6ebcSDave Chinner * being logged. 2181c1c6ebcSDave Chinner */ 2191da177e4SLinus Torvalds nfree = 0; 2201da177e4SLinus Torvalds for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) { 221f94c4457SDave Chinner __be32 *agfl_bno; 222f94c4457SDave Chinner 2231da177e4SLinus Torvalds /* 224de497688SDave Chinner * AG freespace header block 2251da177e4SLinus Torvalds */ 226fd23683cSDave Chinner bp = xfs_growfs_get_hdr_buf(mp, 2271da177e4SLinus Torvalds XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), 2281813dd64SDave Chinner XFS_FSS_TO_BB(mp, 1), 0, 2291813dd64SDave Chinner &xfs_agf_buf_ops); 230b522950fSChandra Seetharaman if (!bp) { 2312451337dSDave Chinner error = -ENOMEM; 232b522950fSChandra Seetharaman goto error0; 233b522950fSChandra Seetharaman } 234fd23683cSDave Chinner 2351da177e4SLinus Torvalds agf = XFS_BUF_TO_AGF(bp); 23616259e7dSChristoph Hellwig agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); 23716259e7dSChristoph Hellwig agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); 23816259e7dSChristoph Hellwig agf->agf_seqno = cpu_to_be32(agno); 2391da177e4SLinus Torvalds if (agno == nagcount - 1) 2401da177e4SLinus Torvalds agsize = 2411da177e4SLinus Torvalds nb - 2421da177e4SLinus Torvalds (agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks); 2431da177e4SLinus Torvalds else 2441da177e4SLinus Torvalds agsize = mp->m_sb.sb_agblocks; 24516259e7dSChristoph Hellwig agf->agf_length = cpu_to_be32(agsize); 24616259e7dSChristoph Hellwig agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp)); 24716259e7dSChristoph Hellwig agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp)); 24816259e7dSChristoph Hellwig agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1); 24916259e7dSChristoph Hellwig agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1); 250e70d829fSDarrick J. Wong if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { 251e70d829fSDarrick J. Wong agf->agf_roots[XFS_BTNUM_RMAPi] = 252e70d829fSDarrick J. Wong cpu_to_be32(XFS_RMAP_BLOCK(mp)); 253e70d829fSDarrick J. Wong agf->agf_levels[XFS_BTNUM_RMAPi] = cpu_to_be32(1); 254f32866fdSDarrick J. Wong agf->agf_rmap_blocks = cpu_to_be32(1); 255e70d829fSDarrick J. Wong } 256e70d829fSDarrick J. Wong 257ad747e3bSDave Chinner agf->agf_flfirst = cpu_to_be32(1); 258ad747e3bSDave Chinner agf->agf_fllast = 0; 2591da177e4SLinus Torvalds agf->agf_flcount = 0; 2608018026eSDarrick J. Wong tmpsize = agsize - mp->m_ag_prealloc_blocks; 26116259e7dSChristoph Hellwig agf->agf_freeblks = cpu_to_be32(tmpsize); 26216259e7dSChristoph Hellwig agf->agf_longest = cpu_to_be32(tmpsize); 2634e0e6040SDave Chinner if (xfs_sb_version_hascrc(&mp->m_sb)) 264ac383de2SDave Chinner uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); 265ac4fef69SDarrick J. Wong if (xfs_sb_version_hasreflink(&mp->m_sb)) { 266ac4fef69SDarrick J. Wong agf->agf_refcount_root = cpu_to_be32( 267ac4fef69SDarrick J. Wong xfs_refc_block(mp)); 268ac4fef69SDarrick J. Wong agf->agf_refcount_level = cpu_to_be32(1); 269ac4fef69SDarrick J. Wong agf->agf_refcount_blocks = cpu_to_be32(1); 270ac4fef69SDarrick J. Wong } 2714e0e6040SDave Chinner 272c2b006c1SChristoph Hellwig error = xfs_bwrite(bp); 273c2b006c1SChristoph Hellwig xfs_buf_relse(bp); 274c2b006c1SChristoph Hellwig if (error) 2751da177e4SLinus Torvalds goto error0; 276c2b006c1SChristoph Hellwig 2771da177e4SLinus Torvalds /* 278de497688SDave Chinner * AG freelist header block 279de497688SDave Chinner */ 280de497688SDave Chinner bp = xfs_growfs_get_hdr_buf(mp, 281de497688SDave Chinner XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), 2821813dd64SDave Chinner XFS_FSS_TO_BB(mp, 1), 0, 2831813dd64SDave Chinner &xfs_agfl_buf_ops); 284de497688SDave Chinner if (!bp) { 2852451337dSDave Chinner error = -ENOMEM; 286de497688SDave Chinner goto error0; 287de497688SDave Chinner } 288de497688SDave Chinner 289de497688SDave Chinner agfl = XFS_BUF_TO_AGFL(bp); 29077c95bbaSChristoph Hellwig if (xfs_sb_version_hascrc(&mp->m_sb)) { 29177c95bbaSChristoph Hellwig agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC); 29277c95bbaSChristoph Hellwig agfl->agfl_seqno = cpu_to_be32(agno); 293ac383de2SDave Chinner uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); 29477c95bbaSChristoph Hellwig } 295f94c4457SDave Chinner 296f94c4457SDave Chinner agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp); 297de497688SDave Chinner for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++) 298f94c4457SDave Chinner agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK); 299de497688SDave Chinner 300de497688SDave Chinner error = xfs_bwrite(bp); 301de497688SDave Chinner xfs_buf_relse(bp); 302de497688SDave Chinner if (error) 303de497688SDave Chinner goto error0; 304de497688SDave Chinner 305de497688SDave Chinner /* 3061da177e4SLinus Torvalds * AG inode header block 3071da177e4SLinus Torvalds */ 308fd23683cSDave Chinner bp = xfs_growfs_get_hdr_buf(mp, 3091da177e4SLinus Torvalds XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), 3101813dd64SDave Chinner XFS_FSS_TO_BB(mp, 1), 0, 3111813dd64SDave Chinner &xfs_agi_buf_ops); 312b522950fSChandra Seetharaman if (!bp) { 3132451337dSDave Chinner error = -ENOMEM; 314b522950fSChandra Seetharaman goto error0; 315b522950fSChandra Seetharaman } 316fd23683cSDave Chinner 3171da177e4SLinus Torvalds agi = XFS_BUF_TO_AGI(bp); 31816259e7dSChristoph Hellwig agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); 31916259e7dSChristoph Hellwig agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); 32016259e7dSChristoph Hellwig agi->agi_seqno = cpu_to_be32(agno); 32116259e7dSChristoph Hellwig agi->agi_length = cpu_to_be32(agsize); 3221da177e4SLinus Torvalds agi->agi_count = 0; 32316259e7dSChristoph Hellwig agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp)); 32416259e7dSChristoph Hellwig agi->agi_level = cpu_to_be32(1); 3251da177e4SLinus Torvalds agi->agi_freecount = 0; 32616259e7dSChristoph Hellwig agi->agi_newino = cpu_to_be32(NULLAGINO); 32716259e7dSChristoph Hellwig agi->agi_dirino = cpu_to_be32(NULLAGINO); 328983d09ffSDave Chinner if (xfs_sb_version_hascrc(&mp->m_sb)) 329ac383de2SDave Chinner uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); 330a3fa516dSBrian Foster if (xfs_sb_version_hasfinobt(&mp->m_sb)) { 331a3fa516dSBrian Foster agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp)); 332a3fa516dSBrian Foster agi->agi_free_level = cpu_to_be32(1); 333a3fa516dSBrian Foster } 3341da177e4SLinus Torvalds for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) 33516259e7dSChristoph Hellwig agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); 336983d09ffSDave Chinner 337c2b006c1SChristoph Hellwig error = xfs_bwrite(bp); 338c2b006c1SChristoph Hellwig xfs_buf_relse(bp); 339c2b006c1SChristoph Hellwig if (error) 3401da177e4SLinus Torvalds goto error0; 341c2b006c1SChristoph Hellwig 3421da177e4SLinus Torvalds /* 3431da177e4SLinus Torvalds * BNO btree root block 3441da177e4SLinus Torvalds */ 345fd23683cSDave Chinner bp = xfs_growfs_get_hdr_buf(mp, 3461da177e4SLinus Torvalds XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)), 3471813dd64SDave Chinner BTOBB(mp->m_sb.sb_blocksize), 0, 3481813dd64SDave Chinner &xfs_allocbt_buf_ops); 349fd23683cSDave Chinner 350b522950fSChandra Seetharaman if (!bp) { 3512451337dSDave Chinner error = -ENOMEM; 352b522950fSChandra Seetharaman goto error0; 353b522950fSChandra Seetharaman } 354b64f3a39SDave Chinner 355b6f41e44SEric Sandeen xfs_btree_init_block(mp, bp, XFS_BTNUM_BNO, 0, 1, agno, 0); 356ee1a47abSChristoph Hellwig 357b64f3a39SDave Chinner arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); 3588018026eSDarrick J. Wong arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks); 35916259e7dSChristoph Hellwig arec->ar_blockcount = cpu_to_be32( 36016259e7dSChristoph Hellwig agsize - be32_to_cpu(arec->ar_startblock)); 361b64f3a39SDave Chinner 362c2b006c1SChristoph Hellwig error = xfs_bwrite(bp); 363c2b006c1SChristoph Hellwig xfs_buf_relse(bp); 364c2b006c1SChristoph Hellwig if (error) 3651da177e4SLinus Torvalds goto error0; 366c2b006c1SChristoph Hellwig 3671da177e4SLinus Torvalds /* 3681da177e4SLinus Torvalds * CNT btree root block 3691da177e4SLinus Torvalds */ 370fd23683cSDave Chinner bp = xfs_growfs_get_hdr_buf(mp, 3711da177e4SLinus Torvalds XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)), 3721813dd64SDave Chinner BTOBB(mp->m_sb.sb_blocksize), 0, 3731813dd64SDave Chinner &xfs_allocbt_buf_ops); 374b522950fSChandra Seetharaman if (!bp) { 3752451337dSDave Chinner error = -ENOMEM; 376b522950fSChandra Seetharaman goto error0; 377b522950fSChandra Seetharaman } 378b64f3a39SDave Chinner 379b6f41e44SEric Sandeen xfs_btree_init_block(mp, bp, XFS_BTNUM_CNT, 0, 1, agno, 0); 380ee1a47abSChristoph Hellwig 381b64f3a39SDave Chinner arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); 3828018026eSDarrick J. Wong arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks); 38316259e7dSChristoph Hellwig arec->ar_blockcount = cpu_to_be32( 38416259e7dSChristoph Hellwig agsize - be32_to_cpu(arec->ar_startblock)); 38516259e7dSChristoph Hellwig nfree += be32_to_cpu(arec->ar_blockcount); 386b64f3a39SDave Chinner 387c2b006c1SChristoph Hellwig error = xfs_bwrite(bp); 388c2b006c1SChristoph Hellwig xfs_buf_relse(bp); 389c2b006c1SChristoph Hellwig if (error) 3901da177e4SLinus Torvalds goto error0; 391c2b006c1SChristoph Hellwig 392e70d829fSDarrick J. Wong /* RMAP btree root block */ 393e70d829fSDarrick J. Wong if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { 394e70d829fSDarrick J. Wong struct xfs_rmap_rec *rrec; 395e70d829fSDarrick J. Wong struct xfs_btree_block *block; 396e70d829fSDarrick J. Wong 397e70d829fSDarrick J. Wong bp = xfs_growfs_get_hdr_buf(mp, 398e70d829fSDarrick J. Wong XFS_AGB_TO_DADDR(mp, agno, XFS_RMAP_BLOCK(mp)), 399e70d829fSDarrick J. Wong BTOBB(mp->m_sb.sb_blocksize), 0, 400e70d829fSDarrick J. Wong &xfs_rmapbt_buf_ops); 401e70d829fSDarrick J. Wong if (!bp) { 402e70d829fSDarrick J. Wong error = -ENOMEM; 403e70d829fSDarrick J. Wong goto error0; 404e70d829fSDarrick J. Wong } 405e70d829fSDarrick J. Wong 406b6f41e44SEric Sandeen xfs_btree_init_block(mp, bp, XFS_BTNUM_RMAP, 0, 0, 407f88ae46bSEric Sandeen agno, 0); 408e70d829fSDarrick J. Wong block = XFS_BUF_TO_BLOCK(bp); 409e70d829fSDarrick J. Wong 410e70d829fSDarrick J. Wong 411e70d829fSDarrick J. Wong /* 412e70d829fSDarrick J. Wong * mark the AG header regions as static metadata The BNO 413e70d829fSDarrick J. Wong * btree block is the first block after the headers, so 414e70d829fSDarrick J. Wong * it's location defines the size of region the static 415e70d829fSDarrick J. Wong * metadata consumes. 416e70d829fSDarrick J. Wong * 417e70d829fSDarrick J. Wong * Note: unlike mkfs, we never have to account for log 418e70d829fSDarrick J. Wong * space when growing the data regions 419e70d829fSDarrick J. Wong */ 420e70d829fSDarrick J. Wong rrec = XFS_RMAP_REC_ADDR(block, 1); 421e70d829fSDarrick J. Wong rrec->rm_startblock = 0; 422e70d829fSDarrick J. Wong rrec->rm_blockcount = cpu_to_be32(XFS_BNO_BLOCK(mp)); 423e70d829fSDarrick J. Wong rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_FS); 424e70d829fSDarrick J. Wong rrec->rm_offset = 0; 425e70d829fSDarrick J. Wong be16_add_cpu(&block->bb_numrecs, 1); 426e70d829fSDarrick J. Wong 427e70d829fSDarrick J. Wong /* account freespace btree root blocks */ 428e70d829fSDarrick J. Wong rrec = XFS_RMAP_REC_ADDR(block, 2); 429e70d829fSDarrick J. Wong rrec->rm_startblock = cpu_to_be32(XFS_BNO_BLOCK(mp)); 430e70d829fSDarrick J. Wong rrec->rm_blockcount = cpu_to_be32(2); 431e70d829fSDarrick J. Wong rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG); 432e70d829fSDarrick J. Wong rrec->rm_offset = 0; 433e70d829fSDarrick J. Wong be16_add_cpu(&block->bb_numrecs, 1); 434e70d829fSDarrick J. Wong 435e70d829fSDarrick J. Wong /* account inode btree root blocks */ 436e70d829fSDarrick J. Wong rrec = XFS_RMAP_REC_ADDR(block, 3); 437e70d829fSDarrick J. Wong rrec->rm_startblock = cpu_to_be32(XFS_IBT_BLOCK(mp)); 438e70d829fSDarrick J. Wong rrec->rm_blockcount = cpu_to_be32(XFS_RMAP_BLOCK(mp) - 439e70d829fSDarrick J. Wong XFS_IBT_BLOCK(mp)); 440e70d829fSDarrick J. Wong rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_INOBT); 441e70d829fSDarrick J. Wong rrec->rm_offset = 0; 442e70d829fSDarrick J. Wong be16_add_cpu(&block->bb_numrecs, 1); 443e70d829fSDarrick J. Wong 444e70d829fSDarrick J. Wong /* account for rmap btree root */ 445e70d829fSDarrick J. Wong rrec = XFS_RMAP_REC_ADDR(block, 4); 446e70d829fSDarrick J. Wong rrec->rm_startblock = cpu_to_be32(XFS_RMAP_BLOCK(mp)); 447e70d829fSDarrick J. Wong rrec->rm_blockcount = cpu_to_be32(1); 448e70d829fSDarrick J. Wong rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG); 449e70d829fSDarrick J. Wong rrec->rm_offset = 0; 450e70d829fSDarrick J. Wong be16_add_cpu(&block->bb_numrecs, 1); 451e70d829fSDarrick J. Wong 452ac4fef69SDarrick J. Wong /* account for refc btree root */ 453ac4fef69SDarrick J. Wong if (xfs_sb_version_hasreflink(&mp->m_sb)) { 454ac4fef69SDarrick J. Wong rrec = XFS_RMAP_REC_ADDR(block, 5); 455ac4fef69SDarrick J. Wong rrec->rm_startblock = cpu_to_be32( 456ac4fef69SDarrick J. Wong xfs_refc_block(mp)); 457ac4fef69SDarrick J. Wong rrec->rm_blockcount = cpu_to_be32(1); 458ac4fef69SDarrick J. Wong rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_REFC); 459ac4fef69SDarrick J. Wong rrec->rm_offset = 0; 460ac4fef69SDarrick J. Wong be16_add_cpu(&block->bb_numrecs, 1); 461ac4fef69SDarrick J. Wong } 462ac4fef69SDarrick J. Wong 463e70d829fSDarrick J. Wong error = xfs_bwrite(bp); 464e70d829fSDarrick J. Wong xfs_buf_relse(bp); 465e70d829fSDarrick J. Wong if (error) 466e70d829fSDarrick J. Wong goto error0; 467e70d829fSDarrick J. Wong } 468e70d829fSDarrick J. Wong 4691da177e4SLinus Torvalds /* 4701da177e4SLinus Torvalds * INO btree root block 4711da177e4SLinus Torvalds */ 472fd23683cSDave Chinner bp = xfs_growfs_get_hdr_buf(mp, 4731da177e4SLinus Torvalds XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)), 4741813dd64SDave Chinner BTOBB(mp->m_sb.sb_blocksize), 0, 4751813dd64SDave Chinner &xfs_inobt_buf_ops); 476b522950fSChandra Seetharaman if (!bp) { 4772451337dSDave Chinner error = -ENOMEM; 478b522950fSChandra Seetharaman goto error0; 479b522950fSChandra Seetharaman } 480fd23683cSDave Chinner 481b6f41e44SEric Sandeen xfs_btree_init_block(mp, bp, XFS_BTNUM_INO , 0, 0, agno, 0); 482b64f3a39SDave Chinner 483c2b006c1SChristoph Hellwig error = xfs_bwrite(bp); 484c2b006c1SChristoph Hellwig xfs_buf_relse(bp); 485c2b006c1SChristoph Hellwig if (error) 4861da177e4SLinus Torvalds goto error0; 487a3fa516dSBrian Foster 488a3fa516dSBrian Foster /* 489a3fa516dSBrian Foster * FINO btree root block 490a3fa516dSBrian Foster */ 491a3fa516dSBrian Foster if (xfs_sb_version_hasfinobt(&mp->m_sb)) { 492a3fa516dSBrian Foster bp = xfs_growfs_get_hdr_buf(mp, 493a3fa516dSBrian Foster XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)), 494a3fa516dSBrian Foster BTOBB(mp->m_sb.sb_blocksize), 0, 495a3fa516dSBrian Foster &xfs_inobt_buf_ops); 496a3fa516dSBrian Foster if (!bp) { 4972451337dSDave Chinner error = -ENOMEM; 498a3fa516dSBrian Foster goto error0; 499a3fa516dSBrian Foster } 500a3fa516dSBrian Foster 501b6f41e44SEric Sandeen xfs_btree_init_block(mp, bp, XFS_BTNUM_FINO, 502f88ae46bSEric Sandeen 0, 0, agno, 0); 503a3fa516dSBrian Foster 504a3fa516dSBrian Foster error = xfs_bwrite(bp); 505a3fa516dSBrian Foster xfs_buf_relse(bp); 506a3fa516dSBrian Foster if (error) 507a3fa516dSBrian Foster goto error0; 508a3fa516dSBrian Foster } 509a3fa516dSBrian Foster 510ac4fef69SDarrick J. Wong /* 511ac4fef69SDarrick J. Wong * refcount btree root block 512ac4fef69SDarrick J. Wong */ 513ac4fef69SDarrick J. Wong if (xfs_sb_version_hasreflink(&mp->m_sb)) { 514ac4fef69SDarrick J. Wong bp = xfs_growfs_get_hdr_buf(mp, 515ac4fef69SDarrick J. Wong XFS_AGB_TO_DADDR(mp, agno, xfs_refc_block(mp)), 516ac4fef69SDarrick J. Wong BTOBB(mp->m_sb.sb_blocksize), 0, 517ac4fef69SDarrick J. Wong &xfs_refcountbt_buf_ops); 518ac4fef69SDarrick J. Wong if (!bp) { 519ac4fef69SDarrick J. Wong error = -ENOMEM; 520ac4fef69SDarrick J. Wong goto error0; 521ac4fef69SDarrick J. Wong } 522ac4fef69SDarrick J. Wong 523b6f41e44SEric Sandeen xfs_btree_init_block(mp, bp, XFS_BTNUM_REFC, 524f88ae46bSEric Sandeen 0, 0, agno, 0); 525ac4fef69SDarrick J. Wong 526ac4fef69SDarrick J. Wong error = xfs_bwrite(bp); 527ac4fef69SDarrick J. Wong xfs_buf_relse(bp); 528ac4fef69SDarrick J. Wong if (error) 529ac4fef69SDarrick J. Wong goto error0; 530ac4fef69SDarrick J. Wong } 5311da177e4SLinus Torvalds } 5321da177e4SLinus Torvalds xfs_trans_agblocks_delta(tp, nfree); 5331da177e4SLinus Torvalds /* 5341da177e4SLinus Torvalds * There are new blocks in the old last a.g. 5351da177e4SLinus Torvalds */ 5361da177e4SLinus Torvalds if (new) { 537340785ccSDarrick J. Wong struct xfs_owner_info oinfo; 538340785ccSDarrick J. Wong 5391da177e4SLinus Torvalds /* 5401da177e4SLinus Torvalds * Change the agi length. 5411da177e4SLinus Torvalds */ 5421da177e4SLinus Torvalds error = xfs_ialloc_read_agi(mp, tp, agno, &bp); 5431da177e4SLinus Torvalds if (error) { 5441da177e4SLinus Torvalds goto error0; 5451da177e4SLinus Torvalds } 5461da177e4SLinus Torvalds ASSERT(bp); 5471da177e4SLinus Torvalds agi = XFS_BUF_TO_AGI(bp); 548413d57c9SMarcin Slusarz be32_add_cpu(&agi->agi_length, new); 5491da177e4SLinus Torvalds ASSERT(nagcount == oagcount || 55016259e7dSChristoph Hellwig be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks); 5511da177e4SLinus Torvalds xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH); 5521da177e4SLinus Torvalds /* 5531da177e4SLinus Torvalds * Change agf length. 5541da177e4SLinus Torvalds */ 5551da177e4SLinus Torvalds error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp); 5561da177e4SLinus Torvalds if (error) { 5571da177e4SLinus Torvalds goto error0; 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds ASSERT(bp); 5601da177e4SLinus Torvalds agf = XFS_BUF_TO_AGF(bp); 561413d57c9SMarcin Slusarz be32_add_cpu(&agf->agf_length, new); 56216259e7dSChristoph Hellwig ASSERT(be32_to_cpu(agf->agf_length) == 56316259e7dSChristoph Hellwig be32_to_cpu(agi->agi_length)); 5640b1b213fSChristoph Hellwig 5650164af51STim Shimmin xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH); 566340785ccSDarrick J. Wong 5671da177e4SLinus Torvalds /* 5681da177e4SLinus Torvalds * Free the new space. 569340785ccSDarrick J. Wong * 570340785ccSDarrick J. Wong * XFS_RMAP_OWN_NULL is used here to tell the rmap btree that 571340785ccSDarrick J. Wong * this doesn't actually exist in the rmap btree. 5721da177e4SLinus Torvalds */ 573340785ccSDarrick J. Wong xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_NULL); 574340785ccSDarrick J. Wong error = xfs_free_extent(tp, 575340785ccSDarrick J. Wong XFS_AGB_TO_FSB(mp, agno, 576340785ccSDarrick J. Wong be32_to_cpu(agf->agf_length) - new), 5773fd129b6SDarrick J. Wong new, &oinfo, XFS_AG_RESV_NONE); 578340785ccSDarrick J. Wong if (error) 5791da177e4SLinus Torvalds goto error0; 5801da177e4SLinus Torvalds } 5811c1c6ebcSDave Chinner 5821c1c6ebcSDave Chinner /* 5831c1c6ebcSDave Chinner * Update changed superblock fields transactionally. These are not 5841c1c6ebcSDave Chinner * seen by the rest of the world until the transaction commit applies 5851c1c6ebcSDave Chinner * them atomically to the superblock. 5861c1c6ebcSDave Chinner */ 5871da177e4SLinus Torvalds if (nagcount > oagcount) 5881da177e4SLinus Torvalds xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); 5891da177e4SLinus Torvalds if (nb > mp->m_sb.sb_dblocks) 5901da177e4SLinus Torvalds xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, 5911da177e4SLinus Torvalds nb - mp->m_sb.sb_dblocks); 5921da177e4SLinus Torvalds if (nfree) 5931da177e4SLinus Torvalds xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree); 5941da177e4SLinus Torvalds if (dpct) 5951da177e4SLinus Torvalds xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); 596f8079b85SChristoph Hellwig xfs_trans_set_sync(tp); 59770393313SChristoph Hellwig error = xfs_trans_commit(tp); 5981c1c6ebcSDave Chinner if (error) 5991da177e4SLinus Torvalds return error; 6001c1c6ebcSDave Chinner 6011da177e4SLinus Torvalds /* New allocation groups fully initialized, so update mount struct */ 6021da177e4SLinus Torvalds if (nagimax) 6031da177e4SLinus Torvalds mp->m_maxagi = nagimax; 6041da177e4SLinus Torvalds if (mp->m_sb.sb_imax_pct) { 605*c8ce540dSDarrick J. Wong uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; 6061da177e4SLinus Torvalds do_div(icount, 100); 6071da177e4SLinus Torvalds mp->m_maxicount = icount << mp->m_sb.sb_inopblog; 6081da177e4SLinus Torvalds } else 6091da177e4SLinus Torvalds mp->m_maxicount = 0; 610055388a3SDave Chinner xfs_set_low_space_thresholds(mp); 61152548852SDarrick J. Wong mp->m_alloc_set_aside = xfs_alloc_set_aside(mp); 6121c1c6ebcSDave Chinner 61320e73b00SDarrick J. Wong /* 61420e73b00SDarrick J. Wong * If we expanded the last AG, free the per-AG reservation 61520e73b00SDarrick J. Wong * so we can reinitialize it with the new size. 61620e73b00SDarrick J. Wong */ 61720e73b00SDarrick J. Wong if (new) { 61820e73b00SDarrick J. Wong struct xfs_perag *pag; 61920e73b00SDarrick J. Wong 62020e73b00SDarrick J. Wong pag = xfs_perag_get(mp, agno); 62120e73b00SDarrick J. Wong error = xfs_ag_resv_free(pag); 62220e73b00SDarrick J. Wong xfs_perag_put(pag); 62320e73b00SDarrick J. Wong if (error) 62420e73b00SDarrick J. Wong goto out; 62520e73b00SDarrick J. Wong } 62620e73b00SDarrick J. Wong 62784d69619SDarrick J. Wong /* Reserve AG metadata blocks. */ 62884d69619SDarrick J. Wong error = xfs_fs_reserve_ag_blocks(mp); 62984d69619SDarrick J. Wong if (error && error != -ENOSPC) 63084d69619SDarrick J. Wong goto out; 63184d69619SDarrick J. Wong 6321c1c6ebcSDave Chinner /* update secondary superblocks. */ 6331da177e4SLinus Torvalds for (agno = 1; agno < nagcount; agno++) { 6341375cb65SDave Chinner error = 0; 6351375cb65SDave Chinner /* 6361375cb65SDave Chinner * new secondary superblocks need to be zeroed, not read from 6371375cb65SDave Chinner * disk as the contents of the new area we are growing into is 6381375cb65SDave Chinner * completely unknown. 6391375cb65SDave Chinner */ 6401375cb65SDave Chinner if (agno < oagcount) { 6417ca790a5SDave Chinner error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, 6421da177e4SLinus Torvalds XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), 64398021821SDave Chinner XFS_FSS_TO_BB(mp, 1), 0, &bp, 6441813dd64SDave Chinner &xfs_sb_buf_ops); 6451375cb65SDave Chinner } else { 6461375cb65SDave Chinner bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp, 6471375cb65SDave Chinner XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), 6481375cb65SDave Chinner XFS_FSS_TO_BB(mp, 1), 0); 649b0f539deSDave Chinner if (bp) { 6501813dd64SDave Chinner bp->b_ops = &xfs_sb_buf_ops; 6511375cb65SDave Chinner xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); 652b0f539deSDave Chinner } else 6532451337dSDave Chinner error = -ENOMEM; 6541375cb65SDave Chinner } 6551375cb65SDave Chinner 65659e5a0e8SEric Sandeen /* 65759e5a0e8SEric Sandeen * If we get an error reading or writing alternate superblocks, 65859e5a0e8SEric Sandeen * continue. xfs_repair chooses the "best" superblock based 65959e5a0e8SEric Sandeen * on most matches; if we break early, we'll leave more 66059e5a0e8SEric Sandeen * superblocks un-updated than updated, and xfs_repair may 66159e5a0e8SEric Sandeen * pick them over the properly-updated primary. 66259e5a0e8SEric Sandeen */ 6631da177e4SLinus Torvalds if (error) { 66453487786SDave Chinner xfs_warn(mp, 6651da177e4SLinus Torvalds "error %d reading secondary superblock for ag %d", 6661da177e4SLinus Torvalds error, agno); 66759e5a0e8SEric Sandeen saved_error = error; 66859e5a0e8SEric Sandeen continue; 6691da177e4SLinus Torvalds } 6704d11a402SDave Chinner xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); 67198021821SDave Chinner 672c2b006c1SChristoph Hellwig error = xfs_bwrite(bp); 673c2b006c1SChristoph Hellwig xfs_buf_relse(bp); 674c2b006c1SChristoph Hellwig if (error) { 67553487786SDave Chinner xfs_warn(mp, 6761da177e4SLinus Torvalds "write error %d updating secondary superblock for ag %d", 6771da177e4SLinus Torvalds error, agno); 67859e5a0e8SEric Sandeen saved_error = error; 67959e5a0e8SEric Sandeen continue; 6801da177e4SLinus Torvalds } 6811da177e4SLinus Torvalds } 68284d69619SDarrick J. Wong 68384d69619SDarrick J. Wong out: 68459e5a0e8SEric Sandeen return saved_error ? saved_error : error; 6851da177e4SLinus Torvalds 6861da177e4SLinus Torvalds error0: 6874906e215SChristoph Hellwig xfs_trans_cancel(tp); 6881da177e4SLinus Torvalds return error; 6891da177e4SLinus Torvalds } 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds static int 6921da177e4SLinus Torvalds xfs_growfs_log_private( 6931da177e4SLinus Torvalds xfs_mount_t *mp, /* mount point for filesystem */ 6941da177e4SLinus Torvalds xfs_growfs_log_t *in) /* growfs log input struct */ 6951da177e4SLinus Torvalds { 6961da177e4SLinus Torvalds xfs_extlen_t nb; 6971da177e4SLinus Torvalds 6981da177e4SLinus Torvalds nb = in->newblocks; 6991da177e4SLinus Torvalds if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES)) 7002451337dSDave Chinner return -EINVAL; 7011da177e4SLinus Torvalds if (nb == mp->m_sb.sb_logblocks && 7021da177e4SLinus Torvalds in->isint == (mp->m_sb.sb_logstart != 0)) 7032451337dSDave Chinner return -EINVAL; 7041da177e4SLinus Torvalds /* 7051da177e4SLinus Torvalds * Moving the log is hard, need new interfaces to sync 7061da177e4SLinus Torvalds * the log first, hold off all activity while moving it. 7071da177e4SLinus Torvalds * Can have shorter or longer log in the same space, 7081da177e4SLinus Torvalds * or transform internal to external log or vice versa. 7091da177e4SLinus Torvalds */ 7102451337dSDave Chinner return -ENOSYS; 7111da177e4SLinus Torvalds } 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds /* 7141da177e4SLinus Torvalds * protected versions of growfs function acquire and release locks on the mount 7151da177e4SLinus Torvalds * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG, 7161da177e4SLinus Torvalds * XFS_IOC_FSGROWFSRT 7171da177e4SLinus Torvalds */ 7181da177e4SLinus Torvalds 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds int 7211da177e4SLinus Torvalds xfs_growfs_data( 7221da177e4SLinus Torvalds xfs_mount_t *mp, 7231da177e4SLinus Torvalds xfs_growfs_data_t *in) 7241da177e4SLinus Torvalds { 7251da177e4SLinus Torvalds int error; 726743bb465Ssandeen@sandeen.net 727743bb465Ssandeen@sandeen.net if (!capable(CAP_SYS_ADMIN)) 7282451337dSDave Chinner return -EPERM; 729cc92e7acSChristoph Hellwig if (!mutex_trylock(&mp->m_growlock)) 7302451337dSDave Chinner return -EWOULDBLOCK; 7311da177e4SLinus Torvalds error = xfs_growfs_data_private(mp, in); 73252785112SChristoph Hellwig /* 73352785112SChristoph Hellwig * Increment the generation unconditionally, the error could be from 73452785112SChristoph Hellwig * updating the secondary superblocks, in which case the new size 73552785112SChristoph Hellwig * is live already. 73652785112SChristoph Hellwig */ 73752785112SChristoph Hellwig mp->m_generation++; 738cc92e7acSChristoph Hellwig mutex_unlock(&mp->m_growlock); 7391da177e4SLinus Torvalds return error; 7401da177e4SLinus Torvalds } 7411da177e4SLinus Torvalds 7421da177e4SLinus Torvalds int 7431da177e4SLinus Torvalds xfs_growfs_log( 7441da177e4SLinus Torvalds xfs_mount_t *mp, 7451da177e4SLinus Torvalds xfs_growfs_log_t *in) 7461da177e4SLinus Torvalds { 7471da177e4SLinus Torvalds int error; 748743bb465Ssandeen@sandeen.net 749743bb465Ssandeen@sandeen.net if (!capable(CAP_SYS_ADMIN)) 7502451337dSDave Chinner return -EPERM; 751cc92e7acSChristoph Hellwig if (!mutex_trylock(&mp->m_growlock)) 7522451337dSDave Chinner return -EWOULDBLOCK; 7531da177e4SLinus Torvalds error = xfs_growfs_log_private(mp, in); 754cc92e7acSChristoph Hellwig mutex_unlock(&mp->m_growlock); 7551da177e4SLinus Torvalds return error; 7561da177e4SLinus Torvalds } 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds /* 7591da177e4SLinus Torvalds * exported through ioctl XFS_IOC_FSCOUNTS 7601da177e4SLinus Torvalds */ 7611da177e4SLinus Torvalds 7621da177e4SLinus Torvalds int 7631da177e4SLinus Torvalds xfs_fs_counts( 7641da177e4SLinus Torvalds xfs_mount_t *mp, 7651da177e4SLinus Torvalds xfs_fsop_counts_t *cnt) 7661da177e4SLinus Torvalds { 767501ab323SDave Chinner cnt->allocino = percpu_counter_read_positive(&mp->m_icount); 768e88b64eaSDave Chinner cnt->freeino = percpu_counter_read_positive(&mp->m_ifree); 7690d485adaSDave Chinner cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) - 77052548852SDarrick J. Wong mp->m_alloc_set_aside; 771501ab323SDave Chinner 7723685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 7731da177e4SLinus Torvalds cnt->freertx = mp->m_sb.sb_frextents; 7743685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 7751da177e4SLinus Torvalds return 0; 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds /* 7791da177e4SLinus Torvalds * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS 7801da177e4SLinus Torvalds * 7811da177e4SLinus Torvalds * xfs_reserve_blocks is called to set m_resblks 7821da177e4SLinus Torvalds * in the in-core mount table. The number of unused reserved blocks 783c41564b5SNathan Scott * is kept in m_resblks_avail. 7841da177e4SLinus Torvalds * 7851da177e4SLinus Torvalds * Reserve the requested number of blocks if available. Otherwise return 7861da177e4SLinus Torvalds * as many as possible to satisfy the request. The actual number 7871da177e4SLinus Torvalds * reserved are returned in outval 7881da177e4SLinus Torvalds * 7891da177e4SLinus Torvalds * A null inval pointer indicates that only the current reserved blocks 7901da177e4SLinus Torvalds * available should be returned no settings are changed. 7911da177e4SLinus Torvalds */ 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds int 7941da177e4SLinus Torvalds xfs_reserve_blocks( 7951da177e4SLinus Torvalds xfs_mount_t *mp, 796*c8ce540dSDarrick J. Wong uint64_t *inval, 7971da177e4SLinus Torvalds xfs_fsop_resblks_t *outval) 7981da177e4SLinus Torvalds { 799*c8ce540dSDarrick J. Wong int64_t lcounter, delta; 800*c8ce540dSDarrick J. Wong int64_t fdblks_delta = 0; 801*c8ce540dSDarrick J. Wong uint64_t request; 802*c8ce540dSDarrick J. Wong int64_t free; 803408fd484SBrian Foster int error = 0; 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds /* If inval is null, report current values and return */ 806*c8ce540dSDarrick J. Wong if (inval == (uint64_t *)NULL) { 80784e1e99fSDavid Chinner if (!outval) 8082451337dSDave Chinner return -EINVAL; 8091da177e4SLinus Torvalds outval->resblks = mp->m_resblks; 8101da177e4SLinus Torvalds outval->resblks_avail = mp->m_resblks_avail; 811014c2544SJesper Juhl return 0; 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds 8141da177e4SLinus Torvalds request = *inval; 815dbcabad1SDavid Chinner 816dbcabad1SDavid Chinner /* 817408fd484SBrian Foster * With per-cpu counters, this becomes an interesting problem. we need 818408fd484SBrian Foster * to work out if we are freeing or allocation blocks first, then we can 819408fd484SBrian Foster * do the modification as necessary. 820dbcabad1SDavid Chinner * 821408fd484SBrian Foster * We do this under the m_sb_lock so that if we are near ENOSPC, we will 822408fd484SBrian Foster * hold out any changes while we work out what to do. This means that 823408fd484SBrian Foster * the amount of free space can change while we do this, so we need to 824408fd484SBrian Foster * retry if we end up trying to reserve more space than is available. 825dbcabad1SDavid Chinner */ 8263685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds /* 8291da177e4SLinus Torvalds * If our previous reservation was larger than the current value, 830408fd484SBrian Foster * then move any unused blocks back to the free pool. Modify the resblks 831408fd484SBrian Foster * counters directly since we shouldn't have any problems unreserving 832408fd484SBrian Foster * space. 8331da177e4SLinus Torvalds */ 8341da177e4SLinus Torvalds if (mp->m_resblks > request) { 8351da177e4SLinus Torvalds lcounter = mp->m_resblks_avail - request; 8361da177e4SLinus Torvalds if (lcounter > 0) { /* release unused blocks */ 837dbcabad1SDavid Chinner fdblks_delta = lcounter; 8381da177e4SLinus Torvalds mp->m_resblks_avail -= lcounter; 8391da177e4SLinus Torvalds } 8401da177e4SLinus Torvalds mp->m_resblks = request; 841408fd484SBrian Foster if (fdblks_delta) { 842408fd484SBrian Foster spin_unlock(&mp->m_sb_lock); 843408fd484SBrian Foster error = xfs_mod_fdblocks(mp, fdblks_delta, 0); 844408fd484SBrian Foster spin_lock(&mp->m_sb_lock); 845408fd484SBrian Foster } 8464be536deSDavid Chinner 847408fd484SBrian Foster goto out; 848408fd484SBrian Foster } 849408fd484SBrian Foster 850408fd484SBrian Foster /* 851408fd484SBrian Foster * If the request is larger than the current reservation, reserve the 852408fd484SBrian Foster * blocks before we update the reserve counters. Sample m_fdblocks and 853408fd484SBrian Foster * perform a partial reservation if the request exceeds free space. 854408fd484SBrian Foster */ 855408fd484SBrian Foster error = -ENOSPC; 856408fd484SBrian Foster do { 8570d485adaSDave Chinner free = percpu_counter_sum(&mp->m_fdblocks) - 85852548852SDarrick J. Wong mp->m_alloc_set_aside; 859dbcabad1SDavid Chinner if (!free) 860408fd484SBrian Foster break; 861dbcabad1SDavid Chinner 8621da177e4SLinus Torvalds delta = request - mp->m_resblks; 8634be536deSDavid Chinner lcounter = free - delta; 864408fd484SBrian Foster if (lcounter < 0) 8651da177e4SLinus Torvalds /* We can't satisfy the request, just get what we can */ 866408fd484SBrian Foster fdblks_delta = free; 867408fd484SBrian Foster else 868408fd484SBrian Foster fdblks_delta = delta; 869408fd484SBrian Foster 870408fd484SBrian Foster /* 871408fd484SBrian Foster * We'll either succeed in getting space from the free block 872408fd484SBrian Foster * count or we'll get an ENOSPC. If we get a ENOSPC, it means 873408fd484SBrian Foster * things changed while we were calculating fdblks_delta and so 874408fd484SBrian Foster * we should try again to see if there is anything left to 875408fd484SBrian Foster * reserve. 876408fd484SBrian Foster * 877408fd484SBrian Foster * Don't set the reserved flag here - we don't want to reserve 878408fd484SBrian Foster * the extra reserve blocks from the reserve..... 879408fd484SBrian Foster */ 880408fd484SBrian Foster spin_unlock(&mp->m_sb_lock); 881408fd484SBrian Foster error = xfs_mod_fdblocks(mp, -fdblks_delta, 0); 882408fd484SBrian Foster spin_lock(&mp->m_sb_lock); 883408fd484SBrian Foster } while (error == -ENOSPC); 884408fd484SBrian Foster 885408fd484SBrian Foster /* 886408fd484SBrian Foster * Update the reserve counters if blocks have been successfully 887408fd484SBrian Foster * allocated. 888408fd484SBrian Foster */ 889408fd484SBrian Foster if (!error && fdblks_delta) { 890408fd484SBrian Foster mp->m_resblks += fdblks_delta; 891408fd484SBrian Foster mp->m_resblks_avail += fdblks_delta; 8921da177e4SLinus Torvalds } 893408fd484SBrian Foster 894dbcabad1SDavid Chinner out: 89584e1e99fSDavid Chinner if (outval) { 8961da177e4SLinus Torvalds outval->resblks = mp->m_resblks; 8971da177e4SLinus Torvalds outval->resblks_avail = mp->m_resblks_avail; 89884e1e99fSDavid Chinner } 899dbcabad1SDavid Chinner 900408fd484SBrian Foster spin_unlock(&mp->m_sb_lock); 901408fd484SBrian Foster return error; 9021da177e4SLinus Torvalds } 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds int 9051da177e4SLinus Torvalds xfs_fs_goingdown( 9061da177e4SLinus Torvalds xfs_mount_t *mp, 907*c8ce540dSDarrick J. Wong uint32_t inflags) 9081da177e4SLinus Torvalds { 9091da177e4SLinus Torvalds switch (inflags) { 9101da177e4SLinus Torvalds case XFS_FSOP_GOING_FLAGS_DEFAULT: { 911b267ce99SChristoph Hellwig struct super_block *sb = freeze_bdev(mp->m_super->s_bdev); 9121da177e4SLinus Torvalds 913f33c6797SChristoph Hellwig if (sb && !IS_ERR(sb)) { 9147d04a335SNathan Scott xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); 9151da177e4SLinus Torvalds thaw_bdev(sb->s_bdev, sb); 9161da177e4SLinus Torvalds } 9171da177e4SLinus Torvalds 9181da177e4SLinus Torvalds break; 9191da177e4SLinus Torvalds } 9201da177e4SLinus Torvalds case XFS_FSOP_GOING_FLAGS_LOGFLUSH: 9217d04a335SNathan Scott xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); 9221da177e4SLinus Torvalds break; 9231da177e4SLinus Torvalds case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH: 9247d04a335SNathan Scott xfs_force_shutdown(mp, 9257d04a335SNathan Scott SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR); 9261da177e4SLinus Torvalds break; 9271da177e4SLinus Torvalds default: 9282451337dSDave Chinner return -EINVAL; 9291da177e4SLinus Torvalds } 9301da177e4SLinus Torvalds 9311da177e4SLinus Torvalds return 0; 9321da177e4SLinus Torvalds } 9332af51f3aSDave Chinner 9342af51f3aSDave Chinner /* 9352af51f3aSDave Chinner * Force a shutdown of the filesystem instantly while keeping the filesystem 9362af51f3aSDave Chinner * consistent. We don't do an unmount here; just shutdown the shop, make sure 9372af51f3aSDave Chinner * that absolutely nothing persistent happens to this filesystem after this 9382af51f3aSDave Chinner * point. 9392af51f3aSDave Chinner */ 9402af51f3aSDave Chinner void 9412af51f3aSDave Chinner xfs_do_force_shutdown( 9422af51f3aSDave Chinner xfs_mount_t *mp, 9432af51f3aSDave Chinner int flags, 9442af51f3aSDave Chinner char *fname, 9452af51f3aSDave Chinner int lnnum) 9462af51f3aSDave Chinner { 9472af51f3aSDave Chinner int logerror; 9482af51f3aSDave Chinner 9492af51f3aSDave Chinner logerror = flags & SHUTDOWN_LOG_IO_ERROR; 9502af51f3aSDave Chinner 9512af51f3aSDave Chinner if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { 9522af51f3aSDave Chinner xfs_notice(mp, 9532af51f3aSDave Chinner "%s(0x%x) called from line %d of file %s. Return address = 0x%p", 9542af51f3aSDave Chinner __func__, flags, lnnum, fname, __return_address); 9552af51f3aSDave Chinner } 9562af51f3aSDave Chinner /* 9572af51f3aSDave Chinner * No need to duplicate efforts. 9582af51f3aSDave Chinner */ 9592af51f3aSDave Chinner if (XFS_FORCED_SHUTDOWN(mp) && !logerror) 9602af51f3aSDave Chinner return; 9612af51f3aSDave Chinner 9622af51f3aSDave Chinner /* 9632af51f3aSDave Chinner * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't 9642af51f3aSDave Chinner * queue up anybody new on the log reservations, and wakes up 9652af51f3aSDave Chinner * everybody who's sleeping on log reservations to tell them 9662af51f3aSDave Chinner * the bad news. 9672af51f3aSDave Chinner */ 9682af51f3aSDave Chinner if (xfs_log_force_umount(mp, logerror)) 9692af51f3aSDave Chinner return; 9702af51f3aSDave Chinner 9712af51f3aSDave Chinner if (flags & SHUTDOWN_CORRUPT_INCORE) { 9722af51f3aSDave Chinner xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT, 9732af51f3aSDave Chinner "Corruption of in-memory data detected. Shutting down filesystem"); 9742af51f3aSDave Chinner if (XFS_ERRLEVEL_HIGH <= xfs_error_level) 9752af51f3aSDave Chinner xfs_stack_trace(); 9762af51f3aSDave Chinner } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { 9772af51f3aSDave Chinner if (logerror) { 9782af51f3aSDave Chinner xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR, 9792af51f3aSDave Chinner "Log I/O Error Detected. Shutting down filesystem"); 9802af51f3aSDave Chinner } else if (flags & SHUTDOWN_DEVICE_REQ) { 9812af51f3aSDave Chinner xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, 9822af51f3aSDave Chinner "All device paths lost. Shutting down filesystem"); 9832af51f3aSDave Chinner } else if (!(flags & SHUTDOWN_REMOTE_REQ)) { 9842af51f3aSDave Chinner xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, 9852af51f3aSDave Chinner "I/O Error Detected. Shutting down filesystem"); 9862af51f3aSDave Chinner } 9872af51f3aSDave Chinner } 9882af51f3aSDave Chinner if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { 9892af51f3aSDave Chinner xfs_alert(mp, 9902af51f3aSDave Chinner "Please umount the filesystem and rectify the problem(s)"); 9912af51f3aSDave Chinner } 9922af51f3aSDave Chinner } 99384d69619SDarrick J. Wong 99484d69619SDarrick J. Wong /* 99584d69619SDarrick J. Wong * Reserve free space for per-AG metadata. 99684d69619SDarrick J. Wong */ 99784d69619SDarrick J. Wong int 99884d69619SDarrick J. Wong xfs_fs_reserve_ag_blocks( 99984d69619SDarrick J. Wong struct xfs_mount *mp) 100084d69619SDarrick J. Wong { 100184d69619SDarrick J. Wong xfs_agnumber_t agno; 100284d69619SDarrick J. Wong struct xfs_perag *pag; 100384d69619SDarrick J. Wong int error = 0; 100484d69619SDarrick J. Wong int err2; 100584d69619SDarrick J. Wong 100684d69619SDarrick J. Wong for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { 100784d69619SDarrick J. Wong pag = xfs_perag_get(mp, agno); 100884d69619SDarrick J. Wong err2 = xfs_ag_resv_init(pag); 100984d69619SDarrick J. Wong xfs_perag_put(pag); 101084d69619SDarrick J. Wong if (err2 && !error) 101184d69619SDarrick J. Wong error = err2; 101284d69619SDarrick J. Wong } 101384d69619SDarrick J. Wong 101484d69619SDarrick J. Wong if (error && error != -ENOSPC) { 101584d69619SDarrick J. Wong xfs_warn(mp, 101684d69619SDarrick J. Wong "Error %d reserving per-AG metadata reserve pool.", error); 101784d69619SDarrick J. Wong xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 101884d69619SDarrick J. Wong } 101984d69619SDarrick J. Wong 102084d69619SDarrick J. Wong return error; 102184d69619SDarrick J. Wong } 102284d69619SDarrick J. Wong 102384d69619SDarrick J. Wong /* 102484d69619SDarrick J. Wong * Free space reserved for per-AG metadata. 102584d69619SDarrick J. Wong */ 102684d69619SDarrick J. Wong int 102784d69619SDarrick J. Wong xfs_fs_unreserve_ag_blocks( 102884d69619SDarrick J. Wong struct xfs_mount *mp) 102984d69619SDarrick J. Wong { 103084d69619SDarrick J. Wong xfs_agnumber_t agno; 103184d69619SDarrick J. Wong struct xfs_perag *pag; 103284d69619SDarrick J. Wong int error = 0; 103384d69619SDarrick J. Wong int err2; 103484d69619SDarrick J. Wong 103584d69619SDarrick J. Wong for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { 103684d69619SDarrick J. Wong pag = xfs_perag_get(mp, agno); 103784d69619SDarrick J. Wong err2 = xfs_ag_resv_free(pag); 103884d69619SDarrick J. Wong xfs_perag_put(pag); 103984d69619SDarrick J. Wong if (err2 && !error) 104084d69619SDarrick J. Wong error = err2; 104184d69619SDarrick J. Wong } 104284d69619SDarrick J. Wong 104384d69619SDarrick J. Wong if (error) 104484d69619SDarrick J. Wong xfs_warn(mp, 104584d69619SDarrick J. Wong "Error %d freeing per-AG metadata reserve pool.", error); 104684d69619SDarrick J. Wong 104784d69619SDarrick J. Wong return error; 104884d69619SDarrick J. Wong } 1049