]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xfs: convey filesystem unmount events to the health monitor
authorDarrick J. Wong <djwong@kernel.org>
Wed, 21 Jan 2026 02:06:47 +0000 (18:06 -0800)
committerDarrick J. Wong <djwong@kernel.org>
Wed, 21 Jan 2026 02:06:47 +0000 (18:06 -0800)
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" <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/xfs/libxfs/xfs_fs.h
fs/xfs/xfs_healthmon.c
fs/xfs/xfs_healthmon.h
fs/xfs/xfs_trace.h

index 22b86bc888de5ac274163252417b249a1aba12b0..59de6ab69fb31925ed92e2c8a9cfc842b8490777 100644 (file)
@@ -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;
index f1c6782f5e3915365bbdeb7384b2f92681c00c24..c218838e6e59f46dab35c3fb514896e649cfe2b6 100644 (file)
@@ -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.
index 554ec62125449bc80838c2b2b0e9bb87d1429715..3044bb46485d7e73bfcf6f82785cef3ad7f08ce1 100644 (file)
@@ -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 {
index 04727470b3b410ed0cf146b3ed3bd9a1633c6bcf..305cae8f497b433211ddfc5339fba2d087f9bf89 100644 (file)
@@ -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,