@@ -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);
@@ -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;
@@ -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),
@@ -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 */
@@ -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;
}
@@ -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 *,
@@ -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);
}
}