10b61f8a4SDave Chinner // SPDX-License-Identifier: GPL-2.0+ 23fd129b6SDarrick J. Wong /* 33fd129b6SDarrick J. Wong * Copyright (C) 2016 Oracle. All Rights Reserved. 43fd129b6SDarrick J. Wong * Author: Darrick J. Wong <darrick.wong@oracle.com> 53fd129b6SDarrick J. Wong */ 63fd129b6SDarrick J. Wong #include "xfs.h" 73fd129b6SDarrick J. Wong #include "xfs_fs.h" 83fd129b6SDarrick J. Wong #include "xfs_shared.h" 93fd129b6SDarrick J. Wong #include "xfs_format.h" 103fd129b6SDarrick J. Wong #include "xfs_log_format.h" 113fd129b6SDarrick J. Wong #include "xfs_trans_resv.h" 123fd129b6SDarrick J. Wong #include "xfs_mount.h" 133fd129b6SDarrick J. Wong #include "xfs_alloc.h" 14e9e899a2SDarrick J. Wong #include "xfs_errortag.h" 153fd129b6SDarrick J. Wong #include "xfs_error.h" 163fd129b6SDarrick J. Wong #include "xfs_trace.h" 173fd129b6SDarrick J. Wong #include "xfs_trans.h" 183fd129b6SDarrick J. Wong #include "xfs_rmap_btree.h" 193fd129b6SDarrick J. Wong #include "xfs_btree.h" 2084d69619SDarrick J. Wong #include "xfs_refcount_btree.h" 2176d771b4SChristoph Hellwig #include "xfs_ialloc_btree.h" 229bbafc71SDave Chinner #include "xfs_ag.h" 235f213ddbSDarrick J. Wong #include "xfs_ag_resv.h" 243fd129b6SDarrick J. Wong 253fd129b6SDarrick J. Wong /* 263fd129b6SDarrick J. Wong * Per-AG Block Reservations 273fd129b6SDarrick J. Wong * 283fd129b6SDarrick J. Wong * For some kinds of allocation group metadata structures, it is advantageous 293fd129b6SDarrick J. Wong * to reserve a small number of blocks in each AG so that future expansions of 303fd129b6SDarrick J. Wong * that data structure do not encounter ENOSPC because errors during a btree 313fd129b6SDarrick J. Wong * split cause the filesystem to go offline. 323fd129b6SDarrick J. Wong * 333fd129b6SDarrick J. Wong * Prior to the introduction of reflink, this wasn't an issue because the free 343fd129b6SDarrick J. Wong * space btrees maintain a reserve of space (the AGFL) to handle any expansion 353fd129b6SDarrick J. Wong * that may be necessary; and allocations of other metadata (inodes, BMBT, 363fd129b6SDarrick J. Wong * dir/attr) aren't restricted to a single AG. However, with reflink it is 373fd129b6SDarrick J. Wong * possible to allocate all the space in an AG, have subsequent reflink/CoW 383fd129b6SDarrick J. Wong * activity expand the refcount btree, and discover that there's no space left 393fd129b6SDarrick J. Wong * to handle that expansion. Since we can calculate the maximum size of the 403fd129b6SDarrick J. Wong * refcount btree, we can reserve space for it and avoid ENOSPC. 413fd129b6SDarrick J. Wong * 423fd129b6SDarrick J. Wong * Handling per-AG reservations consists of three changes to the allocator's 433fd129b6SDarrick J. Wong * behavior: First, because these reservations are always needed, we decrease 443fd129b6SDarrick J. Wong * the ag_max_usable counter to reflect the size of the AG after the reserved 453fd129b6SDarrick J. Wong * blocks are taken. Second, the reservations must be reflected in the 463fd129b6SDarrick J. Wong * fdblocks count to maintain proper accounting. Third, each AG must maintain 473fd129b6SDarrick J. Wong * its own reserved block counter so that we can calculate the amount of space 483fd129b6SDarrick J. Wong * that must remain free to maintain the reservations. Fourth, the "remaining 493fd129b6SDarrick J. Wong * reserved blocks" count must be used when calculating the length of the 503fd129b6SDarrick J. Wong * longest free extent in an AG and to clamp maxlen in the per-AG allocation 513fd129b6SDarrick J. Wong * functions. In other words, we maintain a virtual allocation via in-core 523fd129b6SDarrick J. Wong * accounting tricks so that we don't have to clean up after a crash. :) 533fd129b6SDarrick J. Wong * 543fd129b6SDarrick J. Wong * Reserved blocks can be managed by passing one of the enum xfs_ag_resv_type 553fd129b6SDarrick J. Wong * values via struct xfs_alloc_arg or directly to the xfs_free_extent 563fd129b6SDarrick J. Wong * function. It might seem a little funny to maintain a reservoir of blocks 573fd129b6SDarrick J. Wong * to feed another reservoir, but the AGFL only holds enough blocks to get 583fd129b6SDarrick J. Wong * through the next transaction. The per-AG reservation is to ensure (we 593fd129b6SDarrick J. Wong * hope) that each AG never runs out of blocks. Each data structure wanting 603fd129b6SDarrick J. Wong * to use the reservation system should update ask/used in xfs_ag_resv_init. 613fd129b6SDarrick J. Wong */ 623fd129b6SDarrick J. Wong 633fd129b6SDarrick J. Wong /* 643fd129b6SDarrick J. Wong * Are we critically low on blocks? For now we'll define that as the number 653fd129b6SDarrick J. Wong * of blocks we can get our hands on being less than 10% of what we reserved 663fd129b6SDarrick J. Wong * or less than some arbitrary number (maximum btree height). 673fd129b6SDarrick J. Wong */ 683fd129b6SDarrick J. Wong bool 693fd129b6SDarrick J. Wong xfs_ag_resv_critical( 703fd129b6SDarrick J. Wong struct xfs_perag *pag, 713fd129b6SDarrick J. Wong enum xfs_ag_resv_type type) 723fd129b6SDarrick J. Wong { 733fd129b6SDarrick J. Wong xfs_extlen_t avail; 743fd129b6SDarrick J. Wong xfs_extlen_t orig; 753fd129b6SDarrick J. Wong 763fd129b6SDarrick J. Wong switch (type) { 773fd129b6SDarrick J. Wong case XFS_AG_RESV_METADATA: 7821592863SBrian Foster avail = pag->pagf_freeblks - pag->pag_rmapbt_resv.ar_reserved; 793fd129b6SDarrick J. Wong orig = pag->pag_meta_resv.ar_asked; 803fd129b6SDarrick J. Wong break; 8121592863SBrian Foster case XFS_AG_RESV_RMAPBT: 823fd129b6SDarrick J. Wong avail = pag->pagf_freeblks + pag->pagf_flcount - 833fd129b6SDarrick J. Wong pag->pag_meta_resv.ar_reserved; 8421592863SBrian Foster orig = pag->pag_rmapbt_resv.ar_asked; 853fd129b6SDarrick J. Wong break; 863fd129b6SDarrick J. Wong default: 873fd129b6SDarrick J. Wong ASSERT(0); 883fd129b6SDarrick J. Wong return false; 893fd129b6SDarrick J. Wong } 903fd129b6SDarrick J. Wong 913fd129b6SDarrick J. Wong trace_xfs_ag_resv_critical(pag, type, avail); 923fd129b6SDarrick J. Wong 933fd129b6SDarrick J. Wong /* Critically low if less than 10% or max btree height remains. */ 94a35eb415SDarrick J. Wong return XFS_TEST_ERROR(avail < orig / 10 || avail < XFS_BTREE_MAXLEVELS, 959e24cfd0SDarrick J. Wong pag->pag_mount, XFS_ERRTAG_AG_RESV_CRITICAL); 963fd129b6SDarrick J. Wong } 973fd129b6SDarrick J. Wong 983fd129b6SDarrick J. Wong /* 993fd129b6SDarrick J. Wong * How many blocks are reserved but not used, and therefore must not be 1003fd129b6SDarrick J. Wong * allocated away? 1013fd129b6SDarrick J. Wong */ 1023fd129b6SDarrick J. Wong xfs_extlen_t 1033fd129b6SDarrick J. Wong xfs_ag_resv_needed( 1043fd129b6SDarrick J. Wong struct xfs_perag *pag, 1053fd129b6SDarrick J. Wong enum xfs_ag_resv_type type) 1063fd129b6SDarrick J. Wong { 1073fd129b6SDarrick J. Wong xfs_extlen_t len; 1083fd129b6SDarrick J. Wong 10921592863SBrian Foster len = pag->pag_meta_resv.ar_reserved + pag->pag_rmapbt_resv.ar_reserved; 1103fd129b6SDarrick J. Wong switch (type) { 1113fd129b6SDarrick J. Wong case XFS_AG_RESV_METADATA: 11221592863SBrian Foster case XFS_AG_RESV_RMAPBT: 1133fd129b6SDarrick J. Wong len -= xfs_perag_resv(pag, type)->ar_reserved; 1143fd129b6SDarrick J. Wong break; 1153fd129b6SDarrick J. Wong case XFS_AG_RESV_NONE: 1163fd129b6SDarrick J. Wong /* empty */ 1173fd129b6SDarrick J. Wong break; 1183fd129b6SDarrick J. Wong default: 1193fd129b6SDarrick J. Wong ASSERT(0); 1203fd129b6SDarrick J. Wong } 1213fd129b6SDarrick J. Wong 1223fd129b6SDarrick J. Wong trace_xfs_ag_resv_needed(pag, type, len); 1233fd129b6SDarrick J. Wong 1243fd129b6SDarrick J. Wong return len; 1253fd129b6SDarrick J. Wong } 1263fd129b6SDarrick J. Wong 1273fd129b6SDarrick J. Wong /* Clean out a reservation */ 1283fd129b6SDarrick J. Wong static int 1293fd129b6SDarrick J. Wong __xfs_ag_resv_free( 1303fd129b6SDarrick J. Wong struct xfs_perag *pag, 1313fd129b6SDarrick J. Wong enum xfs_ag_resv_type type) 1323fd129b6SDarrick J. Wong { 1333fd129b6SDarrick J. Wong struct xfs_ag_resv *resv; 1343fd129b6SDarrick J. Wong xfs_extlen_t oldresv; 1353fd129b6SDarrick J. Wong int error; 1363fd129b6SDarrick J. Wong 1373fd129b6SDarrick J. Wong trace_xfs_ag_resv_free(pag, type, 0); 1383fd129b6SDarrick J. Wong 1393fd129b6SDarrick J. Wong resv = xfs_perag_resv(pag, type); 1409789dd9eSDarrick J. Wong if (pag->pag_agno == 0) 1413fd129b6SDarrick J. Wong pag->pag_mount->m_ag_max_usable += resv->ar_asked; 1423fd129b6SDarrick J. Wong /* 14321592863SBrian Foster * RMAPBT blocks come from the AGFL and AGFL blocks are always 14421592863SBrian Foster * considered "free", so whatever was reserved at mount time must be 14521592863SBrian Foster * given back at umount. 1463fd129b6SDarrick J. Wong */ 14721592863SBrian Foster if (type == XFS_AG_RESV_RMAPBT) 1483fd129b6SDarrick J. Wong oldresv = resv->ar_orig_reserved; 1493fd129b6SDarrick J. Wong else 1503fd129b6SDarrick J. Wong oldresv = resv->ar_reserved; 1513fd129b6SDarrick J. Wong error = xfs_mod_fdblocks(pag->pag_mount, oldresv, true); 1523fd129b6SDarrick J. Wong resv->ar_reserved = 0; 1533fd129b6SDarrick J. Wong resv->ar_asked = 0; 154d8cb5e42SDarrick J. Wong resv->ar_orig_reserved = 0; 1553fd129b6SDarrick J. Wong 1563fd129b6SDarrick J. Wong if (error) 1573fd129b6SDarrick J. Wong trace_xfs_ag_resv_free_error(pag->pag_mount, pag->pag_agno, 1583fd129b6SDarrick J. Wong error, _RET_IP_); 1593fd129b6SDarrick J. Wong return error; 1603fd129b6SDarrick J. Wong } 1613fd129b6SDarrick J. Wong 1623fd129b6SDarrick J. Wong /* Free a per-AG reservation. */ 1633fd129b6SDarrick J. Wong int 1643fd129b6SDarrick J. Wong xfs_ag_resv_free( 1653fd129b6SDarrick J. Wong struct xfs_perag *pag) 1663fd129b6SDarrick J. Wong { 1673fd129b6SDarrick J. Wong int error; 1683fd129b6SDarrick J. Wong int err2; 1693fd129b6SDarrick J. Wong 17021592863SBrian Foster error = __xfs_ag_resv_free(pag, XFS_AG_RESV_RMAPBT); 1713fd129b6SDarrick J. Wong err2 = __xfs_ag_resv_free(pag, XFS_AG_RESV_METADATA); 1723fd129b6SDarrick J. Wong if (err2 && !error) 1733fd129b6SDarrick J. Wong error = err2; 1743fd129b6SDarrick J. Wong return error; 1753fd129b6SDarrick J. Wong } 1763fd129b6SDarrick J. Wong 1773fd129b6SDarrick J. Wong static int 1783fd129b6SDarrick J. Wong __xfs_ag_resv_init( 1793fd129b6SDarrick J. Wong struct xfs_perag *pag, 1803fd129b6SDarrick J. Wong enum xfs_ag_resv_type type, 1813fd129b6SDarrick J. Wong xfs_extlen_t ask, 1823fd129b6SDarrick J. Wong xfs_extlen_t used) 1833fd129b6SDarrick J. Wong { 1843fd129b6SDarrick J. Wong struct xfs_mount *mp = pag->pag_mount; 1853fd129b6SDarrick J. Wong struct xfs_ag_resv *resv; 1863fd129b6SDarrick J. Wong int error; 187d8cb5e42SDarrick J. Wong xfs_extlen_t hidden_space; 1883fd129b6SDarrick J. Wong 1893fd129b6SDarrick J. Wong if (used > ask) 1903fd129b6SDarrick J. Wong ask = used; 1913fd129b6SDarrick J. Wong 192d8cb5e42SDarrick J. Wong switch (type) { 193d8cb5e42SDarrick J. Wong case XFS_AG_RESV_RMAPBT: 194d8cb5e42SDarrick J. Wong /* 195d8cb5e42SDarrick J. Wong * Space taken by the rmapbt is not subtracted from fdblocks 196d8cb5e42SDarrick J. Wong * because the rmapbt lives in the free space. Here we must 197d8cb5e42SDarrick J. Wong * subtract the entire reservation from fdblocks so that we 198d8cb5e42SDarrick J. Wong * always have blocks available for rmapbt expansion. 199d8cb5e42SDarrick J. Wong */ 200d8cb5e42SDarrick J. Wong hidden_space = ask; 201d8cb5e42SDarrick J. Wong break; 202d8cb5e42SDarrick J. Wong case XFS_AG_RESV_METADATA: 203d8cb5e42SDarrick J. Wong /* 204d8cb5e42SDarrick J. Wong * Space taken by all other metadata btrees are accounted 205d8cb5e42SDarrick J. Wong * on-disk as used space. We therefore only hide the space 206d8cb5e42SDarrick J. Wong * that is reserved but not used by the trees. 207d8cb5e42SDarrick J. Wong */ 208d8cb5e42SDarrick J. Wong hidden_space = ask - used; 209d8cb5e42SDarrick J. Wong break; 210d8cb5e42SDarrick J. Wong default: 211d8cb5e42SDarrick J. Wong ASSERT(0); 212d8cb5e42SDarrick J. Wong return -EINVAL; 213d8cb5e42SDarrick J. Wong } 2142b92faedSGao Xiang 2152b92faedSGao Xiang if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_AG_RESV_FAIL)) 2162b92faedSGao Xiang error = -ENOSPC; 2172b92faedSGao Xiang else 218d8cb5e42SDarrick J. Wong error = xfs_mod_fdblocks(mp, -(int64_t)hidden_space, true); 2194dfa2b84SChristoph Hellwig if (error) { 2203fd129b6SDarrick J. Wong trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno, 2213fd129b6SDarrick J. Wong error, _RET_IP_); 22276d771b4SChristoph Hellwig xfs_warn(mp, 22376d771b4SChristoph Hellwig "Per-AG reservation for AG %u failed. Filesystem may run out of space.", 22476d771b4SChristoph Hellwig pag->pag_agno); 2253fd129b6SDarrick J. Wong return error; 2263fd129b6SDarrick J. Wong } 2273fd129b6SDarrick J. Wong 2289789dd9eSDarrick J. Wong /* 2299789dd9eSDarrick J. Wong * Reduce the maximum per-AG allocation length by however much we're 2309789dd9eSDarrick J. Wong * trying to reserve for an AG. Since this is a filesystem-wide 2319789dd9eSDarrick J. Wong * counter, we only make the adjustment for AG 0. This assumes that 2329789dd9eSDarrick J. Wong * there aren't any AGs hungrier for per-AG reservation than AG 0. 2339789dd9eSDarrick J. Wong */ 2349789dd9eSDarrick J. Wong if (pag->pag_agno == 0) 2354dfa2b84SChristoph Hellwig mp->m_ag_max_usable -= ask; 2364dfa2b84SChristoph Hellwig 2374dfa2b84SChristoph Hellwig resv = xfs_perag_resv(pag, type); 2384dfa2b84SChristoph Hellwig resv->ar_asked = ask; 239d8cb5e42SDarrick J. Wong resv->ar_orig_reserved = hidden_space; 240d8cb5e42SDarrick J. Wong resv->ar_reserved = ask - used; 2414dfa2b84SChristoph Hellwig 2424dfa2b84SChristoph Hellwig trace_xfs_ag_resv_init(pag, type, ask); 2434dfa2b84SChristoph Hellwig return 0; 2444dfa2b84SChristoph Hellwig } 2454dfa2b84SChristoph Hellwig 2463fd129b6SDarrick J. Wong /* Create a per-AG block reservation. */ 2473fd129b6SDarrick J. Wong int 2483fd129b6SDarrick J. Wong xfs_ag_resv_init( 249ebcbef3aSDarrick J. Wong struct xfs_perag *pag, 250ebcbef3aSDarrick J. Wong struct xfs_trans *tp) 2513fd129b6SDarrick J. Wong { 25276d771b4SChristoph Hellwig struct xfs_mount *mp = pag->pag_mount; 2533fd129b6SDarrick J. Wong xfs_extlen_t ask; 2543fd129b6SDarrick J. Wong xfs_extlen_t used; 2552675ad38SBrian Foster int error = 0, error2; 2562675ad38SBrian Foster bool has_resv = false; 2573fd129b6SDarrick J. Wong 2583fd129b6SDarrick J. Wong /* Create the metadata reservation. */ 2593fd129b6SDarrick J. Wong if (pag->pag_meta_resv.ar_asked == 0) { 2603fd129b6SDarrick J. Wong ask = used = 0; 2613fd129b6SDarrick J. Wong 262*30933120SDave Chinner error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask, &used); 26376d771b4SChristoph Hellwig if (error) 26476d771b4SChristoph Hellwig goto out; 26576d771b4SChristoph Hellwig 266*30933120SDave Chinner error = xfs_finobt_calc_reserves(mp, tp, pag, &ask, &used); 26776d771b4SChristoph Hellwig if (error) 26876d771b4SChristoph Hellwig goto out; 26976d771b4SChristoph Hellwig 27076d771b4SChristoph Hellwig error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA, 27176d771b4SChristoph Hellwig ask, used); 27276d771b4SChristoph Hellwig if (error) { 27376d771b4SChristoph Hellwig /* 27476d771b4SChristoph Hellwig * Because we didn't have per-AG reservations when the 27576d771b4SChristoph Hellwig * finobt feature was added we might not be able to 27676d771b4SChristoph Hellwig * reserve all needed blocks. Warn and fall back to the 27776d771b4SChristoph Hellwig * old and potentially buggy code in that case, but 27876d771b4SChristoph Hellwig * ensure we do have the reservation for the refcountbt. 27976d771b4SChristoph Hellwig */ 28076d771b4SChristoph Hellwig ask = used = 0; 28176d771b4SChristoph Hellwig 282e1f6ca11SDarrick J. Wong mp->m_finobt_nores = true; 28376d771b4SChristoph Hellwig 284*30933120SDave Chinner error = xfs_refcountbt_calc_reserves(mp, tp, pag, &ask, 28576d771b4SChristoph Hellwig &used); 28684d69619SDarrick J. Wong if (error) 28784d69619SDarrick J. Wong goto out; 28884d69619SDarrick J. Wong 2893fd129b6SDarrick J. Wong error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA, 2903fd129b6SDarrick J. Wong ask, used); 2913fd129b6SDarrick J. Wong if (error) 2923fd129b6SDarrick J. Wong goto out; 2933fd129b6SDarrick J. Wong } 2942675ad38SBrian Foster if (ask) 2952675ad38SBrian Foster has_resv = true; 29676d771b4SChristoph Hellwig } 2973fd129b6SDarrick J. Wong 29821592863SBrian Foster /* Create the RMAPBT metadata reservation */ 29921592863SBrian Foster if (pag->pag_rmapbt_resv.ar_asked == 0) { 3003fd129b6SDarrick J. Wong ask = used = 0; 3013fd129b6SDarrick J. Wong 302*30933120SDave Chinner error = xfs_rmapbt_calc_reserves(mp, tp, pag, &ask, &used); 30384d69619SDarrick J. Wong if (error) 30484d69619SDarrick J. Wong goto out; 30584d69619SDarrick J. Wong 30621592863SBrian Foster error = __xfs_ag_resv_init(pag, XFS_AG_RESV_RMAPBT, ask, used); 3073fd129b6SDarrick J. Wong if (error) 3083fd129b6SDarrick J. Wong goto out; 3092675ad38SBrian Foster if (ask) 3102675ad38SBrian Foster has_resv = true; 3113fd129b6SDarrick J. Wong } 3123fd129b6SDarrick J. Wong 3132675ad38SBrian Foster out: 3142675ad38SBrian Foster /* 3152675ad38SBrian Foster * Initialize the pagf if we have at least one active reservation on the 3162675ad38SBrian Foster * AG. This may have occurred already via reservation calculation, but 3172675ad38SBrian Foster * fall back to an explicit init to ensure the in-core allocbt usage 3182675ad38SBrian Foster * counters are initialized as soon as possible. This is important 3192675ad38SBrian Foster * because filesystems with large perag reservations are susceptible to 3202675ad38SBrian Foster * free space reservation problems that the allocbt counter is used to 3212675ad38SBrian Foster * address. 3222675ad38SBrian Foster */ 3232675ad38SBrian Foster if (has_resv) { 3242675ad38SBrian Foster error2 = xfs_alloc_pagf_init(mp, tp, pag->pag_agno, 0); 3252675ad38SBrian Foster if (error2) 3262675ad38SBrian Foster return error2; 32720e73b00SDarrick J. Wong ASSERT(xfs_perag_resv(pag, XFS_AG_RESV_METADATA)->ar_reserved + 32821592863SBrian Foster xfs_perag_resv(pag, XFS_AG_RESV_RMAPBT)->ar_reserved <= 32920e73b00SDarrick J. Wong pag->pagf_freeblks + pag->pagf_flcount); 3302675ad38SBrian Foster } 3313fd129b6SDarrick J. Wong return error; 3323fd129b6SDarrick J. Wong } 3333fd129b6SDarrick J. Wong 3343fd129b6SDarrick J. Wong /* Allocate a block from the reservation. */ 3353fd129b6SDarrick J. Wong void 3363fd129b6SDarrick J. Wong xfs_ag_resv_alloc_extent( 3373fd129b6SDarrick J. Wong struct xfs_perag *pag, 3383fd129b6SDarrick J. Wong enum xfs_ag_resv_type type, 3393fd129b6SDarrick J. Wong struct xfs_alloc_arg *args) 3403fd129b6SDarrick J. Wong { 3413fd129b6SDarrick J. Wong struct xfs_ag_resv *resv; 3423fd129b6SDarrick J. Wong xfs_extlen_t len; 3433fd129b6SDarrick J. Wong uint field; 3443fd129b6SDarrick J. Wong 3453fd129b6SDarrick J. Wong trace_xfs_ag_resv_alloc_extent(pag, type, args->len); 3463fd129b6SDarrick J. Wong 3473fd129b6SDarrick J. Wong switch (type) { 3480ab32086SBrian Foster case XFS_AG_RESV_AGFL: 3490ab32086SBrian Foster return; 3503fd129b6SDarrick J. Wong case XFS_AG_RESV_METADATA: 35121592863SBrian Foster case XFS_AG_RESV_RMAPBT: 3523fd129b6SDarrick J. Wong resv = xfs_perag_resv(pag, type); 3533fd129b6SDarrick J. Wong break; 3543fd129b6SDarrick J. Wong default: 3553fd129b6SDarrick J. Wong ASSERT(0); 3563fd129b6SDarrick J. Wong /* fall through */ 3573fd129b6SDarrick J. Wong case XFS_AG_RESV_NONE: 3583fd129b6SDarrick J. Wong field = args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS : 3593fd129b6SDarrick J. Wong XFS_TRANS_SB_FDBLOCKS; 3603fd129b6SDarrick J. Wong xfs_trans_mod_sb(args->tp, field, -(int64_t)args->len); 3613fd129b6SDarrick J. Wong return; 3623fd129b6SDarrick J. Wong } 3633fd129b6SDarrick J. Wong 3643fd129b6SDarrick J. Wong len = min_t(xfs_extlen_t, args->len, resv->ar_reserved); 3653fd129b6SDarrick J. Wong resv->ar_reserved -= len; 36621592863SBrian Foster if (type == XFS_AG_RESV_RMAPBT) 3673fd129b6SDarrick J. Wong return; 3683fd129b6SDarrick J. Wong /* Allocations of reserved blocks only need on-disk sb updates... */ 3693fd129b6SDarrick J. Wong xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_RES_FDBLOCKS, -(int64_t)len); 3703fd129b6SDarrick J. Wong /* ...but non-reserved blocks need in-core and on-disk updates. */ 3713fd129b6SDarrick J. Wong if (args->len > len) 3723fd129b6SDarrick J. Wong xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_FDBLOCKS, 3733fd129b6SDarrick J. Wong -((int64_t)args->len - len)); 3743fd129b6SDarrick J. Wong } 3753fd129b6SDarrick J. Wong 3763fd129b6SDarrick J. Wong /* Free a block to the reservation. */ 3773fd129b6SDarrick J. Wong void 3783fd129b6SDarrick J. Wong xfs_ag_resv_free_extent( 3793fd129b6SDarrick J. Wong struct xfs_perag *pag, 3803fd129b6SDarrick J. Wong enum xfs_ag_resv_type type, 3813fd129b6SDarrick J. Wong struct xfs_trans *tp, 3823fd129b6SDarrick J. Wong xfs_extlen_t len) 3833fd129b6SDarrick J. Wong { 3843fd129b6SDarrick J. Wong xfs_extlen_t leftover; 3853fd129b6SDarrick J. Wong struct xfs_ag_resv *resv; 3863fd129b6SDarrick J. Wong 3873fd129b6SDarrick J. Wong trace_xfs_ag_resv_free_extent(pag, type, len); 3883fd129b6SDarrick J. Wong 3893fd129b6SDarrick J. Wong switch (type) { 3900ab32086SBrian Foster case XFS_AG_RESV_AGFL: 3910ab32086SBrian Foster return; 3923fd129b6SDarrick J. Wong case XFS_AG_RESV_METADATA: 39321592863SBrian Foster case XFS_AG_RESV_RMAPBT: 3943fd129b6SDarrick J. Wong resv = xfs_perag_resv(pag, type); 3953fd129b6SDarrick J. Wong break; 3963fd129b6SDarrick J. Wong default: 3973fd129b6SDarrick J. Wong ASSERT(0); 3983fd129b6SDarrick J. Wong /* fall through */ 3993fd129b6SDarrick J. Wong case XFS_AG_RESV_NONE: 4003fd129b6SDarrick J. Wong xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (int64_t)len); 4013fd129b6SDarrick J. Wong return; 4023fd129b6SDarrick J. Wong } 4033fd129b6SDarrick J. Wong 4043fd129b6SDarrick J. Wong leftover = min_t(xfs_extlen_t, len, resv->ar_asked - resv->ar_reserved); 4053fd129b6SDarrick J. Wong resv->ar_reserved += leftover; 40621592863SBrian Foster if (type == XFS_AG_RESV_RMAPBT) 4073fd129b6SDarrick J. Wong return; 4083fd129b6SDarrick J. Wong /* Freeing into the reserved pool only requires on-disk update... */ 4093fd129b6SDarrick J. Wong xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, len); 4103fd129b6SDarrick J. Wong /* ...but freeing beyond that requires in-core and on-disk update. */ 4113fd129b6SDarrick J. Wong if (len > leftover) 4123fd129b6SDarrick J. Wong xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, len - leftover); 4133fd129b6SDarrick J. Wong } 414