From: Darrick J. Wong <darrick.wong@xxxxxxxxxx> On a big block filesystem, there may be multiple inobt records covering a single inode cluster. These records obviously won't be aligned to cluster alignment rules, and they must cover the entire cluster. Teach scrub to check for these things. Signed-off-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --- fs/xfs/scrub/ialloc.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c index f498dfca3312..4fadea892440 100644 --- a/fs/xfs/scrub/ialloc.c +++ b/fs/xfs/scrub/ialloc.c @@ -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;