aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2018-08-10 01:43:02 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2018-08-10 14:44:31 -0400
commit0e93d3f43ec7d3308bff25ce1be81d46330168c9 (patch)
treecbbaff0933ffd871850e18032eb6015281c65c0c /fs/xfs
parentf9ed6debca45dd9bcc02d77c98822d50aba342f4 (diff)
xfs: repair the AGFL
Repair the AGFL from the rmap data. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Reviewed-by: Brian Foster <bfoster@redhat.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/scrub/agheader_repair.c281
-rw-r--r--fs/xfs/scrub/bitmap.c92
-rw-r--r--fs/xfs/scrub/bitmap.h4
-rw-r--r--fs/xfs/scrub/repair.h2
-rw-r--r--fs/xfs/scrub/scrub.c2
5 files changed, 380 insertions, 1 deletions
diff --git a/fs/xfs/scrub/agheader_repair.c b/fs/xfs/scrub/agheader_repair.c
index aa180492a4a5..9ce302360bbb 100644
--- a/fs/xfs/scrub/agheader_repair.c
+++ b/fs/xfs/scrub/agheader_repair.c
@@ -433,3 +433,284 @@ out_revert:
433 memcpy(agf, &old_agf, sizeof(old_agf)); 433 memcpy(agf, &old_agf, sizeof(old_agf));
434 return error; 434 return error;
435} 435}
436
437/* AGFL */
438
439struct xrep_agfl {
440 /* Bitmap of other OWN_AG metadata blocks. */
441 struct xfs_bitmap agmetablocks;
442
443 /* Bitmap of free space. */
444 struct xfs_bitmap *freesp;
445
446 struct xfs_scrub *sc;
447};
448
449/* Record all OWN_AG (free space btree) information from the rmap data. */
450STATIC int
451xrep_agfl_walk_rmap(
452 struct xfs_btree_cur *cur,
453 struct xfs_rmap_irec *rec,
454 void *priv)
455{
456 struct xrep_agfl *ra = priv;
457 xfs_fsblock_t fsb;
458 int error = 0;
459
460 if (xchk_should_terminate(ra->sc, &error))
461 return error;
462
463 /* Record all the OWN_AG blocks. */
464 if (rec->rm_owner == XFS_RMAP_OWN_AG) {
465 fsb = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_private.a.agno,
466 rec->rm_startblock);
467 error = xfs_bitmap_set(ra->freesp, fsb, rec->rm_blockcount);
468 if (error)
469 return error;
470 }
471
472 return xfs_bitmap_set_btcur_path(&ra->agmetablocks, cur);
473}
474
475/*
476 * Map out all the non-AGFL OWN_AG space in this AG so that we can deduce
477 * which blocks belong to the AGFL.
478 *
479 * Compute the set of old AGFL blocks by subtracting from the list of OWN_AG
480 * blocks the list of blocks owned by all other OWN_AG metadata (bnobt, cntbt,
481 * rmapbt). These are the old AGFL blocks, so return that list and the number
482 * of blocks we're actually going to put back on the AGFL.
483 */
484STATIC int
485xrep_agfl_collect_blocks(
486 struct xfs_scrub *sc,
487 struct xfs_buf *agf_bp,
488 struct xfs_bitmap *agfl_extents,
489 xfs_agblock_t *flcount)
490{
491 struct xrep_agfl ra;
492 struct xfs_mount *mp = sc->mp;
493 struct xfs_btree_cur *cur;
494 struct xfs_bitmap_range *br;
495 struct xfs_bitmap_range *n;
496 int error;
497
498 ra.sc = sc;
499 ra.freesp = agfl_extents;
500 xfs_bitmap_init(&ra.agmetablocks);
501
502 /* Find all space used by the free space btrees & rmapbt. */
503 cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno);
504 error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
505 if (error)
506 goto err;
507 xfs_btree_del_cursor(cur, error);
508
509 /* Find all blocks currently being used by the bnobt. */
510 cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
511 XFS_BTNUM_BNO);
512 error = xfs_bitmap_set_btblocks(&ra.agmetablocks, cur);
513 if (error)
514 goto err;
515 xfs_btree_del_cursor(cur, error);
516
517 /* Find all blocks currently being used by the cntbt. */
518 cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.agno,
519 XFS_BTNUM_CNT);
520 error = xfs_bitmap_set_btblocks(&ra.agmetablocks, cur);
521 if (error)
522 goto err;
523
524 xfs_btree_del_cursor(cur, error);
525
526 /*
527 * Drop the freesp meta blocks that are in use by btrees.
528 * The remaining blocks /should/ be AGFL blocks.
529 */
530 error = xfs_bitmap_disunion(agfl_extents, &ra.agmetablocks);
531 xfs_bitmap_destroy(&ra.agmetablocks);
532 if (error)
533 return error;
534
535 /*
536 * Calculate the new AGFL size. If we found more blocks than fit in
537 * the AGFL we'll free them later.
538 */
539 *flcount = 0;
540 for_each_xfs_bitmap_extent(br, n, agfl_extents) {
541 *flcount += br->len;
542 if (*flcount > xfs_agfl_size(mp))
543 break;
544 }
545 if (*flcount > xfs_agfl_size(mp))
546 *flcount = xfs_agfl_size(mp);
547 return 0;
548
549err:
550 xfs_bitmap_destroy(&ra.agmetablocks);
551 xfs_btree_del_cursor(cur, error);
552 return error;
553}
554
555/* Update the AGF and reset the in-core state. */
556STATIC void
557xrep_agfl_update_agf(
558 struct xfs_scrub *sc,
559 struct xfs_buf *agf_bp,
560 xfs_agblock_t flcount)
561{
562 struct xfs_agf *agf = XFS_BUF_TO_AGF(agf_bp);
563
564 ASSERT(flcount <= xfs_agfl_size(sc->mp));
565
566 /* Trigger fdblocks recalculation */
567 xfs_force_summary_recalc(sc->mp);
568
569 /* Update the AGF counters. */
570 if (sc->sa.pag->pagf_init)
571 sc->sa.pag->pagf_flcount = flcount;
572 agf->agf_flfirst = cpu_to_be32(0);
573 agf->agf_flcount = cpu_to_be32(flcount);
574 agf->agf_fllast = cpu_to_be32(flcount - 1);
575
576 xfs_alloc_log_agf(sc->tp, agf_bp,
577 XFS_AGF_FLFIRST | XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
578}
579
580/* Write out a totally new AGFL. */
581STATIC void
582xrep_agfl_init_header(
583 struct xfs_scrub *sc,
584 struct xfs_buf *agfl_bp,
585 struct xfs_bitmap *agfl_extents,
586 xfs_agblock_t flcount)
587{
588 struct xfs_mount *mp = sc->mp;
589 __be32 *agfl_bno;
590 struct xfs_bitmap_range *br;
591 struct xfs_bitmap_range *n;
592 struct xfs_agfl *agfl;
593 xfs_agblock_t agbno;
594 unsigned int fl_off;
595
596 ASSERT(flcount <= xfs_agfl_size(mp));
597
598 /*
599 * Start rewriting the header by setting the bno[] array to
600 * NULLAGBLOCK, then setting AGFL header fields.
601 */
602 agfl = XFS_BUF_TO_AGFL(agfl_bp);
603 memset(agfl, 0xFF, BBTOB(agfl_bp->b_length));
604 agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
605 agfl->agfl_seqno = cpu_to_be32(sc->sa.agno);
606 uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
607
608 /*
609 * Fill the AGFL with the remaining blocks. If agfl_extents has more
610 * blocks than fit in the AGFL, they will be freed in a subsequent
611 * step.
612 */
613 fl_off = 0;
614 agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agfl_bp);
615 for_each_xfs_bitmap_extent(br, n, agfl_extents) {
616 agbno = XFS_FSB_TO_AGBNO(mp, br->start);
617
618 trace_xrep_agfl_insert(mp, sc->sa.agno, agbno, br->len);
619
620 while (br->len > 0 && fl_off < flcount) {
621 agfl_bno[fl_off] = cpu_to_be32(agbno);
622 fl_off++;
623 agbno++;
624
625 /*
626 * We've now used br->start by putting it in the AGFL,
627 * so bump br so that we don't reap the block later.
628 */
629 br->start++;
630 br->len--;
631 }
632
633 if (br->len)
634 break;
635 list_del(&br->list);
636 kmem_free(br);
637 }
638
639 /* Write new AGFL to disk. */
640 xfs_trans_buf_set_type(sc->tp, agfl_bp, XFS_BLFT_AGFL_BUF);
641 xfs_trans_log_buf(sc->tp, agfl_bp, 0, BBTOB(agfl_bp->b_length) - 1);
642}
643
644/* Repair the AGFL. */
645int
646xrep_agfl(
647 struct xfs_scrub *sc)
648{
649 struct xfs_owner_info oinfo;
650 struct xfs_bitmap agfl_extents;
651 struct xfs_mount *mp = sc->mp;
652 struct xfs_buf *agf_bp;
653 struct xfs_buf *agfl_bp;
654 xfs_agblock_t flcount;
655 int error;
656
657 /* We require the rmapbt to rebuild anything. */
658 if (!xfs_sb_version_hasrmapbt(&mp->m_sb))
659 return -EOPNOTSUPP;
660
661 xchk_perag_get(sc->mp, &sc->sa);
662 xfs_bitmap_init(&agfl_extents);
663
664 /*
665 * Read the AGF so that we can query the rmapbt. We hope that there's
666 * nothing wrong with the AGF, but all the AG header repair functions
667 * have this chicken-and-egg problem.
668 */
669 error = xfs_alloc_read_agf(mp, sc->tp, sc->sa.agno, 0, &agf_bp);
670 if (error)
671 return error;
672 if (!agf_bp)
673 return -ENOMEM;
674
675 /*
676 * Make sure we have the AGFL buffer, as scrub might have decided it
677 * was corrupt after xfs_alloc_read_agfl failed with -EFSCORRUPTED.
678 */
679 error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
680 XFS_AG_DADDR(mp, sc->sa.agno, XFS_AGFL_DADDR(mp)),
681 XFS_FSS_TO_BB(mp, 1), 0, &agfl_bp, NULL);
682 if (error)
683 return error;
684 agfl_bp->b_ops = &xfs_agfl_buf_ops;
685
686 /* Gather all the extents we're going to put on the new AGFL. */
687 error = xrep_agfl_collect_blocks(sc, agf_bp, &agfl_extents, &flcount);
688 if (error)
689 goto err;
690
691 /*
692 * Update AGF and AGFL. We reset the global free block counter when
693 * we adjust the AGF flcount (which can fail) so avoid updating any
694 * buffers until we know that part works.
695 */
696 xrep_agfl_update_agf(sc, agf_bp, flcount);
697 xrep_agfl_init_header(sc, agfl_bp, &agfl_extents, flcount);
698
699 /*
700 * Ok, the AGFL should be ready to go now. Roll the transaction to
701 * make the new AGFL permanent before we start using it to return
702 * freespace overflow to the freespace btrees.
703 */
704 sc->sa.agf_bp = agf_bp;
705 sc->sa.agfl_bp = agfl_bp;
706 error = xrep_roll_ag_trans(sc);
707 if (error)
708 goto err;
709
710 /* Dump any AGFL overflow. */
711 xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_AG);
712 return xrep_reap_extents(sc, &agfl_extents, &oinfo, XFS_AG_RESV_AGFL);
713err:
714 xfs_bitmap_destroy(&agfl_extents);
715 return error;
716}
diff --git a/fs/xfs/scrub/bitmap.c b/fs/xfs/scrub/bitmap.c
index c770e2d0b6aa..fdadc9e1dc49 100644
--- a/fs/xfs/scrub/bitmap.c
+++ b/fs/xfs/scrub/bitmap.c
@@ -9,6 +9,7 @@
9#include "xfs_format.h" 9#include "xfs_format.h"
10#include "xfs_trans_resv.h" 10#include "xfs_trans_resv.h"
11#include "xfs_mount.h" 11#include "xfs_mount.h"
12#include "xfs_btree.h"
12#include "scrub/xfs_scrub.h" 13#include "scrub/xfs_scrub.h"
13#include "scrub/scrub.h" 14#include "scrub/scrub.h"
14#include "scrub/common.h" 15#include "scrub/common.h"
@@ -209,3 +210,94 @@ out:
209} 210}
210#undef LEFT_ALIGNED 211#undef LEFT_ALIGNED
211#undef RIGHT_ALIGNED 212#undef RIGHT_ALIGNED
213
214/*
215 * Record all btree blocks seen while iterating all records of a btree.
216 *
217 * We know that the btree query_all function starts at the left edge and walks
218 * towards the right edge of the tree. Therefore, we know that we can walk up
219 * the btree cursor towards the root; if the pointer for a given level points
220 * to the first record/key in that block, we haven't seen this block before;
221 * and therefore we need to remember that we saw this block in the btree.
222 *
223 * So if our btree is:
224 *
225 * 4
226 * / | \
227 * 1 2 3
228 *
229 * Pretend for this example that each leaf block has 100 btree records. For
230 * the first btree record, we'll observe that bc_ptrs[0] == 1, so we record
231 * that we saw block 1. Then we observe that bc_ptrs[1] == 1, so we record
232 * block 4. The list is [1, 4].
233 *
234 * For the second btree record, we see that bc_ptrs[0] == 2, so we exit the
235 * loop. The list remains [1, 4].
236 *
237 * For the 101st btree record, we've moved onto leaf block 2. Now
238 * bc_ptrs[0] == 1 again, so we record that we saw block 2. We see that
239 * bc_ptrs[1] == 2, so we exit the loop. The list is now [1, 4, 2].
240 *
241 * For the 102nd record, bc_ptrs[0] == 2, so we continue.
242 *
243 * For the 201st record, we've moved on to leaf block 3. bc_ptrs[0] == 1, so
244 * we add 3 to the list. Now it is [1, 4, 2, 3].
245 *
246 * For the 300th record we just exit, with the list being [1, 4, 2, 3].
247 */
248
249/*
250 * Record all the buffers pointed to by the btree cursor. Callers already
251 * engaged in a btree walk should call this function to capture the list of
252 * blocks going from the leaf towards the root.
253 */
254int
255xfs_bitmap_set_btcur_path(
256 struct xfs_bitmap *bitmap,
257 struct xfs_btree_cur *cur)
258{
259 struct xfs_buf *bp;
260 xfs_fsblock_t fsb;
261 int i;
262 int error;
263
264 for (i = 0; i < cur->bc_nlevels && cur->bc_ptrs[i] == 1; i++) {
265 xfs_btree_get_block(cur, i, &bp);
266 if (!bp)
267 continue;
268 fsb = XFS_DADDR_TO_FSB(cur->bc_mp, bp->b_bn);
269 error = xfs_bitmap_set(bitmap, fsb, 1);
270 if (error)
271 return error;
272 }
273
274 return 0;
275}
276
277/* Collect a btree's block in the bitmap. */
278STATIC int
279xfs_bitmap_collect_btblock(
280 struct xfs_btree_cur *cur,
281 int level,
282 void *priv)
283{
284 struct xfs_bitmap *bitmap = priv;
285 struct xfs_buf *bp;
286 xfs_fsblock_t fsbno;
287
288 xfs_btree_get_block(cur, level, &bp);
289 if (!bp)
290 return 0;
291
292 fsbno = XFS_DADDR_TO_FSB(cur->bc_mp, bp->b_bn);
293 return xfs_bitmap_set(bitmap, fsbno, 1);
294}
295
296/* Walk the btree and mark the bitmap wherever a btree block is found. */
297int
298xfs_bitmap_set_btblocks(
299 struct xfs_bitmap *bitmap,
300 struct xfs_btree_cur *cur)
301{
302 return xfs_btree_visit_blocks(cur, xfs_bitmap_collect_btblock, bitmap);
303}
diff --git a/fs/xfs/scrub/bitmap.h b/fs/xfs/scrub/bitmap.h
index dad652ee9177..ae8ecbce6fa6 100644
--- a/fs/xfs/scrub/bitmap.h
+++ b/fs/xfs/scrub/bitmap.h
@@ -28,5 +28,9 @@ void xfs_bitmap_destroy(struct xfs_bitmap *bitmap);
28 28
29int xfs_bitmap_set(struct xfs_bitmap *bitmap, uint64_t start, uint64_t len); 29int xfs_bitmap_set(struct xfs_bitmap *bitmap, uint64_t start, uint64_t len);
30int xfs_bitmap_disunion(struct xfs_bitmap *bitmap, struct xfs_bitmap *sub); 30int xfs_bitmap_disunion(struct xfs_bitmap *bitmap, struct xfs_bitmap *sub);
31int xfs_bitmap_set_btcur_path(struct xfs_bitmap *bitmap,
32 struct xfs_btree_cur *cur);
33int xfs_bitmap_set_btblocks(struct xfs_bitmap *bitmap,
34 struct xfs_btree_cur *cur);
31 35
32#endif /* __XFS_SCRUB_BITMAP_H__ */ 36#endif /* __XFS_SCRUB_BITMAP_H__ */
diff --git a/fs/xfs/scrub/repair.h b/fs/xfs/scrub/repair.h
index 6f0903c51a47..1d283360b5ab 100644
--- a/fs/xfs/scrub/repair.h
+++ b/fs/xfs/scrub/repair.h
@@ -59,6 +59,7 @@ int xrep_ino_dqattach(struct xfs_scrub *sc);
59int xrep_probe(struct xfs_scrub *sc); 59int xrep_probe(struct xfs_scrub *sc);
60int xrep_superblock(struct xfs_scrub *sc); 60int xrep_superblock(struct xfs_scrub *sc);
61int xrep_agf(struct xfs_scrub *sc); 61int xrep_agf(struct xfs_scrub *sc);
62int xrep_agfl(struct xfs_scrub *sc);
62 63
63#else 64#else
64 65
@@ -83,6 +84,7 @@ xrep_calc_ag_resblks(
83#define xrep_probe xrep_notsupported 84#define xrep_probe xrep_notsupported
84#define xrep_superblock xrep_notsupported 85#define xrep_superblock xrep_notsupported
85#define xrep_agf xrep_notsupported 86#define xrep_agf xrep_notsupported
87#define xrep_agfl xrep_notsupported
86 88
87#endif /* CONFIG_XFS_ONLINE_REPAIR */ 89#endif /* CONFIG_XFS_ONLINE_REPAIR */
88 90
diff --git a/fs/xfs/scrub/scrub.c b/fs/xfs/scrub/scrub.c
index 1e8a17c8e2b9..2670f4cf62f4 100644
--- a/fs/xfs/scrub/scrub.c
+++ b/fs/xfs/scrub/scrub.c
@@ -220,7 +220,7 @@ static const struct xchk_meta_ops meta_scrub_ops[] = {
220 .type = ST_PERAG, 220 .type = ST_PERAG,
221 .setup = xchk_setup_fs, 221 .setup = xchk_setup_fs,
222 .scrub = xchk_agfl, 222 .scrub = xchk_agfl,
223 .repair = xrep_notsupported, 223 .repair = xrep_agfl,
224 }, 224 },
225 [XFS_SCRUB_TYPE_AGI] = { /* agi */ 225 [XFS_SCRUB_TYPE_AGI] = { /* agi */
226 .type = ST_PERAG, 226 .type = ST_PERAG,