summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-09-01 11:17:56 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-12-15 17:29:17 -0800
commitd4334d0dcc4f1e25869eef89536db6a8d0ef28f1 (patch)
tree82b6faae429f30c13245571e78bbefbe5b56f47b /fs/xfs/scrub
parent81603d160bee4e13b11eafe7d72c0140ba50d1c5 (diff)
xfs: scrub the realtime rmapbt
Check the realtime reverse mapping btree against the rtbitmap, and modify the rtbitmap scrub to check against the rtrmapbt. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs/xfs/scrub')
-rw-r--r--fs/xfs/scrub/bmap.c2
-rw-r--r--fs/xfs/scrub/common.c35
-rw-r--r--fs/xfs/scrub/common.h8
-rw-r--r--fs/xfs/scrub/health.c1
-rw-r--r--fs/xfs/scrub/repair.c1
-rw-r--r--fs/xfs/scrub/rtrmap.c100
-rw-r--r--fs/xfs/scrub/scrub.c9
-rw-r--r--fs/xfs/scrub/scrub.h8
-rw-r--r--fs/xfs/scrub/trace.h4
9 files changed, 165 insertions, 3 deletions
diff --git a/fs/xfs/scrub/bmap.c b/fs/xfs/scrub/bmap.c
index 81beb8e7e504..bede41ecedb3 100644
--- a/fs/xfs/scrub/bmap.c
+++ b/fs/xfs/scrub/bmap.c
@@ -315,6 +315,7 @@ xchk_bmap_rt_iextent_xref(
xchk_xref_is_used_rt_space(info->sc, irec->br_startblock,
irec->br_blockcount);
+ xchk_rt_btcur_free(&info->sc->sr);
xchk_rt_unlock(info->sc, &info->sc->sr);
}
@@ -750,6 +751,7 @@ xchk_bmap(
case XFS_DINODE_FMT_UUID:
case XFS_DINODE_FMT_DEV:
case XFS_DINODE_FMT_LOCAL:
+ case XFS_DINODE_FMT_RMAP:
/* No mappings to check. */
goto out;
case XFS_DINODE_FMT_EXTENTS:
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 615032d69078..4b2582035f5a 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -29,6 +29,7 @@
#include "xfs_ag.h"
#include "xfs_error.h"
#include "xfs_rtalloc.h"
+#include "xfs_rtrmap_btree.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/trace.h"
@@ -599,6 +600,16 @@ xchk_ag_init(
return 0;
}
+/* Lock everything we need to work on realtime metadata. */
+void
+xchk_rt_lock(
+ struct xfs_scrub *sc,
+ struct xchk_rt *sr)
+{
+ xfs_rtlock(NULL, sc->mp, XFS_RTLOCK_ALL);
+ sr->locked = true;
+}
+
/*
* For scrubbing a realtime file, grab all the in-core resources we'll need to
* check the realtime metadata, which means taking the ILOCK of the realtime
@@ -610,8 +621,28 @@ xchk_rt_init(
struct xfs_scrub *sc,
struct xchk_rt *sr)
{
- xfs_rtlock(NULL, sc->mp, XFS_RTLOCK_ALL);
- sr->locked = true;
+ struct xfs_mount *mp = sc->mp;
+
+ xchk_rt_lock(sc, sr);
+
+ if (xfs_has_rtrmapbt(mp))
+ sr->rmap_cur = xfs_rtrmapbt_init_cursor(mp, sc->tp,
+ mp->m_rrmapip);
+}
+
+/*
+ * Free all the btree cursors and other incore data relating to the realtime
+ * volume. This has to be done /before/ committing (or cancelling) the scrub
+ * transaction.
+ */
+void
+xchk_rt_btcur_free(
+ struct xchk_rt *sr)
+{
+ if (sr->rmap_cur)
+ xfs_btree_del_cursor(sr->rmap_cur, XFS_BTREE_ERROR);
+
+ sr->rmap_cur = NULL;
}
/*
diff --git a/fs/xfs/scrub/common.h b/fs/xfs/scrub/common.h
index 263dbd9e5b46..a4d9d4abc7f4 100644
--- a/fs/xfs/scrub/common.h
+++ b/fs/xfs/scrub/common.h
@@ -92,6 +92,7 @@ int xchk_setup_parent(struct xfs_scrub *sc);
#ifdef CONFIG_XFS_RT
int xchk_setup_rtbitmap(struct xfs_scrub *sc);
int xchk_setup_rtsummary(struct xfs_scrub *sc);
+int xchk_setup_rtrmapbt(struct xfs_scrub *sc);
#else
static inline int
xchk_setup_rtbitmap(struct xfs_scrub *sc)
@@ -103,6 +104,11 @@ xchk_setup_rtsummary(struct xfs_scrub *sc)
{
return -ENOENT;
}
+static inline int
+xchk_setup_rtrmapbt(struct xfs_scrub *sc)
+{
+ return -ENOENT;
+}
#endif
#ifdef CONFIG_XFS_QUOTA
int xchk_setup_quota(struct xfs_scrub *sc);
@@ -143,6 +149,8 @@ xchk_ag_init_existing(
}
void xchk_rt_init(struct xfs_scrub *sc, struct xchk_rt *sr);
+void xchk_rt_btcur_free(struct xchk_rt *sr);
+void xchk_rt_lock(struct xfs_scrub *sc, struct xchk_rt *sr);
void xchk_rt_unlock(struct xfs_scrub *sc, struct xchk_rt *sr);
int xchk_ag_read_headers(struct xfs_scrub *sc, xfs_agnumber_t agno,
struct xchk_ag *sa);
diff --git a/fs/xfs/scrub/health.c b/fs/xfs/scrub/health.c
index 9fbc10981566..e35c5190a06f 100644
--- a/fs/xfs/scrub/health.c
+++ b/fs/xfs/scrub/health.c
@@ -107,6 +107,7 @@ static const struct xchk_health_map type_to_health_flag[XFS_SCRUB_TYPE_NR] = {
[XFS_SCRUB_TYPE_PQUOTA] = { XHG_FS, XFS_SICK_FS_PQUOTA },
[XFS_SCRUB_TYPE_FSCOUNTERS] = { XHG_FS, XFS_SICK_FS_COUNTERS },
[XFS_SCRUB_TYPE_QUOTACHECK] = { XHG_FS, XFS_SICK_FS_QUOTACHECK },
+ [XFS_SCRUB_TYPE_RTRMAPBT] = { XHG_RT, XFS_SICK_RT_RMAPBT },
};
/* Return the health status mask for this scrub type. */
diff --git a/fs/xfs/scrub/repair.c b/fs/xfs/scrub/repair.c
index 94245da9c63a..e3e7f75778d6 100644
--- a/fs/xfs/scrub/repair.c
+++ b/fs/xfs/scrub/repair.c
@@ -59,6 +59,7 @@ xrep_attempt(
trace_xrep_attempt(XFS_I(file_inode(sc->file)), sc->sm, error);
xchk_ag_btcur_free(&sc->sa);
+ xchk_rt_btcur_free(&sc->sr);
/* Repair whatever's broken. */
ASSERT(sc->ops->repair);
diff --git a/fs/xfs/scrub/rtrmap.c b/fs/xfs/scrub/rtrmap.c
new file mode 100644
index 000000000000..2928f57c29ed
--- /dev/null
+++ b/fs/xfs/scrub/rtrmap.c
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2021 Oracle. All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+#include "xfs.h"
+#include "xfs_fs.h"
+#include "xfs_shared.h"
+#include "xfs_format.h"
+#include "xfs_trans_resv.h"
+#include "xfs_mount.h"
+#include "xfs_defer.h"
+#include "xfs_btree.h"
+#include "xfs_bit.h"
+#include "xfs_log_format.h"
+#include "xfs_trans.h"
+#include "xfs_sb.h"
+#include "xfs_rmap.h"
+#include "xfs_rmap_btree.h"
+#include "xfs_rtrmap_btree.h"
+#include "xfs_inode.h"
+#include "xfs_rtalloc.h"
+#include "scrub/xfs_scrub.h"
+#include "scrub/scrub.h"
+#include "scrub/common.h"
+#include "scrub/btree.h"
+#include "scrub/trace.h"
+
+/* Set us up with the realtime metadata locked. */
+int
+xchk_setup_rtrmapbt(
+ struct xfs_scrub *sc)
+{
+ struct xfs_mount *mp = sc->mp;
+ int error = 0;
+
+ error = xchk_setup_fs(sc);
+ if (error)
+ return error;
+
+ error = xchk_install_inode(sc, mp->m_rrmapip);
+ if (error)
+ return error;
+
+ xchk_rt_init(sc, &sc->sr);
+ return 0;
+}
+
+/* Realtime reverse mapping. */
+
+/* Scrub a realtime rmapbt record. */
+STATIC int
+xchk_rtrmapbt_rec(
+ struct xchk_btree *bs,
+ const union xfs_btree_rec *rec)
+{
+ struct xfs_mount *mp = bs->cur->bc_mp;
+ struct xfs_rmap_irec irec;
+ bool non_inode;
+ bool is_bmbt;
+ bool is_attr;
+ int error;
+
+ error = xfs_rmap_btrec_to_irec(bs->cur, rec, &irec);
+ if (!xchk_btree_process_error(bs->sc, bs->cur, 0, &error))
+ goto out;
+
+ if (irec.rm_startblock + irec.rm_blockcount <= irec.rm_startblock ||
+ (!xfs_verify_rtbno(mp, irec.rm_startblock) ||
+ !xfs_verify_rtbno(mp, irec.rm_startblock +
+ irec.rm_blockcount - 1)))
+ xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+
+ /* Check flags. */
+ non_inode = XFS_RMAP_NON_INODE_OWNER(irec.rm_owner);
+ is_bmbt = irec.rm_flags & XFS_RMAP_BMBT_BLOCK;
+ is_attr = irec.rm_flags & XFS_RMAP_ATTR_FORK;
+
+ if (is_bmbt || non_inode || is_attr)
+ xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+
+ if (!xfs_verify_ino(mp, irec.rm_owner))
+ xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+
+out:
+ return error;
+}
+
+/* Scrub the realtime rmap btree. */
+int
+xchk_rtrmapbt(
+ struct xfs_scrub *sc)
+{
+ struct xfs_owner_info oinfo;
+ struct xfs_mount *mp = sc->mp;
+
+ xfs_rmap_ino_bmbt_owner(&oinfo, mp->m_rrmapip->i_ino, XFS_DATA_FORK);
+ return xchk_btree(sc, sc->sr.rmap_cur, xchk_rtrmapbt_rec, &oinfo,
+ NULL);
+}
diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c
index d7756680aee8..d0b6abb0647d 100644
--- a/fs/xfs/scrub/scrub.c
+++ b/fs/xfs/scrub/scrub.c
@@ -158,6 +158,8 @@ xchk_teardown(
int error)
{
xchk_ag_free(sc, &sc->sa);
+ xchk_rt_btcur_free(&sc->sr);
+
if (sc->tp) {
if (error == 0 && (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR))
error = xfs_trans_commit(sc->tp);
@@ -376,6 +378,13 @@ static const struct xchk_meta_ops meta_scrub_ops[] = {
.scrub = xchk_health_record,
.repair = xrep_notsupported,
},
+ [XFS_SCRUB_TYPE_RTRMAPBT] = { /* realtime rmapbt */
+ .type = ST_FS,
+ .setup = xchk_setup_rtrmapbt,
+ .scrub = xchk_rtrmapbt,
+ .has = xfs_has_rtrmapbt,
+ .repair = xrep_notsupported,
+ },
};
/* This isn't a stable feature, warn once per day. */
diff --git a/fs/xfs/scrub/scrub.h b/fs/xfs/scrub/scrub.h
index c88279780fe4..fbbc7af5b67e 100644
--- a/fs/xfs/scrub/scrub.h
+++ b/fs/xfs/scrub/scrub.h
@@ -62,6 +62,8 @@ struct xchk_ag {
/* Btree cursors for the RT volume. */
struct xchk_rt {
bool locked;
+
+ struct xfs_btree_cur *rmap_cur;
};
struct xfs_scrub {
@@ -158,6 +160,7 @@ int xchk_parent(struct xfs_scrub *sc);
#ifdef CONFIG_XFS_RT
int xchk_rtbitmap(struct xfs_scrub *sc);
int xchk_rtsummary(struct xfs_scrub *sc);
+int xchk_rtrmapbt(struct xfs_scrub *sc);
#else
static inline int
xchk_rtbitmap(struct xfs_scrub *sc)
@@ -169,6 +172,11 @@ xchk_rtsummary(struct xfs_scrub *sc)
{
return -ENOENT;
}
+static inline int
+xchk_rtrmapbt(struct xfs_scrub *sc)
+{
+ return -ENOENT;
+}
#endif
#ifdef CONFIG_XFS_QUOTA
int xchk_quota(struct xfs_scrub *sc);
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index c4545d7ff347..dc1019dd4d9f 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -62,6 +62,7 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_UQUOTA);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_GQUOTA);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_PQUOTA);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_FSCOUNTERS);
+TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RTRMAPBT);
#define XFS_SCRUB_TYPE_STRINGS \
{ XFS_SCRUB_TYPE_PROBE, "probe" }, \
@@ -90,7 +91,8 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_FSCOUNTERS);
{ XFS_SCRUB_TYPE_PQUOTA, "prjquota" }, \
{ XFS_SCRUB_TYPE_FSCOUNTERS, "fscounters" }, \
{ XFS_SCRUB_TYPE_QUOTACHECK, "quotacheck" }, \
- { XFS_SCRUB_TYPE_HEALTHY, "healthy" }
+ { XFS_SCRUB_TYPE_HEALTHY, "healthy" }, \
+ { XFS_SCRUB_TYPE_RTRMAPBT, "rtrmapbt" }
#define XFS_SCRUB_FLAG_STRINGS \
{ XFS_SCRUB_IFLAG_REPAIR, "repair" }, \