]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
xfs_repair: reserve per-AG space while rebuilding rt metadata
authorDarrick J. Wong <djwong@kernel.org>
Mon, 24 Feb 2025 18:22:02 +0000 (10:22 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Tue, 25 Feb 2025 17:16:01 +0000 (09:16 -0800)
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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
include/libxfs.h
repair/phase6.c

index 79f8e1ff03d3f56e78fc471db339af46dd23bcd6..82b34b9d81c3a7a6817a10d0fedb7ad32b0e69ff 100644 (file)
@@ -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]))
index 2ddfd0526767e0fe830640b2ff5e8996233d7ed9..30ea19fda9fd875d136671d31d385c744f07b485 100644 (file)
@@ -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"));