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-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 61 71 85.9 %
Date: 2023-07-31 20:08:22 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     1820280 : xchk_setup_ag_allocbt(
      25             :         struct xfs_scrub        *sc)
      26             : {
      27     1820280 :         if (xchk_need_intent_drain(sc))
      28        9967 :                 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
      29             : 
      30     1820280 :         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   327558495 : xchk_allocbt_xref_other(
      46             :         struct xfs_scrub        *sc,
      47             :         xfs_agblock_t           agbno,
      48             :         xfs_extlen_t            len)
      49             : {
      50   327558495 :         struct xfs_btree_cur    **pcur;
      51   327558495 :         xfs_agblock_t           fbno;
      52   327558495 :         xfs_extlen_t            flen;
      53   327558495 :         int                     has_otherrec;
      54   327558495 :         int                     error;
      55             : 
      56   327558495 :         if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT)
      57   162576543 :                 pcur = &sc->sa.cnt_cur;
      58             :         else
      59   164981952 :                 pcur = &sc->sa.bno_cur;
      60   327558495 :         if (!*pcur || xchk_skip_xref(sc->sm))
      61       26592 :                 return;
      62             : 
      63   327531903 :         error = xfs_alloc_lookup_le(*pcur, agbno, len, &has_otherrec);
      64   327552006 :         if (!xchk_should_check_xref(sc, &error, pcur))
      65             :                 return;
      66   327533770 :         if (!has_otherrec) {
      67           0 :                 xchk_btree_xref_set_corrupt(sc, *pcur, 0);
      68           0 :                 return;
      69             :         }
      70             : 
      71   327533770 :         error = xfs_alloc_get_rec(*pcur, &fbno, &flen, &has_otherrec);
      72   327481052 :         if (!xchk_should_check_xref(sc, &error, pcur))
      73             :                 return;
      74   327508741 :         if (!has_otherrec) {
      75           0 :                 xchk_btree_xref_set_corrupt(sc, *pcur, 0);
      76           0 :                 return;
      77             :         }
      78             : 
      79   327508741 :         if (fbno != agbno || flen != len)
      80        2459 :                 xchk_btree_xref_set_corrupt(sc, *pcur, 0);
      81             : }
      82             : 
      83             : /* Cross-reference with the other btrees. */
      84             : STATIC void
      85   327471428 : xchk_allocbt_xref(
      86             :         struct xfs_scrub        *sc,
      87             :         const struct xfs_alloc_rec_incore *irec)
      88             : {
      89   327471428 :         xfs_agblock_t           agbno = irec->ar_startblock;
      90   327471428 :         xfs_extlen_t            len = irec->ar_blockcount;
      91             : 
      92   327471428 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
      93             :                 return;
      94             : 
      95   327474445 :         xchk_allocbt_xref_other(sc, agbno, len);
      96   327551234 :         xchk_xref_is_not_inode_chunk(sc, agbno, len);
      97   327594659 :         xchk_xref_has_no_owner(sc, agbno, len);
      98   327562823 :         xchk_xref_is_not_shared(sc, agbno, len);
      99   327550796 :         xchk_xref_is_not_cow_staging(sc, agbno, len);
     100             : }
     101             : 
     102             : /* Flag failures for records that could be merged. */
     103             : STATIC void
     104   327470022 : xchk_allocbt_mergeable(
     105             :         struct xchk_btree       *bs,
     106             :         struct xchk_alloc       *ca,
     107             :         const struct xfs_alloc_rec_incore *irec)
     108             : {
     109   327470022 :         if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     110             :                 return;
     111             : 
     112   327470022 :         if (ca->prev.ar_blockcount > 0 &&
     113   325630184 :             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   654940044 :         memcpy(&ca->prev, irec, sizeof(*irec));
     118             : }
     119             : 
     120             : /* Scrub a bnobt/cntbt record. */
     121             : STATIC int
     122   327491792 : xchk_allocbt_rec(
     123             :         struct xchk_btree               *bs,
     124             :         const union xfs_btree_rec       *rec)
     125             : {
     126   327491792 :         struct xfs_alloc_rec_incore     irec;
     127   327491792 :         struct xchk_alloc       *ca = bs->private;
     128             : 
     129   327491792 :         xfs_alloc_btrec_to_irec(rec, &irec);
     130   327398486 :         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   327443329 :         xchk_allocbt_mergeable(bs, ca, &irec);
     136   327469557 :         xchk_allocbt_xref(bs->sc, &irec);
     137             : 
     138   327469557 :         return 0;
     139             : }
     140             : 
     141             : /* Scrub the freespace btrees for some AG. */
     142             : STATIC int
     143     1804641 : xchk_allocbt(
     144             :         struct xfs_scrub        *sc,
     145             :         xfs_btnum_t             which)
     146             : {
     147     1804641 :         struct xchk_alloc       ca = { };
     148     1804641 :         struct xfs_btree_cur    *cur;
     149             : 
     150     1804641 :         cur = which == XFS_BTNUM_BNO ? sc->sa.bno_cur : sc->sa.cnt_cur;
     151     1804641 :         return xchk_btree(sc, cur, xchk_allocbt_rec, &XFS_RMAP_OINFO_AG, &ca);
     152             : }
     153             : 
     154             : int
     155      901451 : xchk_bnobt(
     156             :         struct xfs_scrub        *sc)
     157             : {
     158      901451 :         return xchk_allocbt(sc, XFS_BTNUM_BNO);
     159             : }
     160             : 
     161             : int
     162      906231 : xchk_cntbt(
     163             :         struct xfs_scrub        *sc)
     164             : {
     165      906231 :         return xchk_allocbt(sc, XFS_BTNUM_CNT);
     166             : }
     167             : 
     168             : /* xref check that the extent is not free */
     169             : void
     170  1480641913 : xchk_xref_is_used_space(
     171             :         struct xfs_scrub        *sc,
     172             :         xfs_agblock_t           agbno,
     173             :         xfs_extlen_t            len)
     174             : {
     175  1480641913 :         enum xbtree_recpacking  outcome;
     176  1480641913 :         int                     error;
     177             : 
     178  1480641913 :         if (!sc->sa.bno_cur || xchk_skip_xref(sc->sm))
     179           0 :                 return;
     180             : 
     181  1480641913 :         error = xfs_alloc_has_records(sc->sa.bno_cur, agbno, len, &outcome);
     182  1481472040 :         if (!xchk_should_check_xref(sc, &error, &sc->sa.bno_cur))
     183             :                 return;
     184  1478945062 :         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