LCOV - code coverage report
Current view: top level - fs/xfs/scrub - rtrmap.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsx @ Mon Jul 31 20:08:34 PDT 2023 Lines: 117 133 88.0 %
Date: 2023-07-31 20:08:34 Functions: 12 12 100.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2018-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_defer.h"
      13             : #include "xfs_btree.h"
      14             : #include "xfs_bit.h"
      15             : #include "xfs_log_format.h"
      16             : #include "xfs_trans.h"
      17             : #include "xfs_sb.h"
      18             : #include "xfs_rmap.h"
      19             : #include "xfs_rmap_btree.h"
      20             : #include "xfs_rtrmap_btree.h"
      21             : #include "xfs_inode.h"
      22             : #include "xfs_rtalloc.h"
      23             : #include "xfs_rtgroup.h"
      24             : #include "xfs_refcount.h"
      25             : #include "scrub/xfs_scrub.h"
      26             : #include "scrub/scrub.h"
      27             : #include "scrub/common.h"
      28             : #include "scrub/btree.h"
      29             : #include "scrub/trace.h"
      30             : #include "scrub/repair.h"
      31             : 
      32             : /* Set us up with the realtime metadata locked. */
      33             : int
      34      106453 : xchk_setup_rtrmapbt(
      35             :         struct xfs_scrub        *sc)
      36             : {
      37      106453 :         struct xfs_mount        *mp = sc->mp;
      38      106453 :         struct xfs_rtgroup      *rtg;
      39      106453 :         int                     error = 0;
      40             : 
      41      106453 :         if (xchk_need_intent_drain(sc))
      42        4504 :                 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
      43             : 
      44      106453 :         rtg = xfs_rtgroup_get(mp, sc->sm->sm_agno);
      45      106510 :         if (!rtg)
      46             :                 return -ENOENT;
      47             : 
      48      213020 :         if (xchk_could_repair(sc)) {
      49       11467 :                 error = xrep_setup_rtrmapbt(sc);
      50       11467 :                 if (error)
      51             :                         return error;
      52             :         }
      53             : 
      54      106510 :         error = xchk_setup_rt(sc);
      55      106448 :         if (error)
      56          40 :                 goto out_rtg;
      57             : 
      58      106408 :         error = xchk_install_live_inode(sc, rtg->rtg_rmapip);
      59      106455 :         if (error)
      60           0 :                 goto out_rtg;
      61             : 
      62      106455 :         error = xchk_ino_dqattach(sc);
      63      106386 :         if (error)
      64           0 :                 goto out_rtg;
      65             : 
      66      106386 :         error = xchk_rtgroup_init(sc, rtg->rtg_rgno, &sc->sr, XCHK_RTGLOCK_ALL);
      67      106499 : out_rtg:
      68      106499 :         xfs_rtgroup_put(rtg);
      69      106499 :         return error;
      70             : }
      71             : 
      72             : /* Realtime reverse mapping. */
      73             : 
      74             : struct xchk_rtrmap {
      75             :         /*
      76             :          * The furthest-reaching of the rmapbt records that we've already
      77             :          * processed.  This enables us to detect overlapping records for space
      78             :          * allocations that cannot be shared.
      79             :          */
      80             :         struct xfs_rmap_irec    overlap_rec;
      81             : 
      82             :         /*
      83             :          * The previous rmapbt record, so that we can check for two records
      84             :          * that could be one.
      85             :          */
      86             :         struct xfs_rmap_irec    prev_rec;
      87             : };
      88             : 
      89             : static inline bool
      90   364386008 : xchk_rtrmapbt_is_shareable(
      91             :         struct xfs_scrub                *sc,
      92             :         const struct xfs_rmap_irec      *irec)
      93             : {
      94   364386008 :         if (!xfs_has_rtreflink(sc->mp))
      95             :                 return false;
      96   364386008 :         if (irec->rm_flags & XFS_RMAP_UNWRITTEN)
      97           0 :                 return false;
      98             :         return true;
      99             : }
     100             : 
     101             : /* Flag failures for records that overlap but cannot. */
     102             : STATIC void
     103   759607637 : xchk_rtrmapbt_check_overlapping(
     104             :         struct xchk_btree               *bs,
     105             :         struct xchk_rtrmap              *cr,
     106             :         const struct xfs_rmap_irec      *irec)
     107             : {
     108   759607637 :         xfs_rtblock_t                   pnext, inext;
     109             : 
     110   759607637 :         if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     111             :                 return;
     112             : 
     113             :         /* No previous record? */
     114   759607637 :         if (cr->overlap_rec.rm_blockcount == 0)
     115      102396 :                 goto set_prev;
     116             : 
     117             :         /* Do overlap_rec and irec overlap? */
     118   759505241 :         pnext = cr->overlap_rec.rm_startblock + cr->overlap_rec.rm_blockcount;
     119   759505241 :         if (pnext <= irec->rm_startblock)
     120   577221455 :                 goto set_prev;
     121             : 
     122             :         /* Overlap is only allowed if both records are data fork mappings. */
     123   182283786 :         if (!xchk_rtrmapbt_is_shareable(bs->sc, &cr->overlap_rec) ||
     124   182283786 :             !xchk_rtrmapbt_is_shareable(bs->sc, irec))
     125           0 :                 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
     126             : 
     127             :         /* Save whichever rmap record extends furthest. */
     128   182128938 :         inext = irec->rm_startblock + irec->rm_blockcount;
     129   182128938 :         if (pnext > inext)
     130             :                 return;
     131             : 
     132   151914564 : set_prev:
     133  1458476830 :         memcpy(&cr->overlap_rec, irec, sizeof(struct xfs_rmap_irec));
     134             : }
     135             : 
     136             : /* Decide if two reverse-mapping records can be merged. */
     137             : static inline bool
     138   759623794 : xchk_rtrmap_mergeable(
     139             :         struct xchk_rtrmap              *cr,
     140             :         const struct xfs_rmap_irec      *r2)
     141             : {
     142   759623794 :         const struct xfs_rmap_irec      *r1 = &cr->prev_rec;
     143             : 
     144             :         /* Ignore if prev_rec is not yet initialized. */
     145   759623794 :         if (cr->prev_rec.rm_blockcount == 0)
     146             :                 return false;
     147             : 
     148   759521398 :         if (r1->rm_owner != r2->rm_owner)
     149             :                 return false;
     150    87378439 :         if (r1->rm_startblock + r1->rm_blockcount != r2->rm_startblock)
     151             :                 return false;
     152    46384035 :         if ((unsigned long long)r1->rm_blockcount + r2->rm_blockcount >
     153             :             XFS_RMAP_LEN_MAX)
     154             :                 return false;
     155    46384035 :         if (r1->rm_flags != r2->rm_flags)
     156             :                 return false;
     157    14280392 :         return r1->rm_offset + r1->rm_blockcount == r2->rm_offset;
     158             : }
     159             : 
     160             : /* Flag failures for records that could be merged. */
     161             : STATIC void
     162   759556919 : xchk_rtrmapbt_check_mergeable(
     163             :         struct xchk_btree               *bs,
     164             :         struct xchk_rtrmap              *cr,
     165             :         const struct xfs_rmap_irec      *irec)
     166             : {
     167   759556919 :         if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     168             :                 return;
     169             : 
     170   759556919 :         if (xchk_rtrmap_mergeable(cr, irec))
     171           0 :                 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
     172             : 
     173  1519113838 :         memcpy(&cr->prev_rec, irec, sizeof(struct xfs_rmap_irec));
     174             : }
     175             : 
     176             : /* Cross-reference a rmap against the refcount btree. */
     177             : STATIC void
     178   757220251 : xchk_rtrmapbt_xref_rtrefc(
     179             :         struct xfs_scrub        *sc,
     180             :         struct xfs_rmap_irec    *irec)
     181             : {
     182   757220251 :         xfs_rgblock_t           fbno;
     183   757220251 :         xfs_extlen_t            flen;
     184   757220251 :         bool                    is_inode;
     185   757220251 :         bool                    is_bmbt;
     186   757220251 :         bool                    is_attr;
     187   757220251 :         bool                    is_unwritten;
     188   757220251 :         int                     error;
     189             : 
     190   757220251 :         if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm))
     191       29499 :                 return;
     192             : 
     193   757190752 :         is_inode = !XFS_RMAP_NON_INODE_OWNER(irec->rm_owner);
     194   757190752 :         is_bmbt = irec->rm_flags & XFS_RMAP_BMBT_BLOCK;
     195   757190752 :         is_attr = irec->rm_flags & XFS_RMAP_ATTR_FORK;
     196   757190752 :         is_unwritten = irec->rm_flags & XFS_RMAP_UNWRITTEN;
     197             : 
     198             :         /* If this is shared, must be a data fork extent. */
     199   757190752 :         error = xfs_refcount_find_shared(sc->sr.refc_cur, irec->rm_startblock,
     200             :                         irec->rm_blockcount, &fbno, &flen, false);
     201   756981916 :         if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
     202             :                 return;
     203   756946607 :         if (flen != 0 && (!is_inode || is_attr || is_bmbt || is_unwritten))
     204           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sr.refc_cur, 0);
     205             : }
     206             : 
     207             : /* Cross-reference with other metadata. */
     208             : STATIC void
     209   759385065 : xchk_rtrmapbt_xref(
     210             :         struct xfs_scrub        *sc,
     211             :         struct xfs_rmap_irec    *irec)
     212             : {
     213   759385065 :         xfs_rtblock_t           rtbno;
     214             : 
     215   759385065 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     216             :                 return;
     217             : 
     218   759349175 :         rtbno = xfs_rgbno_to_rtb(sc->mp, sc->sr.rtg->rtg_rgno,
     219             :                         irec->rm_startblock);
     220             : 
     221   759651500 :         xchk_xref_is_used_rt_space(sc, rtbno, irec->rm_blockcount);
     222   760221502 :         if (irec->rm_owner == XFS_RMAP_OWN_COW)
     223     2915067 :                 xchk_xref_is_cow_staging(sc, irec->rm_startblock,
     224             :                                 irec->rm_blockcount);
     225             :         else
     226   757306435 :                 xchk_rtrmapbt_xref_rtrefc(sc, irec);
     227             : }
     228             : 
     229             : /* Scrub a realtime rmapbt record. */
     230             : STATIC int
     231   759911603 : xchk_rtrmapbt_rec(
     232             :         struct xchk_btree               *bs,
     233             :         const union xfs_btree_rec       *rec)
     234             : {
     235   759911603 :         struct xchk_rtrmap              *cr = bs->private;
     236   759911603 :         struct xfs_rmap_irec            irec;
     237             : 
     238  1519359199 :         if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL ||
     239   759733392 :             xfs_rmap_check_irec(bs->cur, &irec) != NULL) {
     240           0 :                 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
     241           0 :                 return 0;
     242             :         }
     243             : 
     244   759459048 :         if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     245             :                 return 0;
     246             : 
     247   759493328 :         xchk_rtrmapbt_check_mergeable(bs, cr, &irec);
     248   759478438 :         xchk_rtrmapbt_check_overlapping(bs, cr, &irec);
     249   759355736 :         xchk_rtrmapbt_xref(bs->sc, &irec);
     250   759355736 :         return 0;
     251             : }
     252             : 
     253             : /* Scrub the realtime rmap btree. */
     254             : int
     255      102352 : xchk_rtrmapbt(
     256             :         struct xfs_scrub        *sc)
     257             : {
     258      102352 :         struct xfs_owner_info   oinfo;
     259      102352 :         struct xchk_rtrmap      cr = { };
     260      102352 :         int                     error;
     261             : 
     262      102352 :         error = xchk_metadata_inode_forks(sc);
     263      102396 :         if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
     264             :                 return error;
     265             : 
     266      102396 :         xfs_rmap_ino_bmbt_owner(&oinfo, sc->sr.rtg->rtg_rmapip->i_ino,
     267             :                         XFS_DATA_FORK);
     268      102396 :         return xchk_btree(sc, sc->sr.rmap_cur, xchk_rtrmapbt_rec, &oinfo, &cr);
     269             : }
     270             : 
     271             : /* xref check that the extent has no realtime reverse mapping at all */
     272             : void
     273    24778535 : xchk_xref_has_no_rt_owner(
     274             :         struct xfs_scrub        *sc,
     275             :         xfs_rgblock_t           bno,
     276             :         xfs_extlen_t            len)
     277             : {
     278    24778535 :         enum xbtree_recpacking  outcome;
     279    24778535 :         int                     error;
     280             : 
     281    24778535 :         if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
     282           0 :                 return;
     283             : 
     284    24778535 :         error = xfs_rmap_has_records(sc->sr.rmap_cur, bno, len, &outcome);
     285    24781813 :         if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
     286             :                 return;
     287    24781720 :         if (outcome != XBTREE_RECPACKING_EMPTY)
     288           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
     289             : }
     290             : 
     291             : /* xref check that the extent is completely mapped */
     292             : void
     293    24873409 : xchk_xref_has_rt_owner(
     294             :         struct xfs_scrub        *sc,
     295             :         xfs_rgblock_t           bno,
     296             :         xfs_extlen_t            len)
     297             : {
     298    24873409 :         enum xbtree_recpacking  outcome;
     299    24873409 :         int                     error;
     300             : 
     301    24873409 :         if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
     302           0 :                 return;
     303             : 
     304    24873409 :         error = xfs_rmap_has_records(sc->sr.rmap_cur, bno, len, &outcome);
     305    24873638 :         if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
     306             :                 return;
     307    24873513 :         if (outcome != XBTREE_RECPACKING_FULL)
     308           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
     309             : }
     310             : 
     311             : /* xref check that the extent is only owned by a given owner */
     312             : void
     313    31046016 : xchk_xref_is_only_rt_owned_by(
     314             :         struct xfs_scrub                *sc,
     315             :         xfs_agblock_t                   bno,
     316             :         xfs_extlen_t                    len,
     317             :         const struct xfs_owner_info     *oinfo)
     318             : {
     319    31046016 :         struct xfs_rmap_matches         res;
     320    31046016 :         int                             error;
     321             : 
     322    31046016 :         if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
     323           0 :                 return;
     324             : 
     325    31046016 :         error = xfs_rmap_count_owners(sc->sr.rmap_cur, bno, len, oinfo, &res);
     326    31061287 :         if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
     327             :                 return;
     328    31059913 :         if (res.matches != 1)
     329           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
     330    31059913 :         if (res.bad_non_owner_matches)
     331           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
     332    31059913 :         if (res.non_owner_matches)
     333           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
     334             : }

Generated by: LCOV version 1.14