summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2026-01-21 05:06:47 +0300
committerDarrick J. Wong <djwong@kernel.org>2026-01-21 05:06:47 +0300
commit5eb4cb18e445d09f64ef4b7c8fdc3b2296cb0702 (patch)
tree2261593673b5224df963bfce13eede10d1fd356c
parent25ca57fa3624cae9c6b5c6d3fc7f38318ca1402e (diff)
downloadlinux-5eb4cb18e445d09f64ef4b7c8fdc3b2296cb0702.tar.xz
xfs: convey metadata health events to the health monitor
Connect the filesystem metadata health event collection system to the health monitor so that xfs can send events to xfs_healer as it collects information. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/xfs/libxfs/xfs_fs.h35
-rw-r--r--fs/xfs/libxfs/xfs_health.h5
-rw-r--r--fs/xfs/xfs_health.c123
-rw-r--r--fs/xfs/xfs_healthmon.c181
-rw-r--r--fs/xfs/xfs_healthmon.h39
-rw-r--r--fs/xfs/xfs_trace.h130
6 files changed, 511 insertions, 2 deletions
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 59de6ab69fb3..04e1dcf61257 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -1008,6 +1008,12 @@ struct xfs_rtgroup_geometry {
/* affects the whole fs */
#define XFS_HEALTH_MONITOR_DOMAIN_MOUNT (0)
+/* metadata health events */
+#define XFS_HEALTH_MONITOR_DOMAIN_FS (1)
+#define XFS_HEALTH_MONITOR_DOMAIN_AG (2)
+#define XFS_HEALTH_MONITOR_DOMAIN_INODE (3)
+#define XFS_HEALTH_MONITOR_DOMAIN_RTGROUP (4)
+
/* Health monitor event types */
/* status of the monitor itself */
@@ -1017,11 +1023,37 @@ struct xfs_rtgroup_geometry {
/* filesystem was unmounted */
#define XFS_HEALTH_MONITOR_TYPE_UNMOUNT (2)
+/* metadata health events */
+#define XFS_HEALTH_MONITOR_TYPE_SICK (3)
+#define XFS_HEALTH_MONITOR_TYPE_CORRUPT (4)
+#define XFS_HEALTH_MONITOR_TYPE_HEALTHY (5)
+
/* lost events */
struct xfs_health_monitor_lost {
__u64 count;
};
+/* fs/rt metadata */
+struct xfs_health_monitor_fs {
+ /* XFS_FSOP_GEOM_SICK_* flags */
+ __u32 mask;
+};
+
+/* ag/rtgroup metadata */
+struct xfs_health_monitor_group {
+ /* XFS_{AG,RTGROUP}_SICK_* flags */
+ __u32 mask;
+ __u32 gno;
+};
+
+/* inode metadata */
+struct xfs_health_monitor_inode {
+ /* XFS_BS_SICK_* flags */
+ __u32 mask;
+ __u32 gen;
+ __u64 ino;
+};
+
struct xfs_health_monitor_event {
/* XFS_HEALTH_MONITOR_DOMAIN_* */
__u32 domain;
@@ -1039,6 +1071,9 @@ struct xfs_health_monitor_event {
*/
union {
struct xfs_health_monitor_lost lost;
+ struct xfs_health_monitor_fs fs;
+ struct xfs_health_monitor_group group;
+ struct xfs_health_monitor_inode inode;
} e;
/* zeroes */
diff --git a/fs/xfs/libxfs/xfs_health.h b/fs/xfs/libxfs/xfs_health.h
index b31000f7190c..1d45cf5789e8 100644
--- a/fs/xfs/libxfs/xfs_health.h
+++ b/fs/xfs/libxfs/xfs_health.h
@@ -289,4 +289,9 @@ void xfs_bulkstat_health(struct xfs_inode *ip, struct xfs_bulkstat *bs);
#define xfs_metadata_is_sick(error) \
(unlikely((error) == -EFSCORRUPTED || (error) == -EFSBADCRC))
+unsigned int xfs_healthmon_inode_mask(unsigned int sick_mask);
+unsigned int xfs_healthmon_rtgroup_mask(unsigned int sick_mask);
+unsigned int xfs_healthmon_perag_mask(unsigned int sick_mask);
+unsigned int xfs_healthmon_fs_mask(unsigned int sick_mask);
+
#endif /* __XFS_HEALTH_H__ */
diff --git a/fs/xfs/xfs_health.c b/fs/xfs/xfs_health.c
index 3d50397f8f7c..f243c06fd447 100644
--- a/fs/xfs/xfs_health.c
+++ b/fs/xfs/xfs_health.c
@@ -108,14 +108,19 @@ xfs_fs_mark_sick(
struct xfs_mount *mp,
unsigned int mask)
{
+ unsigned int old_mask;
+
ASSERT(!(mask & ~XFS_SICK_FS_ALL));
trace_xfs_fs_mark_sick(mp, mask);
spin_lock(&mp->m_sb_lock);
+ old_mask = mp->m_fs_sick;
mp->m_fs_sick |= mask;
spin_unlock(&mp->m_sb_lock);
fserror_report_metadata(mp->m_super, -EFSCORRUPTED, GFP_NOFS);
+ if (mask)
+ xfs_healthmon_report_fs(mp, XFS_HEALTHMON_SICK, old_mask, mask);
}
/* Mark per-fs metadata as having been checked and found unhealthy by fsck. */
@@ -124,15 +129,21 @@ xfs_fs_mark_corrupt(
struct xfs_mount *mp,
unsigned int mask)
{
+ unsigned int old_mask;
+
ASSERT(!(mask & ~XFS_SICK_FS_ALL));
trace_xfs_fs_mark_corrupt(mp, mask);
spin_lock(&mp->m_sb_lock);
+ old_mask = mp->m_fs_sick;
mp->m_fs_sick |= mask;
mp->m_fs_checked |= mask;
spin_unlock(&mp->m_sb_lock);
fserror_report_metadata(mp->m_super, -EFSCORRUPTED, GFP_NOFS);
+ if (mask)
+ xfs_healthmon_report_fs(mp, XFS_HEALTHMON_CORRUPT, old_mask,
+ mask);
}
/* Mark a per-fs metadata healed. */
@@ -141,15 +152,22 @@ xfs_fs_mark_healthy(
struct xfs_mount *mp,
unsigned int mask)
{
+ unsigned int old_mask;
+
ASSERT(!(mask & ~XFS_SICK_FS_ALL));
trace_xfs_fs_mark_healthy(mp, mask);
spin_lock(&mp->m_sb_lock);
+ old_mask = mp->m_fs_sick;
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;
spin_unlock(&mp->m_sb_lock);
+
+ if (mask)
+ xfs_healthmon_report_fs(mp, XFS_HEALTHMON_HEALTHY, old_mask,
+ mask);
}
/* Sample which per-fs metadata are unhealthy. */
@@ -199,14 +217,20 @@ xfs_group_mark_sick(
struct xfs_group *xg,
unsigned int mask)
{
+ unsigned int old_mask;
+
xfs_group_check_mask(xg, mask);
trace_xfs_group_mark_sick(xg, mask);
spin_lock(&xg->xg_state_lock);
+ old_mask = xg->xg_sick;
xg->xg_sick |= mask;
spin_unlock(&xg->xg_state_lock);
fserror_report_metadata(xg->xg_mount->m_super, -EFSCORRUPTED, GFP_NOFS);
+ if (mask)
+ xfs_healthmon_report_group(xg, XFS_HEALTHMON_SICK, old_mask,
+ mask);
}
/*
@@ -217,15 +241,21 @@ xfs_group_mark_corrupt(
struct xfs_group *xg,
unsigned int mask)
{
+ unsigned int old_mask;
+
xfs_group_check_mask(xg, mask);
trace_xfs_group_mark_corrupt(xg, mask);
spin_lock(&xg->xg_state_lock);
+ old_mask = xg->xg_sick;
xg->xg_sick |= mask;
xg->xg_checked |= mask;
spin_unlock(&xg->xg_state_lock);
fserror_report_metadata(xg->xg_mount->m_super, -EFSCORRUPTED, GFP_NOFS);
+ if (mask)
+ xfs_healthmon_report_group(xg, XFS_HEALTHMON_CORRUPT, old_mask,
+ mask);
}
/*
@@ -236,15 +266,22 @@ xfs_group_mark_healthy(
struct xfs_group *xg,
unsigned int mask)
{
+ unsigned int old_mask;
+
xfs_group_check_mask(xg, mask);
trace_xfs_group_mark_healthy(xg, mask);
spin_lock(&xg->xg_state_lock);
+ old_mask = xg->xg_sick;
xg->xg_sick &= ~mask;
if (!(xg->xg_sick & XFS_SICK_AG_PRIMARY))
xg->xg_sick &= ~XFS_SICK_AG_SECONDARY;
xg->xg_checked |= mask;
spin_unlock(&xg->xg_state_lock);
+
+ if (mask)
+ xfs_healthmon_report_group(xg, XFS_HEALTHMON_HEALTHY, old_mask,
+ mask);
}
/* Sample which per-ag metadata are unhealthy. */
@@ -283,10 +320,13 @@ xfs_inode_mark_sick(
struct xfs_inode *ip,
unsigned int mask)
{
+ unsigned int old_mask;
+
ASSERT(!(mask & ~XFS_SICK_INO_ALL));
trace_xfs_inode_mark_sick(ip, mask);
spin_lock(&ip->i_flags_lock);
+ old_mask = ip->i_sick;
ip->i_sick |= mask;
spin_unlock(&ip->i_flags_lock);
@@ -300,6 +340,9 @@ xfs_inode_mark_sick(
spin_unlock(&VFS_I(ip)->i_lock);
fserror_report_file_metadata(VFS_I(ip), -EFSCORRUPTED, GFP_NOFS);
+ if (mask)
+ xfs_healthmon_report_inode(ip, XFS_HEALTHMON_SICK, old_mask,
+ mask);
}
/* Mark inode metadata as having been checked and found unhealthy by fsck. */
@@ -308,10 +351,13 @@ xfs_inode_mark_corrupt(
struct xfs_inode *ip,
unsigned int mask)
{
+ unsigned int old_mask;
+
ASSERT(!(mask & ~XFS_SICK_INO_ALL));
trace_xfs_inode_mark_corrupt(ip, mask);
spin_lock(&ip->i_flags_lock);
+ old_mask = ip->i_sick;
ip->i_sick |= mask;
ip->i_checked |= mask;
spin_unlock(&ip->i_flags_lock);
@@ -326,6 +372,9 @@ xfs_inode_mark_corrupt(
spin_unlock(&VFS_I(ip)->i_lock);
fserror_report_file_metadata(VFS_I(ip), -EFSCORRUPTED, GFP_NOFS);
+ if (mask)
+ xfs_healthmon_report_inode(ip, XFS_HEALTHMON_CORRUPT, old_mask,
+ mask);
}
/* Mark parts of an inode healed. */
@@ -334,15 +383,22 @@ xfs_inode_mark_healthy(
struct xfs_inode *ip,
unsigned int mask)
{
+ unsigned int old_mask;
+
ASSERT(!(mask & ~XFS_SICK_INO_ALL));
trace_xfs_inode_mark_healthy(ip, mask);
spin_lock(&ip->i_flags_lock);
+ old_mask = ip->i_sick;
ip->i_sick &= ~mask;
if (!(ip->i_sick & XFS_SICK_INO_PRIMARY))
ip->i_sick &= ~XFS_SICK_INO_SECONDARY;
ip->i_checked |= mask;
spin_unlock(&ip->i_flags_lock);
+
+ if (mask)
+ xfs_healthmon_report_inode(ip, XFS_HEALTHMON_HEALTHY, old_mask,
+ mask);
}
/* Sample which parts of an inode are unhealthy. */
@@ -422,6 +478,25 @@ xfs_fsop_geom_health(
}
}
+/*
+ * Translate XFS_SICK_FS_* into XFS_FSOP_GEOM_SICK_* except for the rt free
+ * space codes, which are sent via the rtgroup events.
+ */
+unsigned int
+xfs_healthmon_fs_mask(
+ unsigned int sick_mask)
+{
+ const struct ioctl_sick_map *m;
+ unsigned int ioctl_mask = 0;
+
+ for_each_sick_map(fs_map, m) {
+ if (sick_mask & m->sick_mask)
+ ioctl_mask |= m->ioctl_mask;
+ }
+
+ return ioctl_mask;
+}
+
static const struct ioctl_sick_map ag_map[] = {
{ XFS_SICK_AG_SB, XFS_AG_GEOM_SICK_SB },
{ XFS_SICK_AG_AGF, XFS_AG_GEOM_SICK_AGF },
@@ -458,6 +533,22 @@ xfs_ag_geom_health(
}
}
+/* Translate XFS_SICK_AG_* into XFS_AG_GEOM_SICK_*. */
+unsigned int
+xfs_healthmon_perag_mask(
+ unsigned int sick_mask)
+{
+ const struct ioctl_sick_map *m;
+ unsigned int ioctl_mask = 0;
+
+ for_each_sick_map(ag_map, m) {
+ if (sick_mask & m->sick_mask)
+ ioctl_mask |= m->ioctl_mask;
+ }
+
+ return ioctl_mask;
+}
+
static const struct ioctl_sick_map rtgroup_map[] = {
{ XFS_SICK_RG_SUPER, XFS_RTGROUP_GEOM_SICK_SUPER },
{ XFS_SICK_RG_BITMAP, XFS_RTGROUP_GEOM_SICK_BITMAP },
@@ -488,6 +579,22 @@ xfs_rtgroup_geom_health(
}
}
+/* Translate XFS_SICK_RG_* into XFS_RTGROUP_GEOM_SICK_*. */
+unsigned int
+xfs_healthmon_rtgroup_mask(
+ unsigned int sick_mask)
+{
+ const struct ioctl_sick_map *m;
+ unsigned int ioctl_mask = 0;
+
+ for_each_sick_map(rtgroup_map, m) {
+ if (sick_mask & m->sick_mask)
+ ioctl_mask |= m->ioctl_mask;
+ }
+
+ return ioctl_mask;
+}
+
static const struct ioctl_sick_map ino_map[] = {
{ XFS_SICK_INO_CORE, XFS_BS_SICK_INODE },
{ XFS_SICK_INO_BMBTD, XFS_BS_SICK_BMBTD },
@@ -526,6 +633,22 @@ xfs_bulkstat_health(
}
}
+/* Translate XFS_SICK_INO_* into XFS_BS_SICK_*. */
+unsigned int
+xfs_healthmon_inode_mask(
+ unsigned int sick_mask)
+{
+ const struct ioctl_sick_map *m;
+ unsigned int ioctl_mask = 0;
+
+ for_each_sick_map(ino_map, m) {
+ if (sick_mask & m->sick_mask)
+ ioctl_mask |= m->ioctl_mask;
+ }
+
+ return ioctl_mask;
+}
+
/* Mark a block mapping sick. */
void
xfs_bmap_mark_sick(
diff --git a/fs/xfs/xfs_healthmon.c b/fs/xfs/xfs_healthmon.c
index c218838e6e59..0039a79822e8 100644
--- a/fs/xfs/xfs_healthmon.c
+++ b/fs/xfs/xfs_healthmon.c
@@ -18,6 +18,7 @@
#include "xfs_da_btree.h"
#include "xfs_quota_defs.h"
#include "xfs_rtgroup.h"
+#include "xfs_health.h"
#include "xfs_healthmon.h"
#include <linux/anon_inodes.h>
@@ -174,6 +175,33 @@ xfs_healthmon_merge_events(
case XFS_HEALTHMON_LOST:
existing->lostcount += new->lostcount;
return true;
+
+ case XFS_HEALTHMON_SICK:
+ case XFS_HEALTHMON_CORRUPT:
+ case XFS_HEALTHMON_HEALTHY:
+ switch (existing->domain) {
+ case XFS_HEALTHMON_FS:
+ existing->fsmask |= new->fsmask;
+ return true;
+ case XFS_HEALTHMON_AG:
+ case XFS_HEALTHMON_RTGROUP:
+ if (existing->group == new->group){
+ existing->grpmask |= new->grpmask;
+ return true;
+ }
+ return false;
+ case XFS_HEALTHMON_INODE:
+ if (existing->ino == new->ino &&
+ existing->gen == new->gen) {
+ existing->imask |= new->imask;
+ return true;
+ }
+ return false;
+ default:
+ ASSERT(0);
+ return false;
+ }
+ return false;
}
return false;
@@ -337,6 +365,135 @@ xfs_healthmon_unmount(
xfs_healthmon_put(hm);
}
+/* Compute the reporting mask for non-unmount metadata health events. */
+static inline unsigned int
+metadata_event_mask(
+ struct xfs_healthmon *hm,
+ enum xfs_healthmon_type type,
+ unsigned int old_mask,
+ unsigned int new_mask)
+{
+ /* If we want all events, return all events. */
+ if (hm->verbose)
+ return new_mask;
+
+ switch (type) {
+ case XFS_HEALTHMON_SICK:
+ /* Always report runtime corruptions */
+ return new_mask;
+ case XFS_HEALTHMON_CORRUPT:
+ /* Only report new fsck errors */
+ return new_mask & ~old_mask;
+ case XFS_HEALTHMON_HEALTHY:
+ /* Only report healthy metadata that got fixed */
+ return new_mask & old_mask;
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ return 0;
+}
+
+/* Report XFS_FS_SICK_* events to healthmon */
+void
+xfs_healthmon_report_fs(
+ struct xfs_mount *mp,
+ enum xfs_healthmon_type type,
+ unsigned int old_mask,
+ unsigned int new_mask)
+{
+ struct xfs_healthmon_event event = {
+ .type = type,
+ .domain = XFS_HEALTHMON_FS,
+ };
+ struct xfs_healthmon *hm = xfs_healthmon_get(mp);
+
+ if (!hm)
+ return;
+
+ event.fsmask = metadata_event_mask(hm, type, old_mask, new_mask) &
+ ~XFS_SICK_FS_SECONDARY;
+ trace_xfs_healthmon_report_fs(hm, old_mask, new_mask, &event);
+
+ if (event.fsmask)
+ xfs_healthmon_push(hm, &event);
+
+ xfs_healthmon_put(hm);
+}
+
+/* Report XFS_SICK_(AG|RG)* flags to healthmon */
+void
+xfs_healthmon_report_group(
+ struct xfs_group *xg,
+ enum xfs_healthmon_type type,
+ unsigned int old_mask,
+ unsigned int new_mask)
+{
+ struct xfs_healthmon_event event = {
+ .type = type,
+ .group = xg->xg_gno,
+ };
+ struct xfs_healthmon *hm = xfs_healthmon_get(xg->xg_mount);
+
+ if (!hm)
+ return;
+
+ switch (xg->xg_type) {
+ case XG_TYPE_RTG:
+ event.domain = XFS_HEALTHMON_RTGROUP;
+ event.grpmask = metadata_event_mask(hm, type, old_mask,
+ new_mask) &
+ ~XFS_SICK_RG_SECONDARY;
+ break;
+ case XG_TYPE_AG:
+ event.domain = XFS_HEALTHMON_AG;
+ event.grpmask = metadata_event_mask(hm, type, old_mask,
+ new_mask) &
+ ~XFS_SICK_AG_SECONDARY;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+
+ trace_xfs_healthmon_report_group(hm, old_mask, new_mask, &event);
+
+ if (event.grpmask)
+ xfs_healthmon_push(hm, &event);
+
+ xfs_healthmon_put(hm);
+}
+
+/* Report XFS_SICK_INO_* flags to healthmon */
+void
+xfs_healthmon_report_inode(
+ struct xfs_inode *ip,
+ enum xfs_healthmon_type type,
+ unsigned int old_mask,
+ unsigned int new_mask)
+{
+ struct xfs_healthmon_event event = {
+ .type = type,
+ .domain = XFS_HEALTHMON_INODE,
+ .ino = ip->i_ino,
+ .gen = VFS_I(ip)->i_generation,
+ };
+ struct xfs_healthmon *hm = xfs_healthmon_get(ip->i_mount);
+
+ if (!hm)
+ return;
+
+ event.imask = metadata_event_mask(hm, type, old_mask, new_mask) &
+ ~XFS_SICK_INO_SECONDARY;
+ trace_xfs_healthmon_report_inode(hm, old_mask, event.imask, &event);
+
+ if (event.imask)
+ xfs_healthmon_push(hm, &event);
+
+ xfs_healthmon_put(hm);
+}
+
static inline void
xfs_healthmon_reset_outbuf(
struct xfs_healthmon *hm)
@@ -347,11 +504,19 @@ xfs_healthmon_reset_outbuf(
static const unsigned int domain_map[] = {
[XFS_HEALTHMON_MOUNT] = XFS_HEALTH_MONITOR_DOMAIN_MOUNT,
+ [XFS_HEALTHMON_FS] = XFS_HEALTH_MONITOR_DOMAIN_FS,
+ [XFS_HEALTHMON_AG] = XFS_HEALTH_MONITOR_DOMAIN_AG,
+ [XFS_HEALTHMON_INODE] = XFS_HEALTH_MONITOR_DOMAIN_INODE,
+ [XFS_HEALTHMON_RTGROUP] = XFS_HEALTH_MONITOR_DOMAIN_RTGROUP,
};
static const unsigned int type_map[] = {
[XFS_HEALTHMON_RUNNING] = XFS_HEALTH_MONITOR_TYPE_RUNNING,
[XFS_HEALTHMON_LOST] = XFS_HEALTH_MONITOR_TYPE_LOST,
+ [XFS_HEALTHMON_SICK] = XFS_HEALTH_MONITOR_TYPE_SICK,
+ [XFS_HEALTHMON_CORRUPT] = XFS_HEALTH_MONITOR_TYPE_CORRUPT,
+ [XFS_HEALTHMON_HEALTHY] = XFS_HEALTH_MONITOR_TYPE_HEALTHY,
+ [XFS_HEALTHMON_UNMOUNT] = XFS_HEALTH_MONITOR_TYPE_UNMOUNT,
};
/* Render event as a V0 structure */
@@ -384,6 +549,22 @@ xfs_healthmon_format_v0(
break;
}
break;
+ case XFS_HEALTHMON_FS:
+ hme.e.fs.mask = xfs_healthmon_fs_mask(event->fsmask);
+ break;
+ case XFS_HEALTHMON_RTGROUP:
+ hme.e.group.mask = xfs_healthmon_rtgroup_mask(event->grpmask);
+ hme.e.group.gno = event->group;
+ break;
+ case XFS_HEALTHMON_AG:
+ hme.e.group.mask = xfs_healthmon_perag_mask(event->grpmask);
+ hme.e.group.gno = event->group;
+ break;
+ case XFS_HEALTHMON_INODE:
+ hme.e.inode.mask = xfs_healthmon_inode_mask(event->imask);
+ hme.e.inode.ino = event->ino;
+ hme.e.inode.gen = event->gen;
+ break;
default:
break;
}
diff --git a/fs/xfs/xfs_healthmon.h b/fs/xfs/xfs_healthmon.h
index 3044bb46485d..121e59426395 100644
--- a/fs/xfs/xfs_healthmon.h
+++ b/fs/xfs/xfs_healthmon.h
@@ -71,10 +71,21 @@ enum xfs_healthmon_type {
XFS_HEALTHMON_RUNNING, /* monitor running */
XFS_HEALTHMON_LOST, /* message lost */
XFS_HEALTHMON_UNMOUNT, /* filesystem is unmounting */
+
+ /* metadata health events */
+ XFS_HEALTHMON_SICK, /* runtime corruption observed */
+ XFS_HEALTHMON_CORRUPT, /* fsck reported corruption */
+ XFS_HEALTHMON_HEALTHY, /* fsck reported healthy structure */
};
enum xfs_healthmon_domain {
XFS_HEALTHMON_MOUNT, /* affects the whole fs */
+
+ /* metadata health events */
+ XFS_HEALTHMON_FS, /* main filesystem metadata */
+ XFS_HEALTHMON_AG, /* allocation group metadata */
+ XFS_HEALTHMON_INODE, /* inode metadata */
+ XFS_HEALTHMON_RTGROUP, /* realtime group metadata */
};
struct xfs_healthmon_event {
@@ -90,9 +101,37 @@ struct xfs_healthmon_event {
struct {
uint64_t lostcount;
};
+ /* fs/rt metadata */
+ struct {
+ /* XFS_SICK_* flags */
+ unsigned int fsmask;
+ };
+ /* ag/rtgroup metadata */
+ struct {
+ /* XFS_SICK_(AG|RG)* flags */
+ unsigned int grpmask;
+ unsigned int group;
+ };
+ /* inode metadata */
+ struct {
+ /* XFS_SICK_INO_* flags */
+ unsigned int imask;
+ uint32_t gen;
+ xfs_ino_t ino;
+ };
};
};
+void xfs_healthmon_report_fs(struct xfs_mount *mp,
+ enum xfs_healthmon_type type, unsigned int old_mask,
+ unsigned int new_mask);
+void xfs_healthmon_report_group(struct xfs_group *xg,
+ enum xfs_healthmon_type type, unsigned int old_mask,
+ unsigned int new_mask);
+void xfs_healthmon_report_inode(struct xfs_inode *ip,
+ enum xfs_healthmon_type type, unsigned int old_mask,
+ unsigned int new_mask);
+
long xfs_ioc_health_monitor(struct file *file,
struct xfs_health_monitor __user *arg);
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 305cae8f497b..debe9846418a 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -6009,15 +6009,29 @@ DEFINE_HEALTHMON_EVENT(xfs_healthmon_report_unmount);
#define XFS_HEALTHMON_TYPE_STRINGS \
{ XFS_HEALTHMON_LOST, "lost" }, \
- { XFS_HEALTHMON_UNMOUNT, "unmount" }
+ { XFS_HEALTHMON_UNMOUNT, "unmount" }, \
+ { XFS_HEALTHMON_SICK, "sick" }, \
+ { XFS_HEALTHMON_CORRUPT, "corrupt" }, \
+ { XFS_HEALTHMON_HEALTHY, "healthy" }
#define XFS_HEALTHMON_DOMAIN_STRINGS \
- { XFS_HEALTHMON_MOUNT, "mount" }
+ { XFS_HEALTHMON_MOUNT, "mount" }, \
+ { XFS_HEALTHMON_FS, "fs" }, \
+ { XFS_HEALTHMON_AG, "ag" }, \
+ { XFS_HEALTHMON_INODE, "inode" }, \
+ { XFS_HEALTHMON_RTGROUP, "rtgroup" }
TRACE_DEFINE_ENUM(XFS_HEALTHMON_LOST);
TRACE_DEFINE_ENUM(XFS_HEALTHMON_UNMOUNT);
+TRACE_DEFINE_ENUM(XFS_HEALTHMON_SICK);
+TRACE_DEFINE_ENUM(XFS_HEALTHMON_CORRUPT);
+TRACE_DEFINE_ENUM(XFS_HEALTHMON_HEALTHY);
TRACE_DEFINE_ENUM(XFS_HEALTHMON_MOUNT);
+TRACE_DEFINE_ENUM(XFS_HEALTHMON_FS);
+TRACE_DEFINE_ENUM(XFS_HEALTHMON_AG);
+TRACE_DEFINE_ENUM(XFS_HEALTHMON_INODE);
+TRACE_DEFINE_ENUM(XFS_HEALTHMON_RTGROUP);
DECLARE_EVENT_CLASS(xfs_healthmon_event_class,
TP_PROTO(const struct xfs_healthmon *hm,
@@ -6054,6 +6068,19 @@ DECLARE_EVENT_CLASS(xfs_healthmon_event_class,
break;
}
break;
+ case XFS_HEALTHMON_FS:
+ __entry->mask = event->fsmask;
+ break;
+ case XFS_HEALTHMON_AG:
+ case XFS_HEALTHMON_RTGROUP:
+ __entry->mask = event->grpmask;
+ __entry->group = event->group;
+ break;
+ case XFS_HEALTHMON_INODE:
+ __entry->mask = event->imask;
+ __entry->ino = event->ino;
+ __entry->gen = event->gen;
+ break;
}
),
TP_printk("dev %d:%d type %s domain %s mask 0x%x ino 0x%llx gen 0x%x offset 0x%llx len 0x%llx group 0x%x lost %llu",
@@ -6081,6 +6108,105 @@ DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_format_overflow);
DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_drop);
DEFINE_HEALTHMONEVENT_EVENT(xfs_healthmon_merge);
+TRACE_EVENT(xfs_healthmon_report_fs,
+ TP_PROTO(const struct xfs_healthmon *hm,
+ unsigned int old_mask, unsigned int new_mask,
+ const struct xfs_healthmon_event *event),
+ TP_ARGS(hm, old_mask, new_mask, event),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(unsigned int, type)
+ __field(unsigned int, domain)
+ __field(unsigned int, old_mask)
+ __field(unsigned int, new_mask)
+ __field(unsigned int, fsmask)
+ ),
+ TP_fast_assign(
+ __entry->dev = hm->dev;
+ __entry->type = event->type;
+ __entry->domain = event->domain;
+ __entry->old_mask = old_mask;
+ __entry->new_mask = new_mask;
+ __entry->fsmask = event->fsmask;
+ ),
+ TP_printk("dev %d:%d type %s domain %s oldmask 0x%x newmask 0x%x fsmask 0x%x",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __print_symbolic(__entry->type, XFS_HEALTHMON_TYPE_STRINGS),
+ __print_symbolic(__entry->domain, XFS_HEALTHMON_DOMAIN_STRINGS),
+ __entry->old_mask,
+ __entry->new_mask,
+ __entry->fsmask)
+);
+
+TRACE_EVENT(xfs_healthmon_report_group,
+ TP_PROTO(const struct xfs_healthmon *hm,
+ unsigned int old_mask, unsigned int new_mask,
+ const struct xfs_healthmon_event *event),
+ TP_ARGS(hm, old_mask, new_mask, event),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(unsigned int, type)
+ __field(unsigned int, domain)
+ __field(unsigned int, old_mask)
+ __field(unsigned int, new_mask)
+ __field(unsigned int, grpmask)
+ __field(unsigned int, group)
+ ),
+ TP_fast_assign(
+ __entry->dev = hm->dev;
+ __entry->type = event->type;
+ __entry->domain = event->domain;
+ __entry->old_mask = old_mask;
+ __entry->new_mask = new_mask;
+ __entry->grpmask = event->grpmask;
+ __entry->group = event->group;
+ ),
+ TP_printk("dev %d:%d type %s domain %s oldmask 0x%x newmask 0x%x grpmask 0x%x group 0x%x",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __print_symbolic(__entry->type, XFS_HEALTHMON_TYPE_STRINGS),
+ __print_symbolic(__entry->domain, XFS_HEALTHMON_DOMAIN_STRINGS),
+ __entry->old_mask,
+ __entry->new_mask,
+ __entry->grpmask,
+ __entry->group)
+);
+
+TRACE_EVENT(xfs_healthmon_report_inode,
+ TP_PROTO(const struct xfs_healthmon *hm,
+ unsigned int old_mask, unsigned int new_mask,
+ const struct xfs_healthmon_event *event),
+ TP_ARGS(hm, old_mask, new_mask, event),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(unsigned int, type)
+ __field(unsigned int, domain)
+ __field(unsigned int, old_mask)
+ __field(unsigned int, new_mask)
+ __field(unsigned int, imask)
+ __field(unsigned long long, ino)
+ __field(unsigned int, gen)
+ ),
+ TP_fast_assign(
+ __entry->dev = hm->dev;
+ __entry->type = event->type;
+ __entry->domain = event->domain;
+ __entry->old_mask = old_mask;
+ __entry->new_mask = new_mask;
+ __entry->imask = event->imask;
+ __entry->ino = event->ino;
+ __entry->gen = event->gen;
+ ),
+ TP_printk("dev %d:%d type %s domain %s oldmask 0x%x newmask 0x%x imask 0x%x ino 0x%llx gen 0x%x",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __print_symbolic(__entry->type, XFS_HEALTHMON_TYPE_STRINGS),
+ __print_symbolic(__entry->domain, XFS_HEALTHMON_DOMAIN_STRINGS),
+ __entry->old_mask,
+ __entry->new_mask,
+ __entry->imask,
+ __entry->ino,
+ __entry->gen)
+);
+
#endif /* _TRACE_XFS_H */
#undef TRACE_INCLUDE_PATH