From: Darrick J. Wong <djwong@xxxxxxxxxx> 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" <djwong@xxxxxxxxxx> --- repair/dino_chunks.c | 11 +++++++++++ repair/dinode.c | 49 +++++++++++++++++++++++++++++++++++++++++-------- repair/dir2.c | 5 +++++ repair/incore.h | 1 + repair/rmap.c | 5 ++++- repair/rmap.h | 2 +- repair/scan.c | 8 ++++---- 7 files changed, 67 insertions(+), 14 deletions(-) diff --git a/repair/dino_chunks.c b/repair/dino_chunks.c index 8c5387cdf4ea52..250985ec264ead 100644 --- a/repair/dino_chunks.c +++ b/repair/dino_chunks.c @@ -1036,6 +1036,17 @@ process_inode_chunk( _("would clear rtgroup rmap inode %" PRIu64 "\n"), ino); } + } else if (is_rtrefcount_inode(ino)) { + refcount_avoid_check(mp); + if (!no_modify) { + do_warn( + _("cleared rtgroup refcount inode %" PRIu64 "\n"), + ino); + } else { + do_warn( + _("would clear rtgroup 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 ac5db8b0ea4392..3260df94511ed2 100644 --- a/repair/dinode.c +++ b/repair/dinode.c @@ -181,6 +181,9 @@ clear_dinode( if (is_rtrmap_inode(ino_num)) rmap_avoid_check(mp); + + if (is_rtrefcount_inode(ino_num)) + refcount_avoid_check(mp); } /* @@ -1139,14 +1142,27 @@ _("rtrefcount inode %" PRIu64 " not flagged as metadata\n"), return 1; } - if (!is_rtrefcount_inode(lino)) { - do_warn( -_("could not associate refcount inode %" PRIu64 " with any rtgroup\n"), - lino); - return 1; - } - + /* + * If this rtrefcount file claims to be from an rtgroup that actually + * exists, check that inode discovery actually found it. Note that + * we can have stray rtrefcount files from failed growfsrt operations. + */ priv.rgno = metafile_rgnumber(dip); + if (priv.rgno < mp->m_sb.sb_rgcount) { + if (type != XR_INO_RTREFC) { + do_warn( +_("rtrefcount inode %" PRIu64 " was not found in the metadata directory tree\n"), + lino); + return 1; + } + + if (!is_rtrefcount_inode(lino)) { + do_warn( +_("could not associate refcount inode %" PRIu64 " with any rtgroup\n"), + lino); + return 1; + } + } dib = (struct xfs_rtrefcount_root *)XFS_DFORK_PTR(dip, XFS_DATA_FORK); *tot = 0; @@ -1179,7 +1195,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; @@ -2143,6 +2159,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; } @@ -2253,6 +2272,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; } @@ -3453,6 +3484,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; diff --git a/repair/dir2.c b/repair/dir2.c index af00b2d8d6c852..a80160afaea5cf 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 4add12615e0a04..57019148f588c3 100644 --- a/repair/incore.h +++ b/repair/incore.h @@ -242,6 +242,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 85a65048db9afc..e39c74cc7b44f7 100644 --- a/repair/rmap.c +++ b/repair/rmap.c @@ -1699,8 +1699,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)) + mark_rtgroup_inodes_bad(mp, XFS_RTGI_REFCOUNT); refcbt_suspect = true; } diff --git a/repair/rmap.h b/repair/rmap.h index 23859bf6c2ad42..c0984d97322861 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/scan.c b/repair/scan.c index 21fa9018800c77..86565ebb9f2faf 100644 --- a/repair/scan.c +++ b/repair/scan.c @@ -1980,7 +1980,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; } @@ -2285,7 +2285,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; } @@ -3148,7 +3148,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); @@ -3166,7 +3166,7 @@ validate_agf( } else { do_warn(_("bad agbno %u for refcntbt root, agno %d\n"), bno, agno); - refcount_avoid_check(); + refcount_avoid_check(mp); } }