summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2026-01-21 05:06:48 +0300
committerDarrick J. Wong <djwong@kernel.org>2026-01-21 05:06:48 +0300
commit74c4795e50f816dbf5cf094691fc4f95bbc729ad (patch)
tree4d07b690a62b0eb97aef317daf00b4a54c297cbe
parent5eb4cb18e445d09f64ef4b7c8fdc3b2296cb0702 (diff)
downloadlinux-74c4795e50f816dbf5cf094691fc4f95bbc729ad.tar.xz
xfs: convey filesystem shutdown events to the health monitor
Connect the filesystem shutdown code to the health monitor so that xfs can send events about that to the xfs_healer daemon. Signed-off-by: "Darrick J. Wong" <djwong@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/xfs/libxfs/xfs_fs.h18
-rw-r--r--fs/xfs/xfs_fsops.c2
-rw-r--r--fs/xfs/xfs_healthmon.c70
-rw-r--r--fs/xfs/xfs_healthmon.h9
-rw-r--r--fs/xfs/xfs_trace.h23
5 files changed, 121 insertions, 1 deletions
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 04e1dcf61257..c8f7011a7ef8 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -1028,6 +1028,9 @@ struct xfs_rtgroup_geometry {
#define XFS_HEALTH_MONITOR_TYPE_CORRUPT (4)
#define XFS_HEALTH_MONITOR_TYPE_HEALTHY (5)
+/* filesystem shutdown */
+#define XFS_HEALTH_MONITOR_TYPE_SHUTDOWN (6)
+
/* lost events */
struct xfs_health_monitor_lost {
__u64 count;
@@ -1054,6 +1057,20 @@ struct xfs_health_monitor_inode {
__u64 ino;
};
+/* shutdown reasons */
+#define XFS_HEALTH_SHUTDOWN_META_IO_ERROR (1u << 0)
+#define XFS_HEALTH_SHUTDOWN_LOG_IO_ERROR (1u << 1)
+#define XFS_HEALTH_SHUTDOWN_FORCE_UMOUNT (1u << 2)
+#define XFS_HEALTH_SHUTDOWN_CORRUPT_INCORE (1u << 3)
+#define XFS_HEALTH_SHUTDOWN_CORRUPT_ONDISK (1u << 4)
+#define XFS_HEALTH_SHUTDOWN_DEVICE_REMOVED (1u << 5)
+
+/* shutdown */
+struct xfs_health_monitor_shutdown {
+ /* XFS_HEALTH_SHUTDOWN_* flags */
+ __u32 reasons;
+};
+
struct xfs_health_monitor_event {
/* XFS_HEALTH_MONITOR_DOMAIN_* */
__u32 domain;
@@ -1074,6 +1091,7 @@ struct xfs_health_monitor_event {
struct xfs_health_monitor_fs fs;
struct xfs_health_monitor_group group;
struct xfs_health_monitor_inode inode;
+ struct xfs_health_monitor_shutdown shutdown;
} e;
/* zeroes */
diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
index b7c21f68edc7..368173bf8a40 100644
--- a/fs/xfs/xfs_fsops.c
+++ b/fs/xfs/xfs_fsops.c
@@ -25,6 +25,7 @@
#include "xfs_rtrmap_btree.h"
#include "xfs_rtrefcount_btree.h"
#include "xfs_metafile.h"
+#include "xfs_healthmon.h"
#include <linux/fserror.h>
@@ -544,6 +545,7 @@ xfs_do_force_shutdown(
xfs_stack_trace();
fserror_report_shutdown(mp->m_super, GFP_KERNEL);
+ xfs_healthmon_report_shutdown(mp, flags);
}
/*
diff --git a/fs/xfs/xfs_healthmon.c b/fs/xfs/xfs_healthmon.c
index 0039a79822e8..97f764e79541 100644
--- a/fs/xfs/xfs_healthmon.c
+++ b/fs/xfs/xfs_healthmon.c
@@ -20,6 +20,7 @@
#include "xfs_rtgroup.h"
#include "xfs_health.h"
#include "xfs_healthmon.h"
+#include "xfs_fsops.h"
#include <linux/anon_inodes.h>
#include <linux/eventpoll.h>
@@ -202,6 +203,11 @@ xfs_healthmon_merge_events(
return false;
}
return false;
+
+ case XFS_HEALTHMON_SHUTDOWN:
+ /* yes, we can race to shutdown */
+ existing->flags |= new->flags;
+ return true;
}
return false;
@@ -494,6 +500,28 @@ xfs_healthmon_report_inode(
xfs_healthmon_put(hm);
}
+/* Add a shutdown event to the reporting queue. */
+void
+xfs_healthmon_report_shutdown(
+ struct xfs_mount *mp,
+ uint32_t flags)
+{
+ struct xfs_healthmon_event event = {
+ .type = XFS_HEALTHMON_SHUTDOWN,
+ .domain = XFS_HEALTHMON_MOUNT,
+ .flags = flags,
+ };
+ struct xfs_healthmon *hm = xfs_healthmon_get(mp);
+
+ if (!hm)
+ return;
+
+ trace_xfs_healthmon_report_shutdown(hm, flags);
+
+ xfs_healthmon_push(hm, &event);
+ xfs_healthmon_put(hm);
+}
+
static inline void
xfs_healthmon_reset_outbuf(
struct xfs_healthmon *hm)
@@ -502,6 +530,44 @@ xfs_healthmon_reset_outbuf(
hm->bufhead = 0;
}
+struct flags_map {
+ unsigned int in_mask;
+ unsigned int out_mask;
+};
+
+static const struct flags_map shutdown_map[] = {
+ { SHUTDOWN_META_IO_ERROR, XFS_HEALTH_SHUTDOWN_META_IO_ERROR },
+ { SHUTDOWN_LOG_IO_ERROR, XFS_HEALTH_SHUTDOWN_LOG_IO_ERROR },
+ { SHUTDOWN_FORCE_UMOUNT, XFS_HEALTH_SHUTDOWN_FORCE_UMOUNT },
+ { SHUTDOWN_CORRUPT_INCORE, XFS_HEALTH_SHUTDOWN_CORRUPT_INCORE },
+ { SHUTDOWN_CORRUPT_ONDISK, XFS_HEALTH_SHUTDOWN_CORRUPT_ONDISK },
+ { SHUTDOWN_DEVICE_REMOVED, XFS_HEALTH_SHUTDOWN_DEVICE_REMOVED },
+};
+
+static inline unsigned int
+__map_flags(
+ const struct flags_map *map,
+ size_t array_len,
+ unsigned int flags)
+{
+ const struct flags_map *m;
+ unsigned int ret = 0;
+
+ for (m = map; m < map + array_len; m++) {
+ if (flags & m->in_mask)
+ ret |= m->out_mask;
+ }
+
+ return ret;
+}
+
+#define map_flags(map, flags) __map_flags((map), ARRAY_SIZE(map), (flags))
+
+static inline unsigned int shutdown_mask(unsigned int in)
+{
+ return map_flags(shutdown_map, in);
+}
+
static const unsigned int domain_map[] = {
[XFS_HEALTHMON_MOUNT] = XFS_HEALTH_MONITOR_DOMAIN_MOUNT,
[XFS_HEALTHMON_FS] = XFS_HEALTH_MONITOR_DOMAIN_FS,
@@ -517,6 +583,7 @@ static const unsigned int type_map[] = {
[XFS_HEALTHMON_CORRUPT] = XFS_HEALTH_MONITOR_TYPE_CORRUPT,
[XFS_HEALTHMON_HEALTHY] = XFS_HEALTH_MONITOR_TYPE_HEALTHY,
[XFS_HEALTHMON_UNMOUNT] = XFS_HEALTH_MONITOR_TYPE_UNMOUNT,
+ [XFS_HEALTHMON_SHUTDOWN] = XFS_HEALTH_MONITOR_TYPE_SHUTDOWN,
};
/* Render event as a V0 structure */
@@ -545,6 +612,9 @@ xfs_healthmon_format_v0(
case XFS_HEALTHMON_LOST:
hme.e.lost.count = event->lostcount;
break;
+ case XFS_HEALTHMON_SHUTDOWN:
+ hme.e.shutdown.reasons = shutdown_mask(event->flags);
+ break;
default:
break;
}
diff --git a/fs/xfs/xfs_healthmon.h b/fs/xfs/xfs_healthmon.h
index 121e59426395..1f68b5d65a8e 100644
--- a/fs/xfs/xfs_healthmon.h
+++ b/fs/xfs/xfs_healthmon.h
@@ -72,6 +72,9 @@ enum xfs_healthmon_type {
XFS_HEALTHMON_LOST, /* message lost */
XFS_HEALTHMON_UNMOUNT, /* filesystem is unmounting */
+ /* filesystem shutdown */
+ XFS_HEALTHMON_SHUTDOWN,
+
/* metadata health events */
XFS_HEALTHMON_SICK, /* runtime corruption observed */
XFS_HEALTHMON_CORRUPT, /* fsck reported corruption */
@@ -119,6 +122,10 @@ struct xfs_healthmon_event {
uint32_t gen;
xfs_ino_t ino;
};
+ /* shutdown */
+ struct {
+ unsigned int flags;
+ };
};
};
@@ -132,6 +139,8 @@ void xfs_healthmon_report_inode(struct xfs_inode *ip,
enum xfs_healthmon_type type, unsigned int old_mask,
unsigned int new_mask);
+void xfs_healthmon_report_shutdown(struct xfs_mount *mp, uint32_t flags);
+
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 debe9846418a..ec99a6d3dd31 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -6012,7 +6012,8 @@ DEFINE_HEALTHMON_EVENT(xfs_healthmon_report_unmount);
{ XFS_HEALTHMON_UNMOUNT, "unmount" }, \
{ XFS_HEALTHMON_SICK, "sick" }, \
{ XFS_HEALTHMON_CORRUPT, "corrupt" }, \
- { XFS_HEALTHMON_HEALTHY, "healthy" }
+ { XFS_HEALTHMON_HEALTHY, "healthy" }, \
+ { XFS_HEALTHMON_SHUTDOWN, "shutdown" }
#define XFS_HEALTHMON_DOMAIN_STRINGS \
{ XFS_HEALTHMON_MOUNT, "mount" }, \
@@ -6022,6 +6023,7 @@ DEFINE_HEALTHMON_EVENT(xfs_healthmon_report_unmount);
{ XFS_HEALTHMON_RTGROUP, "rtgroup" }
TRACE_DEFINE_ENUM(XFS_HEALTHMON_LOST);
+TRACE_DEFINE_ENUM(XFS_HEALTHMON_SHUTDOWN);
TRACE_DEFINE_ENUM(XFS_HEALTHMON_UNMOUNT);
TRACE_DEFINE_ENUM(XFS_HEALTHMON_SICK);
TRACE_DEFINE_ENUM(XFS_HEALTHMON_CORRUPT);
@@ -6063,6 +6065,9 @@ DECLARE_EVENT_CLASS(xfs_healthmon_event_class,
switch (__entry->domain) {
case XFS_HEALTHMON_MOUNT:
switch (__entry->type) {
+ case XFS_HEALTHMON_SHUTDOWN:
+ __entry->mask = event->flags;
+ break;
case XFS_HEALTHMON_LOST:
__entry->lostcount = event->lostcount;
break;
@@ -6207,6 +6212,22 @@ TRACE_EVENT(xfs_healthmon_report_inode,
__entry->gen)
);
+TRACE_EVENT(xfs_healthmon_report_shutdown,
+ TP_PROTO(const struct xfs_healthmon *hm, uint32_t shutdown_flags),
+ TP_ARGS(hm, shutdown_flags),
+ TP_STRUCT__entry(
+ __field(dev_t, dev)
+ __field(uint32_t, shutdown_flags)
+ ),
+ TP_fast_assign(
+ __entry->dev = hm->dev;
+ __entry->shutdown_flags = shutdown_flags;
+ ),
+ TP_printk("dev %d:%d shutdown_flags %s",
+ MAJOR(__entry->dev), MINOR(__entry->dev),
+ __print_flags(__entry->shutdown_flags, "|", XFS_SHUTDOWN_STRINGS))
+);
+
#endif /* _TRACE_XFS_H */
#undef TRACE_INCLUDE_PATH