Commit f1077579 authored by Chandan Babu R's avatar Chandan Babu R

Merge tag 'indirect-health-reporting-6.9_2024-02-23' of...

Merge tag 'indirect-health-reporting-6.9_2024-02-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux into xfs-6.9-mergeC

xfs: indirect health reporting

This series enables the XFS health reporting infrastructure to remember
indirect health concerns when resources are scarce.  For example, if a
scrub notices that there's something wrong with an inode's metadata but
memory reclaim needs to free the incore inode, we want to record in the
perag data the fact that there was some inode somewhere with an error.
The perag structures never go away.

The first two patches in this series set that up, and the third one
provides a means for xfs_scrub to tell the kernel that it can forget the
indirect problem report.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChandan Babu R <chandanbabu@kernel.org>

* tag 'indirect-health-reporting-6.9_2024-02-23' of https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfs-linux:
  xfs: update health status if we get a clean bill of health
  xfs: remember sick inodes that get inactivated
  xfs: add secondary and indirect classes to the health tracking system
parents 6fe1910e a1f3e0cc
...@@ -294,6 +294,7 @@ struct xfs_ag_geometry { ...@@ -294,6 +294,7 @@ struct xfs_ag_geometry {
#define XFS_AG_GEOM_SICK_FINOBT (1 << 7) /* free inode index */ #define XFS_AG_GEOM_SICK_FINOBT (1 << 7) /* free inode index */
#define XFS_AG_GEOM_SICK_RMAPBT (1 << 8) /* reverse mappings */ #define XFS_AG_GEOM_SICK_RMAPBT (1 << 8) /* reverse mappings */
#define XFS_AG_GEOM_SICK_REFCNTBT (1 << 9) /* reference counts */ #define XFS_AG_GEOM_SICK_REFCNTBT (1 << 9) /* reference counts */
#define XFS_AG_GEOM_SICK_INODES (1 << 10) /* bad inodes were seen */
/* /*
* Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT
...@@ -713,9 +714,10 @@ struct xfs_scrub_metadata { ...@@ -713,9 +714,10 @@ struct xfs_scrub_metadata {
#define XFS_SCRUB_TYPE_FSCOUNTERS 24 /* fs summary counters */ #define XFS_SCRUB_TYPE_FSCOUNTERS 24 /* fs summary counters */
#define XFS_SCRUB_TYPE_QUOTACHECK 25 /* quota counters */ #define XFS_SCRUB_TYPE_QUOTACHECK 25 /* quota counters */
#define XFS_SCRUB_TYPE_NLINKS 26 /* inode link counts */ #define XFS_SCRUB_TYPE_NLINKS 26 /* inode link counts */
#define XFS_SCRUB_TYPE_HEALTHY 27 /* everything checked out ok */
/* Number of scrub subcommands. */ /* Number of scrub subcommands. */
#define XFS_SCRUB_TYPE_NR 27 #define XFS_SCRUB_TYPE_NR 28
/* i: Repair this metadata. */ /* i: Repair this metadata. */
#define XFS_SCRUB_IFLAG_REPAIR (1u << 0) #define XFS_SCRUB_IFLAG_REPAIR (1u << 0)
......
...@@ -31,6 +31,19 @@ ...@@ -31,6 +31,19 @@
* - !checked && sick => errors have been observed during normal operation, * - !checked && sick => errors have been observed during normal operation,
* but the metadata has not been checked thoroughly * but the metadata has not been checked thoroughly
* - !checked && !sick => has not been examined since mount * - !checked && !sick => has not been examined since mount
*
* Evidence of health problems can be sorted into three basic categories:
*
* a) Primary evidence, which signals that something is defective within the
* general grouping of metadata.
*
* b) Secondary evidence, which are side effects of primary problem but are
* not themselves problems. These can be forgotten when the primary
* health problems are addressed.
*
* c) Indirect evidence, which points to something being wrong in another
* group, but we had to release resources and this is all that's left of
* that state.
*/ */
struct xfs_mount; struct xfs_mount;
...@@ -63,6 +76,7 @@ struct xfs_da_args; ...@@ -63,6 +76,7 @@ struct xfs_da_args;
#define XFS_SICK_AG_FINOBT (1 << 7) /* free inode index */ #define XFS_SICK_AG_FINOBT (1 << 7) /* free inode index */
#define XFS_SICK_AG_RMAPBT (1 << 8) /* reverse mappings */ #define XFS_SICK_AG_RMAPBT (1 << 8) /* reverse mappings */
#define XFS_SICK_AG_REFCNTBT (1 << 9) /* reference counts */ #define XFS_SICK_AG_REFCNTBT (1 << 9) /* reference counts */
#define XFS_SICK_AG_INODES (1 << 10) /* inactivated bad inodes */
/* Observable health issues for inode metadata. */ /* Observable health issues for inode metadata. */
#define XFS_SICK_INO_CORE (1 << 0) /* inode core */ #define XFS_SICK_INO_CORE (1 << 0) /* inode core */
...@@ -79,6 +93,9 @@ struct xfs_da_args; ...@@ -79,6 +93,9 @@ struct xfs_da_args;
#define XFS_SICK_INO_DIR_ZAPPED (1 << 10) /* directory erased */ #define XFS_SICK_INO_DIR_ZAPPED (1 << 10) /* directory erased */
#define XFS_SICK_INO_SYMLINK_ZAPPED (1 << 11) /* symlink erased */ #define XFS_SICK_INO_SYMLINK_ZAPPED (1 << 11) /* symlink erased */
/* Don't propagate sick status to ag health summary during inactivation */
#define XFS_SICK_INO_FORGET (1 << 12)
/* Primary evidence of health problems in a given group. */ /* Primary evidence of health problems in a given group. */
#define XFS_SICK_FS_PRIMARY (XFS_SICK_FS_COUNTERS | \ #define XFS_SICK_FS_PRIMARY (XFS_SICK_FS_COUNTERS | \
XFS_SICK_FS_UQUOTA | \ XFS_SICK_FS_UQUOTA | \
...@@ -115,6 +132,36 @@ struct xfs_da_args; ...@@ -115,6 +132,36 @@ struct xfs_da_args;
XFS_SICK_INO_DIR_ZAPPED | \ XFS_SICK_INO_DIR_ZAPPED | \
XFS_SICK_INO_SYMLINK_ZAPPED) XFS_SICK_INO_SYMLINK_ZAPPED)
/* Secondary state related to (but not primary evidence of) health problems. */
#define XFS_SICK_FS_SECONDARY (0)
#define XFS_SICK_RT_SECONDARY (0)
#define XFS_SICK_AG_SECONDARY (0)
#define XFS_SICK_INO_SECONDARY (XFS_SICK_INO_FORGET)
/* Evidence of health problems elsewhere. */
#define XFS_SICK_FS_INDIRECT (0)
#define XFS_SICK_RT_INDIRECT (0)
#define XFS_SICK_AG_INDIRECT (XFS_SICK_AG_INODES)
#define XFS_SICK_INO_INDIRECT (0)
/* All health masks. */
#define XFS_SICK_FS_ALL (XFS_SICK_FS_PRIMARY | \
XFS_SICK_FS_SECONDARY | \
XFS_SICK_FS_INDIRECT)
#define XFS_SICK_RT_ALL (XFS_SICK_RT_PRIMARY | \
XFS_SICK_RT_SECONDARY | \
XFS_SICK_RT_INDIRECT)
#define XFS_SICK_AG_ALL (XFS_SICK_AG_PRIMARY | \
XFS_SICK_AG_SECONDARY | \
XFS_SICK_AG_INDIRECT)
#define XFS_SICK_INO_ALL (XFS_SICK_INO_PRIMARY | \
XFS_SICK_INO_SECONDARY | \
XFS_SICK_INO_INDIRECT | \
XFS_SICK_INO_ZAPPED)
/* /*
* These functions must be provided by the xfs implementation. Function * These functions must be provided by the xfs implementation. Function
* behavior with respect to the first argument should be as follows: * behavior with respect to the first argument should be as follows:
......
...@@ -139,7 +139,7 @@ xfs_imap_to_bp( ...@@ -139,7 +139,7 @@ xfs_imap_to_bp(
imap->im_len, XBF_UNMAPPED, bpp, &xfs_inode_buf_ops); imap->im_len, XBF_UNMAPPED, bpp, &xfs_inode_buf_ops);
if (xfs_metadata_is_sick(error)) if (xfs_metadata_is_sick(error))
xfs_agno_mark_sick(mp, xfs_daddr_to_agno(mp, imap->im_blkno), xfs_agno_mark_sick(mp, xfs_daddr_to_agno(mp, imap->im_blkno),
XFS_SICK_AG_INOBT); XFS_SICK_AG_INODES);
return error; return error;
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "xfs_health.h" #include "xfs_health.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/health.h" #include "scrub/health.h"
#include "scrub/common.h"
/* /*
* Scrub and In-Core Filesystem Health Assessments * Scrub and In-Core Filesystem Health Assessments
...@@ -149,6 +150,24 @@ xchk_file_looks_zapped( ...@@ -149,6 +150,24 @@ xchk_file_looks_zapped(
return xfs_inode_has_sickness(sc->ip, mask); return xfs_inode_has_sickness(sc->ip, mask);
} }
/*
* Scrub gave the filesystem a clean bill of health, so clear all the indirect
* markers of past problems (at least for the fs and ags) so that we can be
* healthy again.
*/
STATIC void
xchk_mark_all_healthy(
struct xfs_mount *mp)
{
struct xfs_perag *pag;
xfs_agnumber_t agno;
xfs_fs_mark_healthy(mp, XFS_SICK_FS_INDIRECT);
xfs_rt_mark_healthy(mp, XFS_SICK_RT_INDIRECT);
for_each_perag(mp, agno, pag)
xfs_ag_mark_healthy(pag, XFS_SICK_AG_INDIRECT);
}
/* /*
* Update filesystem health assessments based on what we found and did. * Update filesystem health assessments based on what we found and did.
* *
...@@ -166,6 +185,18 @@ xchk_update_health( ...@@ -166,6 +185,18 @@ xchk_update_health(
struct xfs_perag *pag; struct xfs_perag *pag;
bool bad; bool bad;
/*
* The HEALTHY scrub type is a request from userspace to clear all the
* indirect flags after a clean scan of the entire filesystem. As such
* there's no sick flag defined for it, so we branch here ahead of the
* mask check.
*/
if (sc->sm->sm_type == XFS_SCRUB_TYPE_HEALTHY &&
!(sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)) {
xchk_mark_all_healthy(sc->mp);
return;
}
if (!sc->sick_mask) if (!sc->sick_mask)
return; return;
...@@ -183,9 +214,19 @@ xchk_update_health( ...@@ -183,9 +214,19 @@ xchk_update_health(
case XHG_INO: case XHG_INO:
if (!sc->ip) if (!sc->ip)
return; return;
if (bad) if (bad) {
xfs_inode_mark_corrupt(sc->ip, sc->sick_mask); unsigned int mask = sc->sick_mask;
else
/*
* If we're coming in for repairs then we don't want
* sickness flags to propagate to the incore health
* status if the inode gets inactivated before we can
* fix it.
*/
if (sc->sm->sm_flags & XFS_SCRUB_IFLAG_REPAIR)
mask |= XFS_SICK_INO_FORGET;
xfs_inode_mark_corrupt(sc->ip, mask);
} else
xfs_inode_mark_healthy(sc->ip, sc->sick_mask); xfs_inode_mark_healthy(sc->ip, sc->sick_mask);
break; break;
case XHG_FS: case XHG_FS:
...@@ -275,3 +316,36 @@ xchk_ag_btree_healthy_enough( ...@@ -275,3 +316,36 @@ xchk_ag_btree_healthy_enough(
return true; return true;
} }
/*
* Quick scan to double-check that there isn't any evidence of lingering
* primary health problems. If we're still clear, then the health update will
* take care of clearing the indirect evidence.
*/
int
xchk_health_record(
struct xfs_scrub *sc)
{
struct xfs_mount *mp = sc->mp;
struct xfs_perag *pag;
xfs_agnumber_t agno;
unsigned int sick;
unsigned int checked;
xfs_fs_measure_sickness(mp, &sick, &checked);
if (sick & XFS_SICK_FS_PRIMARY)
xchk_set_corrupt(sc);
xfs_rt_measure_sickness(mp, &sick, &checked);
if (sick & XFS_SICK_RT_PRIMARY)
xchk_set_corrupt(sc);
for_each_perag(mp, agno, pag) {
xfs_ag_measure_sickness(pag, &sick, &checked);
if (sick & XFS_SICK_AG_PRIMARY)
xchk_set_corrupt(sc);
}
return 0;
}
...@@ -12,5 +12,6 @@ bool xchk_ag_btree_healthy_enough(struct xfs_scrub *sc, struct xfs_perag *pag, ...@@ -12,5 +12,6 @@ bool xchk_ag_btree_healthy_enough(struct xfs_scrub *sc, struct xfs_perag *pag,
xfs_btnum_t btnum); xfs_btnum_t btnum);
void xchk_mark_healthy_if_clean(struct xfs_scrub *sc, unsigned int mask); void xchk_mark_healthy_if_clean(struct xfs_scrub *sc, unsigned int mask);
bool xchk_file_looks_zapped(struct xfs_scrub *sc, unsigned int mask); bool xchk_file_looks_zapped(struct xfs_scrub *sc, unsigned int mask);
int xchk_health_record(struct xfs_scrub *sc);
#endif /* __XFS_SCRUB_HEALTH_H__ */ #endif /* __XFS_SCRUB_HEALTH_H__ */
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "xfs_errortag.h" #include "xfs_errortag.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_reflink.h" #include "xfs_reflink.h"
#include "xfs_health.h"
#include "scrub/scrub.h" #include "scrub/scrub.h"
#include "scrub/common.h" #include "scrub/common.h"
#include "scrub/trace.h" #include "scrub/trace.h"
......
...@@ -378,6 +378,12 @@ static const struct xchk_meta_ops meta_scrub_ops[] = { ...@@ -378,6 +378,12 @@ static const struct xchk_meta_ops meta_scrub_ops[] = {
.scrub = xchk_nlinks, .scrub = xchk_nlinks,
.repair = xrep_nlinks, .repair = xrep_nlinks,
}, },
[XFS_SCRUB_TYPE_HEALTHY] = { /* fs healthy; clean all reminders */
.type = ST_FS,
.setup = xchk_setup_fs,
.scrub = xchk_health_record,
.repair = xrep_notsupported,
},
}; };
static int static int
......
...@@ -69,6 +69,7 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_PQUOTA); ...@@ -69,6 +69,7 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_PQUOTA);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_FSCOUNTERS); TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_FSCOUNTERS);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_QUOTACHECK); TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_QUOTACHECK);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_NLINKS); TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_NLINKS);
TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_HEALTHY);
#define XFS_SCRUB_TYPE_STRINGS \ #define XFS_SCRUB_TYPE_STRINGS \
{ XFS_SCRUB_TYPE_PROBE, "probe" }, \ { XFS_SCRUB_TYPE_PROBE, "probe" }, \
...@@ -97,7 +98,8 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_NLINKS); ...@@ -97,7 +98,8 @@ TRACE_DEFINE_ENUM(XFS_SCRUB_TYPE_NLINKS);
{ XFS_SCRUB_TYPE_PQUOTA, "prjquota" }, \ { XFS_SCRUB_TYPE_PQUOTA, "prjquota" }, \
{ XFS_SCRUB_TYPE_FSCOUNTERS, "fscounters" }, \ { XFS_SCRUB_TYPE_FSCOUNTERS, "fscounters" }, \
{ XFS_SCRUB_TYPE_QUOTACHECK, "quotacheck" }, \ { XFS_SCRUB_TYPE_QUOTACHECK, "quotacheck" }, \
{ XFS_SCRUB_TYPE_NLINKS, "nlinks" } { XFS_SCRUB_TYPE_NLINKS, "nlinks" }, \
{ XFS_SCRUB_TYPE_HEALTHY, "healthy" }
#define XFS_SCRUB_FLAG_STRINGS \ #define XFS_SCRUB_FLAG_STRINGS \
{ XFS_SCRUB_IFLAG_REPAIR, "repair" }, \ { XFS_SCRUB_IFLAG_REPAIR, "repair" }, \
......
...@@ -97,7 +97,7 @@ xfs_fs_mark_sick( ...@@ -97,7 +97,7 @@ xfs_fs_mark_sick(
struct xfs_mount *mp, struct xfs_mount *mp,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY)); ASSERT(!(mask & ~XFS_SICK_FS_ALL));
trace_xfs_fs_mark_sick(mp, mask); trace_xfs_fs_mark_sick(mp, mask);
spin_lock(&mp->m_sb_lock); spin_lock(&mp->m_sb_lock);
...@@ -111,7 +111,7 @@ xfs_fs_mark_corrupt( ...@@ -111,7 +111,7 @@ xfs_fs_mark_corrupt(
struct xfs_mount *mp, struct xfs_mount *mp,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY)); ASSERT(!(mask & ~XFS_SICK_FS_ALL));
trace_xfs_fs_mark_corrupt(mp, mask); trace_xfs_fs_mark_corrupt(mp, mask);
spin_lock(&mp->m_sb_lock); spin_lock(&mp->m_sb_lock);
...@@ -126,11 +126,13 @@ xfs_fs_mark_healthy( ...@@ -126,11 +126,13 @@ xfs_fs_mark_healthy(
struct xfs_mount *mp, struct xfs_mount *mp,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~XFS_SICK_FS_PRIMARY)); ASSERT(!(mask & ~XFS_SICK_FS_ALL));
trace_xfs_fs_mark_healthy(mp, mask); trace_xfs_fs_mark_healthy(mp, mask);
spin_lock(&mp->m_sb_lock); spin_lock(&mp->m_sb_lock);
mp->m_fs_sick &= ~mask; mp->m_fs_sick &= ~mask;
if (!(mp->m_fs_sick & XFS_SICK_FS_PRIMARY))
mp->m_fs_sick &= ~XFS_SICK_FS_SECONDARY;
mp->m_fs_checked |= mask; mp->m_fs_checked |= mask;
spin_unlock(&mp->m_sb_lock); spin_unlock(&mp->m_sb_lock);
} }
...@@ -154,7 +156,7 @@ xfs_rt_mark_sick( ...@@ -154,7 +156,7 @@ xfs_rt_mark_sick(
struct xfs_mount *mp, struct xfs_mount *mp,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY)); ASSERT(!(mask & ~XFS_SICK_RT_ALL));
trace_xfs_rt_mark_sick(mp, mask); trace_xfs_rt_mark_sick(mp, mask);
spin_lock(&mp->m_sb_lock); spin_lock(&mp->m_sb_lock);
...@@ -168,7 +170,7 @@ xfs_rt_mark_corrupt( ...@@ -168,7 +170,7 @@ xfs_rt_mark_corrupt(
struct xfs_mount *mp, struct xfs_mount *mp,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY)); ASSERT(!(mask & ~XFS_SICK_RT_ALL));
trace_xfs_rt_mark_corrupt(mp, mask); trace_xfs_rt_mark_corrupt(mp, mask);
spin_lock(&mp->m_sb_lock); spin_lock(&mp->m_sb_lock);
...@@ -183,11 +185,13 @@ xfs_rt_mark_healthy( ...@@ -183,11 +185,13 @@ xfs_rt_mark_healthy(
struct xfs_mount *mp, struct xfs_mount *mp,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~XFS_SICK_RT_PRIMARY)); ASSERT(!(mask & ~XFS_SICK_RT_ALL));
trace_xfs_rt_mark_healthy(mp, mask); trace_xfs_rt_mark_healthy(mp, mask);
spin_lock(&mp->m_sb_lock); spin_lock(&mp->m_sb_lock);
mp->m_rt_sick &= ~mask; mp->m_rt_sick &= ~mask;
if (!(mp->m_rt_sick & XFS_SICK_RT_PRIMARY))
mp->m_rt_sick &= ~XFS_SICK_RT_SECONDARY;
mp->m_rt_checked |= mask; mp->m_rt_checked |= mask;
spin_unlock(&mp->m_sb_lock); spin_unlock(&mp->m_sb_lock);
} }
...@@ -228,7 +232,7 @@ xfs_ag_mark_sick( ...@@ -228,7 +232,7 @@ xfs_ag_mark_sick(
struct xfs_perag *pag, struct xfs_perag *pag,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY)); ASSERT(!(mask & ~XFS_SICK_AG_ALL));
trace_xfs_ag_mark_sick(pag->pag_mount, pag->pag_agno, mask); trace_xfs_ag_mark_sick(pag->pag_mount, pag->pag_agno, mask);
spin_lock(&pag->pag_state_lock); spin_lock(&pag->pag_state_lock);
...@@ -242,7 +246,7 @@ xfs_ag_mark_corrupt( ...@@ -242,7 +246,7 @@ xfs_ag_mark_corrupt(
struct xfs_perag *pag, struct xfs_perag *pag,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY)); ASSERT(!(mask & ~XFS_SICK_AG_ALL));
trace_xfs_ag_mark_corrupt(pag->pag_mount, pag->pag_agno, mask); trace_xfs_ag_mark_corrupt(pag->pag_mount, pag->pag_agno, mask);
spin_lock(&pag->pag_state_lock); spin_lock(&pag->pag_state_lock);
...@@ -257,11 +261,13 @@ xfs_ag_mark_healthy( ...@@ -257,11 +261,13 @@ xfs_ag_mark_healthy(
struct xfs_perag *pag, struct xfs_perag *pag,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~XFS_SICK_AG_PRIMARY)); ASSERT(!(mask & ~XFS_SICK_AG_ALL));
trace_xfs_ag_mark_healthy(pag->pag_mount, pag->pag_agno, mask); trace_xfs_ag_mark_healthy(pag->pag_mount, pag->pag_agno, mask);
spin_lock(&pag->pag_state_lock); spin_lock(&pag->pag_state_lock);
pag->pag_sick &= ~mask; pag->pag_sick &= ~mask;
if (!(pag->pag_sick & XFS_SICK_AG_PRIMARY))
pag->pag_sick &= ~XFS_SICK_AG_SECONDARY;
pag->pag_checked |= mask; pag->pag_checked |= mask;
spin_unlock(&pag->pag_state_lock); spin_unlock(&pag->pag_state_lock);
} }
...@@ -285,7 +291,7 @@ xfs_inode_mark_sick( ...@@ -285,7 +291,7 @@ xfs_inode_mark_sick(
struct xfs_inode *ip, struct xfs_inode *ip,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~(XFS_SICK_INO_PRIMARY | XFS_SICK_INO_ZAPPED))); ASSERT(!(mask & ~XFS_SICK_INO_ALL));
trace_xfs_inode_mark_sick(ip, mask); trace_xfs_inode_mark_sick(ip, mask);
spin_lock(&ip->i_flags_lock); spin_lock(&ip->i_flags_lock);
...@@ -308,7 +314,7 @@ xfs_inode_mark_corrupt( ...@@ -308,7 +314,7 @@ xfs_inode_mark_corrupt(
struct xfs_inode *ip, struct xfs_inode *ip,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~(XFS_SICK_INO_PRIMARY | XFS_SICK_INO_ZAPPED))); ASSERT(!(mask & ~XFS_SICK_INO_ALL));
trace_xfs_inode_mark_corrupt(ip, mask); trace_xfs_inode_mark_corrupt(ip, mask);
spin_lock(&ip->i_flags_lock); spin_lock(&ip->i_flags_lock);
...@@ -332,11 +338,13 @@ xfs_inode_mark_healthy( ...@@ -332,11 +338,13 @@ xfs_inode_mark_healthy(
struct xfs_inode *ip, struct xfs_inode *ip,
unsigned int mask) unsigned int mask)
{ {
ASSERT(!(mask & ~(XFS_SICK_INO_PRIMARY | XFS_SICK_INO_ZAPPED))); ASSERT(!(mask & ~XFS_SICK_INO_ALL));
trace_xfs_inode_mark_healthy(ip, mask); trace_xfs_inode_mark_healthy(ip, mask);
spin_lock(&ip->i_flags_lock); spin_lock(&ip->i_flags_lock);
ip->i_sick &= ~mask; ip->i_sick &= ~mask;
if (!(ip->i_sick & XFS_SICK_INO_PRIMARY))
ip->i_sick &= ~XFS_SICK_INO_SECONDARY;
ip->i_checked |= mask; ip->i_checked |= mask;
spin_unlock(&ip->i_flags_lock); spin_unlock(&ip->i_flags_lock);
} }
...@@ -423,6 +431,7 @@ static const struct ioctl_sick_map ag_map[] = { ...@@ -423,6 +431,7 @@ static const struct ioctl_sick_map ag_map[] = {
{ XFS_SICK_AG_FINOBT, XFS_AG_GEOM_SICK_FINOBT }, { XFS_SICK_AG_FINOBT, XFS_AG_GEOM_SICK_FINOBT },
{ XFS_SICK_AG_RMAPBT, XFS_AG_GEOM_SICK_RMAPBT }, { XFS_SICK_AG_RMAPBT, XFS_AG_GEOM_SICK_RMAPBT },
{ XFS_SICK_AG_REFCNTBT, XFS_AG_GEOM_SICK_REFCNTBT }, { XFS_SICK_AG_REFCNTBT, XFS_AG_GEOM_SICK_REFCNTBT },
{ XFS_SICK_AG_INODES, XFS_AG_GEOM_SICK_INODES },
{ 0, 0 }, { 0, 0 },
}; };
......
...@@ -1738,6 +1738,39 @@ xfs_inode_needs_inactive( ...@@ -1738,6 +1738,39 @@ xfs_inode_needs_inactive(
return xfs_can_free_eofblocks(ip, true); return xfs_can_free_eofblocks(ip, true);
} }
/*
* Save health status somewhere, if we're dumping an inode with uncorrected
* errors and online repair isn't running.
*/
static inline void
xfs_inactive_health(
struct xfs_inode *ip)
{
struct xfs_mount *mp = ip->i_mount;
struct xfs_perag *pag;
unsigned int sick;
unsigned int checked;
xfs_inode_measure_sickness(ip, &sick, &checked);
if (!sick)
return;
trace_xfs_inode_unfixed_corruption(ip, sick);
if (sick & XFS_SICK_INO_FORGET)
return;
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
if (!pag) {
/* There had better still be a perag structure! */
ASSERT(0);
return;
}
xfs_ag_mark_sick(pag, XFS_SICK_AG_INODES);
xfs_perag_put(pag);
}
/* /*
* xfs_inactive * xfs_inactive
* *
...@@ -1766,6 +1799,8 @@ xfs_inactive( ...@@ -1766,6 +1799,8 @@ xfs_inactive(
mp = ip->i_mount; mp = ip->i_mount;
ASSERT(!xfs_iflags_test(ip, XFS_IRECOVERY)); ASSERT(!xfs_iflags_test(ip, XFS_IRECOVERY));
xfs_inactive_health(ip);
/* /*
* If this is a read-only mount, don't do this (would generate I/O) * If this is a read-only mount, don't do this (would generate I/O)
* unless we're in log recovery and cleaning the iunlinked list. * unless we're in log recovery and cleaning the iunlinked list.
......
...@@ -3985,6 +3985,7 @@ DEFINE_EVENT(xfs_inode_corrupt_class, name, \ ...@@ -3985,6 +3985,7 @@ DEFINE_EVENT(xfs_inode_corrupt_class, name, \
DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_sick); DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_sick);
DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_corrupt); DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_corrupt);
DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_healthy); DEFINE_INODE_CORRUPT_EVENT(xfs_inode_mark_healthy);
DEFINE_INODE_CORRUPT_EVENT(xfs_inode_unfixed_corruption);
TRACE_EVENT(xfs_iwalk_ag, TRACE_EVENT(xfs_iwalk_ag,
TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment