summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2019-02-01 20:08:52 +0300
committerDarrick J. Wong <darrick.wong@oracle.com>2019-02-12 03:06:39 +0300
commit4539b8a7807848ad5c9e4d1d4199f34eb88669c5 (patch)
tree318580883d04498584e995fb2d514155e38fe462
parentb9454fe056bda3b208225e4ac76bcc7c912f350a (diff)
downloadlinux-4539b8a7807848ad5c9e4d1d4199f34eb88669c5.tar.xz
xfs: scrub big block inode btrees correctly
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>
-rw-r--r--fs/xfs/scrub/ialloc.c10
1 files changed, 9 insertions, 1 deletions
diff --git a/fs/xfs/scrub/ialloc.c b/fs/xfs/scrub/ialloc.c
index 708f6607db71..1929d79ea6b3 100644
--- a/fs/xfs/scrub/ialloc.c
+++ b/fs/xfs/scrub/ialloc.c
@@ -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;