xfs: scrub big block inode btrees correctly
authorDarrick J. Wong <darrick.wong@oracle.com>
Fri, 1 Feb 2019 17:08:52 +0000 (09:08 -0800)
committerDarrick J. Wong <darrick.wong@oracle.com>
Tue, 12 Feb 2019 00:06:39 +0000 (16:06 -0800)
Teach scrub how to handle the case that there are one or more inobt
records covering a given inode cluster.  This fixes the operation on big
block filesystems (e.g. 64k blocks, 512 byte inodes).

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
fs/xfs/scrub/ialloc.c

index 708f6607db71b56e8641bc5d737b08cacadc55c2..1929d79ea6b39d789fa811ce189577199c5b92b0 100644 (file)
@@ -162,6 +162,7 @@ xchk_iallocbt_check_cluster_ifree(
        xfs_ino_t                       fsino;
        xfs_agino_t                     agino;
        unsigned int                    offset;
+       unsigned int                    cluster_buf_base;
        bool                            irec_free;
        bool                            ino_inuse;
        bool                            freemask_ok;
@@ -174,10 +175,17 @@ xchk_iallocbt_check_cluster_ifree(
         * Given an inobt record, an offset of a cluster within the record, and
         * an offset of an inode within a cluster, compute which fs inode we're
         * talking about and the offset of that inode within the buffer.
+        *
+        * Be careful about inobt records that don't align with the start of
+        * the inode buffer when block sizes are large enough to hold multiple
+        * inode chunks.  When this happens, cluster_base will be zero but
+        * ir_startino can be large enough to make cluster_buf_base nonzero.
         */
        agino = irec->ir_startino + cluster_base + cluster_index;
        fsino = XFS_AGINO_TO_INO(mp, bs->cur->bc_private.a.agno, agino);
-       offset = cluster_index * mp->m_sb.sb_inodesize;
+       cluster_buf_base = XFS_INO_TO_OFFSET(mp, irec->ir_startino);
+       ASSERT(cluster_buf_base == 0 || cluster_base == 0);
+       offset = (cluster_buf_base + cluster_index) * mp->m_sb.sb_inodesize;
        if (offset >= BBTOB(cluster_bp->b_length)) {
                xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
                goto out;