[PATCH 24/27] xfs_repair: reserve per-AG space while rebuilding rt metadata

Darrick J. Wong
2025-02-06T22:55:59Z

Realtime metadata btrees can consume quite a bit of space on a full
filesystem. Since the metadata are just regular files, we need to
make the per-AG reservations to avoid overfilling any of the AGs while
rebuilding metadata. This avoids the situation where a filesystem comes
straight from repair and immediately trips over not having enough space
in an AG.

Signed-off-by: "Darrick J. Wong" <djwong@kernel.org>
---
include/libxfs.h | 1 +
repair/phase6.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 46 insertions(+)

diff --git a/include/libxfs.h b/include/libxfs.h
index 79f8e1ff03d3f5..82b34b9d81c3a7 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -101,6 +101,7 @@ struct iomap;
#include "xfs_rtgroup.h"
#include "xfs_rtbitmap.h"
#include "xfs_rtrmap_btree.h"
+#include "xfs_ag_resv.h"

#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
diff --git a/repair/phase6.c b/repair/phase6.c
index 2ddfd0526767e0..30ea19fda9fd87 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -3540,10 +3540,41 @@ reset_quota_metadir_inodes(
libxfs_irele(dp);
}

+static int
+reserve_ag_blocks(
+ struct xfs_mount *mp)
+{
+ struct xfs_perag *pag = NULL;
+ int error = 0;
+ int err2;
+
+ mp->m_finobt_nores = false;
+
+ while ((pag = xfs_perag_next(mp, pag))) {
+ err2 = -libxfs_ag_resv_init(pag, NULL);
+ if (err2 && !error)
+ error = err2;
+ }
+
+ return error;
+}
+
+static void
+unreserve_ag_blocks(
+ struct xfs_mount *mp)
+{
+ struct xfs_perag *pag = NULL;
+
+ while ((pag = xfs_perag_next(mp, pag)))
+ libxfs_ag_resv_free(pag);
+}
+
void
phase6(xfs_mount_t *mp)
{
ino_tree_node_t *irec;
+ bool reserve_perag;
+ int error;
int i;

parent_ptr_init(mp);
@@ -3588,6 +3619,17 @@ phase6(xfs_mount_t *mp)
do_warn(_("would reinitialize metadata root directory\n"));
}

+ reserve_perag = xfs_has_realtime(mp) && !no_modify;
+ if (reserve_perag) {
+ error = reserve_ag_blocks(mp);
+ if (error) {
+ if (error != ENOSPC)
+ do_warn(
+ _("could not reserve per-AG space to rebuild realtime metadata"));
+ reserve_perag = false;
+ }
+ }
+
if (xfs_has_rtgroups(mp))
reset_rt_metadir_inodes(mp);
else
@@ -3596,6 +3638,9 @@ phase6(xfs_mount_t *mp)
if (xfs_has_metadir(mp) && xfs_has_quota(mp) && !no_modify)
reset_quota_metadir_inodes(mp);

+ if (reserve_perag)
+ unreserve_ag_blocks(mp);
+
mark_standalone_inodes(mp);

do_log(_(" - traversing filesystem ...\n"));