From da82ccee4884c9a74f30a71cd2eda4cbb23c3aaa Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Wed, 3 Jul 2024 14:22:34 -0700 Subject: [PATCH] xfs_repair: find and mark the rtrefcountbt inode Make sure that we find the realtime refcountbt inode and mark it appropriately, just in case we find a rogue inode claiming to be an rtrefcount, or just plain garbage in the superblock field. Signed-off-by: Darrick J. Wong --- repair/dino_chunks.c | 11 +++++++++++ repair/dinode.c | 30 +++++++++++++++++++++++++++++- repair/dir2.c | 5 +++++ repair/incore.h | 1 + repair/rmap.c | 5 ++++- repair/rmap.h | 2 +- repair/rt.h | 5 +++++ repair/scan.c | 8 ++++---- 8 files changed, 60 insertions(+), 7 deletions(-) diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 4d6d9cb3e..24ca210a6 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -1017,6 +1017,17 @@ next_readbuf: _("would clear realtime rmap inode %" PRIu64 "\n"), ino); } + } else if (is_rtrefcount_inode(ino)) { + refcount_avoid_check(mp); + if (!no_modify) { + do_warn( + _("cleared realtime refcount inode %" PRIu64 "\n"), + ino); + } else { + do_warn( + _("would clear realtime refcount 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 524de5982..3e41b2566 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -157,6 +157,9 @@ clear_dinode(xfs_mount_t *mp, struct xfs_dinode *dino, xfs_ino_t ino_num) if (is_rtrmap_inode(ino_num)) rmap_avoid_check(mp); + if (is_rtrefcount_inode(ino_num)) + refcount_avoid_check(mp); + /* and clear the forks */ memset(XFS_DFORK_DPTR(dino), 0, XFS_LITINO(mp)); return; @@ -1113,6 +1116,12 @@ _("rtrefcount inode %" PRIu64 " not flagged as metadata\n"), lino); return 1; } + if (type != XR_INO_RTREFC) { + do_warn( +_("rtrefcount inode %" PRIu64 " was not found in the metadata directory tree\n"), + lino); + return 1; + } priv.rgno = rtgroup_for_rtrefcount_inode(mp, lino); if (priv.rgno == NULLRGNUMBER) { @@ -1153,7 +1162,7 @@ _("computed size of rtrefcountbt root (%zu bytes) is greater than space in " error = process_rtrefc_reclist(mp, rp, numrecs, &priv, "rtrefcountbt root"); if (error) { - refcount_avoid_check(); + refcount_avoid_check(mp); return 1; } return 0; @@ -2111,6 +2120,9 @@ process_check_metadata_inodes( if (is_rtrmap_inode(lino)) return process_check_rt_inode(mp, dinoc, lino, type, dirty, XR_INO_RTRMAP, _("realtime rmap btree")); + if (is_rtrefcount_inode(lino)) + return process_check_rt_inode(mp, dinoc, lino, type, dirty, + XR_INO_RTREFC, _("realtime refcount btree")); return 0; } @@ -2221,6 +2233,18 @@ _("found inode %" PRIu64 " claiming to be a rtrmapbt file, but rmapbt is disable } break; + case XR_INO_RTREFC: + /* + * if we have no refcountbt, any inode claiming + * to be a real-time file is bogus + */ + if (!xfs_has_reflink(mp)) { + do_warn( +_("found inode %" PRIu64 " claiming to be a rtrefcountbt file, but reflink is disabled\n"), lino); + return 1; + } + break; + default: break; } @@ -2250,6 +2274,7 @@ _("bad attr fork offset %d in dev inode %" PRIu64 ", should be %d\n"), } break; case XFS_DINODE_FMT_RMAP: + case XFS_DINODE_FMT_REFCOUNT: if (!(xfs_has_metadir(mp) && xfs_has_parent(mp))) { do_warn( _("metadata inode %" PRIu64 " type %d cannot have attr fork\n"), @@ -3397,6 +3422,8 @@ _("bad (negative) size %" PRId64 " on inode %" PRIu64 "\n"), type = XR_INO_PQUOTA; else if (is_rtrmap_inode(lino)) type = XR_INO_RTRMAP; + else if (is_rtrefcount_inode(lino)) + type = XR_INO_RTREFC; else type = XR_INO_DATA; break; @@ -3504,6 +3531,7 @@ _("Bad CoW extent size %u on inode %" PRIu64 ", "), case XR_INO_GQUOTA: case XR_INO_PQUOTA: case XR_INO_RTRMAP: + case XR_INO_RTREFC: /* * This inode was recognized as being filesystem * metadata, so preserve the inode and its contents for diff --git a/repair/dir2.c b/repair/dir2.c index affb556e6..d489a742a 100644 --- a/repair/dir2.c +++ b/repair/dir2.c @@ -282,6 +282,9 @@ process_sf_dir2( } else if (is_rtrmap_inode(lino)) { junkit = 1; junkreason = _("realtime rmap"); + } else if (is_rtrefcount_inode(lino)) { + junkit = 1; + junkreason = _("realtime refcount"); } else if ((irec_p = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, lino), XFS_INO_TO_AGINO(mp, lino))) != NULL) { @@ -761,6 +764,8 @@ process_dir2_data( clearreason = _("metadata directory root"); } else if (is_rtrmap_inode(ent_ino)) { clearreason = _("realtime rmap"); + } else if (is_rtrefcount_inode(ent_ino)) { + clearreason = _("realtime refcount"); } else { irec_p = find_inode_rec(mp, XFS_INO_TO_AGNO(mp, ent_ino), diff --git a/repair/incore.h b/repair/incore.h index 28777bac7..70be9fa25 100644 --- a/repair/incore.h +++ b/repair/incore.h @@ -222,6 +222,7 @@ int count_bcnt_extents(xfs_agnumber_t); #define XR_INO_GQUOTA 13 /* group quota inode */ #define XR_INO_PQUOTA 14 /* project quota inode */ #define XR_INO_RTRMAP 15 /* realtime rmap */ +#define XR_INO_RTREFC 16 /* realtime refcount */ /* inode allocation tree */ diff --git a/repair/rmap.c b/repair/rmap.c index 115cd6fee..74a874724 100644 --- a/repair/rmap.c +++ b/repair/rmap.c @@ -1691,8 +1691,11 @@ init_refcount_cursor( * Disable the refcount btree check. */ void -refcount_avoid_check(void) +refcount_avoid_check( + struct xfs_mount *mp) { + if (xfs_has_rtgroups(mp)) + rtginode_avoid_check(mp, XFS_RTG_REFCOUNT); refcbt_suspect = true; } diff --git a/repair/rmap.h b/repair/rmap.h index 23859bf6c..c0984d973 100644 --- a/repair/rmap.h +++ b/repair/rmap.h @@ -41,7 +41,7 @@ extern void rmap_high_key_from_rec(struct xfs_rmap_irec *rec, extern int compute_refcounts(struct xfs_mount *, xfs_agnumber_t); uint64_t refcount_record_count(struct xfs_mount *mp, xfs_agnumber_t agno); extern int init_refcount_cursor(xfs_agnumber_t, struct xfs_slab_cursor **); -extern void refcount_avoid_check(void); +extern void refcount_avoid_check(struct xfs_mount *mp); void check_refcounts(struct xfs_mount *mp, xfs_agnumber_t agno); extern void record_inode_reflink_flag(struct xfs_mount *, struct xfs_dinode *, diff --git a/repair/rt.h b/repair/rt.h index 3d3b08904..b54fbad11 100644 --- a/repair/rt.h +++ b/repair/rt.h @@ -60,6 +60,11 @@ static inline bool is_rtrmap_inode(xfs_ino_t ino) return is_rtgroup_inode(ino, XFS_RTG_RMAP); } +static inline bool is_rtrefcount_inode(xfs_ino_t ino) +{ + return is_rtgroup_inode(ino, XFS_RTG_REFCOUNT); +} + void rtginode_avoid_check(struct xfs_mount *mp, enum xfs_rtg_inodes type); #endif /* _XFS_REPAIR_RT_H_ */ diff --git a/repair/scan.c b/repair/scan.c index 110bbf23c..55f4c6f5e 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -1976,7 +1976,7 @@ _("extent (%u/%u) len %u claimed, state is %d\n"), libxfs_perag_put(pag); out: if (suspect) - refcount_avoid_check(); + refcount_avoid_check(mp); return; } @@ -2269,7 +2269,7 @@ _("%s btree block claimed (state %d), agno %d, agbno %d, suspect %d\n"), } out: if (suspect) { - refcount_avoid_check(); + refcount_avoid_check(mp); return 1; } @@ -3132,7 +3132,7 @@ validate_agf( if (levels == 0 || levels > mp->m_refc_maxlevels) { do_warn(_("bad levels %u for refcountbt root, agno %d\n"), levels, agno); - refcount_avoid_check(); + refcount_avoid_check(mp); } bno = be32_to_cpu(agf->agf_refcount_root); @@ -3150,7 +3150,7 @@ validate_agf( } else { do_warn(_("bad agbno %u for refcntbt root, agno %d\n"), bno, agno); - refcount_avoid_check(); + refcount_avoid_check(mp); } } -- 2.50.1