@@ -57,6 +57,12 @@ struct xchk_iallocbt {
/* Block alignment of inode clusters. */
unsigned int cluster_align;
+
+ /* Expected next startino, for big block filesystems. */
+ xfs_agino_t next_startino;
+
+ /* Expected end of the current inode cluster. */
+ xfs_agino_t next_cluster_ino;
};
/*
@@ -288,6 +294,27 @@ xchk_iallocbt_rec_alignment(
struct xchk_iallocbt *iabt = bs->private;
xfs_agino_t imask;
+ if (iabt->next_startino != NULLAGINO) {
+ /*
+ * We're midway through a cluster of inodes that is mapped by
+ * multiple inobt records. Did we get the record for the next
+ * irec in the sequence?
+ */
+ if (irec->ir_startino != iabt->next_startino) {
+ xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
+ return;
+ }
+
+ iabt->next_startino += XFS_INODES_PER_CHUNK;
+
+ /* Are we done with the cluster? */
+ if (iabt->next_startino >= iabt->next_cluster_ino) {
+ iabt->next_startino = NULLAGINO;
+ iabt->next_cluster_ino = NULLAGINO;
+ }
+ return;
+ }
+
imask = XFS_OFFBNO_TO_AGINO(mp, iabt->cluster_align, 0) - 1;
if (irec->ir_startino & imask) {
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
@@ -299,6 +326,17 @@ xchk_iallocbt_rec_alignment(
xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
return;
}
+
+ if (iabt->inodes_per_cluster <= XFS_INODES_PER_CHUNK)
+ return;
+
+ /*
+ * If this is the start of an inode cluster that can be mapped by
+ * multiple inobt records, the next inobt record must follow exactly
+ * after this one.
+ */
+ iabt->next_startino = irec->ir_startino + XFS_INODES_PER_CHUNK;
+ iabt->next_cluster_ino = irec->ir_startino + iabt->inodes_per_cluster;
}
/* Scrub an inobt/finobt record. */
@@ -470,6 +508,8 @@ xchk_iallocbt(
.inodes = 0,
.cluster_align = xfs_ialloc_cluster_alignment(sc->mp),
.blocks_per_cluster = xfs_icluster_size_fsb(sc->mp),
+ .next_startino = NULLAGINO,
+ .next_cluster_ino = NULLAGINO,
};
int error;