1212#include "xfs_btree.h"
1313#include "xfs_rmap.h"
1414#include "xfs_refcount.h"
15+ #include "xfs_ag.h"
16+ #include "xfs_bit.h"
1517#include "scrub/scrub.h"
1618#include "scrub/common.h"
1719#include "scrub/btree.h"
18- #include "xfs_ag .h"
20+ #include "scrub/bitmap .h"
1921
2022/*
2123 * Set us up to scrub reverse mapping btrees.
@@ -45,6 +47,13 @@ struct xchk_rmap {
4547 * that could be one.
4648 */
4749 struct xfs_rmap_irec prev_rec ;
50+
51+ /* Bitmaps containing all blocks for each type of AG metadata. */
52+ struct xagb_bitmap fs_owned ;
53+ struct xagb_bitmap log_owned ;
54+
55+ /* Did we complete the AG space metadata bitmaps? */
56+ bool bitmaps_complete ;
4857};
4958
5059/* Cross-reference a rmap against the refcount btree. */
@@ -249,6 +258,68 @@ xchk_rmapbt_check_mergeable(
249258 memcpy (& cr -> prev_rec , irec , sizeof (struct xfs_rmap_irec ));
250259}
251260
261+ /* Compare an rmap for AG metadata against the metadata walk. */
262+ STATIC int
263+ xchk_rmapbt_mark_bitmap (
264+ struct xchk_btree * bs ,
265+ struct xchk_rmap * cr ,
266+ const struct xfs_rmap_irec * irec )
267+ {
268+ struct xfs_scrub * sc = bs -> sc ;
269+ struct xagb_bitmap * bmp = NULL ;
270+ xfs_extlen_t fsbcount = irec -> rm_blockcount ;
271+
272+ /*
273+ * Skip corrupt records. It is essential that we detect records in the
274+ * btree that cannot overlap but do, flag those as CORRUPT, and skip
275+ * the bitmap comparison to avoid generating false XCORRUPT reports.
276+ */
277+ if (sc -> sm -> sm_flags & XFS_SCRUB_OFLAG_CORRUPT )
278+ return 0 ;
279+
280+ /*
281+ * If the AG metadata walk didn't complete, there's no point in
282+ * comparing against partial results.
283+ */
284+ if (!cr -> bitmaps_complete )
285+ return 0 ;
286+
287+ switch (irec -> rm_owner ) {
288+ case XFS_RMAP_OWN_FS :
289+ bmp = & cr -> fs_owned ;
290+ break ;
291+ case XFS_RMAP_OWN_LOG :
292+ bmp = & cr -> log_owned ;
293+ break ;
294+ }
295+
296+ if (!bmp )
297+ return 0 ;
298+
299+ if (xagb_bitmap_test (bmp , irec -> rm_startblock , & fsbcount )) {
300+ /*
301+ * The start of this reverse mapping corresponds to a set
302+ * region in the bitmap. If the mapping covers more area than
303+ * the set region, then it covers space that wasn't found by
304+ * the AG metadata walk.
305+ */
306+ if (fsbcount < irec -> rm_blockcount )
307+ xchk_btree_xref_set_corrupt (bs -> sc ,
308+ bs -> sc -> sa .rmap_cur , 0 );
309+ } else {
310+ /*
311+ * The start of this reverse mapping does not correspond to a
312+ * completely set region in the bitmap. The region wasn't
313+ * fully set by walking the AG metadata, so this is a
314+ * cross-referencing corruption.
315+ */
316+ xchk_btree_xref_set_corrupt (bs -> sc , bs -> sc -> sa .rmap_cur , 0 );
317+ }
318+
319+ /* Unset the region so that we can detect missing rmap records. */
320+ return xagb_bitmap_clear (bmp , irec -> rm_startblock , irec -> rm_blockcount );
321+ }
322+
252323/* Scrub an rmapbt record. */
253324STATIC int
254325xchk_rmapbt_rec (
@@ -268,9 +339,80 @@ xchk_rmapbt_rec(
268339 xchk_rmapbt_check_mergeable (bs , cr , & irec );
269340 xchk_rmapbt_check_overlapping (bs , cr , & irec );
270341 xchk_rmapbt_xref (bs -> sc , & irec );
342+
343+ return xchk_rmapbt_mark_bitmap (bs , cr , & irec );
344+ }
345+
346+ /*
347+ * Set up bitmaps mapping all the AG metadata to compare with the rmapbt
348+ * records.
349+ */
350+ STATIC int
351+ xchk_rmapbt_walk_ag_metadata (
352+ struct xfs_scrub * sc ,
353+ struct xchk_rmap * cr )
354+ {
355+ struct xfs_mount * mp = sc -> mp ;
356+ int error ;
357+
358+ /* OWN_FS: AG headers */
359+ error = xagb_bitmap_set (& cr -> fs_owned , XFS_SB_BLOCK (mp ),
360+ XFS_AGFL_BLOCK (mp ) - XFS_SB_BLOCK (mp ) + 1 );
361+ if (error )
362+ goto out ;
363+
364+ /* OWN_LOG: Internal log */
365+ if (xfs_ag_contains_log (mp , sc -> sa .pag -> pag_agno )) {
366+ error = xagb_bitmap_set (& cr -> log_owned ,
367+ XFS_FSB_TO_AGBNO (mp , mp -> m_sb .sb_logstart ),
368+ mp -> m_sb .sb_logblocks );
369+ if (error )
370+ goto out ;
371+ }
372+
373+ out :
374+ /*
375+ * If there's an error, set XFAIL and disable the bitmap
376+ * cross-referencing checks, but proceed with the scrub anyway.
377+ */
378+ if (error )
379+ xchk_btree_xref_process_error (sc , sc -> sa .rmap_cur ,
380+ sc -> sa .rmap_cur -> bc_nlevels - 1 , & error );
381+ else
382+ cr -> bitmaps_complete = true;
271383 return 0 ;
272384}
273385
386+ /*
387+ * Check for set regions in the bitmaps; if there are any, the rmap records do
388+ * not describe all the AG metadata.
389+ */
390+ STATIC void
391+ xchk_rmapbt_check_bitmaps (
392+ struct xfs_scrub * sc ,
393+ struct xchk_rmap * cr )
394+ {
395+ struct xfs_btree_cur * cur = sc -> sa .rmap_cur ;
396+ unsigned int level ;
397+
398+ if (sc -> sm -> sm_flags & (XFS_SCRUB_OFLAG_CORRUPT |
399+ XFS_SCRUB_OFLAG_XFAIL ))
400+ return ;
401+ if (!cur )
402+ return ;
403+ level = cur -> bc_nlevels - 1 ;
404+
405+ /*
406+ * Any bitmap with bits still set indicates that the reverse mapping
407+ * doesn't cover the entire primary structure.
408+ */
409+ if (xagb_bitmap_hweight (& cr -> fs_owned ) != 0 )
410+ xchk_btree_xref_set_corrupt (sc , cur , level );
411+
412+ if (xagb_bitmap_hweight (& cr -> log_owned ) != 0 )
413+ xchk_btree_xref_set_corrupt (sc , cur , level );
414+ }
415+
274416/* Scrub the rmap btree for some AG. */
275417int
276418xchk_rmapbt (
@@ -283,8 +425,23 @@ xchk_rmapbt(
283425 if (!cr )
284426 return - ENOMEM ;
285427
428+ xagb_bitmap_init (& cr -> fs_owned );
429+ xagb_bitmap_init (& cr -> log_owned );
430+
431+ error = xchk_rmapbt_walk_ag_metadata (sc , cr );
432+ if (error )
433+ goto out ;
434+
286435 error = xchk_btree (sc , sc -> sa .rmap_cur , xchk_rmapbt_rec ,
287436 & XFS_RMAP_OINFO_AG , cr );
437+ if (error )
438+ goto out ;
439+
440+ xchk_rmapbt_check_bitmaps (sc , cr );
441+
442+ out :
443+ xagb_bitmap_destroy (& cr -> log_owned );
444+ xagb_bitmap_destroy (& cr -> fs_owned );
288445 kfree (cr );
289446 return error ;
290447}
0 commit comments