10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 37b718769SNathan Scott * Copyright (c) 2000-2005 Silicon Graphics, Inc. 47b718769SNathan Scott * All Rights Reserved. 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds #include "xfs.h" 7a844f451SNathan Scott #include "xfs_fs.h" 870a9883cSDave Chinner #include "xfs_shared.h" 9239880efSDave Chinner #include "xfs_format.h" 10a4fbe6abSDave Chinner #include "xfs_log_format.h" 11239880efSDave Chinner #include "xfs_trans_resv.h" 121da177e4SLinus Torvalds #include "xfs_sb.h" 131da177e4SLinus Torvalds #include "xfs_mount.h" 143ab78df2SDarrick J. Wong #include "xfs_defer.h" 15239880efSDave Chinner #include "xfs_trans.h" 161da177e4SLinus Torvalds #include "xfs_error.h" 17a4fbe6abSDave Chinner #include "xfs_btree.h" 181da177e4SLinus Torvalds #include "xfs_alloc.h" 191da177e4SLinus Torvalds #include "xfs_fsops.h" 201da177e4SLinus Torvalds #include "xfs_trans_space.h" 211da177e4SLinus Torvalds #include "xfs_rtalloc.h" 220b1b213fSChristoph Hellwig #include "xfs_trace.h" 23239880efSDave Chinner #include "xfs_log.h" 24b16817b6SDave Chinner #include "xfs_ag.h" 2584d69619SDarrick J. Wong #include "xfs_ag_resv.h" 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /* 28b16817b6SDave Chinner * growfs operations 291da177e4SLinus Torvalds */ 301da177e4SLinus Torvalds static int 311da177e4SLinus Torvalds xfs_growfs_data_private( 321da177e4SLinus Torvalds xfs_mount_t *mp, /* mount point for filesystem */ 331da177e4SLinus Torvalds xfs_growfs_data_t *in) /* growfs data input struct */ 341da177e4SLinus Torvalds { 351da177e4SLinus Torvalds xfs_buf_t *bp; 3683a7f86eSDave Chinner int error; 371da177e4SLinus Torvalds xfs_agnumber_t nagcount; 381da177e4SLinus Torvalds xfs_agnumber_t nagimax = 0; 391da177e4SLinus Torvalds xfs_rfsblock_t nb, nb_mod; 401da177e4SLinus Torvalds xfs_rfsblock_t new; 411da177e4SLinus Torvalds xfs_agnumber_t oagcount; 421da177e4SLinus Torvalds xfs_trans_t *tp; 430410c3bbSDave Chinner struct aghdr_init_data id = {}; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds nb = in->newblocks; 4687444b8cSDave Chinner if (nb < mp->m_sb.sb_dblocks) 472451337dSDave Chinner return -EINVAL; 484cc929eeSNathan Scott if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb))) 494cc929eeSNathan Scott return error; 50ba372674SDave Chinner error = xfs_buf_read_uncached(mp->m_ddev_targp, 511da177e4SLinus Torvalds XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1), 52ba372674SDave Chinner XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL); 53ba372674SDave Chinner if (error) 54eab4e633SDave Chinner return error; 551da177e4SLinus Torvalds xfs_buf_relse(bp); 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds new = nb; /* use new as a temporary here */ 581da177e4SLinus Torvalds nb_mod = do_div(new, mp->m_sb.sb_agblocks); 591da177e4SLinus Torvalds nagcount = new + (nb_mod != 0); 601da177e4SLinus Torvalds if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) { 611da177e4SLinus Torvalds nagcount--; 62e6da7c9fSEric Sandeen nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks; 631da177e4SLinus Torvalds if (nb < mp->m_sb.sb_dblocks) 642451337dSDave Chinner return -EINVAL; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds new = nb - mp->m_sb.sb_dblocks; 671da177e4SLinus Torvalds oagcount = mp->m_sb.sb_agcount; 681c1c6ebcSDave Chinner 691c1c6ebcSDave Chinner /* allocate the new per-ag structures */ 701da177e4SLinus Torvalds if (nagcount > oagcount) { 711c1c6ebcSDave Chinner error = xfs_initialize_perag(mp, nagcount, &nagimax); 721c1c6ebcSDave Chinner if (error) 731c1c6ebcSDave Chinner return error; 741da177e4SLinus Torvalds } 751c1c6ebcSDave Chinner 76253f4911SChristoph Hellwig error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, 77253f4911SChristoph Hellwig XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp); 78253f4911SChristoph Hellwig if (error) 791da177e4SLinus Torvalds return error; 801da177e4SLinus Torvalds 811c1c6ebcSDave Chinner /* 829aebe805SDave Chinner * Write new AG headers to disk. Non-transactional, but need to be 839aebe805SDave Chinner * written and completed prior to the growfs transaction being logged. 849aebe805SDave Chinner * To do this, we use a delayed write buffer list and wait for 859aebe805SDave Chinner * submission and IO completion of the list as a whole. This allows the 869aebe805SDave Chinner * IO subsystem to merge all the AG headers in a single AG into a single 879aebe805SDave Chinner * IO and hide most of the latency of the IO from us. 889aebe805SDave Chinner * 899aebe805SDave Chinner * This also means that if we get an error whilst building the buffer 909aebe805SDave Chinner * list to write, we can cancel the entire list without having written 919aebe805SDave Chinner * anything. 921c1c6ebcSDave Chinner */ 930410c3bbSDave Chinner INIT_LIST_HEAD(&id.buffer_list); 940410c3bbSDave Chinner for (id.agno = nagcount - 1; 950410c3bbSDave Chinner id.agno >= oagcount; 960410c3bbSDave Chinner id.agno--, new -= id.agsize) { 97f94c4457SDave Chinner 980410c3bbSDave Chinner if (id.agno == nagcount - 1) 990410c3bbSDave Chinner id.agsize = nb - 1000410c3bbSDave Chinner (id.agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks); 1011da177e4SLinus Torvalds else 1020410c3bbSDave Chinner id.agsize = mp->m_sb.sb_agblocks; 103e70d829fSDarrick J. Wong 104b16817b6SDave Chinner error = xfs_ag_init_headers(mp, &id); 1059aebe805SDave Chinner if (error) { 1060410c3bbSDave Chinner xfs_buf_delwri_cancel(&id.buffer_list); 10783a7f86eSDave Chinner goto out_trans_cancel; 1081da177e4SLinus Torvalds } 1099aebe805SDave Chinner } 1100410c3bbSDave Chinner error = xfs_buf_delwri_submit(&id.buffer_list); 1119aebe805SDave Chinner if (error) 11283a7f86eSDave Chinner goto out_trans_cancel; 1139aebe805SDave Chinner 1140410c3bbSDave Chinner xfs_trans_agblocks_delta(tp, id.nfree); 115cce77bcfSDave Chinner 11649dd56f2SDave Chinner /* If there are new blocks in the old last AG, extend it. */ 1171da177e4SLinus Torvalds if (new) { 11849dd56f2SDave Chinner error = xfs_ag_extend_space(mp, tp, &id, new); 119340785ccSDarrick J. Wong if (error) 12083a7f86eSDave Chinner goto out_trans_cancel; 1211da177e4SLinus Torvalds } 1221c1c6ebcSDave Chinner 1231c1c6ebcSDave Chinner /* 1241c1c6ebcSDave Chinner * Update changed superblock fields transactionally. These are not 1251c1c6ebcSDave Chinner * seen by the rest of the world until the transaction commit applies 1261c1c6ebcSDave Chinner * them atomically to the superblock. 1271c1c6ebcSDave Chinner */ 1281da177e4SLinus Torvalds if (nagcount > oagcount) 1291da177e4SLinus Torvalds xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); 1301da177e4SLinus Torvalds if (nb > mp->m_sb.sb_dblocks) 1311da177e4SLinus Torvalds xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, 1321da177e4SLinus Torvalds nb - mp->m_sb.sb_dblocks); 1330410c3bbSDave Chinner if (id.nfree) 1340410c3bbSDave Chinner xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, id.nfree); 135f8079b85SChristoph Hellwig xfs_trans_set_sync(tp); 13670393313SChristoph Hellwig error = xfs_trans_commit(tp); 1371c1c6ebcSDave Chinner if (error) 1381da177e4SLinus Torvalds return error; 1391c1c6ebcSDave Chinner 1401da177e4SLinus Torvalds /* New allocation groups fully initialized, so update mount struct */ 1411da177e4SLinus Torvalds if (nagimax) 1421da177e4SLinus Torvalds mp->m_maxagi = nagimax; 143055388a3SDave Chinner xfs_set_low_space_thresholds(mp); 14452548852SDarrick J. Wong mp->m_alloc_set_aside = xfs_alloc_set_aside(mp); 1451c1c6ebcSDave Chinner 14620e73b00SDarrick J. Wong /* 14720e73b00SDarrick J. Wong * If we expanded the last AG, free the per-AG reservation 14820e73b00SDarrick J. Wong * so we can reinitialize it with the new size. 14920e73b00SDarrick J. Wong */ 15020e73b00SDarrick J. Wong if (new) { 15120e73b00SDarrick J. Wong struct xfs_perag *pag; 15220e73b00SDarrick J. Wong 1530410c3bbSDave Chinner pag = xfs_perag_get(mp, id.agno); 15420e73b00SDarrick J. Wong error = xfs_ag_resv_free(pag); 15520e73b00SDarrick J. Wong xfs_perag_put(pag); 15620e73b00SDarrick J. Wong if (error) 15783a7f86eSDave Chinner return error; 15820e73b00SDarrick J. Wong } 15920e73b00SDarrick J. Wong 16083a7f86eSDave Chinner /* 16183a7f86eSDave Chinner * Reserve AG metadata blocks. ENOSPC here does not mean there was a 16283a7f86eSDave Chinner * growfs failure, just that there still isn't space for new user data 16383a7f86eSDave Chinner * after the grow has been run. 16483a7f86eSDave Chinner */ 16584d69619SDarrick J. Wong error = xfs_fs_reserve_ag_blocks(mp); 16683a7f86eSDave Chinner if (error == -ENOSPC) 16783a7f86eSDave Chinner error = 0; 16883a7f86eSDave Chinner return error; 16983a7f86eSDave Chinner 17083a7f86eSDave Chinner out_trans_cancel: 17183a7f86eSDave Chinner xfs_trans_cancel(tp); 17283a7f86eSDave Chinner return error; 17383a7f86eSDave Chinner } 17483a7f86eSDave Chinner 17583a7f86eSDave Chinner static int 17683a7f86eSDave Chinner xfs_growfs_log_private( 17783a7f86eSDave Chinner xfs_mount_t *mp, /* mount point for filesystem */ 17883a7f86eSDave Chinner xfs_growfs_log_t *in) /* growfs log input struct */ 17983a7f86eSDave Chinner { 18083a7f86eSDave Chinner xfs_extlen_t nb; 18183a7f86eSDave Chinner 18283a7f86eSDave Chinner nb = in->newblocks; 18383a7f86eSDave Chinner if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES)) 18483a7f86eSDave Chinner return -EINVAL; 18583a7f86eSDave Chinner if (nb == mp->m_sb.sb_logblocks && 18683a7f86eSDave Chinner in->isint == (mp->m_sb.sb_logstart != 0)) 18783a7f86eSDave Chinner return -EINVAL; 18883a7f86eSDave Chinner /* 18983a7f86eSDave Chinner * Moving the log is hard, need new interfaces to sync 19083a7f86eSDave Chinner * the log first, hold off all activity while moving it. 19183a7f86eSDave Chinner * Can have shorter or longer log in the same space, 19283a7f86eSDave Chinner * or transform internal to external log or vice versa. 19383a7f86eSDave Chinner */ 19483a7f86eSDave Chinner return -ENOSYS; 19583a7f86eSDave Chinner } 19683a7f86eSDave Chinner 19783a7f86eSDave Chinner static int 19883a7f86eSDave Chinner xfs_growfs_imaxpct( 19983a7f86eSDave Chinner struct xfs_mount *mp, 20083a7f86eSDave Chinner __u32 imaxpct) 20183a7f86eSDave Chinner { 20283a7f86eSDave Chinner struct xfs_trans *tp; 20383a7f86eSDave Chinner int dpct; 20483a7f86eSDave Chinner int error; 20583a7f86eSDave Chinner 20683a7f86eSDave Chinner if (imaxpct > 100) 20783a7f86eSDave Chinner return -EINVAL; 20883a7f86eSDave Chinner 20983a7f86eSDave Chinner error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, 21083a7f86eSDave Chinner XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp); 21183a7f86eSDave Chinner if (error) 21283a7f86eSDave Chinner return error; 21383a7f86eSDave Chinner 21483a7f86eSDave Chinner dpct = imaxpct - mp->m_sb.sb_imax_pct; 21583a7f86eSDave Chinner xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); 21683a7f86eSDave Chinner xfs_trans_set_sync(tp); 21783a7f86eSDave Chinner return xfs_trans_commit(tp); 21883a7f86eSDave Chinner } 21983a7f86eSDave Chinner 22083a7f86eSDave Chinner /* 2211da177e4SLinus Torvalds * protected versions of growfs function acquire and release locks on the mount 2221da177e4SLinus Torvalds * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG, 2231da177e4SLinus Torvalds * XFS_IOC_FSGROWFSRT 2241da177e4SLinus Torvalds */ 2251da177e4SLinus Torvalds int 2261da177e4SLinus Torvalds xfs_growfs_data( 22787444b8cSDave Chinner struct xfs_mount *mp, 22887444b8cSDave Chinner struct xfs_growfs_data *in) 2291da177e4SLinus Torvalds { 23087444b8cSDave Chinner int error = 0; 231743bb465Ssandeen@sandeen.net 232743bb465Ssandeen@sandeen.net if (!capable(CAP_SYS_ADMIN)) 2332451337dSDave Chinner return -EPERM; 234cc92e7acSChristoph Hellwig if (!mutex_trylock(&mp->m_growlock)) 2352451337dSDave Chinner return -EWOULDBLOCK; 23687444b8cSDave Chinner 23787444b8cSDave Chinner /* update imaxpct separately to the physical grow of the filesystem */ 23887444b8cSDave Chinner if (in->imaxpct != mp->m_sb.sb_imax_pct) { 23987444b8cSDave Chinner error = xfs_growfs_imaxpct(mp, in->imaxpct); 24087444b8cSDave Chinner if (error) 24187444b8cSDave Chinner goto out_error; 24287444b8cSDave Chinner } 24387444b8cSDave Chinner 24487444b8cSDave Chinner if (in->newblocks != mp->m_sb.sb_dblocks) { 2451da177e4SLinus Torvalds error = xfs_growfs_data_private(mp, in); 24687444b8cSDave Chinner if (error) 24787444b8cSDave Chinner goto out_error; 24887444b8cSDave Chinner } 24987444b8cSDave Chinner 25087444b8cSDave Chinner /* Post growfs calculations needed to reflect new state in operations */ 25187444b8cSDave Chinner if (mp->m_sb.sb_imax_pct) { 25287444b8cSDave Chinner uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; 25387444b8cSDave Chinner do_div(icount, 100); 25443004b2aSDarrick J. Wong mp->m_maxicount = XFS_FSB_TO_INO(mp, icount); 25587444b8cSDave Chinner } else 25687444b8cSDave Chinner mp->m_maxicount = 0; 25787444b8cSDave Chinner 25883a7f86eSDave Chinner /* Update secondary superblocks now the physical grow has completed */ 259b16817b6SDave Chinner error = xfs_update_secondary_sbs(mp); 26083a7f86eSDave Chinner 26187444b8cSDave Chinner out_error: 26252785112SChristoph Hellwig /* 26352785112SChristoph Hellwig * Increment the generation unconditionally, the error could be from 26452785112SChristoph Hellwig * updating the secondary superblocks, in which case the new size 26552785112SChristoph Hellwig * is live already. 26652785112SChristoph Hellwig */ 26752785112SChristoph Hellwig mp->m_generation++; 268cc92e7acSChristoph Hellwig mutex_unlock(&mp->m_growlock); 2691da177e4SLinus Torvalds return error; 2701da177e4SLinus Torvalds } 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds int 2731da177e4SLinus Torvalds xfs_growfs_log( 2741da177e4SLinus Torvalds xfs_mount_t *mp, 2751da177e4SLinus Torvalds xfs_growfs_log_t *in) 2761da177e4SLinus Torvalds { 2771da177e4SLinus Torvalds int error; 278743bb465Ssandeen@sandeen.net 279743bb465Ssandeen@sandeen.net if (!capable(CAP_SYS_ADMIN)) 2802451337dSDave Chinner return -EPERM; 281cc92e7acSChristoph Hellwig if (!mutex_trylock(&mp->m_growlock)) 2822451337dSDave Chinner return -EWOULDBLOCK; 2831da177e4SLinus Torvalds error = xfs_growfs_log_private(mp, in); 284cc92e7acSChristoph Hellwig mutex_unlock(&mp->m_growlock); 2851da177e4SLinus Torvalds return error; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds /* 2891da177e4SLinus Torvalds * exported through ioctl XFS_IOC_FSCOUNTS 2901da177e4SLinus Torvalds */ 2911da177e4SLinus Torvalds 292*91083269SEric Sandeen void 2931da177e4SLinus Torvalds xfs_fs_counts( 2941da177e4SLinus Torvalds xfs_mount_t *mp, 2951da177e4SLinus Torvalds xfs_fsop_counts_t *cnt) 2961da177e4SLinus Torvalds { 297501ab323SDave Chinner cnt->allocino = percpu_counter_read_positive(&mp->m_icount); 298e88b64eaSDave Chinner cnt->freeino = percpu_counter_read_positive(&mp->m_ifree); 2990d485adaSDave Chinner cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) - 30052548852SDarrick J. Wong mp->m_alloc_set_aside; 301501ab323SDave Chinner 3023685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 3031da177e4SLinus Torvalds cnt->freertx = mp->m_sb.sb_frextents; 3043685c2a1SEric Sandeen spin_unlock(&mp->m_sb_lock); 3051da177e4SLinus Torvalds } 3061da177e4SLinus Torvalds 3071da177e4SLinus Torvalds /* 3081da177e4SLinus Torvalds * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS 3091da177e4SLinus Torvalds * 3101da177e4SLinus Torvalds * xfs_reserve_blocks is called to set m_resblks 3111da177e4SLinus Torvalds * in the in-core mount table. The number of unused reserved blocks 312c41564b5SNathan Scott * is kept in m_resblks_avail. 3131da177e4SLinus Torvalds * 3141da177e4SLinus Torvalds * Reserve the requested number of blocks if available. Otherwise return 3151da177e4SLinus Torvalds * as many as possible to satisfy the request. The actual number 3161da177e4SLinus Torvalds * reserved are returned in outval 3171da177e4SLinus Torvalds * 3181da177e4SLinus Torvalds * A null inval pointer indicates that only the current reserved blocks 3191da177e4SLinus Torvalds * available should be returned no settings are changed. 3201da177e4SLinus Torvalds */ 3211da177e4SLinus Torvalds 3221da177e4SLinus Torvalds int 3231da177e4SLinus Torvalds xfs_reserve_blocks( 3241da177e4SLinus Torvalds xfs_mount_t *mp, 325c8ce540dSDarrick J. Wong uint64_t *inval, 3261da177e4SLinus Torvalds xfs_fsop_resblks_t *outval) 3271da177e4SLinus Torvalds { 328c8ce540dSDarrick J. Wong int64_t lcounter, delta; 329c8ce540dSDarrick J. Wong int64_t fdblks_delta = 0; 330c8ce540dSDarrick J. Wong uint64_t request; 331c8ce540dSDarrick J. Wong int64_t free; 332408fd484SBrian Foster int error = 0; 3331da177e4SLinus Torvalds 3341da177e4SLinus Torvalds /* If inval is null, report current values and return */ 335c8ce540dSDarrick J. Wong if (inval == (uint64_t *)NULL) { 33684e1e99fSDavid Chinner if (!outval) 3372451337dSDave Chinner return -EINVAL; 3381da177e4SLinus Torvalds outval->resblks = mp->m_resblks; 3391da177e4SLinus Torvalds outval->resblks_avail = mp->m_resblks_avail; 340014c2544SJesper Juhl return 0; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds request = *inval; 344dbcabad1SDavid Chinner 345dbcabad1SDavid Chinner /* 346408fd484SBrian Foster * With per-cpu counters, this becomes an interesting problem. we need 347408fd484SBrian Foster * to work out if we are freeing or allocation blocks first, then we can 348408fd484SBrian Foster * do the modification as necessary. 349dbcabad1SDavid Chinner * 350408fd484SBrian Foster * We do this under the m_sb_lock so that if we are near ENOSPC, we will 351408fd484SBrian Foster * hold out any changes while we work out what to do. This means that 352408fd484SBrian Foster * the amount of free space can change while we do this, so we need to 353408fd484SBrian Foster * retry if we end up trying to reserve more space than is available. 354dbcabad1SDavid Chinner */ 3553685c2a1SEric Sandeen spin_lock(&mp->m_sb_lock); 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds /* 3581da177e4SLinus Torvalds * If our previous reservation was larger than the current value, 359408fd484SBrian Foster * then move any unused blocks back to the free pool. Modify the resblks 360408fd484SBrian Foster * counters directly since we shouldn't have any problems unreserving 361408fd484SBrian Foster * space. 3621da177e4SLinus Torvalds */ 3631da177e4SLinus Torvalds if (mp->m_resblks > request) { 3641da177e4SLinus Torvalds lcounter = mp->m_resblks_avail - request; 3651da177e4SLinus Torvalds if (lcounter > 0) { /* release unused blocks */ 366dbcabad1SDavid Chinner fdblks_delta = lcounter; 3671da177e4SLinus Torvalds mp->m_resblks_avail -= lcounter; 3681da177e4SLinus Torvalds } 3691da177e4SLinus Torvalds mp->m_resblks = request; 370408fd484SBrian Foster if (fdblks_delta) { 371408fd484SBrian Foster spin_unlock(&mp->m_sb_lock); 372408fd484SBrian Foster error = xfs_mod_fdblocks(mp, fdblks_delta, 0); 373408fd484SBrian Foster spin_lock(&mp->m_sb_lock); 374408fd484SBrian Foster } 3754be536deSDavid Chinner 376408fd484SBrian Foster goto out; 377408fd484SBrian Foster } 378408fd484SBrian Foster 379408fd484SBrian Foster /* 380408fd484SBrian Foster * If the request is larger than the current reservation, reserve the 381408fd484SBrian Foster * blocks before we update the reserve counters. Sample m_fdblocks and 382408fd484SBrian Foster * perform a partial reservation if the request exceeds free space. 383408fd484SBrian Foster */ 384408fd484SBrian Foster error = -ENOSPC; 385408fd484SBrian Foster do { 3860d485adaSDave Chinner free = percpu_counter_sum(&mp->m_fdblocks) - 38752548852SDarrick J. Wong mp->m_alloc_set_aside; 388aafe12ceSDarrick J. Wong if (free <= 0) 389408fd484SBrian Foster break; 390dbcabad1SDavid Chinner 3911da177e4SLinus Torvalds delta = request - mp->m_resblks; 3924be536deSDavid Chinner lcounter = free - delta; 393408fd484SBrian Foster if (lcounter < 0) 3941da177e4SLinus Torvalds /* We can't satisfy the request, just get what we can */ 395408fd484SBrian Foster fdblks_delta = free; 396408fd484SBrian Foster else 397408fd484SBrian Foster fdblks_delta = delta; 398408fd484SBrian Foster 399408fd484SBrian Foster /* 400408fd484SBrian Foster * We'll either succeed in getting space from the free block 401408fd484SBrian Foster * count or we'll get an ENOSPC. If we get a ENOSPC, it means 402408fd484SBrian Foster * things changed while we were calculating fdblks_delta and so 403408fd484SBrian Foster * we should try again to see if there is anything left to 404408fd484SBrian Foster * reserve. 405408fd484SBrian Foster * 406408fd484SBrian Foster * Don't set the reserved flag here - we don't want to reserve 407408fd484SBrian Foster * the extra reserve blocks from the reserve..... 408408fd484SBrian Foster */ 409408fd484SBrian Foster spin_unlock(&mp->m_sb_lock); 410408fd484SBrian Foster error = xfs_mod_fdblocks(mp, -fdblks_delta, 0); 411408fd484SBrian Foster spin_lock(&mp->m_sb_lock); 412408fd484SBrian Foster } while (error == -ENOSPC); 413408fd484SBrian Foster 414408fd484SBrian Foster /* 415408fd484SBrian Foster * Update the reserve counters if blocks have been successfully 416408fd484SBrian Foster * allocated. 417408fd484SBrian Foster */ 418408fd484SBrian Foster if (!error && fdblks_delta) { 419408fd484SBrian Foster mp->m_resblks += fdblks_delta; 420408fd484SBrian Foster mp->m_resblks_avail += fdblks_delta; 4211da177e4SLinus Torvalds } 422408fd484SBrian Foster 423dbcabad1SDavid Chinner out: 42484e1e99fSDavid Chinner if (outval) { 4251da177e4SLinus Torvalds outval->resblks = mp->m_resblks; 4261da177e4SLinus Torvalds outval->resblks_avail = mp->m_resblks_avail; 42784e1e99fSDavid Chinner } 428dbcabad1SDavid Chinner 429408fd484SBrian Foster spin_unlock(&mp->m_sb_lock); 430408fd484SBrian Foster return error; 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 4331da177e4SLinus Torvalds int 4341da177e4SLinus Torvalds xfs_fs_goingdown( 4351da177e4SLinus Torvalds xfs_mount_t *mp, 436c8ce540dSDarrick J. Wong uint32_t inflags) 4371da177e4SLinus Torvalds { 4381da177e4SLinus Torvalds switch (inflags) { 4391da177e4SLinus Torvalds case XFS_FSOP_GOING_FLAGS_DEFAULT: { 440b267ce99SChristoph Hellwig struct super_block *sb = freeze_bdev(mp->m_super->s_bdev); 4411da177e4SLinus Torvalds 442f33c6797SChristoph Hellwig if (sb && !IS_ERR(sb)) { 4437d04a335SNathan Scott xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); 4441da177e4SLinus Torvalds thaw_bdev(sb->s_bdev, sb); 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds 4471da177e4SLinus Torvalds break; 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds case XFS_FSOP_GOING_FLAGS_LOGFLUSH: 4507d04a335SNathan Scott xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); 4511da177e4SLinus Torvalds break; 4521da177e4SLinus Torvalds case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH: 4537d04a335SNathan Scott xfs_force_shutdown(mp, 4547d04a335SNathan Scott SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR); 4551da177e4SLinus Torvalds break; 4561da177e4SLinus Torvalds default: 4572451337dSDave Chinner return -EINVAL; 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds return 0; 4611da177e4SLinus Torvalds } 4622af51f3aSDave Chinner 4632af51f3aSDave Chinner /* 4642af51f3aSDave Chinner * Force a shutdown of the filesystem instantly while keeping the filesystem 4652af51f3aSDave Chinner * consistent. We don't do an unmount here; just shutdown the shop, make sure 4662af51f3aSDave Chinner * that absolutely nothing persistent happens to this filesystem after this 4672af51f3aSDave Chinner * point. 4682af51f3aSDave Chinner */ 4692af51f3aSDave Chinner void 4702af51f3aSDave Chinner xfs_do_force_shutdown( 47156668a5cSDave Chinner struct xfs_mount *mp, 4722af51f3aSDave Chinner int flags, 4732af51f3aSDave Chinner char *fname, 4742af51f3aSDave Chinner int lnnum) 4752af51f3aSDave Chinner { 47656668a5cSDave Chinner bool logerror = flags & SHUTDOWN_LOG_IO_ERROR; 4772af51f3aSDave Chinner 4782af51f3aSDave Chinner /* 4792af51f3aSDave Chinner * No need to duplicate efforts. 4802af51f3aSDave Chinner */ 4812af51f3aSDave Chinner if (XFS_FORCED_SHUTDOWN(mp) && !logerror) 4822af51f3aSDave Chinner return; 4832af51f3aSDave Chinner 4842af51f3aSDave Chinner /* 4852af51f3aSDave Chinner * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't 4862af51f3aSDave Chinner * queue up anybody new on the log reservations, and wakes up 4872af51f3aSDave Chinner * everybody who's sleeping on log reservations to tell them 4882af51f3aSDave Chinner * the bad news. 4892af51f3aSDave Chinner */ 4902af51f3aSDave Chinner if (xfs_log_force_umount(mp, logerror)) 4912af51f3aSDave Chinner return; 4922af51f3aSDave Chinner 49356668a5cSDave Chinner if (flags & SHUTDOWN_FORCE_UMOUNT) { 49456668a5cSDave Chinner xfs_alert(mp, 49556668a5cSDave Chinner "User initiated shutdown received. Shutting down filesystem"); 49656668a5cSDave Chinner return; 49756668a5cSDave Chinner } 49856668a5cSDave Chinner 49956668a5cSDave Chinner xfs_notice(mp, 50056668a5cSDave Chinner "%s(0x%x) called from line %d of file %s. Return address = "PTR_FMT, 50156668a5cSDave Chinner __func__, flags, lnnum, fname, __return_address); 50256668a5cSDave Chinner 5032af51f3aSDave Chinner if (flags & SHUTDOWN_CORRUPT_INCORE) { 5042af51f3aSDave Chinner xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT, 5052af51f3aSDave Chinner "Corruption of in-memory data detected. Shutting down filesystem"); 5062af51f3aSDave Chinner if (XFS_ERRLEVEL_HIGH <= xfs_error_level) 5072af51f3aSDave Chinner xfs_stack_trace(); 50856668a5cSDave Chinner } else if (logerror) { 5092af51f3aSDave Chinner xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR, 5102af51f3aSDave Chinner "Log I/O Error Detected. Shutting down filesystem"); 5112af51f3aSDave Chinner } else if (flags & SHUTDOWN_DEVICE_REQ) { 5122af51f3aSDave Chinner xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, 5132af51f3aSDave Chinner "All device paths lost. Shutting down filesystem"); 5142af51f3aSDave Chinner } else if (!(flags & SHUTDOWN_REMOTE_REQ)) { 5152af51f3aSDave Chinner xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, 5162af51f3aSDave Chinner "I/O Error Detected. Shutting down filesystem"); 5172af51f3aSDave Chinner } 51856668a5cSDave Chinner 5192af51f3aSDave Chinner xfs_alert(mp, 52056668a5cSDave Chinner "Please unmount the filesystem and rectify the problem(s)"); 5212af51f3aSDave Chinner } 52284d69619SDarrick J. Wong 52384d69619SDarrick J. Wong /* 52484d69619SDarrick J. Wong * Reserve free space for per-AG metadata. 52584d69619SDarrick J. Wong */ 52684d69619SDarrick J. Wong int 52784d69619SDarrick J. Wong xfs_fs_reserve_ag_blocks( 52884d69619SDarrick J. Wong struct xfs_mount *mp) 52984d69619SDarrick J. Wong { 53084d69619SDarrick J. Wong xfs_agnumber_t agno; 53184d69619SDarrick J. Wong struct xfs_perag *pag; 53284d69619SDarrick J. Wong int error = 0; 53384d69619SDarrick J. Wong int err2; 53484d69619SDarrick J. Wong 53515a268d9SDarrick J. Wong mp->m_finobt_nores = false; 53684d69619SDarrick J. Wong for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { 53784d69619SDarrick J. Wong pag = xfs_perag_get(mp, agno); 538ebcbef3aSDarrick J. Wong err2 = xfs_ag_resv_init(pag, NULL); 53984d69619SDarrick J. Wong xfs_perag_put(pag); 54084d69619SDarrick J. Wong if (err2 && !error) 54184d69619SDarrick J. Wong error = err2; 54284d69619SDarrick J. Wong } 54384d69619SDarrick J. Wong 54484d69619SDarrick J. Wong if (error && error != -ENOSPC) { 54584d69619SDarrick J. Wong xfs_warn(mp, 54684d69619SDarrick J. Wong "Error %d reserving per-AG metadata reserve pool.", error); 54784d69619SDarrick J. Wong xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); 54884d69619SDarrick J. Wong } 54984d69619SDarrick J. Wong 55084d69619SDarrick J. Wong return error; 55184d69619SDarrick J. Wong } 55284d69619SDarrick J. Wong 55384d69619SDarrick J. Wong /* 55484d69619SDarrick J. Wong * Free space reserved for per-AG metadata. 55584d69619SDarrick J. Wong */ 55684d69619SDarrick J. Wong int 55784d69619SDarrick J. Wong xfs_fs_unreserve_ag_blocks( 55884d69619SDarrick J. Wong struct xfs_mount *mp) 55984d69619SDarrick J. Wong { 56084d69619SDarrick J. Wong xfs_agnumber_t agno; 56184d69619SDarrick J. Wong struct xfs_perag *pag; 56284d69619SDarrick J. Wong int error = 0; 56384d69619SDarrick J. Wong int err2; 56484d69619SDarrick J. Wong 56584d69619SDarrick J. Wong for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { 56684d69619SDarrick J. Wong pag = xfs_perag_get(mp, agno); 56784d69619SDarrick J. Wong err2 = xfs_ag_resv_free(pag); 56884d69619SDarrick J. Wong xfs_perag_put(pag); 56984d69619SDarrick J. Wong if (err2 && !error) 57084d69619SDarrick J. Wong error = err2; 57184d69619SDarrick J. Wong } 57284d69619SDarrick J. Wong 57384d69619SDarrick J. Wong if (error) 57484d69619SDarrick J. Wong xfs_warn(mp, 57584d69619SDarrick J. Wong "Error %d freeing per-AG metadata reserve pool.", error); 57684d69619SDarrick J. Wong 57784d69619SDarrick J. Wong return error; 57884d69619SDarrick J. Wong } 579