#define XFS_SCRUB_TYPE_DIRTREE 28 /* directory tree structure */
#define XFS_SCRUB_TYPE_METAPATH 29 /* metadata directory tree paths */
#define XFS_SCRUB_TYPE_RGSUPER 30 /* realtime superblock */
+#define XFS_SCRUB_TYPE_RGBITMAP 31 /* realtime group bitmap */
/* Number of scrub subcommands. */
-#define XFS_SCRUB_TYPE_NR 31
+#define XFS_SCRUB_TYPE_NR 32
/*
* This special type code only applies to the vectored scrub implementation.
__u64 rg_reserved[13]; /* o: zero */
};
#define XFS_RTGROUP_GEOM_SICK_SUPER (1U << 0) /* superblock */
+#define XFS_RTGROUP_GEOM_SICK_BITMAP (1U << 1) /* rtbitmap for this group */
/*
* ioctl commands that are used by Linux filesystems
/* Observable health issues for realtime group metadata. */
#define XFS_SICK_RG_SUPER (1 << 0) /* rt group superblock */
+#define XFS_SICK_RG_BITMAP (1 << 1) /* rt group part of rtbitmap */
/* Observable health issues for AG metadata. */
#define XFS_SICK_AG_SB (1 << 0) /* superblock */
#define XFS_SICK_RT_PRIMARY (XFS_SICK_RT_BITMAP | \
XFS_SICK_RT_SUMMARY)
-#define XFS_SICK_RG_PRIMARY (XFS_SICK_RG_SUPER)
+#define XFS_SICK_RG_PRIMARY (XFS_SICK_RG_SUPER | \
+ XFS_SICK_RG_BITMAP)
#define XFS_SICK_AG_PRIMARY (XFS_SICK_AG_SB | \
XFS_SICK_AG_AGF | \
int xchk_setup_rtbitmap(struct xfs_scrub *sc);
int xchk_setup_rtsummary(struct xfs_scrub *sc);
int xchk_setup_rgsuperblock(struct xfs_scrub *sc);
+int xchk_setup_rgbitmap(struct xfs_scrub *sc);
#else
# define xchk_setup_rtbitmap xchk_setup_nothing
# define xchk_setup_rtsummary xchk_setup_nothing
# define xchk_setup_rgsuperblock xchk_setup_nothing
+# define xchk_setup_rgbitmap xchk_setup_nothing
#endif
#ifdef CONFIG_XFS_QUOTA
int xchk_ino_dqattach(struct xfs_scrub *sc);
void xchk_rt_unlock_rtbitmap(struct xfs_scrub *sc);
#ifdef CONFIG_XFS_RT
+
+/* All the locks we need to check an rtgroup. */
+#define XCHK_RTGLOCK_ALL (XFS_RTGLOCK_BITMAP_SHARED)
+
int xchk_rtgroup_init(struct xfs_scrub *sc, xfs_rgnumber_t rgno,
struct xchk_rt *sr, unsigned int rtglock_flags);
void xchk_rtgroup_unlock(struct xfs_scrub *sc, struct xchk_rt *sr);
[XFS_SCRUB_TYPE_DIRTREE] = { XHG_INO, XFS_SICK_INO_DIRTREE },
[XFS_SCRUB_TYPE_METAPATH] = { XHG_FS, XFS_SICK_FS_METAPATH },
[XFS_SCRUB_TYPE_RGSUPER] = { XHG_RTGROUP, XFS_SICK_RG_SUPER },
+ [XFS_SCRUB_TYPE_RGBITMAP] = { XHG_RTGROUP, XFS_SICK_RG_BITMAP },
};
/* Return the health status mask for this scrub type. */
#include "xfs_bmap.h"
#include "xfs_bit.h"
#include "xfs_sb.h"
+#include "xfs_rtgroup.h"
#include "scrub/scrub.h"
#include "scrub/common.h"
#include "scrub/repair.h"
#include "scrub/rtbitmap.h"
+static inline void
+xchk_rtbitmap_compute_geometry(
+ struct xfs_mount *mp,
+ struct xchk_rtbitmap *rtb)
+{
+ if (mp->m_sb.sb_rblocks == 0)
+ return;
+
+ rtb->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
+ rtb->rextslog = xfs_compute_rextslog(rtb->rextents);
+ rtb->rbmblocks = xfs_rtbitmap_blockcount(mp, rtb->rextents);
+}
+
+/* Set us up with the realtime group metadata locked. */
+int
+xchk_setup_rgbitmap(
+ struct xfs_scrub *sc)
+{
+ struct xfs_mount *mp = sc->mp;
+ struct xchk_rgbitmap *rgb;
+ int error;
+
+ rgb = kzalloc(sizeof(struct xchk_rgbitmap), XCHK_GFP_FLAGS);
+ if (!rgb)
+ return -ENOMEM;
+ rgb->sc = sc;
+ sc->buf = rgb;
+
+ error = xchk_trans_alloc(sc, 0);
+ if (error)
+ return error;
+
+ error = xchk_install_live_inode(sc, mp->m_rbmip);
+ if (error)
+ return error;
+
+ error = xchk_rtgroup_init(sc, sc->sm->sm_agno, &sc->sr,
+ XCHK_RTGLOCK_ALL);
+ if (error)
+ return error;
+
+ /*
+ * Now that we've locked the rtbitmap, we can't race with growfsrt
+ * trying to expand the bitmap or change the size of the rt volume.
+ * Hence it is safe to compute and check the geometry values.
+ */
+ xchk_rtbitmap_compute_geometry(mp, &rgb->rtb);
+ return 0;
+}
+
/* Set us up with the realtime metadata locked. */
int
xchk_setup_rtbitmap(
* trying to expand the bitmap or change the size of the rt volume.
* Hence it is safe to compute and check the geometry values.
*/
- if (mp->m_sb.sb_rblocks) {
- rtb->rextents = xfs_rtb_to_rtx(mp, mp->m_sb.sb_rblocks);
- rtb->rextslog = xfs_compute_rextslog(rtb->rextents);
- rtb->rbmblocks = xfs_rtbitmap_blockcount(mp, rtb->rextents);
+ xchk_rtbitmap_compute_geometry(mp, rtb);
+ return 0;
+}
+
+/* Per-rtgroup bitmap contents. */
+
+/* Scrub a free extent record from the realtime bitmap. */
+STATIC int
+xchk_rgbitmap_rec(
+ struct xfs_mount *mp,
+ struct xfs_trans *tp,
+ const struct xfs_rtalloc_rec *rec,
+ void *priv)
+{
+ struct xchk_rgbitmap *rgb = priv;
+ struct xfs_scrub *sc = rgb->sc;
+ xfs_rtblock_t startblock;
+ xfs_filblks_t blockcount;
+
+ startblock = xfs_rtx_to_rtb(mp, rec->ar_startext);
+ blockcount = xfs_rtx_to_rtb(mp, rec->ar_extcount);
+
+ if (!xfs_verify_rtbext(mp, startblock, blockcount))
+ xchk_fblock_set_corrupt(sc, XFS_DATA_FORK, 0);
+ return 0;
+}
+
+/* Scrub this group's realtime bitmap. */
+int
+xchk_rgbitmap(
+ struct xfs_scrub *sc)
+{
+ struct xfs_mount *mp = sc->mp;
+ struct xfs_rtgroup *rtg = sc->sr.rtg;
+ struct xchk_rgbitmap *rgb = sc->buf;
+ xfs_rtblock_t start, last;
+ xfs_rgblock_t last_rgbno = rtg->rtg_blockcount - 1;
+ int error;
+
+ /* Sanity check the realtime bitmap size. */
+ if (sc->ip->i_disk_size < XFS_FSB_TO_B(mp, rgb->rtb.rbmblocks)) {
+ xchk_ino_set_corrupt(sc, sc->ip->i_ino);
+ return 0;
}
+
+ /*
+ * Check only the portion of the rtbitmap that corresponds to this
+ * realtime group.
+ */
+ start = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, 0);
+ last = xfs_rgbno_to_rtb(mp, rtg->rtg_rgno, last_rgbno);
+
+ error = xfs_rtalloc_query_range(mp, sc->tp, xfs_rtb_to_rtx(mp, start),
+ xfs_rtb_to_rtx(mp, last), xchk_rgbitmap_rec, rgb);
+ if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
+ return error;
+
return 0;
}
if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
return error;
+ /*
+ * Each rtgroup checks its portion of the rt bitmap, so if we don't
+ * have that feature, we have to check the bitmap contents now.
+ */
+ if (xfs_has_rtgroups(mp))
+ return 0;
+
error = xfs_rtalloc_query_all(mp, sc->tp, xchk_rtbitmap_rec, sc);
if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, 0, &error))
return error;
unsigned int resblks;
};
+struct xchk_rgbitmap {
+ struct xfs_scrub *sc;
+
+ struct xchk_rtbitmap rtb;
+};
+
#ifdef CONFIG_XFS_ONLINE_REPAIR
int xrep_setup_rtbitmap(struct xfs_scrub *sc, struct xchk_rtbitmap *rtb);
#else
.has = xfs_has_rtsb,
.repair = xrep_rgsuperblock,
},
+ [XFS_SCRUB_TYPE_RGBITMAP] = { /* realtime group bitmap */
+ .type = ST_RTGROUP,
+ .setup = xchk_setup_rgbitmap,
+ .scrub = xchk_rgbitmap,
+ .has = xfs_has_rtgroups,
+ .repair = xrep_notsupported,
+ },
};
static int
int xchk_rtbitmap(struct xfs_scrub *sc);
int xchk_rtsummary(struct xfs_scrub *sc);
int xchk_rgsuperblock(struct xfs_scrub *sc);
+int xchk_rgbitmap(struct xfs_scrub *sc);
#else
# define xchk_rtbitmap xchk_nothing
# define xchk_rtsummary xchk_nothing
# define xchk_rgsuperblock xchk_nothing
+# define xchk_rgbitmap xchk_nothing
#endif
#ifdef CONFIG_XFS_QUOTA
int xchk_quota(struct xfs_scrub *sc);
[XFS_SCRUB_TYPE_DIRTREE] = "dirtree",
[XFS_SCRUB_TYPE_METAPATH] = "metapath",
[XFS_SCRUB_TYPE_RGSUPER] = "rgsuper",
+ [XFS_SCRUB_TYPE_RGBITMAP] = "rgbitmap",
};
/* Format the scrub stats into a text buffer, similar to pcp style. */
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_BARRIER);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_METAPATH);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RGSUPER);
+TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_RGBITMAP);
#define XFS_SCRUB_TYPE_STRINGS \
{ XFS_SCRUB_TYPE_PROBE, "probe" }, \
{ XFS_SCRUB_TYPE_DIRTREE, "dirtree" }, \
{ XFS_SCRUB_TYPE_BARRIER, "barrier" }, \
{ XFS_SCRUB_TYPE_METAPATH, "metapath" }, \
- { XFS_SCRUB_TYPE_RGSUPER, "rgsuper" }
+ { XFS_SCRUB_TYPE_RGSUPER, "rgsuper" }, \
+ { XFS_SCRUB_TYPE_RGBITMAP, "rgbitmap" }
#define XFS_SCRUB_FLAG_STRINGS \
{ XFS_SCRUB_IFLAG_REPAIR, "repair" }, \
static const struct ioctl_sick_map rtgroup_map[] = {
{ XFS_SICK_RG_SUPER, XFS_RTGROUP_GEOM_SICK_SUPER },
+ { XFS_SICK_RG_BITMAP, XFS_RTGROUP_GEOM_SICK_BITMAP },
{ 0, 0 },
};