@@ -39,6 +39,12 @@ struct xchk_rmap {
3939 * allocations that cannot be shared.
4040 */
4141 struct xfs_rmap_irec overlap_rec ;
42+
43+ /*
44+ * The previous rmapbt record, so that we can check for two records
45+ * that could be one.
46+ */
47+ struct xfs_rmap_irec prev_rec ;
4248};
4349
4450/* Cross-reference a rmap against the refcount btree. */
@@ -198,6 +204,51 @@ xchk_rmapbt_check_overlapping(
198204 memcpy (& cr -> overlap_rec , irec , sizeof (struct xfs_rmap_irec ));
199205}
200206
207+ /* Decide if two reverse-mapping records can be merged. */
208+ static inline bool
209+ xchk_rmap_mergeable (
210+ struct xchk_rmap * cr ,
211+ const struct xfs_rmap_irec * r2 )
212+ {
213+ const struct xfs_rmap_irec * r1 = & cr -> prev_rec ;
214+
215+ /* Ignore if prev_rec is not yet initialized. */
216+ if (cr -> prev_rec .rm_blockcount == 0 )
217+ return false;
218+
219+ if (r1 -> rm_owner != r2 -> rm_owner )
220+ return false;
221+ if (r1 -> rm_startblock + r1 -> rm_blockcount != r2 -> rm_startblock )
222+ return false;
223+ if ((unsigned long long )r1 -> rm_blockcount + r2 -> rm_blockcount >
224+ XFS_RMAP_LEN_MAX )
225+ return false;
226+ if (XFS_RMAP_NON_INODE_OWNER (r2 -> rm_owner ))
227+ return true;
228+ /* must be an inode owner below here */
229+ if (r1 -> rm_flags != r2 -> rm_flags )
230+ return false;
231+ if (r1 -> rm_flags & XFS_RMAP_BMBT_BLOCK )
232+ return true;
233+ return r1 -> rm_offset + r1 -> rm_blockcount == r2 -> rm_offset ;
234+ }
235+
236+ /* Flag failures for records that could be merged. */
237+ STATIC void
238+ xchk_rmapbt_check_mergeable (
239+ struct xchk_btree * bs ,
240+ struct xchk_rmap * cr ,
241+ const struct xfs_rmap_irec * irec )
242+ {
243+ if (bs -> sc -> sm -> sm_flags & XFS_SCRUB_OFLAG_CORRUPT )
244+ return ;
245+
246+ if (xchk_rmap_mergeable (cr , irec ))
247+ xchk_btree_set_corrupt (bs -> sc , bs -> cur , 0 );
248+
249+ memcpy (& cr -> prev_rec , irec , sizeof (struct xfs_rmap_irec ));
250+ }
251+
201252/* Scrub an rmapbt record. */
202253STATIC int
203254xchk_rmapbt_rec (
@@ -214,6 +265,7 @@ xchk_rmapbt_rec(
214265 }
215266
216267 xchk_rmapbt_check_unwritten_in_keyflags (bs );
268+ xchk_rmapbt_check_mergeable (bs , cr , & irec );
217269 xchk_rmapbt_check_overlapping (bs , cr , & irec );
218270 xchk_rmapbt_xref (bs -> sc , & irec );
219271 return 0 ;
0 commit comments