From 25ca57fa3624cae9c6b5c6d3fc7f38318ca1402e Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Tue, 20 Jan 2026 18:06:47 -0800 Subject: [PATCH] xfs: convey filesystem unmount events to the health monitor In xfs_healthmon_unmount, send events to xfs_healer so that it knows that nothing further can be done for the filesystem. Signed-off-by: "Darrick J. Wong" Reviewed-by: Christoph Hellwig --- fs/xfs/libxfs/xfs_fs.h | 3 +++ fs/xfs/xfs_healthmon.c | 32 +++++++++++++++++++++++++++++++- fs/xfs/xfs_healthmon.h | 4 ++++ fs/xfs/xfs_trace.h | 6 +++++- 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h index 22b86bc888de5..59de6ab69fb31 100644 --- a/fs/xfs/libxfs/xfs_fs.h +++ b/fs/xfs/libxfs/xfs_fs.h @@ -1014,6 +1014,9 @@ struct xfs_rtgroup_geometry { #define XFS_HEALTH_MONITOR_TYPE_RUNNING (0) #define XFS_HEALTH_MONITOR_TYPE_LOST (1) +/* filesystem was unmounted */ +#define XFS_HEALTH_MONITOR_TYPE_UNMOUNT (2) + /* lost events */ struct xfs_health_monitor_lost { __u64 count; diff --git a/fs/xfs/xfs_healthmon.c b/fs/xfs/xfs_healthmon.c index f1c6782f5e391..c218838e6e59f 100644 --- a/fs/xfs/xfs_healthmon.c +++ b/fs/xfs/xfs_healthmon.c @@ -90,6 +90,7 @@ xfs_healthmon_put( kfree(event); } + kfree(hm->unmount_event); kfree(hm->buffer); mutex_destroy(&hm->lock); kfree_rcu_mightsleep(hm); @@ -166,6 +167,7 @@ xfs_healthmon_merge_events( switch (existing->type) { case XFS_HEALTHMON_RUNNING: + case XFS_HEALTHMON_UNMOUNT: /* should only ever be one of these events anyway */ return false; @@ -307,7 +309,10 @@ out_unlock: return error; } -/* Detach the xfs mount from this healthmon instance. */ +/* + * Report that the filesystem is being unmounted, then detach the xfs mount + * from this healthmon instance. + */ void xfs_healthmon_unmount( struct xfs_mount *mp) @@ -317,6 +322,17 @@ xfs_healthmon_unmount( if (!hm) return; + trace_xfs_healthmon_report_unmount(hm); + + /* + * Insert the unmount notification at the start of the event queue so + * that userspace knows the filesystem went away as soon as possible. + * There's nothing actionable for userspace after an unmount. Once + * we've inserted the unmount event, hm no longer owns that event. + */ + __xfs_healthmon_insert(hm, hm->unmount_event); + hm->unmount_event = NULL; + xfs_healthmon_detach(hm); xfs_healthmon_put(hm); } @@ -713,6 +729,20 @@ xfs_ioc_health_monitor( running_event->domain = XFS_HEALTHMON_MOUNT; __xfs_healthmon_insert(hm, running_event); + /* + * Preallocate the unmount event so that we can't fail to notify the + * filesystem later. This is key for triggering fast exit of the + * xfs_healer daemon. + */ + hm->unmount_event = kzalloc(sizeof(struct xfs_healthmon_event), + GFP_NOFS); + if (!hm->unmount_event) { + ret = -ENOMEM; + goto out_hm; + } + hm->unmount_event->type = XFS_HEALTHMON_UNMOUNT; + hm->unmount_event->domain = XFS_HEALTHMON_MOUNT; + /* * Try to attach this health monitor to the xfs_mount. The monitor is * considered live and will receive events if this succeeds. diff --git a/fs/xfs/xfs_healthmon.h b/fs/xfs/xfs_healthmon.h index 554ec62125449..3044bb46485d7 100644 --- a/fs/xfs/xfs_healthmon.h +++ b/fs/xfs/xfs_healthmon.h @@ -34,6 +34,9 @@ struct xfs_healthmon { struct xfs_healthmon_event *first_event; struct xfs_healthmon_event *last_event; + /* preallocated event for unmount */ + struct xfs_healthmon_event *unmount_event; + /* number of events in the list */ unsigned int events; @@ -67,6 +70,7 @@ void xfs_healthmon_unmount(struct xfs_mount *mp); enum xfs_healthmon_type { XFS_HEALTHMON_RUNNING, /* monitor running */ XFS_HEALTHMON_LOST, /* message lost */ + XFS_HEALTHMON_UNMOUNT, /* filesystem is unmounting */ }; enum xfs_healthmon_domain { diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 04727470b3b41..305cae8f497b4 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -6005,14 +6005,18 @@ DEFINE_HEALTHMON_EVENT(xfs_healthmon_read_start); DEFINE_HEALTHMON_EVENT(xfs_healthmon_read_finish); DEFINE_HEALTHMON_EVENT(xfs_healthmon_release); DEFINE_HEALTHMON_EVENT(xfs_healthmon_detach); +DEFINE_HEALTHMON_EVENT(xfs_healthmon_report_unmount); #define XFS_HEALTHMON_TYPE_STRINGS \ - { XFS_HEALTHMON_LOST, "lost" } + { XFS_HEALTHMON_LOST, "lost" }, \ + { XFS_HEALTHMON_UNMOUNT, "unmount" } #define XFS_HEALTHMON_DOMAIN_STRINGS \ { XFS_HEALTHMON_MOUNT, "mount" } TRACE_DEFINE_ENUM(XFS_HEALTHMON_LOST); +TRACE_DEFINE_ENUM(XFS_HEALTHMON_UNMOUNT); + TRACE_DEFINE_ENUM(XFS_HEALTHMON_MOUNT); DECLARE_EVENT_CLASS(xfs_healthmon_event_class, -- 2.47.3