Skip to content

Commit 7fbaab5

Browse files
author
Darrick J. Wong
committed
xfs: port refcount repair to the new refcount bag structure
Port the refcount record generating code to use the new refcount bag data structure. Signed-off-by: Darrick J. Wong <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
1 parent 7a2192a commit 7fbaab5

4 files changed

Lines changed: 81 additions & 107 deletions

File tree

fs/xfs/scrub/refcount.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
#include "xfs_fs.h"
88
#include "xfs_shared.h"
99
#include "xfs_format.h"
10+
#include "xfs_log_format.h"
1011
#include "xfs_trans_resv.h"
1112
#include "xfs_mount.h"
13+
#include "xfs_trans.h"
1214
#include "xfs_ag.h"
1315
#include "xfs_btree.h"
1416
#include "xfs_rmap.h"
@@ -17,6 +19,7 @@
1719
#include "scrub/common.h"
1820
#include "scrub/btree.h"
1921
#include "scrub/trace.h"
22+
#include "scrub/repair.h"
2023

2124
/*
2225
* Set us up to scrub reference count btrees.
@@ -27,6 +30,15 @@ xchk_setup_ag_refcountbt(
2730
{
2831
if (xchk_need_intent_drain(sc))
2932
xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
33+
34+
if (xchk_could_repair(sc)) {
35+
int error;
36+
37+
error = xrep_setup_ag_refcountbt(sc);
38+
if (error)
39+
return error;
40+
}
41+
3042
return xchk_setup_ag_btree(sc, false);
3143
}
3244

fs/xfs/scrub/refcount_repair.c

Lines changed: 58 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "scrub/xfarray.h"
3939
#include "scrub/newbt.h"
4040
#include "scrub/reap.h"
41+
#include "scrub/rcbag.h"
4142

4243
/*
4344
* Rebuilding the Reference Count Btree
@@ -98,12 +99,6 @@
9899
* insert all the records.
99100
*/
100101

101-
/* The only parts of the rmap that we care about for computing refcounts. */
102-
struct xrep_refc_rmap {
103-
xfs_agblock_t startblock;
104-
xfs_extlen_t blockcount;
105-
} __packed;
106-
107102
struct xrep_refc {
108103
/* refcount extents */
109104
struct xfarray *refcount_records;
@@ -123,6 +118,20 @@ struct xrep_refc {
123118
xfs_extlen_t btblocks;
124119
};
125120

121+
/* Set us up to repair refcount btrees. */
122+
int
123+
xrep_setup_ag_refcountbt(
124+
struct xfs_scrub *sc)
125+
{
126+
char *descr;
127+
int error;
128+
129+
descr = xchk_xfile_ag_descr(sc, "rmap record bag");
130+
error = xrep_setup_xfbtree(sc, descr);
131+
kfree(descr);
132+
return error;
133+
}
134+
126135
/* Check for any obvious conflicts with this shared/CoW staging extent. */
127136
STATIC int
128137
xrep_refc_check_ext(
@@ -224,10 +233,9 @@ xrep_refc_rmap_shareable(
224233
STATIC int
225234
xrep_refc_walk_rmaps(
226235
struct xrep_refc *rr,
227-
struct xrep_refc_rmap *rrm,
236+
struct xfs_rmap_irec *rmap,
228237
bool *have_rec)
229238
{
230-
struct xfs_rmap_irec rmap;
231239
struct xfs_btree_cur *cur = rr->sc->sa.rmap_cur;
232240
struct xfs_mount *mp = cur->bc_mp;
233241
int have_gt;
@@ -251,31 +259,30 @@ xrep_refc_walk_rmaps(
251259
if (!have_gt)
252260
return 0;
253261

254-
error = xfs_rmap_get_rec(cur, &rmap, &have_gt);
262+
error = xfs_rmap_get_rec(cur, rmap, &have_gt);
255263
if (error)
256264
return error;
257265
if (XFS_IS_CORRUPT(mp, !have_gt)) {
258266
xfs_btree_mark_sick(cur);
259267
return -EFSCORRUPTED;
260268
}
261269

262-
if (rmap.rm_owner == XFS_RMAP_OWN_COW) {
263-
error = xrep_refc_stash_cow(rr, rmap.rm_startblock,
264-
rmap.rm_blockcount);
270+
if (rmap->rm_owner == XFS_RMAP_OWN_COW) {
271+
error = xrep_refc_stash_cow(rr, rmap->rm_startblock,
272+
rmap->rm_blockcount);
265273
if (error)
266274
return error;
267-
} else if (rmap.rm_owner == XFS_RMAP_OWN_REFC) {
275+
} else if (rmap->rm_owner == XFS_RMAP_OWN_REFC) {
268276
/* refcountbt block, dump it when we're done. */
269-
rr->btblocks += rmap.rm_blockcount;
277+
rr->btblocks += rmap->rm_blockcount;
270278
error = xagb_bitmap_set(&rr->old_refcountbt_blocks,
271-
rmap.rm_startblock, rmap.rm_blockcount);
279+
rmap->rm_startblock,
280+
rmap->rm_blockcount);
272281
if (error)
273282
return error;
274283
}
275-
} while (!xrep_refc_rmap_shareable(mp, &rmap));
284+
} while (!xrep_refc_rmap_shareable(mp, rmap));
276285

277-
rrm->startblock = rmap.rm_startblock;
278-
rrm->blockcount = rmap.rm_blockcount;
279286
*have_rec = true;
280287
return 0;
281288
}
@@ -357,45 +364,6 @@ xrep_refc_sort_records(
357364
return error;
358365
}
359366

360-
#define RRM_NEXT(r) ((r).startblock + (r).blockcount)
361-
/*
362-
* Find the next block where the refcount changes, given the next rmap we
363-
* looked at and the ones we're already tracking.
364-
*/
365-
static inline int
366-
xrep_refc_next_edge(
367-
struct xfarray *rmap_bag,
368-
struct xrep_refc_rmap *next_rrm,
369-
bool next_valid,
370-
xfs_agblock_t *nbnop)
371-
{
372-
struct xrep_refc_rmap rrm;
373-
xfarray_idx_t array_cur = XFARRAY_CURSOR_INIT;
374-
xfs_agblock_t nbno = NULLAGBLOCK;
375-
int error;
376-
377-
if (next_valid)
378-
nbno = next_rrm->startblock;
379-
380-
while ((error = xfarray_iter(rmap_bag, &array_cur, &rrm)) == 1)
381-
nbno = min_t(xfs_agblock_t, nbno, RRM_NEXT(rrm));
382-
383-
if (error)
384-
return error;
385-
386-
/*
387-
* We should have found /something/ because either next_rrm is the next
388-
* interesting rmap to look at after emitting this refcount extent, or
389-
* there are other rmaps in rmap_bag contributing to the current
390-
* sharing count. But if something is seriously wrong, bail out.
391-
*/
392-
if (nbno == NULLAGBLOCK)
393-
return -EFSCORRUPTED;
394-
395-
*nbnop = nbno;
396-
return 0;
397-
}
398-
399367
/*
400368
* Walk forward through the rmap btree to collect all rmaps starting at
401369
* @bno in @rmap_bag. These represent the file(s) that share ownership of
@@ -405,22 +373,21 @@ xrep_refc_next_edge(
405373
static int
406374
xrep_refc_push_rmaps_at(
407375
struct xrep_refc *rr,
408-
struct xfarray *rmap_bag,
376+
struct rcbag *rcstack,
409377
xfs_agblock_t bno,
410-
struct xrep_refc_rmap *rrm,
411-
bool *have,
412-
uint64_t *stack_sz)
378+
struct xfs_rmap_irec *rmap,
379+
bool *have)
413380
{
414381
struct xfs_scrub *sc = rr->sc;
415382
int have_gt;
416383
int error;
417384

418-
while (*have && rrm->startblock == bno) {
419-
error = xfarray_store_anywhere(rmap_bag, rrm);
385+
while (*have && rmap->rm_startblock == bno) {
386+
error = rcbag_add(rcstack, rr->sc->tp, rmap);
420387
if (error)
421388
return error;
422-
(*stack_sz)++;
423-
error = xrep_refc_walk_rmaps(rr, rrm, have);
389+
390+
error = xrep_refc_walk_rmaps(rr, rmap, have);
424391
if (error)
425392
return error;
426393
}
@@ -441,12 +408,9 @@ STATIC int
441408
xrep_refc_find_refcounts(
442409
struct xrep_refc *rr)
443410
{
444-
struct xrep_refc_rmap rrm;
445411
struct xfs_scrub *sc = rr->sc;
446-
struct xfarray *rmap_bag;
447-
char *descr;
448-
uint64_t old_stack_sz;
449-
uint64_t stack_sz = 0;
412+
struct rcbag *rcstack;
413+
uint64_t old_stack_height;
450414
xfs_agblock_t sbno;
451415
xfs_agblock_t cbno;
452416
xfs_agblock_t nbno;
@@ -456,14 +420,11 @@ xrep_refc_find_refcounts(
456420
xrep_ag_btcur_init(sc, &sc->sa);
457421

458422
/*
459-
* Set up a sparse array to store all the rmap records that we're
460-
* tracking to generate a reference count record. If this exceeds
423+
* Set up a bag to store all the rmap records that we're tracking to
424+
* generate a reference count record. If the size of the bag exceeds
461425
* MAXREFCOUNT, we clamp rc_refcount.
462426
*/
463-
descr = xchk_xfile_ag_descr(sc, "rmap record bag");
464-
error = xfarray_create(descr, 0, sizeof(struct xrep_refc_rmap),
465-
&rmap_bag);
466-
kfree(descr);
427+
error = rcbag_init(sc->mp, sc->xmbtp, &rcstack);
467428
if (error)
468429
goto out_cur;
469430

@@ -474,76 +435,68 @@ xrep_refc_find_refcounts(
474435

475436
/* Process reverse mappings into refcount data. */
476437
while (xfs_btree_has_more_records(sc->sa.rmap_cur)) {
438+
struct xfs_rmap_irec rmap;
439+
477440
/* Push all rmaps with pblk == sbno onto the stack */
478-
error = xrep_refc_walk_rmaps(rr, &rrm, &have);
441+
error = xrep_refc_walk_rmaps(rr, &rmap, &have);
479442
if (error)
480443
goto out_bag;
481444
if (!have)
482445
break;
483-
sbno = cbno = rrm.startblock;
484-
error = xrep_refc_push_rmaps_at(rr, rmap_bag, sbno,
485-
&rrm, &have, &stack_sz);
446+
sbno = cbno = rmap.rm_startblock;
447+
error = xrep_refc_push_rmaps_at(rr, rcstack, sbno, &rmap,
448+
&have);
486449
if (error)
487450
goto out_bag;
488451

489452
/* Set nbno to the bno of the next refcount change */
490-
error = xrep_refc_next_edge(rmap_bag, &rrm, have, &nbno);
453+
error = rcbag_next_edge(rcstack, sc->tp, &rmap, have, &nbno);
491454
if (error)
492455
goto out_bag;
493456

494457
ASSERT(nbno > sbno);
495-
old_stack_sz = stack_sz;
458+
old_stack_height = rcbag_count(rcstack);
496459

497460
/* While stack isn't empty... */
498-
while (stack_sz) {
499-
xfarray_idx_t array_cur = XFARRAY_CURSOR_INIT;
500-
461+
while (rcbag_count(rcstack) > 0) {
501462
/* Pop all rmaps that end at nbno */
502-
while ((error = xfarray_iter(rmap_bag, &array_cur,
503-
&rrm)) == 1) {
504-
if (RRM_NEXT(rrm) != nbno)
505-
continue;
506-
error = xfarray_unset(rmap_bag, array_cur - 1);
507-
if (error)
508-
goto out_bag;
509-
stack_sz--;
510-
}
463+
error = rcbag_remove_ending_at(rcstack, sc->tp, nbno);
511464
if (error)
512465
goto out_bag;
513466

514467
/* Push array items that start at nbno */
515-
error = xrep_refc_walk_rmaps(rr, &rrm, &have);
468+
error = xrep_refc_walk_rmaps(rr, &rmap, &have);
516469
if (error)
517470
goto out_bag;
518471
if (have) {
519-
error = xrep_refc_push_rmaps_at(rr, rmap_bag,
520-
nbno, &rrm, &have, &stack_sz);
472+
error = xrep_refc_push_rmaps_at(rr, rcstack,
473+
nbno, &rmap, &have);
521474
if (error)
522475
goto out_bag;
523476
}
524477

525478
/* Emit refcount if necessary */
526479
ASSERT(nbno > cbno);
527-
if (stack_sz != old_stack_sz) {
528-
if (old_stack_sz > 1) {
480+
if (rcbag_count(rcstack) != old_stack_height) {
481+
if (old_stack_height > 1) {
529482
error = xrep_refc_stash(rr,
530483
XFS_REFC_DOMAIN_SHARED,
531484
cbno, nbno - cbno,
532-
old_stack_sz);
485+
old_stack_height);
533486
if (error)
534487
goto out_bag;
535488
}
536489
cbno = nbno;
537490
}
538491

539492
/* Stack empty, go find the next rmap */
540-
if (stack_sz == 0)
493+
if (rcbag_count(rcstack) == 0)
541494
break;
542-
old_stack_sz = stack_sz;
495+
old_stack_height = rcbag_count(rcstack);
543496
sbno = nbno;
544497

545498
/* Set nbno to the bno of the next refcount change */
546-
error = xrep_refc_next_edge(rmap_bag, &rrm, have,
499+
error = rcbag_next_edge(rcstack, sc->tp, &rmap, have,
547500
&nbno);
548501
if (error)
549502
goto out_bag;
@@ -552,14 +505,13 @@ xrep_refc_find_refcounts(
552505
}
553506
}
554507

555-
ASSERT(stack_sz == 0);
508+
ASSERT(rcbag_count(rcstack) == 0);
556509
out_bag:
557-
xfarray_destroy(rmap_bag);
510+
rcbag_free(&rcstack);
558511
out_cur:
559512
xchk_ag_btcur_free(&sc->sa);
560513
return error;
561514
}
562-
#undef RRM_NEXT
563515

564516
/* Retrieve refcountbt data for bulk load. */
565517
STATIC int

fs/xfs/scrub/repair.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ int xrep_reset_perag_resv(struct xfs_scrub *sc);
8989
int xrep_bmap(struct xfs_scrub *sc, int whichfork, bool allow_unwritten);
9090
int xrep_metadata_inode_forks(struct xfs_scrub *sc);
9191
int xrep_setup_ag_rmapbt(struct xfs_scrub *sc);
92+
int xrep_setup_ag_refcountbt(struct xfs_scrub *sc);
9293

9394
/* Repair setup functions */
9495
int xrep_setup_ag_allocbt(struct xfs_scrub *sc);
@@ -186,6 +187,7 @@ xrep_setup_nothing(
186187
}
187188
#define xrep_setup_ag_allocbt xrep_setup_nothing
188189
#define xrep_setup_ag_rmapbt xrep_setup_nothing
190+
#define xrep_setup_ag_refcountbt xrep_setup_nothing
189191

190192
#define xrep_setup_inode(sc, imap) ((void)0)
191193

0 commit comments

Comments
 (0)