root/fs/xfs/scrub/health.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xchk_health_mask_for_scrub_type
  2. xchk_update_health
  3. xchk_ag_btree_healthy_enough

   1 // SPDX-License-Identifier: GPL-2.0+
   2 /*
   3  * Copyright (C) 2019 Oracle.  All Rights Reserved.
   4  * Author: Darrick J. Wong <darrick.wong@oracle.com>
   5  */
   6 #include "xfs.h"
   7 #include "xfs_fs.h"
   8 #include "xfs_shared.h"
   9 #include "xfs_format.h"
  10 #include "xfs_btree.h"
  11 #include "xfs_sb.h"
  12 #include "xfs_health.h"
  13 #include "scrub/scrub.h"
  14 
  15 /*
  16  * Scrub and In-Core Filesystem Health Assessments
  17  * ===============================================
  18  *
  19  * Online scrub and repair have the time and the ability to perform stronger
  20  * checks than we can do from the metadata verifiers, because they can
  21  * cross-reference records between data structures.  Therefore, scrub is in a
  22  * good position to update the online filesystem health assessments to reflect
  23  * the good/bad state of the data structure.
  24  *
  25  * We therefore extend scrub in the following ways to achieve this:
  26  *
  27  * 1. Create a "sick_mask" field in the scrub context.  When we're setting up a
  28  * scrub call, set this to the default XFS_SICK_* flag(s) for the selected
  29  * scrub type (call it A).  Scrub and repair functions can override the default
  30  * sick_mask value if they choose.
  31  *
  32  * 2. If the scrubber returns a runtime error code, we exit making no changes
  33  * to the incore sick state.
  34  *
  35  * 3. If the scrubber finds that A is clean, use sick_mask to clear the incore
  36  * sick flags before exiting.
  37  *
  38  * 4. If the scrubber finds that A is corrupt, use sick_mask to set the incore
  39  * sick flags.  If the user didn't want to repair then we exit, leaving the
  40  * metadata structure unfixed and the sick flag set.
  41  *
  42  * 5. Now we know that A is corrupt and the user wants to repair, so run the
  43  * repairer.  If the repairer returns an error code, we exit with that error
  44  * code, having made no further changes to the incore sick state.
  45  *
  46  * 6. If repair rebuilds A correctly and the subsequent re-scrub of A is clean,
  47  * use sick_mask to clear the incore sick flags.  This should have the effect
  48  * that A is no longer marked sick.
  49  *
  50  * 7. If repair rebuilds A incorrectly, the re-scrub will find it corrupt and
  51  * use sick_mask to set the incore sick flags.  This should have no externally
  52  * visible effect since we already set them in step (4).
  53  *
  54  * There are some complications to this story, however.  For certain types of
  55  * complementary metadata indices (e.g. inobt/finobt), it is easier to rebuild
  56  * both structures at the same time.  The following principles apply to this
  57  * type of repair strategy:
  58  *
  59  * 8. Any repair function that rebuilds multiple structures should update
  60  * sick_mask_visible to reflect whatever other structures are rebuilt, and
  61  * verify that all the rebuilt structures can pass a scrub check.  The outcomes
  62  * of 5-7 still apply, but with a sick_mask that covers everything being
  63  * rebuilt.
  64  */
  65 
  66 /* Map our scrub type to a sick mask and a set of health update functions. */
  67 
  68 enum xchk_health_group {
  69         XHG_FS = 1,
  70         XHG_RT,
  71         XHG_AG,
  72         XHG_INO,
  73 };
  74 
  75 struct xchk_health_map {
  76         enum xchk_health_group  group;
  77         unsigned int            sick_mask;
  78 };
  79 
  80 static const struct xchk_health_map type_to_health_flag[XFS_SCRUB_TYPE_NR] = {
  81         [XFS_SCRUB_TYPE_SB]             = { XHG_AG,  XFS_SICK_AG_SB },
  82         [XFS_SCRUB_TYPE_AGF]            = { XHG_AG,  XFS_SICK_AG_AGF },
  83         [XFS_SCRUB_TYPE_AGFL]           = { XHG_AG,  XFS_SICK_AG_AGFL },
  84         [XFS_SCRUB_TYPE_AGI]            = { XHG_AG,  XFS_SICK_AG_AGI },
  85         [XFS_SCRUB_TYPE_BNOBT]          = { XHG_AG,  XFS_SICK_AG_BNOBT },
  86         [XFS_SCRUB_TYPE_CNTBT]          = { XHG_AG,  XFS_SICK_AG_CNTBT },
  87         [XFS_SCRUB_TYPE_INOBT]          = { XHG_AG,  XFS_SICK_AG_INOBT },
  88         [XFS_SCRUB_TYPE_FINOBT]         = { XHG_AG,  XFS_SICK_AG_FINOBT },
  89         [XFS_SCRUB_TYPE_RMAPBT]         = { XHG_AG,  XFS_SICK_AG_RMAPBT },
  90         [XFS_SCRUB_TYPE_REFCNTBT]       = { XHG_AG,  XFS_SICK_AG_REFCNTBT },
  91         [XFS_SCRUB_TYPE_INODE]          = { XHG_INO, XFS_SICK_INO_CORE },
  92         [XFS_SCRUB_TYPE_BMBTD]          = { XHG_INO, XFS_SICK_INO_BMBTD },
  93         [XFS_SCRUB_TYPE_BMBTA]          = { XHG_INO, XFS_SICK_INO_BMBTA },
  94         [XFS_SCRUB_TYPE_BMBTC]          = { XHG_INO, XFS_SICK_INO_BMBTC },
  95         [XFS_SCRUB_TYPE_DIR]            = { XHG_INO, XFS_SICK_INO_DIR },
  96         [XFS_SCRUB_TYPE_XATTR]          = { XHG_INO, XFS_SICK_INO_XATTR },
  97         [XFS_SCRUB_TYPE_SYMLINK]        = { XHG_INO, XFS_SICK_INO_SYMLINK },
  98         [XFS_SCRUB_TYPE_PARENT]         = { XHG_INO, XFS_SICK_INO_PARENT },
  99         [XFS_SCRUB_TYPE_RTBITMAP]       = { XHG_RT,  XFS_SICK_RT_BITMAP },
 100         [XFS_SCRUB_TYPE_RTSUM]          = { XHG_RT,  XFS_SICK_RT_SUMMARY },
 101         [XFS_SCRUB_TYPE_UQUOTA]         = { XHG_FS,  XFS_SICK_FS_UQUOTA },
 102         [XFS_SCRUB_TYPE_GQUOTA]         = { XHG_FS,  XFS_SICK_FS_GQUOTA },
 103         [XFS_SCRUB_TYPE_PQUOTA]         = { XHG_FS,  XFS_SICK_FS_PQUOTA },
 104         [XFS_SCRUB_TYPE_FSCOUNTERS]     = { XHG_FS,  XFS_SICK_FS_COUNTERS },
 105 };
 106 
 107 /* Return the health status mask for this scrub type. */
 108 unsigned int
 109 xchk_health_mask_for_scrub_type(
 110         __u32                   scrub_type)
 111 {
 112         return type_to_health_flag[scrub_type].sick_mask;
 113 }
 114 
 115 /*
 116  * Update filesystem health assessments based on what we found and did.
 117  *
 118  * If the scrubber finds errors, we mark sick whatever's mentioned in
 119  * sick_mask, no matter whether this is a first scan or an
 120  * evaluation of repair effectiveness.
 121  *
 122  * Otherwise, no direct corruption was found, so mark whatever's in
 123  * sick_mask as healthy.
 124  */
 125 void
 126 xchk_update_health(
 127         struct xfs_scrub        *sc)
 128 {
 129         struct xfs_perag        *pag;
 130         bool                    bad;
 131 
 132         if (!sc->sick_mask)
 133                 return;
 134 
 135         bad = (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT);
 136         switch (type_to_health_flag[sc->sm->sm_type].group) {
 137         case XHG_AG:
 138                 pag = xfs_perag_get(sc->mp, sc->sm->sm_agno);
 139                 if (bad)
 140                         xfs_ag_mark_sick(pag, sc->sick_mask);
 141                 else
 142                         xfs_ag_mark_healthy(pag, sc->sick_mask);
 143                 xfs_perag_put(pag);
 144                 break;
 145         case XHG_INO:
 146                 if (!sc->ip)
 147                         return;
 148                 if (bad)
 149                         xfs_inode_mark_sick(sc->ip, sc->sick_mask);
 150                 else
 151                         xfs_inode_mark_healthy(sc->ip, sc->sick_mask);
 152                 break;
 153         case XHG_FS:
 154                 if (bad)
 155                         xfs_fs_mark_sick(sc->mp, sc->sick_mask);
 156                 else
 157                         xfs_fs_mark_healthy(sc->mp, sc->sick_mask);
 158                 break;
 159         case XHG_RT:
 160                 if (bad)
 161                         xfs_rt_mark_sick(sc->mp, sc->sick_mask);
 162                 else
 163                         xfs_rt_mark_healthy(sc->mp, sc->sick_mask);
 164                 break;
 165         default:
 166                 ASSERT(0);
 167                 break;
 168         }
 169 }
 170 
 171 /* Is the given per-AG btree healthy enough for scanning? */
 172 bool
 173 xchk_ag_btree_healthy_enough(
 174         struct xfs_scrub        *sc,
 175         struct xfs_perag        *pag,
 176         xfs_btnum_t             btnum)
 177 {
 178         unsigned int            mask = 0;
 179 
 180         /*
 181          * We always want the cursor if it's the same type as whatever we're
 182          * scrubbing, even if we already know the structure is corrupt.
 183          *
 184          * Otherwise, we're only interested in the btree for cross-referencing.
 185          * If we know the btree is bad then don't bother, just set XFAIL.
 186          */
 187         switch (btnum) {
 188         case XFS_BTNUM_BNO:
 189                 if (sc->sm->sm_type == XFS_SCRUB_TYPE_BNOBT)
 190                         return true;
 191                 mask = XFS_SICK_AG_BNOBT;
 192                 break;
 193         case XFS_BTNUM_CNT:
 194                 if (sc->sm->sm_type == XFS_SCRUB_TYPE_CNTBT)
 195                         return true;
 196                 mask = XFS_SICK_AG_CNTBT;
 197                 break;
 198         case XFS_BTNUM_INO:
 199                 if (sc->sm->sm_type == XFS_SCRUB_TYPE_INOBT)
 200                         return true;
 201                 mask = XFS_SICK_AG_INOBT;
 202                 break;
 203         case XFS_BTNUM_FINO:
 204                 if (sc->sm->sm_type == XFS_SCRUB_TYPE_FINOBT)
 205                         return true;
 206                 mask = XFS_SICK_AG_FINOBT;
 207                 break;
 208         case XFS_BTNUM_RMAP:
 209                 if (sc->sm->sm_type == XFS_SCRUB_TYPE_RMAPBT)
 210                         return true;
 211                 mask = XFS_SICK_AG_RMAPBT;
 212                 break;
 213         case XFS_BTNUM_REFC:
 214                 if (sc->sm->sm_type == XFS_SCRUB_TYPE_REFCNTBT)
 215                         return true;
 216                 mask = XFS_SICK_AG_REFCNTBT;
 217                 break;
 218         default:
 219                 ASSERT(0);
 220                 return true;
 221         }
 222 
 223         if (xfs_ag_has_sickness(pag, mask)) {
 224                 sc->sm->sm_flags |= XFS_SCRUB_OFLAG_XFAIL;
 225                 return false;
 226         }
 227 
 228         return true;
 229 }

/* [<][>][^][v][top][bottom][index][help] */