diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_ag_resv.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_ag_resv.c | 26 |
1 files changed, 23 insertions, 3 deletions
diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c index d51b62494c2f..9c7561aceb95 100644 --- a/fs/xfs/libxfs/xfs_ag_resv.c +++ b/fs/xfs/libxfs/xfs_ag_resv.c @@ -74,6 +74,13 @@ xfs_ag_resv_critical( xfs_extlen_t orig; xfs_extlen_t btree_maxlevels; + /* + * Pretend we're critically low on reservations in this AG to scare + * everyone else away. + */ + if (pag->pagf_noalloc) + return true; + switch (type) { case XFS_AG_RESV_METADATA: avail = pag->pagf_freeblks - pag->pag_rmapbt_resv.ar_reserved; @@ -116,7 +123,12 @@ xfs_ag_resv_needed( break; case XFS_AG_RESV_IMETA: case XFS_AG_RESV_NONE: - /* empty */ + /* + * In noalloc mode, we pretend that all the free blocks in this + * AG have been allocated. Make this AG look full. + */ + if (pag->pagf_noalloc) + len += xfs_ag_fdblocks(pag); break; default: ASSERT(0); @@ -345,6 +357,8 @@ xfs_ag_resv_alloc_extent( xfs_extlen_t len; uint field; + ASSERT(type != XFS_AG_RESV_NONE || !pag->pagf_noalloc); + trace_xfs_ag_resv_alloc_extent(pag, type, args->len); switch (type) { @@ -402,7 +416,13 @@ xfs_ag_resv_free_extent( ASSERT(0); fallthrough; case XFS_AG_RESV_NONE: - xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (int64_t)len); + /* + * If the AG is in noalloc mode, we don't give back to fdblocks + * until we lift noalloc mode. + */ + if (!pag->pagf_noalloc) + xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, + (int64_t)len); fallthrough; case XFS_AG_RESV_IGNORE: return; @@ -415,6 +435,6 @@ xfs_ag_resv_free_extent( /* Freeing into the reserved pool only requires on-disk update... */ xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, len); /* ...but freeing beyond that requires in-core and on-disk update. */ - if (len > leftover) + if (len > leftover && !pag->pagf_noalloc) xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, len - leftover); } |