From: Darrick J. Wong <djwong@xxxxxxxxxx> 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@xxxxxxxxxx> --- 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 8935cf856e70c8..fe106f0b6ab536 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 0a9059db9302a3..2d341975e53993 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;