summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_ag_resv.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/libxfs/xfs_ag_resv.c')
-rw-r--r--fs/xfs/libxfs/xfs_ag_resv.c26
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);
}