diff options
Diffstat (limited to 'fs/xfs/libxfs/xfs_ialloc.c')
-rw-r--r-- | fs/xfs/libxfs/xfs_ialloc.c | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index 48296adbb0fb..ad53aa5e4ea7 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c @@ -133,16 +133,45 @@ xfs_inobt_get_rec( struct xfs_inobt_rec_incore *irec, int *stat) { + struct xfs_mount *mp = cur->bc_mp; + xfs_agnumber_t agno = cur->bc_private.a.agno; union xfs_btree_rec *rec; int error; + uint64_t realfree; error = xfs_btree_get_rec(cur, &rec, stat); if (error || *stat == 0) return error; - xfs_inobt_btrec_to_irec(cur->bc_mp, rec, irec); + xfs_inobt_btrec_to_irec(mp, rec, irec); + + if (!xfs_verify_agino(mp, agno, irec->ir_startino)) + goto out_bad_rec; + if (irec->ir_count < XFS_INODES_PER_HOLEMASK_BIT || + irec->ir_count > XFS_INODES_PER_CHUNK) + goto out_bad_rec; + if (irec->ir_freecount > XFS_INODES_PER_CHUNK) + goto out_bad_rec; + + /* if there are no holes, return the first available offset */ + if (!xfs_inobt_issparse(irec->ir_holemask)) + realfree = irec->ir_free; + else + realfree = irec->ir_free & xfs_inobt_irec_to_allocmask(irec); + if (hweight64(realfree) != irec->ir_freecount) + goto out_bad_rec; return 0; + +out_bad_rec: + xfs_warn(mp, + "%s Inode BTree record corruption in AG %d detected!", + cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free", agno); + xfs_warn(mp, +"start inode 0x%x, count 0x%x, free 0x%x freemask 0x%llx, holemask 0x%x", + irec->ir_startino, irec->ir_count, irec->ir_freecount, + irec->ir_free, irec->ir_holemask); + return -EFSCORRUPTED; } /* |