LCOV - code coverage report
Current view: top level - fs/xfs/scrub - alloc.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwa @ Mon Jul 31 20:08:17 PDT 2023 Lines: 61 71 85.9 %
Date: 2023-07-31 20:08:17 Functions: 9 9 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2017-2023 Oracle.  All Rights Reserved.
       4             :  * Author: Darrick J. Wong <djwong@kernel.org>
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_fs.h"
       8             : #include "xfs_shared.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_trans_resv.h"
      11             : #include "xfs_mount.h"
      12             : #include "xfs_btree.h"
      13             : #include "xfs_alloc.h"
      14             : #include "xfs_rmap.h"
      15             : #include "scrub/scrub.h"
      16             : #include "scrub/common.h"
      17             : #include "scrub/btree.h"
      18             : #include "xfs_ag.h"
      19             : 
      20             : /*
      21             :  * Set us up to scrub free space btrees.
      22             :  */
      23             : int
      24     1657988 : xchk_setup_ag_allocbt(
      25             :         struct xfs_scrub        *sc)
      26             : {
      27     1657988 :         if (xchk_need_intent_drain(sc))
      28        7625 :                 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
      29             : 
      30     1657988 :         return xchk_setup_ag_btree(sc, false);
      31             : }
      32             : 
      33             : /* Free space btree scrubber. */
      34             : 
      35             : struct xchk_alloc {
      36             :         /* Previous free space extent. */
      37             :         struct xfs_alloc_rec_incore     prev;
      38             : };
      39             : 
      40             : /*
      41             :  * Ensure there's a corresponding cntbt/bnobt record matching this
      42             :  * bnobt/cntbt record, respectively.
      43             :  */
      44             : STATIC void
      45   243608113 : xchk_allocbt_xref_other(
      46             :         struct xfs_scrub        *sc,
      47             :         xfs_agblock_t           agbno,
      48             :         xfs_extlen_t            len)
      49             : {
      50   243608113 :         struct xfs_btree_cur    **pcur;
      51   243608113 :         xfs_agblock_t           fbno;
      52   243608113 :         xfs_extlen_t            flen;
      53   243608113 :         int                     has_otherrec;
      54   243608113 :         int                     error;
      55             : 
      56   243608113 :         if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT)
      57   120923620 :                 pcur = &sc->sa.cnt_cur;
      58             :         else
      59   122684493 :                 pcur = &sc->sa.bno_cur;
      60   243608113 :         if (!*pcur || xchk_skip_xref(sc->sm))
      61         547 :                 return;
      62             : 
      63   243607581 :         error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec);
      64   243605478 :         if (!xchk_should_check_xref(sc, &error, pcur))
      65             :                 return;
      66   243604989 :         if (!has_otherrec) {
      67           0 :                 xchk_btree_xref_set_corrupt(sc, *pcur, 0);
      68           0 :                 return;
      69             :         }
      70             : 
      71   243604989 :         error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec);
      72   243606813 :         if (!xchk_should_check_xref(sc, &error, pcur))
      73             :                 return;
      74   243607702 :         if (!has_otherrec) {
      75           0 :                 xchk_btree_xref_set_corrupt(sc, *pcur, 0);
      76           0 :                 return;
      77             :         }
      78             : 
      79   243607702 :         if (fbno != agbno || flen != len)
      80         444 :                 xchk_btree_xref_set_corrupt(sc, *pcur, 0);
      81             : }
      82             : 
      83             : /* Cross-reference with the other btrees. */
      84             : STATIC void
      85   243608233 : xchk_allocbt_xref(
      86             :         struct xfs_scrub        *sc,
      87             :         const struct xfs_alloc_rec_incore *irec)
      88             : {
      89   243608233 :         xfs_agblock_t           agbno = irec->ar_startblock;
      90   243608233 :         xfs_extlen_t            len = irec->ar_blockcount;
      91             : 
      92   243608233 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
      93             :                 return;
      94             : 
      95   243608575 :         xchk_allocbt_xref_other(sc, agbno, len);
      96   243606857 :         xchk_xref_is_not_inode_chunk(sc, agbno, len);
      97   243605832 :         xchk_xref_has_no_owner(sc, agbno, len);
      98   243603996 :         xchk_xref_is_not_shared(sc, agbno, len);
      99   243608075 :         xchk_xref_is_not_cow_staging(sc, agbno, len);
     100             : }
     101             : 
     102             : /* Flag failures for records that could be merged. */
     103             : STATIC void
     104   243608158 : xchk_allocbt_mergeable(
     105             :         struct xchk_btree       *bs,
     106             :         struct xchk_alloc       *ca,
     107             :         const struct xfs_alloc_rec_incore *irec)
     108             : {
     109   243608158 :         if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     110             :                 return;
     111             : 
     112   243608158 :         if (ca->prev.ar_blockcount > 0 &&
     113   241958142 :             ca->prev.ar_startblock + ca->prev.ar_blockcount == irec->ar_startblock &&
     114           0 :             ca->prev.ar_blockcount + irec->ar_blockcount < (uint32_t)~0U)
     115           0 :                 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
     116             : 
     117   487216316 :         memcpy(&ca->prev, irec, sizeof(*irec));
     118             : }
     119             : 
     120             : /* Scrub a bnobt/cntbt record. */
     121             : STATIC int
     122   243607769 : xchk_allocbt_rec(
     123             :         struct xchk_btree               *bs,
     124             :         const union xfs_btree_rec       *rec)
     125             : {
     126   243607769 :         struct xfs_alloc_rec_incore     irec;
     127   243607769 :         struct xchk_alloc       *ca = bs->private;
     128             : 
     129   243607769 :         xfs_alloc_btrec_to_irec(rec, &irec);
     130   243608542 :         if (xfs_alloc_check_irec(bs->cur, &irec) != NULL) {
     131           0 :                 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
     132           0 :                 return 0;
     133             :         }
     134             : 
     135   243608644 :         xchk_allocbt_mergeable(bs, ca, &irec);
     136   243607958 :         xchk_allocbt_xref(bs->sc, &irec);
     137             : 
     138   243607958 :         return 0;
     139             : }
     140             : 
     141             : /* Scrub the freespace btrees for some AG. */
     142             : STATIC int
     143     1650351 : xchk_allocbt(
     144             :         struct xfs_scrub        *sc,
     145             :         xfs_btnum_t             which)
     146             : {
     147     1650351 :         struct xchk_alloc       ca = { };
     148     1650351 :         struct xfs_btree_cur    *cur;
     149             : 
     150     1650351 :         cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur;
     151     1650351 :         return xchk_btree(sc, cur, xchk_allocbt_rec, &XFS_RMAP_OINFO_AG, &ca);
     152             : }
     153             : 
     154             : int
     155      824907 : xchk_bnobt(
     156             :         struct xfs_scrub        *sc)
     157             : {
     158      824907 :         return xchk_allocbt(sc, XFS_BTNUM_BNO);
     159             : }
     160             : 
     161             : int
     162      825459 : xchk_cntbt(
     163             :         struct xfs_scrub        *sc)
     164             : {
     165      825459 :         return xchk_allocbt(sc, XFS_BTNUM_CNT);
     166             : }
     167             : 
     168             : /* xref check that the extent is not free */
     169             : void
     170  1328730051 : xchk_xref_is_used_space(
     171             :         struct xfs_scrub        *sc,
     172             :         xfs_agblock_t           agbno,
     173             :         xfs_extlen_t            len)
     174             : {
     175  1328730051 :         enum xbtree_recpacking  outcome;
     176  1328730051 :         int                     error;
     177             : 
     178  1328730051 :         if (!sc->sa.bno_cur || xchk_skip_xref(sc->sm))
     179           0 :                 return;
     180             : 
     181  1328730051 :         error = xfs_alloc_has_records(sc->sa.bno_cur, agbno, len, &outcome);
     182  1328775665 :         if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur))
     183             :                 return;
     184  1328768102 :         if (outcome != XBTREE_RECPACKING_EMPTY)
     185           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sa.bno_cur, 0);
     186             : }

Generated by: LCOV version 1.14