Lines Matching +full:scrubber +full:- +full:done
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2018-2023 Oracle. All Rights Reserved.
42 * told us to fix it. This function returns -EAGAIN to mean "re-run scrub",
53 trace_xrep_attempt(XFS_I(file_inode(sc->file)), sc->sm, error); in xrep_attempt()
55 xchk_ag_btcur_free(&sc->sa); in xrep_attempt()
58 ASSERT(sc->ops->repair); in xrep_attempt()
59 run->repair_attempted = true; in xrep_attempt()
61 error = sc->ops->repair(sc); in xrep_attempt()
62 trace_xrep_done(XFS_I(file_inode(sc->file)), sc->sm, error); in xrep_attempt()
63 run->repair_ns += xchk_stats_elapsed_ns(repair_start); in xrep_attempt()
70 sc->sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT; in xrep_attempt()
71 sc->flags |= XREP_ALREADY_FIXED; in xrep_attempt()
72 run->repair_succeeded = true; in xrep_attempt()
73 return -EAGAIN; in xrep_attempt()
74 case -ECHRNG: in xrep_attempt()
75 sc->flags |= XCHK_NEED_DRAIN; in xrep_attempt()
76 run->retries++; in xrep_attempt()
77 return -EAGAIN; in xrep_attempt()
78 case -EDEADLOCK: in xrep_attempt()
80 if (!(sc->flags & XCHK_TRY_HARDER)) { in xrep_attempt()
81 sc->flags |= XCHK_TRY_HARDER; in xrep_attempt()
82 run->retries++; in xrep_attempt()
83 return -EAGAIN; in xrep_attempt()
93 * EAGAIN tells the caller to re-scrub, so we cannot return in xrep_attempt()
96 ASSERT(error != -EAGAIN); in xrep_attempt()
105 * administrator isn't running xfs_scrub in no-repairs mode.
119 * Repair probe -- userspace uses this to probe if we're willing to repair a
153 if (sc->sa.agi_bp) { in xrep_roll_ag_trans()
154 xfs_ialloc_log_agi(sc->tp, sc->sa.agi_bp, XFS_AGI_MAGICNUM); in xrep_roll_ag_trans()
155 xfs_trans_bhold(sc->tp, sc->sa.agi_bp); in xrep_roll_ag_trans()
158 if (sc->sa.agf_bp) { in xrep_roll_ag_trans()
159 xfs_alloc_log_agf(sc->tp, sc->sa.agf_bp, XFS_AGF_MAGICNUM); in xrep_roll_ag_trans()
160 xfs_trans_bhold(sc->tp, sc->sa.agf_bp); in xrep_roll_ag_trans()
169 error = xfs_trans_roll(&sc->tp); in xrep_roll_ag_trans()
174 if (sc->sa.agi_bp) in xrep_roll_ag_trans()
175 xfs_trans_bjoin(sc->tp, sc->sa.agi_bp); in xrep_roll_ag_trans()
176 if (sc->sa.agf_bp) in xrep_roll_ag_trans()
177 xfs_trans_bjoin(sc->tp, sc->sa.agf_bp); in xrep_roll_ag_trans()
187 if (!sc->ip) in xrep_roll_trans()
189 return xfs_trans_roll_inode(&sc->tp, sc->ip); in xrep_roll_trans()
208 if (sc->sa.agi_bp) { in xrep_defer_finish()
209 xfs_ialloc_log_agi(sc->tp, sc->sa.agi_bp, XFS_AGI_MAGICNUM); in xrep_defer_finish()
210 xfs_trans_bhold(sc->tp, sc->sa.agi_bp); in xrep_defer_finish()
213 if (sc->sa.agf_bp) { in xrep_defer_finish()
214 xfs_alloc_log_agf(sc->tp, sc->sa.agf_bp, XFS_AGF_MAGICNUM); in xrep_defer_finish()
215 xfs_trans_bhold(sc->tp, sc->sa.agf_bp); in xrep_defer_finish()
225 error = xfs_defer_finish(&sc->tp); in xrep_defer_finish()
234 if (sc->sa.agi_bp) in xrep_defer_finish()
235 xfs_trans_bhold_release(sc->tp, sc->sa.agi_bp); in xrep_defer_finish()
236 if (sc->sa.agf_bp) in xrep_defer_finish()
237 xfs_trans_bhold_release(sc->tp, sc->sa.agf_bp); in xrep_defer_finish()
255 pag->pagf_freeblks > xfs_ag_resv_needed(pag, type) + nr_blocks; in xrep_ag_has_space()
261 * any type of per-AG btree.
267 struct xfs_mount *mp = sc->mp; in xrep_calc_ag_resblks()
268 struct xfs_scrub_metadata *sm = sc->sm; in xrep_calc_ag_resblks()
281 if (!(sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)) in xrep_calc_ag_resblks()
284 pag = xfs_perag_get(mp, sm->sm_agno); in xrep_calc_ag_resblks()
286 /* Use in-core icount if possible. */ in xrep_calc_ag_resblks()
287 icount = pag->pagi_count; in xrep_calc_ag_resblks()
292 icount = pag->pagi_count; in xrep_calc_ag_resblks()
300 aglen = pag->block_count; in xrep_calc_ag_resblks()
304 struct xfs_agf *agf = bp->b_addr; in xrep_calc_ag_resblks()
306 aglen = be32_to_cpu(agf->agf_length); in xrep_calc_ag_resblks()
307 freelen = be32_to_cpu(agf->agf_freeblks); in xrep_calc_ag_resblks()
308 usedlen = aglen - freelen; in xrep_calc_ag_resblks()
312 /* If the icount is impossible, make some worst-case assumptions. */ in xrep_calc_ag_resblks()
315 icount = pag->agino_max - pag->agino_min + 1; in xrep_calc_ag_resblks()
318 /* If the block counts are impossible, make worst-case assumptions. */ in xrep_calc_ag_resblks()
320 aglen != pag->block_count || in xrep_calc_ag_resblks()
322 aglen = pag->block_count; in xrep_calc_ag_resblks()
328 trace_xrep_calc_ag_resblks(mp, sm->sm_agno, icount, aglen, in xrep_calc_ag_resblks()
352 * For non-reflink filesystems we can't have more records than in xrep_calc_ag_resblks()
356 * what we hope is an generous over-estimation. in xrep_calc_ag_resblks()
367 trace_xrep_calc_ag_resblks_btsize(mp, sm->sm_agno, bnobt_sz, in xrep_calc_ag_resblks()
374 * Reconstructing per-AG Btrees
407 args.mp = sc->mp; in xrep_fix_freelist()
408 args.tp = sc->tp; in xrep_fix_freelist()
409 args.agno = sc->sa.pag->pag_agno; in xrep_fix_freelist()
411 args.pag = sc->sa.pag; in xrep_fix_freelist()
418 * Finding per-AG Btree Roots for AGF/AGI Reconstruction
460 return (*agbno == bno) ? -ECANCELED : 0; in xrep_findroot_agfl_walk()
472 struct xfs_mount *mp = ri->sc->mp; in xrep_findroot_block()
479 daddr = XFS_AGB_TO_DADDR(mp, ri->sc->sa.pag->pag_agno, agbno); in xrep_findroot_block()
488 error = xfs_agfl_walk(mp, ri->agf, ri->agfl_bp, in xrep_findroot_block()
490 if (error == -ECANCELED) in xrep_findroot_block()
499 * avoid xfs_trans_read_buf's behavior of dumping the DONE state (which in xrep_findroot_block()
514 error = xfs_trans_read_buf(mp, ri->sc->tp, mp->m_ddev_targp, daddr, in xrep_findroot_block()
515 mp->m_bsize, 0, &bp, NULL); in xrep_findroot_block()
521 ASSERT(fab->buf_ops->magic[1] != 0); in xrep_findroot_block()
522 if (btblock->bb_magic != fab->buf_ops->magic[1]) in xrep_findroot_block()
539 if (bp->b_ops) { in xrep_findroot_block()
540 if (bp->b_ops != fab->buf_ops) in xrep_findroot_block()
544 if (!uuid_equal(&btblock->bb_u.s.bb_uuid, in xrep_findroot_block()
545 &mp->m_sb.sb_meta_uuid)) in xrep_findroot_block()
552 bp->b_ops = fab->buf_ops; in xrep_findroot_block()
553 fab->buf_ops->verify_read(bp); in xrep_findroot_block()
554 if (bp->b_error) { in xrep_findroot_block()
555 bp->b_ops = NULL; in xrep_findroot_block()
556 bp->b_error = 0; in xrep_findroot_block()
583 if (block_level + 1 == fab->height) { in xrep_findroot_block()
584 fab->root = NULLAGBLOCK; in xrep_findroot_block()
586 } else if (block_level < fab->height) { in xrep_findroot_block()
595 fab->height = block_level + 1; in xrep_findroot_block()
602 if (btblock->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) && in xrep_findroot_block()
603 btblock->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK)) in xrep_findroot_block()
604 fab->root = agbno; in xrep_findroot_block()
606 fab->root = NULLAGBLOCK; in xrep_findroot_block()
608 trace_xrep_findroot_block(mp, ri->sc->sa.pag->pag_agno, agbno, in xrep_findroot_block()
609 be32_to_cpu(btblock->bb_magic), fab->height - 1); in xrep_findroot_block()
611 xfs_trans_brelse(ri->sc->tp, bp); in xrep_findroot_block()
628 bool done; in xrep_findroot_rmap() local
632 if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner)) in xrep_findroot_rmap()
636 for (b = 0; b < rec->rm_blockcount; b++) { in xrep_findroot_rmap()
637 done = false; in xrep_findroot_rmap()
638 for (fab = ri->btree_info; fab->buf_ops; fab++) { in xrep_findroot_rmap()
639 if (rec->rm_owner != fab->rmap_owner) in xrep_findroot_rmap()
642 rec->rm_owner, rec->rm_startblock + b, in xrep_findroot_rmap()
643 &done); in xrep_findroot_rmap()
646 if (done) in xrep_findroot_rmap()
654 /* Find the roots of the per-AG btrees described in btree_info. */
662 struct xfs_mount *mp = sc->mp; in xrep_find_ag_btree_roots()
673 ri.agf = agf_bp->b_addr; in xrep_find_ag_btree_roots()
675 for (fab = btree_info; fab->buf_ops; fab++) { in xrep_find_ag_btree_roots()
676 ASSERT(agfl_bp || fab->rmap_owner != XFS_RMAP_OWN_AG); in xrep_find_ag_btree_roots()
677 ASSERT(XFS_RMAP_NON_INODE_OWNER(fab->rmap_owner)); in xrep_find_ag_btree_roots()
678 fab->root = NULLAGBLOCK; in xrep_find_ag_btree_roots()
679 fab->height = 0; in xrep_find_ag_btree_roots()
682 cur = xfs_rmapbt_init_cursor(mp, sc->tp, agf_bp, sc->sa.pag); in xrep_find_ag_btree_roots()
699 if (!(flag & sc->mp->m_qflags)) in xrep_force_quotacheck()
702 mutex_lock(&sc->mp->m_quotainfo->qi_quotaofflock); in xrep_force_quotacheck()
703 sc->mp->m_qflags &= ~flag; in xrep_force_quotacheck()
704 spin_lock(&sc->mp->m_sb_lock); in xrep_force_quotacheck()
705 sc->mp->m_sb.sb_qflags &= ~flag; in xrep_force_quotacheck()
706 spin_unlock(&sc->mp->m_sb_lock); in xrep_force_quotacheck()
707 xfs_log_sb(sc->tp); in xrep_force_quotacheck()
708 mutex_unlock(&sc->mp->m_quotainfo->qi_quotaofflock); in xrep_force_quotacheck()
715 * We cannot allow the dquot code to allocate an on-disk dquot block here
716 * because we're already in transaction context. The on-disk dquot should
727 ASSERT(sc->tp != NULL); in xrep_ino_dqattach()
728 ASSERT(sc->ip != NULL); in xrep_ino_dqattach()
730 error = xfs_qm_dqattach(sc->ip); in xrep_ino_dqattach()
732 case -EFSBADCRC: in xrep_ino_dqattach()
733 case -EFSCORRUPTED: in xrep_ino_dqattach()
734 case -ENOENT: in xrep_ino_dqattach()
735 xfs_err_ratelimited(sc->mp, in xrep_ino_dqattach()
737 (unsigned long long)sc->ip->i_ino, error); in xrep_ino_dqattach()
738 if (XFS_IS_UQUOTA_ON(sc->mp) && !sc->ip->i_udquot) in xrep_ino_dqattach()
740 if (XFS_IS_GQUOTA_ON(sc->mp) && !sc->ip->i_gdquot) in xrep_ino_dqattach()
742 if (XFS_IS_PQUOTA_ON(sc->mp) && !sc->ip->i_pdquot) in xrep_ino_dqattach()
745 case -ESRCH: in xrep_ino_dqattach()
770 inode_has_nrext64 = xfs_inode_has_large_extent_counts(sc->ip); in xrep_ino_ensure_extent_count()
775 return -EFSCORRUPTED; in xrep_ino_ensure_extent_count()
776 if (!xfs_has_large_extent_counts(sc->mp)) in xrep_ino_ensure_extent_count()
777 return -EFSCORRUPTED; in xrep_ino_ensure_extent_count()
781 return -EFSCORRUPTED; in xrep_ino_ensure_extent_count()
783 sc->ip->i_diflags2 |= XFS_DIFLAG2_NREXT64; in xrep_ino_ensure_extent_count()
784 xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE); in xrep_ino_ensure_extent_count()
797 struct xfs_mount *mp = sc->mp; in xrep_ag_btcur_init()
799 /* Set up a bnobt cursor for cross-referencing. */ in xrep_ag_btcur_init()
800 if (sc->sm->sm_type != XFS_SCRUB_TYPE_BNOBT && in xrep_ag_btcur_init()
801 sc->sm->sm_type != XFS_SCRUB_TYPE_CNTBT) { in xrep_ag_btcur_init()
802 sa->bno_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp, in xrep_ag_btcur_init()
803 sc->sa.pag, XFS_BTNUM_BNO); in xrep_ag_btcur_init()
804 sa->cnt_cur = xfs_allocbt_init_cursor(mp, sc->tp, sa->agf_bp, in xrep_ag_btcur_init()
805 sc->sa.pag, XFS_BTNUM_CNT); in xrep_ag_btcur_init()
808 /* Set up a inobt cursor for cross-referencing. */ in xrep_ag_btcur_init()
809 if (sc->sm->sm_type != XFS_SCRUB_TYPE_INOBT && in xrep_ag_btcur_init()
810 sc->sm->sm_type != XFS_SCRUB_TYPE_FINOBT) { in xrep_ag_btcur_init()
811 sa->ino_cur = xfs_inobt_init_cursor(sc->sa.pag, sc->tp, in xrep_ag_btcur_init()
812 sa->agi_bp, XFS_BTNUM_INO); in xrep_ag_btcur_init()
814 sa->fino_cur = xfs_inobt_init_cursor(sc->sa.pag, in xrep_ag_btcur_init()
815 sc->tp, sa->agi_bp, XFS_BTNUM_FINO); in xrep_ag_btcur_init()
818 /* Set up a rmapbt cursor for cross-referencing. */ in xrep_ag_btcur_init()
819 if (sc->sm->sm_type != XFS_SCRUB_TYPE_RMAPBT && in xrep_ag_btcur_init()
821 sa->rmap_cur = xfs_rmapbt_init_cursor(mp, sc->tp, sa->agf_bp, in xrep_ag_btcur_init()
822 sc->sa.pag); in xrep_ag_btcur_init()
824 /* Set up a refcountbt cursor for cross-referencing. */ in xrep_ag_btcur_init()
825 if (sc->sm->sm_type != XFS_SCRUB_TYPE_REFCNTBT && in xrep_ag_btcur_init()
827 sa->refc_cur = xfs_refcountbt_init_cursor(mp, sc->tp, in xrep_ag_btcur_init()
828 sa->agf_bp, sc->sa.pag); in xrep_ag_btcur_init()
832 * Reinitialize the in-core AG state after a repair by rereading the AGF
840 struct xfs_perag *pag = sc->sa.pag; in xrep_reinit_pagf()
847 clear_bit(XFS_AGSTATE_AGF_INIT, &pag->pag_opstate); in xrep_reinit_pagf()
848 error = xfs_alloc_read_agf(pag, sc->tp, 0, &bp); in xrep_reinit_pagf()
852 if (bp != sc->sa.agf_bp) { in xrep_reinit_pagf()
853 ASSERT(bp == sc->sa.agf_bp); in xrep_reinit_pagf()
854 return -EFSCORRUPTED; in xrep_reinit_pagf()
861 * Reinitialize the in-core AG state after a repair by rereading the AGI
869 struct xfs_perag *pag = sc->sa.pag; in xrep_reinit_pagi()
876 clear_bit(XFS_AGSTATE_AGI_INIT, &pag->pag_opstate); in xrep_reinit_pagi()
877 error = xfs_ialloc_read_agi(pag, sc->tp, &bp); in xrep_reinit_pagi()
881 if (bp != sc->sa.agi_bp) { in xrep_reinit_pagi()
882 ASSERT(bp == sc->sa.agi_bp); in xrep_reinit_pagi()
883 return -EFSCORRUPTED; in xrep_reinit_pagi()
891 * This should only be called to scan an AG while repairing file-based metadata.
901 ASSERT(!sa->pag); in xrep_ag_init()
903 error = xfs_ialloc_read_agi(pag, sc->tp, &sa->agi_bp); in xrep_ag_init()
907 error = xfs_alloc_read_agf(pag, sc->tp, 0, &sa->agf_bp); in xrep_ag_init()
912 sa->pag = xfs_perag_hold(pag); in xrep_ag_init()
917 /* Reinitialize the per-AG block reservation for the AG we just fixed. */
924 if (!(sc->flags & XREP_RESET_PERAG_RESV)) in xrep_reset_perag_resv()
927 ASSERT(sc->sa.pag != NULL); in xrep_reset_perag_resv()
928 ASSERT(sc->ops->type == ST_PERAG); in xrep_reset_perag_resv()
929 ASSERT(sc->tp); in xrep_reset_perag_resv()
931 sc->flags &= ~XREP_RESET_PERAG_RESV; in xrep_reset_perag_resv()
932 error = xfs_ag_resv_free(sc->sa.pag); in xrep_reset_perag_resv()
935 error = xfs_ag_resv_init(sc->sa.pag, sc->tp); in xrep_reset_perag_resv()
936 if (error == -ENOSPC) { in xrep_reset_perag_resv()
937 xfs_err(sc->mp, in xrep_reset_perag_resv()
938 "Insufficient free space to reset per-AG reservation for AG %u after repair.", in xrep_reset_perag_resv()
939 sc->sa.pag->pag_agno); in xrep_reset_perag_resv()
953 if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_FORCE_REBUILD) in xrep_will_attempt()
957 if (XFS_TEST_ERROR(false, sc->mp, XFS_ERRTAG_FORCE_SCRUB_REPAIR)) in xrep_will_attempt()
960 /* Metadata is corrupt or failed cross-referencing. */ in xrep_will_attempt()
961 if (xchk_needs_repair(sc->sm)) in xrep_will_attempt()
967 /* Try to fix some part of a metadata inode by calling another scrubber. */
973 __u32 smtype = sc->sm->sm_type; in xrep_metadata_inode_subtype()
974 __u32 smflags = sc->sm->sm_flags; in xrep_metadata_inode_subtype()
975 unsigned int sick_mask = sc->sick_mask; in xrep_metadata_inode_subtype()
979 * Let's see if the inode needs repair. We're going to open-code calls in xrep_metadata_inode_subtype()
984 sc->sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT; in xrep_metadata_inode_subtype()
985 sc->sm->sm_type = scrub_type; in xrep_metadata_inode_subtype()
999 error = -EFSCORRUPTED; in xrep_metadata_inode_subtype()
1030 error = xfs_defer_finish(&sc->tp); in xrep_metadata_inode_subtype()
1033 error = xfs_trans_roll(&sc->tp); in xrep_metadata_inode_subtype()
1038 * Clear the corruption flags and re-check the metadata that we just in xrep_metadata_inode_subtype()
1041 sc->sm->sm_flags &= ~XFS_SCRUB_FLAGS_OUT; in xrep_metadata_inode_subtype()
1058 if (xchk_needs_repair(sc->sm)) { in xrep_metadata_inode_subtype()
1059 error = -EFSCORRUPTED; in xrep_metadata_inode_subtype()
1063 sc->sick_mask = sick_mask; in xrep_metadata_inode_subtype()
1064 sc->sm->sm_type = smtype; in xrep_metadata_inode_subtype()
1065 sc->sm->sm_flags = smflags; in xrep_metadata_inode_subtype()
1071 * sc->ip points to the metadata inode and the ILOCK is held on that inode.
1097 if (xfs_is_reflink_inode(sc->ip)) { in xrep_metadata_inode_forks()
1099 xfs_trans_ijoin(sc->tp, sc->ip, 0); in xrep_metadata_inode_forks()
1100 error = xfs_reflink_clear_inode_flag(sc->ip, &sc->tp); in xrep_metadata_inode_forks()
1110 error = xfs_trans_roll(&sc->tp); in xrep_metadata_inode_forks()