Skip to content

Commit fed050f

Browse files
author
Darrick J. Wong
committed
xfs: cross-reference rmap records with ag btrees
Strengthen the rmap btree record checker a little more by comparing OWN_FS and OWN_LOG reverse mappings against the AG headers and internal logs, respectively. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Dave Chinner <dchinner@redhat.com>
1 parent a47bd1e commit fed050f

4 files changed

Lines changed: 202 additions & 2 deletions

File tree

fs/xfs/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ xfs-y += $(addprefix scrub/, \
148148
agheader.o \
149149
alloc.o \
150150
attr.o \
151+
bitmap.o \
151152
bmap.o \
152153
btree.o \
153154
common.o \
@@ -172,7 +173,6 @@ xfs-$(CONFIG_XFS_QUOTA) += scrub/quota.o
172173
ifeq ($(CONFIG_XFS_ONLINE_REPAIR),y)
173174
xfs-y += $(addprefix scrub/, \
174175
agheader_repair.o \
175-
bitmap.o \
176176
repair.o \
177177
)
178178
endif

fs/xfs/scrub/bitmap.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,25 @@ xbitmap_empty(
396396
{
397397
return bitmap->xb_root.rb_root.rb_node == NULL;
398398
}
399+
400+
/* Is the start of the range set or clear? And for how long? */
401+
bool
402+
xbitmap_test(
403+
struct xbitmap *bitmap,
404+
uint64_t start,
405+
uint64_t *len)
406+
{
407+
struct xbitmap_node *bn;
408+
uint64_t last = start + *len - 1;
409+
410+
bn = xbitmap_tree_iter_first(&bitmap->xb_root, start, last);
411+
if (!bn)
412+
return false;
413+
if (bn->bn_start <= start) {
414+
if (bn->bn_last < last)
415+
*len = bn->bn_last - start + 1;
416+
return true;
417+
}
418+
*len = bn->bn_start - start;
419+
return false;
420+
}

fs/xfs/scrub/bitmap.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ int xbitmap_walk_bits(struct xbitmap *bitmap, xbitmap_walk_bits_fn fn,
3838
void *priv);
3939

4040
bool xbitmap_empty(struct xbitmap *bitmap);
41+
bool xbitmap_test(struct xbitmap *bitmap, uint64_t start, uint64_t *len);
4142

4243
/* Bitmaps, but for type-checked for xfs_agblock_t */
4344

@@ -66,6 +67,26 @@ static inline int xagb_bitmap_set(struct xagb_bitmap *bitmap,
6667
return xbitmap_set(&bitmap->agbitmap, start, len);
6768
}
6869

70+
static inline bool
71+
xagb_bitmap_test(
72+
struct xagb_bitmap *bitmap,
73+
xfs_agblock_t start,
74+
xfs_extlen_t *len)
75+
{
76+
uint64_t biglen = *len;
77+
bool ret;
78+
79+
ret = xbitmap_test(&bitmap->agbitmap, start, &biglen);
80+
81+
if (start + biglen >= UINT_MAX) {
82+
ASSERT(0);
83+
biglen = UINT_MAX - start;
84+
}
85+
86+
*len = biglen;
87+
return ret;
88+
}
89+
6990
static inline int xagb_bitmap_disunion(struct xagb_bitmap *bitmap,
7091
struct xagb_bitmap *sub)
7192
{

fs/xfs/scrub/rmap.c

Lines changed: 158 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
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. */
253324
STATIC int
254325
xchk_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. */
275417
int
276418
xchk_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

Comments
 (0)