root/fs/xfs/xfs_healthmon.h
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (c) 2024-2026 Oracle.  All Rights Reserved.
 * Author: Darrick J. Wong <djwong@kernel.org>
 */
#ifndef __XFS_HEALTHMON_H__
#define __XFS_HEALTHMON_H__

struct xfs_healthmon {
        /*
         * Weak reference to the xfs filesystem that is being monitored.  It
         * will be set to zero when the filesystem detaches from the monitor.
         * Do not dereference this pointer.
         */
        uintptr_t                       mount_cookie;

        /*
         * Device number of the filesystem being monitored.  This is for
         * consistent tracing even after unmount.
         */
        dev_t                           dev;

        /*
         * Reference count of this structure.  The open healthmon fd holds one
         * ref, the xfs_mount holds another ref if it points to this object,
         * and running event handlers hold their own refs.
         */
        refcount_t                      ref;

        /* lock for event list and event counters */
        struct mutex                    lock;

        /* list of event objects */
        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;

        /* do we want all events? */
        bool                            verbose:1;

        /* waiter so read/poll can sleep until the arrival of events */
        struct wait_queue_head          wait;

        /*
         * Buffer for formatting events for a read_iter call.  Events are
         * formatted into the buffer at bufhead, and buftail determines where
         * to start a copy_iter to get those events to userspace.  All buffer
         * fields are protected by inode_lock.
         */
        char                            *buffer;
        size_t                          bufsize;
        size_t                          bufhead;
        size_t                          buftail;

        /* did we lose previous events? */
        unsigned long long              lost_prev_event;

        /* total counts of events observed and lost events */
        unsigned long long              total_events;
        unsigned long long              total_lost;
};

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 */

        /* filesystem shutdown */
        XFS_HEALTHMON_SHUTDOWN,

        /* metadata health events */
        XFS_HEALTHMON_SICK,     /* runtime corruption observed */
        XFS_HEALTHMON_CORRUPT,  /* fsck reported corruption */
        XFS_HEALTHMON_HEALTHY,  /* fsck reported healthy structure */

        /* media errors */
        XFS_HEALTHMON_MEDIA_ERROR,

        /* file range events */
        XFS_HEALTHMON_BUFREAD,
        XFS_HEALTHMON_BUFWRITE,
        XFS_HEALTHMON_DIOREAD,
        XFS_HEALTHMON_DIOWRITE,
        XFS_HEALTHMON_DATALOST,
};

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 */

        /* media errors */
        XFS_HEALTHMON_DATADEV,
        XFS_HEALTHMON_RTDEV,
        XFS_HEALTHMON_LOGDEV,

        /* file range events */
        XFS_HEALTHMON_FILERANGE,
};

struct xfs_healthmon_event {
        struct xfs_healthmon_event      *next;

        enum xfs_healthmon_type         type;
        enum xfs_healthmon_domain       domain;

        uint64_t                        time_ns;

        union {
                /* lost events */
                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;
                };
                /* shutdown */
                struct {
                        unsigned int    flags;
                };
                /* media errors */
                struct {
                        xfs_daddr_t     daddr;
                        uint64_t        bbcount;
                };
                /* file range events */
                struct {
                        xfs_ino_t       fino;
                        loff_t          fpos;
                        uint64_t        flen;
                        uint32_t        fgen;
                        int             error;
                };
        };
};

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);

void xfs_healthmon_report_shutdown(struct xfs_mount *mp, uint32_t flags);

void xfs_healthmon_report_media(struct xfs_mount *mp, enum xfs_device fdev,
                xfs_daddr_t daddr, uint64_t bbcount);

void xfs_healthmon_report_file_ioerror(struct xfs_inode *ip,
                const struct fserror_event *p);

long xfs_ioc_health_monitor(struct file *file,
                struct xfs_health_monitor __user *arg);

#endif /* __XFS_HEALTHMON_H__ */