LCOV - code coverage report
Current view: top level - fs/xfs - xfs_health.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc3-djwx @ Mon Jul 31 20:08:22 PDT 2023 Lines: 142 161 88.2 %
Date: 2023-07-31 20:08:22 Functions: 14 17 82.4 %

          Line data    Source code
       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_log_format.h"
      11             : #include "xfs_trans_resv.h"
      12             : #include "xfs_mount.h"
      13             : #include "xfs_inode.h"
      14             : #include "xfs_trace.h"
      15             : #include "xfs_health.h"
      16             : #include "xfs_ag.h"
      17             : 
      18             : /*
      19             :  * Warn about metadata corruption that we detected but haven't fixed, and
      20             :  * make sure we're not sitting on anything that would get in the way of
      21             :  * recovery.
      22             :  */
      23             : void
      24       59234 : xfs_health_unmount(
      25             :         struct xfs_mount        *mp)
      26             : {
      27       59234 :         struct xfs_perag        *pag;
      28       59234 :         xfs_agnumber_t          agno;
      29       59234 :         unsigned int            sick = 0;
      30       59234 :         unsigned int            checked = 0;
      31       59234 :         bool                    warn = false;
      32             : 
      33      118468 :         if (xfs_is_shutdown(mp))
      34       13082 :                 return;
      35             : 
      36             :         /* Measure AG corruption levels. */
      37      435628 :         for_each_perag(mp, agno, pag) {
      38      389476 :                 xfs_ag_measure_sickness(pag, &sick, &checked);
      39      389476 :                 if (sick) {
      40          11 :                         trace_xfs_ag_unfixed_corruption(mp, agno, sick);
      41          11 :                         warn = true;
      42             :                 }
      43             :         }
      44             : 
      45             :         /* Measure realtime volume corruption levels. */
      46       46152 :         xfs_rt_measure_sickness(mp, &sick, &checked);
      47       46152 :         if (sick) {
      48           0 :                 trace_xfs_rt_unfixed_corruption(mp, sick);
      49           0 :                 warn = true;
      50             :         }
      51             : 
      52             :         /*
      53             :          * Measure fs corruption and keep the sample around for the warning.
      54             :          * See the note below for why we exempt FS_COUNTERS.
      55             :          */
      56       46152 :         xfs_fs_measure_sickness(mp, &sick, &checked);
      57       46152 :         if (sick & ~XFS_SICK_FS_COUNTERS) {
      58           0 :                 trace_xfs_fs_unfixed_corruption(mp, sick);
      59           0 :                 warn = true;
      60             :         }
      61             : 
      62       46152 :         if (warn) {
      63          11 :                 xfs_warn(mp,
      64             : "Uncorrected metadata errors detected; please run xfs_repair.");
      65             : 
      66             :                 /*
      67             :                  * We discovered uncorrected metadata problems at some point
      68             :                  * during this filesystem mount and have advised the
      69             :                  * administrator to run repair once the unmount completes.
      70             :                  *
      71             :                  * However, we must be careful -- when FSCOUNTERS are flagged
      72             :                  * unhealthy, the unmount procedure omits writing the clean
      73             :                  * unmount record to the log so that the next mount will run
      74             :                  * recovery and recompute the summary counters.  In other
      75             :                  * words, we leave a dirty log to get the counters fixed.
      76             :                  *
      77             :                  * Unfortunately, xfs_repair cannot recover dirty logs, so if
      78             :                  * there were filesystem problems, FSCOUNTERS was flagged, and
      79             :                  * the administrator takes our advice to run xfs_repair,
      80             :                  * they'll have to zap the log before repairing structures.
      81             :                  * We don't really want to encourage this, so we mark the
      82             :                  * FSCOUNTERS healthy so that a subsequent repair run won't see
      83             :                  * a dirty log.
      84             :                  */
      85          11 :                 if (sick & XFS_SICK_FS_COUNTERS)
      86           0 :                         xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);
      87             :         }
      88             : }
      89             : 
      90             : /* Mark unhealthy per-fs metadata. */
      91             : void
      92      611631 : xfs_fs_mark_sick(
      93             :         struct xfs_mount        *mp,
      94             :         unsigned int            mask)
      95             : {
      96      611631 :         ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY));
      97      611631 :         trace_xfs_fs_mark_sick(mp, mask);
      98             : 
      99      611445 :         spin_lock(&mp->m_sb_lock);
     100      612129 :         mp->m_fs_sick |= mask;
     101      612129 :         mp->m_fs_checked |= mask;
     102      612129 :         spin_unlock(&mp->m_sb_lock);
     103      612125 : }
     104             : 
     105             : /* Mark a per-fs metadata healed. */
     106             : void
     107      705103 : xfs_fs_mark_healthy(
     108             :         struct xfs_mount        *mp,
     109             :         unsigned int            mask)
     110             : {
     111      705103 :         ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY));
     112      705103 :         trace_xfs_fs_mark_healthy(mp, mask);
     113             : 
     114      705103 :         spin_lock(&mp->m_sb_lock);
     115      705103 :         mp->m_fs_sick &= ~mask;
     116      705103 :         mp->m_fs_checked |= mask;
     117      705103 :         spin_unlock(&mp->m_sb_lock);
     118      705103 : }
     119             : 
     120             : /* Sample which per-fs metadata are unhealthy. */
     121             : void
     122       94228 : xfs_fs_measure_sickness(
     123             :         struct xfs_mount        *mp,
     124             :         unsigned int            *sick,
     125             :         unsigned int            *checked)
     126             : {
     127      140380 :         spin_lock(&mp->m_sb_lock);
     128     5708605 :         *sick = mp->m_fs_sick;
     129     5708605 :         *checked = mp->m_fs_checked;
     130     5708605 :         spin_unlock(&mp->m_sb_lock);
     131       94228 : }
     132             : 
     133             : /* Mark unhealthy realtime metadata. */
     134             : void
     135           0 : xfs_rt_mark_sick(
     136             :         struct xfs_mount        *mp,
     137             :         unsigned int            mask)
     138             : {
     139           0 :         ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY));
     140           0 :         trace_xfs_rt_mark_sick(mp, mask);
     141             : 
     142           0 :         spin_lock(&mp->m_sb_lock);
     143           0 :         mp->m_rt_sick |= mask;
     144           0 :         mp->m_rt_checked |= mask;
     145           0 :         spin_unlock(&mp->m_sb_lock);
     146           0 : }
     147             : 
     148             : /* Mark a realtime metadata healed. */
     149             : void
     150       89673 : xfs_rt_mark_healthy(
     151             :         struct xfs_mount        *mp,
     152             :         unsigned int            mask)
     153             : {
     154       89673 :         ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY));
     155       89673 :         trace_xfs_rt_mark_healthy(mp, mask);
     156             : 
     157       89673 :         spin_lock(&mp->m_sb_lock);
     158       89673 :         mp->m_rt_sick &= ~mask;
     159       89673 :         mp->m_rt_checked |= mask;
     160       89673 :         spin_unlock(&mp->m_sb_lock);
     161       89673 : }
     162             : 
     163             : /* Sample which realtime metadata are unhealthy. */
     164             : void
     165           0 : xfs_rt_measure_sickness(
     166             :         struct xfs_mount        *mp,
     167             :         unsigned int            *sick,
     168             :         unsigned int            *checked)
     169             : {
     170       46152 :         spin_lock(&mp->m_sb_lock);
     171     5614377 :         *sick = mp->m_rt_sick;
     172     5614377 :         *checked = mp->m_rt_checked;
     173     5614377 :         spin_unlock(&mp->m_sb_lock);
     174           0 : }
     175             : 
     176             : /* Mark unhealthy per-ag metadata. */
     177             : void
     178          11 : xfs_ag_mark_sick(
     179             :         struct xfs_perag        *pag,
     180             :         unsigned int            mask)
     181             : {
     182          11 :         ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY));
     183          11 :         trace_xfs_ag_mark_sick(pag->pag_mount, pag->pag_agno, mask);
     184             : 
     185          11 :         spin_lock(&pag->pag_state_lock);
     186          11 :         pag->pag_sick |= mask;
     187          11 :         pag->pag_checked |= mask;
     188          11 :         spin_unlock(&pag->pag_state_lock);
     189          11 : }
     190             : 
     191             : /* Mark per-ag metadata ok. */
     192             : void
     193    10195838 : xfs_ag_mark_healthy(
     194             :         struct xfs_perag        *pag,
     195             :         unsigned int            mask)
     196             : {
     197    10195838 :         ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY));
     198    10195838 :         trace_xfs_ag_mark_healthy(pag->pag_mount, pag->pag_agno, mask);
     199             : 
     200    10186548 :         spin_lock(&pag->pag_state_lock);
     201    10199174 :         pag->pag_sick &= ~mask;
     202    10199174 :         pag->pag_checked |= mask;
     203    10199174 :         spin_unlock(&pag->pag_state_lock);
     204    10198516 : }
     205             : 
     206             : /* Sample which per-ag metadata are unhealthy. */
     207             : void
     208  3536968954 : xfs_ag_measure_sickness(
     209             :         struct xfs_perag        *pag,
     210             :         unsigned int            *sick,
     211             :         unsigned int            *checked)
     212             : {
     213  3537358430 :         spin_lock(&pag->pag_state_lock);
     214  3539596885 :         *sick = pag->pag_sick;
     215  3539596885 :         *checked = pag->pag_checked;
     216  3539596885 :         spin_unlock(&pag->pag_state_lock);
     217  3539416570 : }
     218             : 
     219             : /* Mark the unhealthy parts of an inode. */
     220             : void
     221          33 : xfs_inode_mark_sick(
     222             :         struct xfs_inode        *ip,
     223             :         unsigned int            mask)
     224             : {
     225          33 :         ASSERT(!(mask & ~XFS_SICK_INO_PRIMARY));
     226          33 :         trace_xfs_inode_mark_sick(ip, mask);
     227             : 
     228          33 :         spin_lock(&ip->i_flags_lock);
     229          33 :         ip->i_sick |= mask;
     230          33 :         ip->i_checked |= mask;
     231          33 :         spin_unlock(&ip->i_flags_lock);
     232             : 
     233             :         /*
     234             :          * Keep this inode around so we don't lose the sickness report.  Scrub
     235             :          * grabs inodes with DONTCACHE assuming that most inode are ok, which
     236             :          * is not the case here.
     237             :          */
     238          33 :         spin_lock(&VFS_I(ip)->i_lock);
     239          33 :         VFS_I(ip)->i_state &= ~I_DONTCACHE;
     240          33 :         spin_unlock(&VFS_I(ip)->i_lock);
     241          33 : }
     242             : 
     243             : /* Mark parts of an inode healed. */
     244             : void
     245  1379670915 : xfs_inode_mark_healthy(
     246             :         struct xfs_inode        *ip,
     247             :         unsigned int            mask)
     248             : {
     249  1379670915 :         ASSERT(!(mask & ~XFS_SICK_INO_PRIMARY));
     250  1379670915 :         trace_xfs_inode_mark_healthy(ip, mask);
     251             : 
     252  1379310355 :         spin_lock(&ip->i_flags_lock);
     253  1382093021 :         ip->i_sick &= ~mask;
     254  1382093021 :         ip->i_checked |= mask;
     255  1382093021 :         spin_unlock(&ip->i_flags_lock);
     256  1382741949 : }
     257             : 
     258             : /* Sample which parts of an inode are unhealthy. */
     259             : void
     260           0 : xfs_inode_measure_sickness(
     261             :         struct xfs_inode        *ip,
     262             :         unsigned int            *sick,
     263             :         unsigned int            *checked)
     264             : {
     265           0 :         spin_lock(&ip->i_flags_lock);
     266 53197045502 :         *sick = ip->i_sick;
     267 53197045502 :         *checked = ip->i_checked;
     268 53197045502 :         spin_unlock(&ip->i_flags_lock);
     269           0 : }
     270             : 
     271             : /* Mappings between internal sick masks and ioctl sick masks. */
     272             : 
     273             : struct ioctl_sick_map {
     274             :         unsigned int            sick_mask;
     275             :         unsigned int            ioctl_mask;
     276             : };
     277             : 
     278             : static const struct ioctl_sick_map fs_map[] = {
     279             :         { XFS_SICK_FS_COUNTERS, XFS_FSOP_GEOM_SICK_COUNTERS},
     280             :         { XFS_SICK_FS_UQUOTA,   XFS_FSOP_GEOM_SICK_UQUOTA },
     281             :         { XFS_SICK_FS_GQUOTA,   XFS_FSOP_GEOM_SICK_GQUOTA },
     282             :         { XFS_SICK_FS_PQUOTA,   XFS_FSOP_GEOM_SICK_PQUOTA },
     283             :         { 0, 0 },
     284             : };
     285             : 
     286             : static const struct ioctl_sick_map rt_map[] = {
     287             :         { XFS_SICK_RT_BITMAP,   XFS_FSOP_GEOM_SICK_RT_BITMAP },
     288             :         { XFS_SICK_RT_SUMMARY,  XFS_FSOP_GEOM_SICK_RT_SUMMARY },
     289             :         { 0, 0 },
     290             : };
     291             : 
     292             : static inline void
     293    33336017 : xfgeo_health_tick(
     294             :         struct xfs_fsop_geom            *geo,
     295             :         unsigned int                    sick,
     296             :         unsigned int                    checked,
     297             :         const struct ioctl_sick_map     *m)
     298             : {
     299    33336017 :         if (checked & m->sick_mask)
     300      710851 :                 geo->checked |= m->ioctl_mask;
     301    33336017 :         if (sick & m->sick_mask)
     302       52702 :                 geo->sick |= m->ioctl_mask;
     303    33336017 : }
     304             : 
     305             : /* Fill out fs geometry health info. */
     306             : void
     307     5556293 : xfs_fsop_geom_health(
     308             :         struct xfs_mount                *mp,
     309             :         struct xfs_fsop_geom            *geo)
     310             : {
     311     5556293 :         const struct ioctl_sick_map     *m;
     312     5556293 :         unsigned int                    sick;
     313     5556293 :         unsigned int                    checked;
     314             : 
     315     5556293 :         geo->sick = 0;
     316     5556293 :         geo->checked = 0;
     317             : 
     318     5556293 :         xfs_fs_measure_sickness(mp, &sick, &checked);
     319    33340906 :         for (m = fs_map; m->sick_mask; m++)
     320    22218483 :                 xfgeo_health_tick(geo, sick, checked, m);
     321             : 
     322     5554198 :         xfs_rt_measure_sickness(mp, &sick, &checked);
     323    22263503 :         for (m = rt_map; m->sick_mask; m++)
     324    11131048 :                 xfgeo_health_tick(geo, sick, checked, m);
     325     5564230 : }
     326             : 
     327             : static const struct ioctl_sick_map ag_map[] = {
     328             :         { XFS_SICK_AG_SB,       XFS_AG_GEOM_SICK_SB },
     329             :         { XFS_SICK_AG_AGF,      XFS_AG_GEOM_SICK_AGF },
     330             :         { XFS_SICK_AG_AGFL,     XFS_AG_GEOM_SICK_AGFL },
     331             :         { XFS_SICK_AG_AGI,      XFS_AG_GEOM_SICK_AGI },
     332             :         { XFS_SICK_AG_BNOBT,    XFS_AG_GEOM_SICK_BNOBT },
     333             :         { XFS_SICK_AG_CNTBT,    XFS_AG_GEOM_SICK_CNTBT },
     334             :         { XFS_SICK_AG_INOBT,    XFS_AG_GEOM_SICK_INOBT },
     335             :         { XFS_SICK_AG_FINOBT,   XFS_AG_GEOM_SICK_FINOBT },
     336             :         { XFS_SICK_AG_RMAPBT,   XFS_AG_GEOM_SICK_RMAPBT },
     337             :         { XFS_SICK_AG_REFCNTBT, XFS_AG_GEOM_SICK_REFCNTBT },
     338             :         { 0, 0 },
     339             : };
     340             : 
     341             : /* Fill out ag geometry health info. */
     342             : void
     343       67727 : xfs_ag_geom_health(
     344             :         struct xfs_perag                *pag,
     345             :         struct xfs_ag_geometry          *ageo)
     346             : {
     347       67727 :         const struct ioctl_sick_map     *m;
     348       67727 :         unsigned int                    sick;
     349       67727 :         unsigned int                    checked;
     350             : 
     351       67727 :         ageo->ag_sick = 0;
     352       67727 :         ageo->ag_checked = 0;
     353             : 
     354       67727 :         xfs_ag_measure_sickness(pag, &sick, &checked);
     355      812724 :         for (m = ag_map; m->sick_mask; m++) {
     356      677270 :                 if (checked & m->sick_mask)
     357      650282 :                         ageo->ag_checked |= m->ioctl_mask;
     358      677270 :                 if (sick & m->sick_mask)
     359          11 :                         ageo->ag_sick |= m->ioctl_mask;
     360             :         }
     361       67727 : }
     362             : 
     363             : static const struct ioctl_sick_map ino_map[] = {
     364             :         { XFS_SICK_INO_CORE,    XFS_BS_SICK_INODE },
     365             :         { XFS_SICK_INO_BMBTD,   XFS_BS_SICK_BMBTD },
     366             :         { XFS_SICK_INO_BMBTA,   XFS_BS_SICK_BMBTA },
     367             :         { XFS_SICK_INO_BMBTC,   XFS_BS_SICK_BMBTC },
     368             :         { XFS_SICK_INO_DIR,     XFS_BS_SICK_DIR },
     369             :         { XFS_SICK_INO_XATTR,   XFS_BS_SICK_XATTR },
     370             :         { XFS_SICK_INO_SYMLINK, XFS_BS_SICK_SYMLINK },
     371             :         { XFS_SICK_INO_PARENT,  XFS_BS_SICK_PARENT },
     372             :         { 0, 0 },
     373             : };
     374             : 
     375             : /* Fill out bulkstat health info. */
     376             : void
     377 52167494627 : xfs_bulkstat_health(
     378             :         struct xfs_inode                *ip,
     379             :         struct xfs_bulkstat             *bs)
     380             : {
     381 52167494627 :         const struct ioctl_sick_map     *m;
     382 52167494627 :         unsigned int                    sick;
     383 52167494627 :         unsigned int                    checked;
     384             : 
     385 52167494627 :         bs->bs_sick = 0;
     386 52167494627 :         bs->bs_checked = 0;
     387             : 
     388 52167494627 :         xfs_inode_measure_sickness(ip, &sick, &checked);
     389 >52082*10^7 :         for (m = ino_map; m->sick_mask; m++) {
     390 >41474*10^7 :                 if (checked & m->sick_mask)
     391 29421947381 :                         bs->bs_checked |= m->ioctl_mask;
     392 >41474*10^7 :                 if (sick & m->sick_mask)
     393           0 :                         bs->bs_sick |= m->ioctl_mask;
     394             :         }
     395 52878031787 : }

Generated by: LCOV version 1.14