[PATCH 16/43] xfs_repair: find and clobber rtgroup bitmap and summary files

Darrick J. Wong
2024-10-11T01:28:44Z

On a rtgroups filesystem, if the rtgroups bitmap or summary files are
garbage, we need to clear the dinode and update the incore bitmap so
that we don't bother to check the old rt freespace metadata.

However, we regenerate the entire rt metadata directory tree during
phase 6. If the bitmap and summary files are ok, we still want to clear
the dinode, but we can still use the incore inode to check the old
freespace contents. Split the clear_dinode function into two pieces,
one that merely zeroes the inode, and the old clear_dinode now turns off
checking.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
repair/dino_chunks.c | 23 +++++++++++++++++++++++
repair/dinode.c | 40 ++++++++++++++++++++++++++++++++++------
2 files changed, 57 insertions(+), 6 deletions(-)

diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c
index 1c3512d00fbe6b..c732345e8f265e 100644
--- a/repair/dino_chunks.c
+++ b/repair/dino_chunks.c
@@ -15,6 +15,7 @@
#include "versions.h"
#include "prefetch.h"
#include "progress.h"
+#include "rt.h"

/*
* validates inode block or chunk, returns # of good inodes
@@ -1000,6 +1001,28 @@ process_inode_chunk(
_("would clear realtime summary inode %" PRIu64 "\n"),
ino);
}
+ } else if (is_rtbitmap_inode(ino)) {
+ mark_rtgroup_inodes_bad(mp, XFS_RTGI_BITMAP);
+ if (!no_modify) {
+ do_warn(
+ _("cleared rtgroup bitmap inode %" PRIu64 "\n"),
+ ino);
+ } else {
+ do_warn(
+ _("would clear rtgroup bitmap inode %" PRIu64 "\n"),
+ ino);
+ }
+ } else if (is_rtsummary_inode(ino)) {
+ mark_rtgroup_inodes_bad(mp, XFS_RTGI_SUMMARY);
+ if (!no_modify) {
+ do_warn(
+ _("cleared rtgroup summary inode %" PRIu64 "\n"),
+ ino);
+ } else {
+ do_warn(
+ _("would clear rtgroup summary inode %" PRIu64 "\n"),
+ ino);
+ }
} else if (!no_modify) {
do_warn(_("cleared inode %" PRIu64 "\n"),
ino);
diff --git a/repair/dinode.c b/repair/dinode.c
index 1f4a7e4d7da365..3cf93eacc83462 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -149,16 +149,36 @@ clear_dinode_unlinked(xfs_mount_t *mp, struct xfs_dinode *dino)
* until after the agi unlinked lists are walked in phase 3.
*/
static void
-clear_dinode(xfs_mount_t *mp, struct xfs_dinode *dino, xfs_ino_t ino_num)
+zero_dinode(
+ struct xfs_mount *mp,
+ struct xfs_dinode *dino,
+ xfs_ino_t ino_num)
{
clear_dinode_core(mp, dino, ino_num);
clear_dinode_unlinked(mp, dino);

/* and clear the forks */
memset(XFS_DFORK_DPTR(dino), 0, XFS_LITINO(mp));
- return;
}

+/*
+ * clear the inode core and, if this is a metadata inode, prevent subsequent
+ * phases from checking the (obviously bad) data in the file.
+ */
+static void
+clear_dinode(
+ struct xfs_mount *mp,
+ struct xfs_dinode *dino,
+ xfs_ino_t ino_num)
+{
+ zero_dinode(mp, dino, ino_num);
+
+ if (is_rtbitmap_inode(ino_num))
+ mark_rtgroup_inodes_bad(mp, XFS_RTGI_BITMAP);
+
+ if (is_rtsummary_inode(ino_num))
+ mark_rtgroup_inodes_bad(mp, XFS_RTGI_SUMMARY);
+}

/*
* misc. inode-related utility routines
@@ -3069,13 +3089,21 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "),
switch (type) {
case XR_INO_RTBITMAP:
case XR_INO_RTSUM:
+ /*
+ * rt bitmap and summary files are always recreated
+ * when rtgroups are enabled. For older filesystems,
+ * they exist at fixed locations and cannot be zapped.
+ */
+ if (xfs_has_rtgroups(mp))
+ zap_metadata = true;
+ break;
case XR_INO_UQUOTA:
case XR_INO_GQUOTA:
case XR_INO_PQUOTA:
/*
- * This inode was recognized as being filesystem
- * metadata, so preserve the inode and its contents for
- * later checking and repair.
+ * Quota checking and repair doesn't happen until
+ * phase7, so preserve quota inodes and their contents
+ * for later.
*/
break;
default:
@@ -3165,7 +3193,7 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "),
* file, zero the ondisk inode and the incore state.
*/
if (check_dups && zap_metadata && !no_modify) {
- clear_dinode(mp, dino, lino);
+ zero_dinode(mp, dino, lino);
*dirty += 1;
*used = is_free;
*isa_dir = 0;