_("would clear realtime rmap inode %" PRIu64 "\n"),
ino);
}
+ } else if (is_rtrefcount_ino(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);
if (is_rtrmap_inode(ino_num))
rmap_avoid_check(mp);
+ if (is_rtrefcount_ino(ino_num))
+ refcount_avoid_check(mp);
+
/* and clear the forks */
memset(XFS_DFORK_DPTR(dino), 0, XFS_LITINO(mp));
return;
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) {
error = process_rtrefc_reclist(mp, rp, numrecs,
&priv, "rtrefcountbt root");
if (error) {
- refcount_avoid_check();
+ refcount_avoid_check(mp);
return 1;
}
return 0;
if (is_rtrmap_inode(lino))
return process_check_rt_inode(mp, dinoc, lino, type, dirty,
XR_INO_RTRMAP, _("realtime rmap btree"));
+ if (is_rtrefcount_ino(lino))
+ return process_check_rt_inode(mp, dinoc, lino, type, dirty,
+ XR_INO_RTREFC, _("realtime refcount btree"));
return 0;
}
}
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;
}
}
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"),
type = XR_INO_PQUOTA;
else if (is_rtrmap_inode(lino))
type = XR_INO_RTRMAP;
+ else if (is_rtrefcount_ino(lino))
+ type = XR_INO_RTREFC;
else
type = XR_INO_DATA;
break;
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
} else if (is_rtrmap_inode(lino)) {
junkit = 1;
junkreason = _("realtime rmap");
+ } else if (is_rtrefcount_ino(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) {
clearreason = _("metadata directory root");
} else if (is_rtrmap_inode(ent_ino)) {
clearreason = _("realtime rmap");
+ } else if (is_rtrefcount_ino(ent_ino)) {
+ clearreason = _("realtime refcount");
} else {
irec_p = find_inode_rec(mp,
XFS_INO_TO_AGNO(mp, ent_ino),
#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 */
*/
xfs_ino_t rg_rmap_ino;
+ /*
+ * inumber of the refcount btree for this rtgroup. This can be set to
+ * NULLFSINO to signal to phase 6 to link a new inode into the metadir.
+ */
+ xfs_ino_t rg_refcount_ino;
+
/* agfl entries from leftover agbt allocations */
int ar_flcount;
};
/* Bitmap of rt group rmap inodes reachable via /realtime/$rgno.rmap. */
static struct bitmap *rmap_inodes;
+/* Bitmap of rt group refcount inodes reachable via /realtime/$rgno.refcount. */
+static struct bitmap *refcount_inodes;
+
static struct xfs_ag_rmap *rmaps_for_group(bool isrt, unsigned int group)
{
if (isrt)
goto nomem;
ag_rmap->rg_rmap_ino = NULLFSINO;
+ ag_rmap->rg_refcount_ino = NULLFSINO;
return;
nomem:
do_error(
return error;
}
+static inline int
+set_rtgroup_refcount_inode(
+ struct xfs_mount *mp,
+ xfs_rgnumber_t rgno)
+{
+ struct xfs_imeta_path *path;
+ struct xfs_ag_rmap *ar = rmaps_for_group(true, rgno);
+ struct xfs_trans *tp;
+ xfs_ino_t ino;
+ int error;
+
+ if (!xfs_has_rtreflink(mp))
+ return 0;
+
+ path = xfs_rtrefcountbt_create_path(mp, rgno);
+ if (!path)
+ return ENOMEM;
+
+ error = -libxfs_trans_alloc_empty(mp, &tp);
+ if (error)
+ goto out_path;
+
+ error = -libxfs_imeta_lookup(tp, path, &ino);
+ if (error)
+ goto out_trans;
+
+ if (!libxfs_verify_ino(mp, ino) ||
+ bitmap_test(refcount_inodes, ino, 1)) {
+ error = EFSCORRUPTED;
+ goto out_trans;
+ }
+
+ error = bitmap_set(refcount_inodes, ino, 1);
+ if (error)
+ goto out_trans;
+
+ ar->rg_refcount_ino = ino;
+
+out_trans:
+ libxfs_trans_cancel(tp);
+out_path:
+ libxfs_imeta_free_path(path);
+ return error;
+}
+
static void
discover_rtgroup_inodes(
struct xfs_mount *mp)
if (error)
goto out;
+ error = bitmap_alloc(&refcount_inodes);
+ if (error) {
+ bitmap_free(&rmap_inodes);
+ goto out;
+ }
+
for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
int err2 = set_rtgroup_rmap_inode(mp, rgno);
if (err2 && !error)
error = err2;
+
+ err2 = set_rtgroup_refcount_inode(mp, rgno);
+ if (err2 && !error)
+ error = err2;
}
out:
static inline void
free_rtmeta_inode_bitmaps(void)
{
+ bitmap_free(&refcount_inodes);
bitmap_free(&rmap_inodes);
}
struct xfs_mount *mp,
xfs_ino_t ino)
{
- /* This will be implemented later. */
+ xfs_rgnumber_t rgno;
+
+ if (!refcount_inodes)
+ return NULLRGNUMBER;
+
+ for (rgno = 0; rgno < mp->m_sb.sb_rgcount; rgno++) {
+ if (rg_rmaps[rgno].rg_refcount_ino == ino)
+ return rgno;
+ }
+
return NULLRGNUMBER;
}
+bool
+is_rtrefcount_ino(
+ xfs_ino_t ino)
+{
+ if (!refcount_inodes)
+ return false;
+ return bitmap_test(refcount_inodes, ino, 1);
+}
+
/*
* Initialize per-AG reverse map data.
*/
* Disable the refcount btree check.
*/
void
-refcount_avoid_check(void)
+refcount_avoid_check(
+ struct xfs_mount *mp)
{
+ struct xfs_rtgroup *rtg;
+ xfs_rgnumber_t rgno;
+
+ for_each_rtgroup(mp, rgno, rtg) {
+ struct xfs_ag_rmap *ar = rmaps_for_group(true, rtg->rtg_rgno);
+
+ ar->rg_refcount_ino = NULLFSINO;
+ }
+
+ bitmap_clear(refcount_inodes, 0, XFS_MAXINUMBER);
refcbt_suspect = true;
}
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 *,
xfs_rgnumber_t rtgroup_for_rtrefcount_inode(struct xfs_mount *mp,
xfs_ino_t ino);
+bool is_rtrefcount_ino(xfs_ino_t ino);
#endif /* RMAP_H_ */
libxfs_perag_put(pag);
out:
if (suspect)
- refcount_avoid_check();
+ refcount_avoid_check(mp);
return;
}
}
out:
if (suspect) {
- refcount_avoid_check();
+ refcount_avoid_check(mp);
return 1;
}
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);
} else {
do_warn(_("bad agbno %u for refcntbt root, agno %d\n"),
bno, agno);
- refcount_avoid_check();
+ refcount_avoid_check(mp);
}
}