summaryrefslogtreecommitdiff
path: root/fs/xfs/libxfs/xfs_ialloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/libxfs/xfs_ialloc.c')
-rw-r--r--fs/xfs/libxfs/xfs_ialloc.c53
1 files changed, 35 insertions, 18 deletions
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c
index 94db50eb706a..2bd7ec89245f 100644
--- a/fs/xfs/libxfs/xfs_ialloc.c
+++ b/fs/xfs/libxfs/xfs_ialloc.c
@@ -95,6 +95,33 @@ xfs_inobt_btrec_to_irec(
irec->ir_free = be64_to_cpu(rec->inobt.ir_free);
}
+/* Simple checks for inode records. */
+xfs_failaddr_t
+xfs_inobt_check_irec(
+ struct xfs_btree_cur *cur,
+ const struct xfs_inobt_rec_incore *irec)
+{
+ uint64_t realfree;
+
+ if (!xfs_verify_agino(cur->bc_ag.pag, irec->ir_startino))
+ return __this_address;
+ if (irec->ir_count < XFS_INODES_PER_HOLEMASK_BIT ||
+ irec->ir_count > XFS_INODES_PER_CHUNK)
+ return __this_address;
+ if (irec->ir_freecount > XFS_INODES_PER_CHUNK)
+ return __this_address;
+
+ /* 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)
+ return __this_address;
+
+ return NULL;
+}
+
/*
* Get the data from the pointed-to record.
*/
@@ -106,38 +133,25 @@ xfs_inobt_get_rec(
{
struct xfs_mount *mp = cur->bc_mp;
union xfs_btree_rec *rec;
+ xfs_failaddr_t fa;
int error;
- uint64_t realfree;
error = xfs_btree_get_rec(cur, &rec, stat);
if (error || *stat == 0)
return error;
xfs_inobt_btrec_to_irec(mp, rec, irec);
-
- if (!xfs_verify_agino(cur->bc_ag.pag, 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)
+ fa = xfs_inobt_check_irec(cur, irec);
+ if (fa)
goto out_bad_rec;
return 0;
out_bad_rec:
xfs_warn(mp,
- "%s Inode BTree record corruption in AG %d detected!",
+ "%s Inode BTree record corruption in AG %d detected at %pS!",
cur->bc_btnum == XFS_BTNUM_INO ? "Used" : "Free",
- cur->bc_ag.pag->pag_agno);
+ cur->bc_ag.pag->pag_agno, fa);
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,
@@ -2705,6 +2719,9 @@ xfs_ialloc_count_inodes_rec(
struct xfs_ialloc_count_inodes *ci = priv;
xfs_inobt_btrec_to_irec(cur->bc_mp, rec, &irec);
+ if (xfs_inobt_check_irec(cur, &irec) != NULL)
+ return -EFSCORRUPTED;
+
ci->count += irec.ir_count;
ci->freecount += irec.ir_freecount;