@@ -165,7 +165,7 @@ xchk_bmap_get_rmap(
165165 return has_rmap ;
166166}
167167
168- /* Make sure that we have rmapbt records for this extent. */
168+ /* Make sure that we have rmapbt records for this data/attr fork extent. */
169169STATIC void
170170xchk_bmap_xref_rmap (
171171 struct xchk_bmap_info * info ,
@@ -174,41 +174,39 @@ xchk_bmap_xref_rmap(
174174{
175175 struct xfs_rmap_irec rmap ;
176176 unsigned long long rmap_end ;
177- uint64_t owner ;
177+ uint64_t owner = info -> sc -> ip -> i_ino ;
178178
179179 if (!info -> sc -> sa .rmap_cur || xchk_skip_xref (info -> sc -> sm ))
180180 return ;
181181
182- if (info -> whichfork == XFS_COW_FORK )
183- owner = XFS_RMAP_OWN_COW ;
184- else
185- owner = info -> sc -> ip -> i_ino ;
186-
187182 /* Find the rmap record for this irec. */
188183 if (!xchk_bmap_get_rmap (info , irec , agbno , owner , & rmap ))
189184 return ;
190185
191- /* Check the rmap. */
186+ /*
187+ * The rmap must be an exact match for this incore file mapping record,
188+ * which may have arisen from multiple ondisk records.
189+ */
190+ if (rmap .rm_startblock != agbno )
191+ xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
192+ irec -> br_startoff );
193+
192194 rmap_end = (unsigned long long )rmap .rm_startblock + rmap .rm_blockcount ;
193- if (rmap .rm_startblock > agbno ||
194- agbno + irec -> br_blockcount > rmap_end )
195+ if (rmap_end != agbno + irec -> br_blockcount )
195196 xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
196197 irec -> br_startoff );
197198
198- /*
199- * Check the logical offsets if applicable. CoW staging extents
200- * don't track logical offsets since the mappings only exist in
201- * memory.
202- */
203- if (info -> whichfork != XFS_COW_FORK ) {
204- rmap_end = (unsigned long long )rmap .rm_offset +
205- rmap .rm_blockcount ;
206- if (rmap .rm_offset > irec -> br_startoff ||
207- irec -> br_startoff + irec -> br_blockcount > rmap_end )
208- xchk_fblock_xref_set_corrupt (info -> sc ,
209- info -> whichfork , irec -> br_startoff );
210- }
199+ /* Check the logical offsets. */
200+ if (rmap .rm_offset != irec -> br_startoff )
201+ xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
202+ irec -> br_startoff );
203+
204+ rmap_end = (unsigned long long )rmap .rm_offset + rmap .rm_blockcount ;
205+ if (rmap_end != irec -> br_startoff + irec -> br_blockcount )
206+ xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
207+ irec -> br_startoff );
211208
209+ /* Check the owner */
212210 if (rmap .rm_owner != owner )
213211 xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
214212 irec -> br_startoff );
@@ -220,8 +218,7 @@ xchk_bmap_xref_rmap(
220218 * records because the blocks are owned (on-disk) by the refcountbt,
221219 * which doesn't track unwritten state.
222220 */
223- if (owner != XFS_RMAP_OWN_COW &&
224- !!(irec -> br_state == XFS_EXT_UNWRITTEN ) !=
221+ if (!!(irec -> br_state == XFS_EXT_UNWRITTEN ) !=
225222 !!(rmap .rm_flags & XFS_RMAP_UNWRITTEN ))
226223 xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
227224 irec -> br_startoff );
@@ -233,23 +230,60 @@ xchk_bmap_xref_rmap(
233230 if (rmap .rm_flags & XFS_RMAP_BMBT_BLOCK )
234231 xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
235232 irec -> br_startoff );
233+ }
234+
235+ /* Make sure that we have rmapbt records for this COW fork extent. */
236+ STATIC void
237+ xchk_bmap_xref_rmap_cow (
238+ struct xchk_bmap_info * info ,
239+ struct xfs_bmbt_irec * irec ,
240+ xfs_agblock_t agbno )
241+ {
242+ struct xfs_rmap_irec rmap ;
243+ unsigned long long rmap_end ;
244+ uint64_t owner = XFS_RMAP_OWN_COW ;
245+
246+ if (!info -> sc -> sa .rmap_cur || xchk_skip_xref (info -> sc -> sm ))
247+ return ;
248+
249+ /* Find the rmap record for this irec. */
250+ if (!xchk_bmap_get_rmap (info , irec , agbno , owner , & rmap ))
251+ return ;
236252
237253 /*
238- * The rmap must correspond exactly with this bmbt record. Skip this
239- * for CoW fork extents because the refcount btree (and not the inode)
240- * is the ondisk owner for those extents .
254+ * CoW staging extents are owned by the refcount btree, so the rmap
255+ * can start before and end after the physical space allocated to this
256+ * mapping. There are no offsets to check .
241257 */
242- if (info -> whichfork != XFS_COW_FORK ) {
243- if (rmap .rm_startblock != agbno )
244- xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
245- irec -> br_startoff );
246-
247- rmap_end = (unsigned long long )rmap .rm_startblock +
248- rmap .rm_blockcount ;
249- if (rmap_end != agbno + irec -> br_blockcount )
250- xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
251- irec -> br_startoff );
252- }
258+ if (rmap .rm_startblock > agbno )
259+ xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
260+ irec -> br_startoff );
261+
262+ rmap_end = (unsigned long long )rmap .rm_startblock + rmap .rm_blockcount ;
263+ if (rmap_end < agbno + irec -> br_blockcount )
264+ xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
265+ irec -> br_startoff );
266+
267+ /* Check the owner */
268+ if (rmap .rm_owner != owner )
269+ xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
270+ irec -> br_startoff );
271+
272+ /*
273+ * No flags allowed. Note that the (in-memory) CoW fork distinguishes
274+ * between unwritten and written extents, but we don't track that in
275+ * the rmap records because the blocks are owned (on-disk) by the
276+ * refcountbt, which doesn't track unwritten state.
277+ */
278+ if (rmap .rm_flags & XFS_RMAP_ATTR_FORK )
279+ xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
280+ irec -> br_startoff );
281+ if (rmap .rm_flags & XFS_RMAP_BMBT_BLOCK )
282+ xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
283+ irec -> br_startoff );
284+ if (rmap .rm_flags & XFS_RMAP_UNWRITTEN )
285+ xchk_fblock_xref_set_corrupt (info -> sc , info -> whichfork ,
286+ irec -> br_startoff );
253287}
254288
255289/* Cross-reference a single rtdev extent record. */
@@ -288,9 +322,9 @@ xchk_bmap_iextent_xref(
288322
289323 xchk_xref_is_used_space (info -> sc , agbno , len );
290324 xchk_xref_is_not_inode_chunk (info -> sc , agbno , len );
291- xchk_bmap_xref_rmap (info , irec , agbno );
292325 switch (info -> whichfork ) {
293326 case XFS_DATA_FORK :
327+ xchk_bmap_xref_rmap (info , irec , agbno );
294328 if (!xfs_is_reflink_inode (info -> sc -> ip )) {
295329 xfs_rmap_ino_owner (& oinfo , info -> sc -> ip -> i_ino ,
296330 info -> whichfork , irec -> br_startoff );
@@ -303,6 +337,7 @@ xchk_bmap_iextent_xref(
303337 irec -> br_blockcount );
304338 break ;
305339 case XFS_ATTR_FORK :
340+ xchk_bmap_xref_rmap (info , irec , agbno );
306341 xfs_rmap_ino_owner (& oinfo , info -> sc -> ip -> i_ino ,
307342 info -> whichfork , irec -> br_startoff );
308343 xchk_xref_is_only_owned_by (info -> sc , agbno , irec -> br_blockcount ,
@@ -313,6 +348,7 @@ xchk_bmap_iextent_xref(
313348 irec -> br_blockcount );
314349 break ;
315350 case XFS_COW_FORK :
351+ xchk_bmap_xref_rmap_cow (info , irec , agbno );
316352 xchk_xref_is_only_owned_by (info -> sc , agbno , irec -> br_blockcount ,
317353 & XFS_RMAP_OINFO_COW );
318354 xchk_xref_is_cow_staging (info -> sc , agbno ,
0 commit comments