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-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 117 133 88.0 %
Date: 2023-07-31 20:08:27 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       42363 : xchk_setup_rtrmapbt(
      35             :         struct xfs_scrub        *sc)
      36             : {
      37       42363 :         struct xfs_mount        *mp = sc->mp;
      38       42363 :         struct xfs_rtgroup      *rtg;
      39       42363 :         int                     error = 0;
      40             : 
      41       42363 :         if (xchk_need_intent_drain(sc))
      42        4000 :                 xchk_fsgates_enable(sc, XCHK_FSGATES_DRAIN);
      43             : 
      44       42363 :         rtg = xfs_rtgroup_get(mp, sc->sm->sm_agno);
      45       42363 :         if (!rtg)
      46             :                 return -ENOENT;
      47             : 
      48       84726 :         if (xchk_could_repair(sc)) {
      49        3356 :                 error = xrep_setup_rtrmapbt(sc);
      50        3356 :                 if (error)
      51             :                         return error;
      52             :         }
      53             : 
      54       42363 :         error = xchk_setup_rt(sc);
      55       42363 :         if (error)
      56           0 :                 goto out_rtg;
      57             : 
      58       42363 :         error = xchk_install_live_inode(sc, rtg->rtg_rmapip);
      59       42363 :         if (error)
      60           0 :                 goto out_rtg;
      61             : 
      62       42363 :         error = xchk_ino_dqattach(sc);
      63       42363 :         if (error)
      64           0 :                 goto out_rtg;
      65             : 
      66       42363 :         error = xchk_rtgroup_init(sc, rtg->rtg_rgno, &sc->sr, XCHK_RTGLOCK_ALL);
      67       42363 : out_rtg:
      68       42363 :         xfs_rtgroup_put(rtg);
      69       42363 :         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   174307720 : xchk_rtrmapbt_is_shareable(
      91             :         struct xfs_scrub                *sc,
      92             :         const struct xfs_rmap_irec      *irec)
      93             : {
      94   174307720 :         if (!xfs_has_rtreflink(sc->mp))
      95             :                 return false;
      96   174307720 :         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   608232186 : xchk_rtrmapbt_check_overlapping(
     104             :         struct xchk_btree               *bs,
     105             :         struct xchk_rtrmap              *cr,
     106             :         const struct xfs_rmap_irec      *irec)
     107             : {
     108   608232186 :         xfs_rtblock_t                   pnext, inext;
     109             : 
     110   608232186 :         if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     111             :                 return;
     112             : 
     113             :         /* No previous record? */
     114   608232186 :         if (cr->overlap_rec.rm_blockcount == 0)
     115       38579 :                 goto set_prev;
     116             : 
     117             :         /* Do overlap_rec and irec overlap? */
     118   608193607 :         pnext = cr->overlap_rec.rm_startblock + cr->overlap_rec.rm_blockcount;
     119   608193607 :         if (pnext <= irec->rm_startblock)
     120   521039432 :                 goto set_prev;
     121             : 
     122             :         /* Overlap is only allowed if both records are data fork mappings. */
     123    87154175 :         if (!xchk_rtrmapbt_is_shareable(bs->sc, &cr->overlap_rec) ||
     124    87154175 :             !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    87154327 :         inext = irec->rm_startblock + irec->rm_blockcount;
     129    87154327 :         if (pnext > inext)
     130             :                 return;
     131             : 
     132    53965790 : set_prev:
     133  1150087602 :         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   608222412 : xchk_rtrmap_mergeable(
     139             :         struct xchk_rtrmap              *cr,
     140             :         const struct xfs_rmap_irec      *r2)
     141             : {
     142   608222412 :         const struct xfs_rmap_irec      *r1 = &cr->prev_rec;
     143             : 
     144             :         /* Ignore if prev_rec is not yet initialized. */
     145   608222412 :         if (cr->prev_rec.rm_blockcount == 0)
     146             :                 return false;
     147             : 
     148   608183833 :         if (r1->rm_owner != r2->rm_owner)
     149             :                 return false;
     150    24897263 :         if (r1->rm_startblock + r1->rm_blockcount != r2->rm_startblock)
     151             :                 return false;
     152    20248554 :         if ((unsigned long long)r1->rm_blockcount + r2->rm_blockcount >
     153             :             XFS_RMAP_LEN_MAX)
     154             :                 return false;
     155    20248554 :         if (r1->rm_flags != r2->rm_flags)
     156             :                 return false;
     157     5963184 :         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   608205040 : xchk_rtrmapbt_check_mergeable(
     163             :         struct xchk_btree               *bs,
     164             :         struct xchk_rtrmap              *cr,
     165             :         const struct xfs_rmap_irec      *irec)
     166             : {
     167   608205040 :         if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     168             :                 return;
     169             : 
     170   608205040 :         if (xchk_rtrmap_mergeable(cr, irec))
     171           0 :                 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
     172             : 
     173  1216410080 :         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   605517435 : xchk_rtrmapbt_xref_rtrefc(
     179             :         struct xfs_scrub        *sc,
     180             :         struct xfs_rmap_irec    *irec)
     181             : {
     182   605517435 :         xfs_rgblock_t           fbno;
     183   605517435 :         xfs_extlen_t            flen;
     184   605517435 :         bool                    is_inode;
     185   605517435 :         bool                    is_bmbt;
     186   605517435 :         bool                    is_attr;
     187   605517435 :         bool                    is_unwritten;
     188   605517435 :         int                     error;
     189             : 
     190   605517435 :         if (!sc->sr.refc_cur || xchk_skip_xref(sc->sm))
     191           0 :                 return;
     192             : 
     193   605517435 :         is_inode = !XFS_RMAP_NON_INODE_OWNER(irec->rm_owner);
     194   605517435 :         is_bmbt = irec->rm_flags & XFS_RMAP_BMBT_BLOCK;
     195   605517435 :         is_attr = irec->rm_flags & XFS_RMAP_ATTR_FORK;
     196   605517435 :         is_unwritten = irec->rm_flags & XFS_RMAP_UNWRITTEN;
     197             : 
     198             :         /* If this is shared, must be a data fork extent. */
     199   605517435 :         error = xfs_refcount_find_shared(sc->sr.refc_cur, irec->rm_startblock,
     200             :                         irec->rm_blockcount, &fbno, &flen, false);
     201   605413245 :         if (!xchk_should_check_xref(sc, &error, &sc->sr.refc_cur))
     202             :                 return;
     203   605449305 :         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   608189667 : xchk_rtrmapbt_xref(
     210             :         struct xfs_scrub        *sc,
     211             :         struct xfs_rmap_irec    *irec)
     212             : {
     213   608189667 :         xfs_rtblock_t           rtbno;
     214             : 
     215   608189667 :         if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     216             :                 return;
     217             : 
     218   608213624 :         rtbno = xfs_rgbno_to_rtb(sc->mp, sc->sr.rtg->rtg_rgno,
     219             :                         irec->rm_startblock);
     220             : 
     221   608223606 :         xchk_xref_is_used_rt_space(sc, rtbno, irec->rm_blockcount);
     222   608236357 :         if (irec->rm_owner == XFS_RMAP_OWN_COW)
     223     2718836 :                 xchk_xref_is_cow_staging(sc, irec->rm_startblock,
     224             :                                 irec->rm_blockcount);
     225             :         else
     226   605517521 :                 xchk_rtrmapbt_xref_rtrefc(sc, irec);
     227             : }
     228             : 
     229             : /* Scrub a realtime rmapbt record. */
     230             : STATIC int
     231   608208924 : xchk_rtrmapbt_rec(
     232             :         struct xchk_btree               *bs,
     233             :         const union xfs_btree_rec       *rec)
     234             : {
     235   608208924 :         struct xchk_rtrmap              *cr = bs->private;
     236   608208924 :         struct xfs_rmap_irec            irec;
     237             : 
     238  1216422480 :         if (xfs_rmap_btrec_to_irec(rec, &irec) != NULL ||
     239   608183733 :             xfs_rmap_check_irec(bs->cur, &irec) != NULL) {
     240       39423 :                 xchk_btree_set_corrupt(bs->sc, bs->cur, 0);
     241       39423 :                 return 0;
     242             :         }
     243             : 
     244   608214050 :         if (bs->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
     245             :                 return 0;
     246             : 
     247   608214474 :         xchk_rtrmapbt_check_mergeable(bs, cr, &irec);
     248   608195486 :         xchk_rtrmapbt_check_overlapping(bs, cr, &irec);
     249   608198791 :         xchk_rtrmapbt_xref(bs->sc, &irec);
     250   608198791 :         return 0;
     251             : }
     252             : 
     253             : /* Scrub the realtime rmap btree. */
     254             : int
     255       38579 : xchk_rtrmapbt(
     256             :         struct xfs_scrub        *sc)
     257             : {
     258       38579 :         struct xfs_owner_info   oinfo;
     259       38579 :         struct xchk_rtrmap      cr = { };
     260       38579 :         int                     error;
     261             : 
     262       38579 :         error = xchk_metadata_inode_forks(sc);
     263       38579 :         if (error || (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT))
     264             :                 return error;
     265             : 
     266       38579 :         xfs_rmap_ino_bmbt_owner(&oinfo, sc->sr.rtg->rtg_rmapip->i_ino,
     267             :                         XFS_DATA_FORK);
     268       38579 :         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     3838017 : xchk_xref_has_no_rt_owner(
     274             :         struct xfs_scrub        *sc,
     275             :         xfs_rgblock_t           bno,
     276             :         xfs_extlen_t            len)
     277             : {
     278     3838017 :         enum xbtree_recpacking  outcome;
     279     3838017 :         int                     error;
     280             : 
     281     3838017 :         if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
     282           0 :                 return;
     283             : 
     284     3838017 :         error = xfs_rmap_has_records(sc->sr.rmap_cur, bno, len, &outcome);
     285     3837974 :         if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
     286             :                 return;
     287     3837972 :         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     3916050 : xchk_xref_has_rt_owner(
     294             :         struct xfs_scrub        *sc,
     295             :         xfs_rgblock_t           bno,
     296             :         xfs_extlen_t            len)
     297             : {
     298     3916050 :         enum xbtree_recpacking  outcome;
     299     3916050 :         int                     error;
     300             : 
     301     3916050 :         if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
     302           0 :                 return;
     303             : 
     304     3916050 :         error = xfs_rmap_has_records(sc->sr.rmap_cur, bno, len, &outcome);
     305     3916155 :         if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
     306             :                 return;
     307     3916174 :         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     5653966 : 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     5653966 :         struct xfs_rmap_matches         res;
     320     5653966 :         int                             error;
     321             : 
     322     5653966 :         if (!sc->sr.rmap_cur || xchk_skip_xref(sc->sm))
     323           0 :                 return;
     324             : 
     325     5653966 :         error = xfs_rmap_count_owners(sc->sr.rmap_cur, bno, len, oinfo, &res);
     326     5654102 :         if (!xchk_should_check_xref(sc, &error, &sc->sr.rmap_cur))
     327             :                 return;
     328     5654096 :         if (res.matches != 1)
     329           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
     330     5654096 :         if (res.bad_non_owner_matches)
     331           0 :                 xchk_btree_xref_set_corrupt(sc, sc->sr.rmap_cur, 0);
     332     5654096 :         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