@@ -95,6 +95,33 @@ xfs_inobt_btrec_to_irec(
9595 irec -> ir_free = be64_to_cpu (rec -> inobt .ir_free );
9696}
9797
98+ /* Simple checks for inode records. */
99+ xfs_failaddr_t
100+ xfs_inobt_check_irec (
101+ struct xfs_btree_cur * cur ,
102+ const struct xfs_inobt_rec_incore * irec )
103+ {
104+ uint64_t realfree ;
105+
106+ if (!xfs_verify_agino (cur -> bc_ag .pag , irec -> ir_startino ))
107+ return __this_address ;
108+ if (irec -> ir_count < XFS_INODES_PER_HOLEMASK_BIT ||
109+ irec -> ir_count > XFS_INODES_PER_CHUNK )
110+ return __this_address ;
111+ if (irec -> ir_freecount > XFS_INODES_PER_CHUNK )
112+ return __this_address ;
113+
114+ /* if there are no holes, return the first available offset */
115+ if (!xfs_inobt_issparse (irec -> ir_holemask ))
116+ realfree = irec -> ir_free ;
117+ else
118+ realfree = irec -> ir_free & xfs_inobt_irec_to_allocmask (irec );
119+ if (hweight64 (realfree ) != irec -> ir_freecount )
120+ return __this_address ;
121+
122+ return NULL ;
123+ }
124+
98125/*
99126 * Get the data from the pointed-to record.
100127 */
@@ -106,38 +133,25 @@ xfs_inobt_get_rec(
106133{
107134 struct xfs_mount * mp = cur -> bc_mp ;
108135 union xfs_btree_rec * rec ;
136+ xfs_failaddr_t fa ;
109137 int error ;
110- uint64_t realfree ;
111138
112139 error = xfs_btree_get_rec (cur , & rec , stat );
113140 if (error || * stat == 0 )
114141 return error ;
115142
116143 xfs_inobt_btrec_to_irec (mp , rec , irec );
117-
118- if (!xfs_verify_agino (cur -> bc_ag .pag , irec -> ir_startino ))
119- goto out_bad_rec ;
120- if (irec -> ir_count < XFS_INODES_PER_HOLEMASK_BIT ||
121- irec -> ir_count > XFS_INODES_PER_CHUNK )
122- goto out_bad_rec ;
123- if (irec -> ir_freecount > XFS_INODES_PER_CHUNK )
124- goto out_bad_rec ;
125-
126- /* if there are no holes, return the first available offset */
127- if (!xfs_inobt_issparse (irec -> ir_holemask ))
128- realfree = irec -> ir_free ;
129- else
130- realfree = irec -> ir_free & xfs_inobt_irec_to_allocmask (irec );
131- if (hweight64 (realfree ) != irec -> ir_freecount )
144+ fa = xfs_inobt_check_irec (cur , irec );
145+ if (fa )
132146 goto out_bad_rec ;
133147
134148 return 0 ;
135149
136150out_bad_rec :
137151 xfs_warn (mp ,
138- "%s Inode BTree record corruption in AG %d detected!" ,
152+ "%s Inode BTree record corruption in AG %d detected at %pS !" ,
139153 cur -> bc_btnum == XFS_BTNUM_INO ? "Used" : "Free" ,
140- cur -> bc_ag .pag -> pag_agno );
154+ cur -> bc_ag .pag -> pag_agno , fa );
141155 xfs_warn (mp ,
142156"start inode 0x%x, count 0x%x, free 0x%x freemask 0x%llx, holemask 0x%x" ,
143157 irec -> ir_startino , irec -> ir_count , irec -> ir_freecount ,
@@ -2690,6 +2704,9 @@ xfs_ialloc_count_inodes_rec(
26902704 struct xfs_ialloc_count_inodes * ci = priv ;
26912705
26922706 xfs_inobt_btrec_to_irec (cur -> bc_mp , rec , & irec );
2707+ if (xfs_inobt_check_irec (cur , & irec ) != NULL )
2708+ return - EFSCORRUPTED ;
2709+
26932710 ci -> count += irec .ir_count ;
26942711 ci -> freecount += irec .ir_freecount ;
26952712
0 commit comments