0001
0002
0003
0004
0005
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_trans_resv.h"
0011 #include "xfs_mount.h"
0012 #include "xfs_btree.h"
0013 #include "xfs_log_format.h"
0014 #include "xfs_trans.h"
0015 #include "xfs_sb.h"
0016 #include "xfs_alloc.h"
0017 #include "xfs_alloc_btree.h"
0018 #include "xfs_ialloc.h"
0019 #include "xfs_ialloc_btree.h"
0020 #include "xfs_rmap.h"
0021 #include "xfs_rmap_btree.h"
0022 #include "xfs_refcount_btree.h"
0023 #include "xfs_ag.h"
0024 #include "scrub/scrub.h"
0025 #include "scrub/common.h"
0026 #include "scrub/trace.h"
0027 #include "scrub/repair.h"
0028 #include "scrub/bitmap.h"
0029
0030
0031
0032
0033 int
0034 xrep_superblock(
0035 struct xfs_scrub *sc)
0036 {
0037 struct xfs_mount *mp = sc->mp;
0038 struct xfs_buf *bp;
0039 xfs_agnumber_t agno;
0040 int error;
0041
0042
0043 agno = sc->sm->sm_agno;
0044 if (agno == 0)
0045 return -EOPNOTSUPP;
0046
0047 error = xfs_sb_get_secondary(mp, sc->tp, agno, &bp);
0048 if (error)
0049 return error;
0050
0051
0052 xfs_buf_zero(bp, 0, BBTOB(bp->b_length));
0053 xfs_sb_to_disk(bp->b_addr, &mp->m_sb);
0054
0055
0056
0057
0058
0059 if (xfs_has_crc(mp)) {
0060 struct xfs_dsb *sb = bp->b_addr;
0061
0062 sb->sb_features_incompat &=
0063 ~cpu_to_be32(XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR);
0064 sb->sb_features_log_incompat = 0;
0065 }
0066
0067
0068 xfs_trans_buf_set_type(sc->tp, bp, XFS_BLFT_SB_BUF);
0069 xfs_trans_log_buf(sc->tp, bp, 0, BBTOB(bp->b_length) - 1);
0070 return error;
0071 }
0072
0073
0074
0075 struct xrep_agf_allocbt {
0076 struct xfs_scrub *sc;
0077 xfs_agblock_t freeblks;
0078 xfs_agblock_t longest;
0079 };
0080
0081
0082 STATIC int
0083 xrep_agf_walk_allocbt(
0084 struct xfs_btree_cur *cur,
0085 const struct xfs_alloc_rec_incore *rec,
0086 void *priv)
0087 {
0088 struct xrep_agf_allocbt *raa = priv;
0089 int error = 0;
0090
0091 if (xchk_should_terminate(raa->sc, &error))
0092 return error;
0093
0094 raa->freeblks += rec->ar_blockcount;
0095 if (rec->ar_blockcount > raa->longest)
0096 raa->longest = rec->ar_blockcount;
0097 return error;
0098 }
0099
0100
0101 STATIC int
0102 xrep_agf_check_agfl_block(
0103 struct xfs_mount *mp,
0104 xfs_agblock_t agbno,
0105 void *priv)
0106 {
0107 struct xfs_scrub *sc = priv;
0108
0109 if (!xfs_verify_agbno(sc->sa.pag, agbno))
0110 return -EFSCORRUPTED;
0111 return 0;
0112 }
0113
0114
0115
0116
0117
0118 enum {
0119 XREP_AGF_BNOBT = 0,
0120 XREP_AGF_CNTBT,
0121 XREP_AGF_RMAPBT,
0122 XREP_AGF_REFCOUNTBT,
0123 XREP_AGF_END,
0124 XREP_AGF_MAX
0125 };
0126
0127
0128 static inline bool
0129 xrep_check_btree_root(
0130 struct xfs_scrub *sc,
0131 struct xrep_find_ag_btree *fab)
0132 {
0133 return xfs_verify_agbno(sc->sa.pag, fab->root) &&
0134 fab->height <= fab->maxlevels;
0135 }
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146 STATIC int
0147 xrep_agf_find_btrees(
0148 struct xfs_scrub *sc,
0149 struct xfs_buf *agf_bp,
0150 struct xrep_find_ag_btree *fab,
0151 struct xfs_buf *agfl_bp)
0152 {
0153 struct xfs_agf *old_agf = agf_bp->b_addr;
0154 int error;
0155
0156
0157 error = xrep_find_ag_btree_roots(sc, agf_bp, fab, agfl_bp);
0158 if (error)
0159 return error;
0160
0161
0162 if (!xrep_check_btree_root(sc, &fab[XREP_AGF_BNOBT]) ||
0163 !xrep_check_btree_root(sc, &fab[XREP_AGF_CNTBT]) ||
0164 !xrep_check_btree_root(sc, &fab[XREP_AGF_RMAPBT]))
0165 return -EFSCORRUPTED;
0166
0167
0168
0169
0170
0171 if (fab[XREP_AGF_RMAPBT].root !=
0172 be32_to_cpu(old_agf->agf_roots[XFS_BTNUM_RMAPi]))
0173 return -EFSCORRUPTED;
0174
0175
0176 if (xfs_has_reflink(sc->mp) &&
0177 !xrep_check_btree_root(sc, &fab[XREP_AGF_REFCOUNTBT]))
0178 return -EFSCORRUPTED;
0179
0180 return 0;
0181 }
0182
0183
0184
0185
0186
0187 STATIC void
0188 xrep_agf_init_header(
0189 struct xfs_scrub *sc,
0190 struct xfs_buf *agf_bp,
0191 struct xfs_agf *old_agf)
0192 {
0193 struct xfs_mount *mp = sc->mp;
0194 struct xfs_agf *agf = agf_bp->b_addr;
0195
0196 memcpy(old_agf, agf, sizeof(*old_agf));
0197 memset(agf, 0, BBTOB(agf_bp->b_length));
0198 agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC);
0199 agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION);
0200 agf->agf_seqno = cpu_to_be32(sc->sa.pag->pag_agno);
0201 agf->agf_length = cpu_to_be32(sc->sa.pag->block_count);
0202 agf->agf_flfirst = old_agf->agf_flfirst;
0203 agf->agf_fllast = old_agf->agf_fllast;
0204 agf->agf_flcount = old_agf->agf_flcount;
0205 if (xfs_has_crc(mp))
0206 uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid);
0207
0208
0209 ASSERT(sc->sa.pag->pagf_init);
0210 sc->sa.pag->pagf_init = 0;
0211 }
0212
0213
0214 STATIC void
0215 xrep_agf_set_roots(
0216 struct xfs_scrub *sc,
0217 struct xfs_agf *agf,
0218 struct xrep_find_ag_btree *fab)
0219 {
0220 agf->agf_roots[XFS_BTNUM_BNOi] =
0221 cpu_to_be32(fab[XREP_AGF_BNOBT].root);
0222 agf->agf_levels[XFS_BTNUM_BNOi] =
0223 cpu_to_be32(fab[XREP_AGF_BNOBT].height);
0224
0225 agf->agf_roots[XFS_BTNUM_CNTi] =
0226 cpu_to_be32(fab[XREP_AGF_CNTBT].root);
0227 agf->agf_levels[XFS_BTNUM_CNTi] =
0228 cpu_to_be32(fab[XREP_AGF_CNTBT].height);
0229
0230 agf->agf_roots[XFS_BTNUM_RMAPi] =
0231 cpu_to_be32(fab[XREP_AGF_RMAPBT].root);
0232 agf->agf_levels[XFS_BTNUM_RMAPi] =
0233 cpu_to_be32(fab[XREP_AGF_RMAPBT].height);
0234
0235 if (xfs_has_reflink(sc->mp)) {
0236 agf->agf_refcount_root =
0237 cpu_to_be32(fab[XREP_AGF_REFCOUNTBT].root);
0238 agf->agf_refcount_level =
0239 cpu_to_be32(fab[XREP_AGF_REFCOUNTBT].height);
0240 }
0241 }
0242
0243
0244 STATIC int
0245 xrep_agf_calc_from_btrees(
0246 struct xfs_scrub *sc,
0247 struct xfs_buf *agf_bp)
0248 {
0249 struct xrep_agf_allocbt raa = { .sc = sc };
0250 struct xfs_btree_cur *cur = NULL;
0251 struct xfs_agf *agf = agf_bp->b_addr;
0252 struct xfs_mount *mp = sc->mp;
0253 xfs_agblock_t btreeblks;
0254 xfs_agblock_t blocks;
0255 int error;
0256
0257
0258 cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
0259 sc->sa.pag, XFS_BTNUM_BNO);
0260 error = xfs_alloc_query_all(cur, xrep_agf_walk_allocbt, &raa);
0261 if (error)
0262 goto err;
0263 error = xfs_btree_count_blocks(cur, &blocks);
0264 if (error)
0265 goto err;
0266 xfs_btree_del_cursor(cur, error);
0267 btreeblks = blocks - 1;
0268 agf->agf_freeblks = cpu_to_be32(raa.freeblks);
0269 agf->agf_longest = cpu_to_be32(raa.longest);
0270
0271
0272 cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
0273 sc->sa.pag, XFS_BTNUM_CNT);
0274 error = xfs_btree_count_blocks(cur, &blocks);
0275 if (error)
0276 goto err;
0277 xfs_btree_del_cursor(cur, error);
0278 btreeblks += blocks - 1;
0279
0280
0281 cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
0282 error = xfs_btree_count_blocks(cur, &blocks);
0283 if (error)
0284 goto err;
0285 xfs_btree_del_cursor(cur, error);
0286 agf->agf_rmap_blocks = cpu_to_be32(blocks);
0287 btreeblks += blocks - 1;
0288
0289 agf->agf_btreeblks = cpu_to_be32(btreeblks);
0290
0291
0292 if (xfs_has_reflink(mp)) {
0293 cur = xfs_refcountbt_init_cursor(mp, sc->tp, agf_bp,
0294 sc->sa.pag);
0295 error = xfs_btree_count_blocks(cur, &blocks);
0296 if (error)
0297 goto err;
0298 xfs_btree_del_cursor(cur, error);
0299 agf->agf_refcount_blocks = cpu_to_be32(blocks);
0300 }
0301
0302 return 0;
0303 err:
0304 xfs_btree_del_cursor(cur, error);
0305 return error;
0306 }
0307
0308
0309 STATIC int
0310 xrep_agf_commit_new(
0311 struct xfs_scrub *sc,
0312 struct xfs_buf *agf_bp)
0313 {
0314 struct xfs_perag *pag;
0315 struct xfs_agf *agf = agf_bp->b_addr;
0316
0317
0318 xfs_force_summary_recalc(sc->mp);
0319
0320
0321 xfs_trans_buf_set_type(sc->tp, agf_bp, XFS_BLFT_AGF_BUF);
0322 xfs_trans_log_buf(sc->tp, agf_bp, 0, BBTOB(agf_bp->b_length) - 1);
0323
0324
0325 pag = sc->sa.pag;
0326 pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks);
0327 pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks);
0328 pag->pagf_longest = be32_to_cpu(agf->agf_longest);
0329 pag->pagf_levels[XFS_BTNUM_BNOi] =
0330 be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]);
0331 pag->pagf_levels[XFS_BTNUM_CNTi] =
0332 be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]);
0333 pag->pagf_levels[XFS_BTNUM_RMAPi] =
0334 be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAPi]);
0335 pag->pagf_refcount_level = be32_to_cpu(agf->agf_refcount_level);
0336 pag->pagf_init = 1;
0337
0338 return 0;
0339 }
0340
0341
0342 int
0343 xrep_agf(
0344 struct xfs_scrub *sc)
0345 {
0346 struct xrep_find_ag_btree fab[XREP_AGF_MAX] = {
0347 [XREP_AGF_BNOBT] = {
0348 .rmap_owner = XFS_RMAP_OWN_AG,
0349 .buf_ops = &xfs_bnobt_buf_ops,
0350 .maxlevels = sc->mp->m_alloc_maxlevels,
0351 },
0352 [XREP_AGF_CNTBT] = {
0353 .rmap_owner = XFS_RMAP_OWN_AG,
0354 .buf_ops = &xfs_cntbt_buf_ops,
0355 .maxlevels = sc->mp->m_alloc_maxlevels,
0356 },
0357 [XREP_AGF_RMAPBT] = {
0358 .rmap_owner = XFS_RMAP_OWN_AG,
0359 .buf_ops = &xfs_rmapbt_buf_ops,
0360 .maxlevels = sc->mp->m_rmap_maxlevels,
0361 },
0362 [XREP_AGF_REFCOUNTBT] = {
0363 .rmap_owner = XFS_RMAP_OWN_REFC,
0364 .buf_ops = &xfs_refcountbt_buf_ops,
0365 .maxlevels = sc->mp->m_refc_maxlevels,
0366 },
0367 [XREP_AGF_END] = {
0368 .buf_ops = NULL,
0369 },
0370 };
0371 struct xfs_agf old_agf;
0372 struct xfs_mount *mp = sc->mp;
0373 struct xfs_buf *agf_bp;
0374 struct xfs_buf *agfl_bp;
0375 struct xfs_agf *agf;
0376 int error;
0377
0378
0379 if (!xfs_has_rmapbt(mp))
0380 return -EOPNOTSUPP;
0381
0382
0383
0384
0385
0386 error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
0387 XFS_AG_DADDR(mp, sc->sa.pag->pag_agno,
0388 XFS_AGF_DADDR(mp)),
0389 XFS_FSS_TO_BB(mp, 1), 0, &agf_bp, NULL);
0390 if (error)
0391 return error;
0392 agf_bp->b_ops = &xfs_agf_buf_ops;
0393 agf = agf_bp->b_addr;
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404 error = xfs_alloc_read_agfl(sc->sa.pag, sc->tp, &agfl_bp);
0405 if (error)
0406 return error;
0407
0408
0409
0410
0411
0412 error = xfs_agfl_walk(sc->mp, agf_bp->b_addr, agfl_bp,
0413 xrep_agf_check_agfl_block, sc);
0414 if (error)
0415 return error;
0416
0417
0418
0419
0420
0421 error = xrep_agf_find_btrees(sc, agf_bp, fab, agfl_bp);
0422 if (error)
0423 return error;
0424
0425
0426 xrep_agf_init_header(sc, agf_bp, &old_agf);
0427 xrep_agf_set_roots(sc, agf, fab);
0428 error = xrep_agf_calc_from_btrees(sc, agf_bp);
0429 if (error)
0430 goto out_revert;
0431
0432
0433 return xrep_agf_commit_new(sc, agf_bp);
0434
0435 out_revert:
0436
0437 sc->sa.pag->pagf_init = 0;
0438 memcpy(agf, &old_agf, sizeof(old_agf));
0439 return error;
0440 }
0441
0442
0443
0444 struct xrep_agfl {
0445
0446 struct xbitmap agmetablocks;
0447
0448
0449 struct xbitmap *freesp;
0450
0451 struct xfs_scrub *sc;
0452 };
0453
0454
0455 STATIC int
0456 xrep_agfl_walk_rmap(
0457 struct xfs_btree_cur *cur,
0458 const struct xfs_rmap_irec *rec,
0459 void *priv)
0460 {
0461 struct xrep_agfl *ra = priv;
0462 xfs_fsblock_t fsb;
0463 int error = 0;
0464
0465 if (xchk_should_terminate(ra->sc, &error))
0466 return error;
0467
0468
0469 if (rec->rm_owner == XFS_RMAP_OWN_AG) {
0470 fsb = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_ag.pag->pag_agno,
0471 rec->rm_startblock);
0472 error = xbitmap_set(ra->freesp, fsb, rec->rm_blockcount);
0473 if (error)
0474 return error;
0475 }
0476
0477 return xbitmap_set_btcur_path(&ra->agmetablocks, cur);
0478 }
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489 STATIC int
0490 xrep_agfl_collect_blocks(
0491 struct xfs_scrub *sc,
0492 struct xfs_buf *agf_bp,
0493 struct xbitmap *agfl_extents,
0494 xfs_agblock_t *flcount)
0495 {
0496 struct xrep_agfl ra;
0497 struct xfs_mount *mp = sc->mp;
0498 struct xfs_btree_cur *cur;
0499 int error;
0500
0501 ra.sc = sc;
0502 ra.freesp = agfl_extents;
0503 xbitmap_init(&ra.agmetablocks);
0504
0505
0506 cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag);
0507 error = xfs_rmap_query_all(cur, xrep_agfl_walk_rmap, &ra);
0508 if (error)
0509 goto err;
0510 xfs_btree_del_cursor(cur, error);
0511
0512
0513 cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
0514 sc->sa.pag, XFS_BTNUM_BNO);
0515 error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
0516 if (error)
0517 goto err;
0518 xfs_btree_del_cursor(cur, error);
0519
0520
0521 cur = xfs_allocbt_init_cursor(mp, sc->tp, agf_bp,
0522 sc->sa.pag, XFS_BTNUM_CNT);
0523 error = xbitmap_set_btblocks(&ra.agmetablocks, cur);
0524 if (error)
0525 goto err;
0526
0527 xfs_btree_del_cursor(cur, error);
0528
0529
0530
0531
0532
0533 error = xbitmap_disunion(agfl_extents, &ra.agmetablocks);
0534 xbitmap_destroy(&ra.agmetablocks);
0535 if (error)
0536 return error;
0537
0538
0539
0540
0541
0542 *flcount = min_t(uint64_t, xbitmap_hweight(agfl_extents),
0543 xfs_agfl_size(mp));
0544 return 0;
0545
0546 err:
0547 xbitmap_destroy(&ra.agmetablocks);
0548 xfs_btree_del_cursor(cur, error);
0549 return error;
0550 }
0551
0552
0553 STATIC void
0554 xrep_agfl_update_agf(
0555 struct xfs_scrub *sc,
0556 struct xfs_buf *agf_bp,
0557 xfs_agblock_t flcount)
0558 {
0559 struct xfs_agf *agf = agf_bp->b_addr;
0560
0561 ASSERT(flcount <= xfs_agfl_size(sc->mp));
0562
0563
0564 xfs_force_summary_recalc(sc->mp);
0565
0566
0567 if (sc->sa.pag->pagf_init)
0568 sc->sa.pag->pagf_flcount = flcount;
0569 agf->agf_flfirst = cpu_to_be32(0);
0570 agf->agf_flcount = cpu_to_be32(flcount);
0571 agf->agf_fllast = cpu_to_be32(flcount - 1);
0572
0573 xfs_alloc_log_agf(sc->tp, agf_bp,
0574 XFS_AGF_FLFIRST | XFS_AGF_FLLAST | XFS_AGF_FLCOUNT);
0575 }
0576
0577
0578 STATIC void
0579 xrep_agfl_init_header(
0580 struct xfs_scrub *sc,
0581 struct xfs_buf *agfl_bp,
0582 struct xbitmap *agfl_extents,
0583 xfs_agblock_t flcount)
0584 {
0585 struct xfs_mount *mp = sc->mp;
0586 __be32 *agfl_bno;
0587 struct xbitmap_range *br;
0588 struct xbitmap_range *n;
0589 struct xfs_agfl *agfl;
0590 xfs_agblock_t agbno;
0591 unsigned int fl_off;
0592
0593 ASSERT(flcount <= xfs_agfl_size(mp));
0594
0595
0596
0597
0598
0599 agfl = XFS_BUF_TO_AGFL(agfl_bp);
0600 memset(agfl, 0xFF, BBTOB(agfl_bp->b_length));
0601 agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC);
0602 agfl->agfl_seqno = cpu_to_be32(sc->sa.pag->pag_agno);
0603 uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid);
0604
0605
0606
0607
0608
0609
0610 fl_off = 0;
0611 agfl_bno = xfs_buf_to_agfl_bno(agfl_bp);
0612 for_each_xbitmap_extent(br, n, agfl_extents) {
0613 agbno = XFS_FSB_TO_AGBNO(mp, br->start);
0614
0615 trace_xrep_agfl_insert(mp, sc->sa.pag->pag_agno, agbno,
0616 br->len);
0617
0618 while (br->len > 0 && fl_off < flcount) {
0619 agfl_bno[fl_off] = cpu_to_be32(agbno);
0620 fl_off++;
0621 agbno++;
0622
0623
0624
0625
0626
0627 br->start++;
0628 br->len--;
0629 }
0630
0631 if (br->len)
0632 break;
0633 list_del(&br->list);
0634 kmem_free(br);
0635 }
0636
0637
0638 xfs_trans_buf_set_type(sc->tp, agfl_bp, XFS_BLFT_AGFL_BUF);
0639 xfs_trans_log_buf(sc->tp, agfl_bp, 0, BBTOB(agfl_bp->b_length) - 1);
0640 }
0641
0642
0643 int
0644 xrep_agfl(
0645 struct xfs_scrub *sc)
0646 {
0647 struct xbitmap agfl_extents;
0648 struct xfs_mount *mp = sc->mp;
0649 struct xfs_buf *agf_bp;
0650 struct xfs_buf *agfl_bp;
0651 xfs_agblock_t flcount;
0652 int error;
0653
0654
0655 if (!xfs_has_rmapbt(mp))
0656 return -EOPNOTSUPP;
0657
0658 xbitmap_init(&agfl_extents);
0659
0660
0661
0662
0663
0664
0665 error = xfs_alloc_read_agf(sc->sa.pag, sc->tp, 0, &agf_bp);
0666 if (error)
0667 return error;
0668
0669
0670
0671
0672
0673 error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
0674 XFS_AG_DADDR(mp, sc->sa.pag->pag_agno,
0675 XFS_AGFL_DADDR(mp)),
0676 XFS_FSS_TO_BB(mp, 1), 0, &agfl_bp, NULL);
0677 if (error)
0678 return error;
0679 agfl_bp->b_ops = &xfs_agfl_buf_ops;
0680
0681
0682 error = xrep_agfl_collect_blocks(sc, agf_bp, &agfl_extents, &flcount);
0683 if (error)
0684 goto err;
0685
0686
0687
0688
0689
0690
0691 xrep_agfl_update_agf(sc, agf_bp, flcount);
0692 xrep_agfl_init_header(sc, agfl_bp, &agfl_extents, flcount);
0693
0694
0695
0696
0697
0698
0699 sc->sa.agf_bp = agf_bp;
0700 sc->sa.agfl_bp = agfl_bp;
0701 error = xrep_roll_ag_trans(sc);
0702 if (error)
0703 goto err;
0704
0705
0706 error = xrep_reap_extents(sc, &agfl_extents, &XFS_RMAP_OINFO_AG,
0707 XFS_AG_RESV_AGFL);
0708 err:
0709 xbitmap_destroy(&agfl_extents);
0710 return error;
0711 }
0712
0713
0714
0715
0716
0717
0718
0719 enum {
0720 XREP_AGI_INOBT = 0,
0721 XREP_AGI_FINOBT,
0722 XREP_AGI_END,
0723 XREP_AGI_MAX
0724 };
0725
0726
0727
0728
0729
0730 STATIC int
0731 xrep_agi_find_btrees(
0732 struct xfs_scrub *sc,
0733 struct xrep_find_ag_btree *fab)
0734 {
0735 struct xfs_buf *agf_bp;
0736 struct xfs_mount *mp = sc->mp;
0737 int error;
0738
0739
0740 error = xfs_alloc_read_agf(sc->sa.pag, sc->tp, 0, &agf_bp);
0741 if (error)
0742 return error;
0743
0744
0745 error = xrep_find_ag_btree_roots(sc, agf_bp, fab, NULL);
0746 if (error)
0747 return error;
0748
0749
0750 if (!xrep_check_btree_root(sc, &fab[XREP_AGI_INOBT]))
0751 return -EFSCORRUPTED;
0752
0753
0754 if (xfs_has_finobt(mp) &&
0755 !xrep_check_btree_root(sc, &fab[XREP_AGI_FINOBT]))
0756 return -EFSCORRUPTED;
0757
0758 return 0;
0759 }
0760
0761
0762
0763
0764
0765 STATIC void
0766 xrep_agi_init_header(
0767 struct xfs_scrub *sc,
0768 struct xfs_buf *agi_bp,
0769 struct xfs_agi *old_agi)
0770 {
0771 struct xfs_agi *agi = agi_bp->b_addr;
0772 struct xfs_mount *mp = sc->mp;
0773
0774 memcpy(old_agi, agi, sizeof(*old_agi));
0775 memset(agi, 0, BBTOB(agi_bp->b_length));
0776 agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC);
0777 agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION);
0778 agi->agi_seqno = cpu_to_be32(sc->sa.pag->pag_agno);
0779 agi->agi_length = cpu_to_be32(sc->sa.pag->block_count);
0780 agi->agi_newino = cpu_to_be32(NULLAGINO);
0781 agi->agi_dirino = cpu_to_be32(NULLAGINO);
0782 if (xfs_has_crc(mp))
0783 uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid);
0784
0785
0786 memcpy(&agi->agi_unlinked, &old_agi->agi_unlinked,
0787 sizeof(agi->agi_unlinked));
0788
0789
0790 ASSERT(sc->sa.pag->pagi_init);
0791 sc->sa.pag->pagi_init = 0;
0792 }
0793
0794
0795 STATIC void
0796 xrep_agi_set_roots(
0797 struct xfs_scrub *sc,
0798 struct xfs_agi *agi,
0799 struct xrep_find_ag_btree *fab)
0800 {
0801 agi->agi_root = cpu_to_be32(fab[XREP_AGI_INOBT].root);
0802 agi->agi_level = cpu_to_be32(fab[XREP_AGI_INOBT].height);
0803
0804 if (xfs_has_finobt(sc->mp)) {
0805 agi->agi_free_root = cpu_to_be32(fab[XREP_AGI_FINOBT].root);
0806 agi->agi_free_level = cpu_to_be32(fab[XREP_AGI_FINOBT].height);
0807 }
0808 }
0809
0810
0811 STATIC int
0812 xrep_agi_calc_from_btrees(
0813 struct xfs_scrub *sc,
0814 struct xfs_buf *agi_bp)
0815 {
0816 struct xfs_btree_cur *cur;
0817 struct xfs_agi *agi = agi_bp->b_addr;
0818 struct xfs_mount *mp = sc->mp;
0819 xfs_agino_t count;
0820 xfs_agino_t freecount;
0821 int error;
0822
0823 cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
0824 sc->sa.pag, XFS_BTNUM_INO);
0825 error = xfs_ialloc_count_inodes(cur, &count, &freecount);
0826 if (error)
0827 goto err;
0828 if (xfs_has_inobtcounts(mp)) {
0829 xfs_agblock_t blocks;
0830
0831 error = xfs_btree_count_blocks(cur, &blocks);
0832 if (error)
0833 goto err;
0834 agi->agi_iblocks = cpu_to_be32(blocks);
0835 }
0836 xfs_btree_del_cursor(cur, error);
0837
0838 agi->agi_count = cpu_to_be32(count);
0839 agi->agi_freecount = cpu_to_be32(freecount);
0840
0841 if (xfs_has_finobt(mp) && xfs_has_inobtcounts(mp)) {
0842 xfs_agblock_t blocks;
0843
0844 cur = xfs_inobt_init_cursor(mp, sc->tp, agi_bp,
0845 sc->sa.pag, XFS_BTNUM_FINO);
0846 error = xfs_btree_count_blocks(cur, &blocks);
0847 if (error)
0848 goto err;
0849 xfs_btree_del_cursor(cur, error);
0850 agi->agi_fblocks = cpu_to_be32(blocks);
0851 }
0852
0853 return 0;
0854 err:
0855 xfs_btree_del_cursor(cur, error);
0856 return error;
0857 }
0858
0859
0860 STATIC int
0861 xrep_agi_commit_new(
0862 struct xfs_scrub *sc,
0863 struct xfs_buf *agi_bp)
0864 {
0865 struct xfs_perag *pag;
0866 struct xfs_agi *agi = agi_bp->b_addr;
0867
0868
0869 xfs_force_summary_recalc(sc->mp);
0870
0871
0872 xfs_trans_buf_set_type(sc->tp, agi_bp, XFS_BLFT_AGI_BUF);
0873 xfs_trans_log_buf(sc->tp, agi_bp, 0, BBTOB(agi_bp->b_length) - 1);
0874
0875
0876 pag = sc->sa.pag;
0877 pag->pagi_count = be32_to_cpu(agi->agi_count);
0878 pag->pagi_freecount = be32_to_cpu(agi->agi_freecount);
0879 pag->pagi_init = 1;
0880
0881 return 0;
0882 }
0883
0884
0885 int
0886 xrep_agi(
0887 struct xfs_scrub *sc)
0888 {
0889 struct xrep_find_ag_btree fab[XREP_AGI_MAX] = {
0890 [XREP_AGI_INOBT] = {
0891 .rmap_owner = XFS_RMAP_OWN_INOBT,
0892 .buf_ops = &xfs_inobt_buf_ops,
0893 .maxlevels = M_IGEO(sc->mp)->inobt_maxlevels,
0894 },
0895 [XREP_AGI_FINOBT] = {
0896 .rmap_owner = XFS_RMAP_OWN_INOBT,
0897 .buf_ops = &xfs_finobt_buf_ops,
0898 .maxlevels = M_IGEO(sc->mp)->inobt_maxlevels,
0899 },
0900 [XREP_AGI_END] = {
0901 .buf_ops = NULL
0902 },
0903 };
0904 struct xfs_agi old_agi;
0905 struct xfs_mount *mp = sc->mp;
0906 struct xfs_buf *agi_bp;
0907 struct xfs_agi *agi;
0908 int error;
0909
0910
0911 if (!xfs_has_rmapbt(mp))
0912 return -EOPNOTSUPP;
0913
0914
0915
0916
0917
0918 error = xfs_trans_read_buf(mp, sc->tp, mp->m_ddev_targp,
0919 XFS_AG_DADDR(mp, sc->sa.pag->pag_agno,
0920 XFS_AGI_DADDR(mp)),
0921 XFS_FSS_TO_BB(mp, 1), 0, &agi_bp, NULL);
0922 if (error)
0923 return error;
0924 agi_bp->b_ops = &xfs_agi_buf_ops;
0925 agi = agi_bp->b_addr;
0926
0927
0928 error = xrep_agi_find_btrees(sc, fab);
0929 if (error)
0930 return error;
0931
0932
0933 xrep_agi_init_header(sc, agi_bp, &old_agi);
0934 xrep_agi_set_roots(sc, agi, fab);
0935 error = xrep_agi_calc_from_btrees(sc, agi_bp);
0936 if (error)
0937 goto out_revert;
0938
0939
0940 return xrep_agi_commit_new(sc, agi_bp);
0941
0942 out_revert:
0943
0944 sc->sa.pag->pagi_init = 0;
0945 memcpy(agi, &old_agi, sizeof(old_agi));
0946 return error;
0947 }