summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_ag_resv.c
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-01-05 17:45:51 -0800
committerDarrick J. Wong <djwong@kernel.org>2021-03-25 17:08:41 -0700
commit74b914d1ceaaf0fd9c5c492a8ff25b6a671c9bb9 (patch)
treea661f67590185704c2aa741ab7e0ee5fc6437673 /fs/xfs/libxfs/xfs_ag_resv.c
parentd16cdb990ba0515732bc043b7bcbd982ef92d42f (diff)
xfs: add metadata reservations for realtime btreesreserve-rt-metadata-space_2021-03-25
Extend the per-AG metadata block reservation system (which is really just an accounting trick) to support reserving blocks for realtime metadata btrees. This ensures that we will never run out of blocks for the rt rmap or refcount btrees during an operation, similar to what the per-ag reservations do. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs/xfs/libxfs/xfs_ag_resv.c')
-rw-r--r--fs/xfs/libxfs/xfs_ag_resv.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/fs/xfs/libxfs/xfs_ag_resv.c b/fs/xfs/libxfs/xfs_ag_resv.c
index d12feec486fb..c0cc9c823c9e 100644
--- a/fs/xfs/libxfs/xfs_ag_resv.c
+++ b/fs/xfs/libxfs/xfs_ag_resv.c
@@ -21,6 +21,7 @@
#include "xfs_ialloc_btree.h"
#include "xfs_sb.h"
#include "xfs_ag_resv.h"
+#include "xfs_ag.h"
/*
* Per-AG Block Reservations
@@ -75,6 +76,10 @@ xfs_ag_resv_critical(
xfs_extlen_t btree_maxlevels;
switch (type) {
+ case XFS_AG_RESV_RTMETADATA:
+ avail = percpu_counter_sum(&pag->pag_mount->m_fdblocks);
+ orig = pag->pag_mount->m_rtmeta_resv.ar_asked;
+ break;
case XFS_AG_RESV_METADATA:
avail = pag->pagf_freeblks - pag->pag_rmapbt_resv.ar_reserved;
orig = pag->pag_meta_resv.ar_asked;
@@ -111,6 +116,7 @@ xfs_ag_resv_needed(
len = pag->pag_meta_resv.ar_reserved + pag->pag_rmapbt_resv.ar_reserved;
switch (type) {
+ case XFS_AG_RESV_RTMETADATA:
case XFS_AG_RESV_METADATA:
case XFS_AG_RESV_RMAPBT:
len -= xfs_perag_resv(pag, type)->ar_reserved;
@@ -177,6 +183,82 @@ xfs_ag_resv_free(
return error;
}
+/* Clean out a rt reservation */
+int
+xfs_rt_resv_free(
+ struct xfs_mount *mp)
+{
+ int error;
+
+ trace_xfs_rt_resv_free(mp, 0);
+
+ error = xfs_mod_fdblocks(mp, mp->m_rtmeta_resv.ar_reserved, true);
+ if (error)
+ return error;
+
+ mp->m_rtmeta_resv.ar_reserved = 0;
+ mp->m_rtmeta_resv.ar_asked = 0;
+ mp->m_rtmeta_resv.ar_orig_reserved = 0;
+ return 0;
+}
+
+static int
+__xfs_rt_resv_init(
+ struct xfs_mount *mp,
+ xfs_filblks_t ask,
+ xfs_filblks_t used)
+{
+ xfs_filblks_t hidden_space;
+ int error;
+
+ /*
+ * Space taken by all other metadata btrees are accounted on-disk as
+ * used space. We therefore only hide the space that is reserved but
+ * not used by the trees.
+ */
+ if (used > ask)
+ ask = used;
+ hidden_space = ask - used;
+
+ error = xfs_mod_fdblocks(mp, -(int64_t)hidden_space, true);
+ if (error) {
+ trace_xfs_ag_resv_init_error(mp, NULLAGNUMBER, error,
+ _RET_IP_);
+ xfs_warn(mp,
+"Space reservation for rt metadata failed. Filesystem may run out of space.");
+ return error;
+ }
+
+ mp->m_rtmeta_resv.ar_asked = ask;
+ mp->m_rtmeta_resv.ar_orig_reserved = hidden_space;
+ mp->m_rtmeta_resv.ar_reserved = ask - used;
+
+ trace_xfs_rt_resv_init(mp, ask);
+ return 0;
+}
+
+/* Create a rt metadata block reservation. */
+int
+xfs_rt_resv_init(
+ struct xfs_mount *mp,
+ struct xfs_trans *tp)
+{
+ xfs_filblks_t ask;
+ xfs_filblks_t used;
+ int error;
+
+ /* Create the rt metadata reservation. */
+ if (mp->m_rtmeta_resv.ar_asked == 0) {
+ ask = used = 0;
+
+ error = __xfs_rt_resv_init(mp, ask, used);
+ if (error)
+ return error;
+ }
+
+ return 0;
+}
+
static int
__xfs_ag_resv_init(
struct xfs_perag *pag,
@@ -202,6 +284,7 @@ __xfs_ag_resv_init(
*/
hidden_space = ask;
break;
+ case XFS_AG_RESV_RTMETADATA:
case XFS_AG_RESV_METADATA:
/*
* Space taken by all other metadata btrees are accounted
@@ -335,6 +418,7 @@ xfs_ag_resv_alloc_extent(
switch (type) {
case XFS_AG_RESV_AGFL:
return;
+ case XFS_AG_RESV_RTMETADATA:
case XFS_AG_RESV_METADATA:
case XFS_AG_RESV_RMAPBT:
resv = xfs_perag_resv(pag, type);
@@ -377,6 +461,7 @@ xfs_ag_resv_free_extent(
switch (type) {
case XFS_AG_RESV_AGFL:
return;
+ case XFS_AG_RESV_RTMETADATA:
case XFS_AG_RESV_METADATA:
case XFS_AG_RESV_RMAPBT:
resv = xfs_perag_resv(pag, type);