1a48373e7SDarrick J. Wong /* SPDX-License-Identifier: GPL-2.0-or-later */ 2a48373e7SDarrick J. Wong /* 3a48373e7SDarrick J. Wong * Copyright (c) 2024-2026 Oracle. All Rights Reserved. 4a48373e7SDarrick J. Wong * Author: Darrick J. Wong <djwong@kernel.org> 5a48373e7SDarrick J. Wong */ 6a48373e7SDarrick J. Wong #ifndef __XFS_HEALTHMON_H__ 7a48373e7SDarrick J. Wong #define __XFS_HEALTHMON_H__ 8a48373e7SDarrick J. Wong 9a48373e7SDarrick J. Wong struct xfs_healthmon { 10a48373e7SDarrick J. Wong /* 11a48373e7SDarrick J. Wong * Weak reference to the xfs filesystem that is being monitored. It 12a48373e7SDarrick J. Wong * will be set to zero when the filesystem detaches from the monitor. 13a48373e7SDarrick J. Wong * Do not dereference this pointer. 14a48373e7SDarrick J. Wong */ 15a48373e7SDarrick J. Wong uintptr_t mount_cookie; 16a48373e7SDarrick J. Wong 17a48373e7SDarrick J. Wong /* 18a48373e7SDarrick J. Wong * Device number of the filesystem being monitored. This is for 19a48373e7SDarrick J. Wong * consistent tracing even after unmount. 20a48373e7SDarrick J. Wong */ 21a48373e7SDarrick J. Wong dev_t dev; 22a48373e7SDarrick J. Wong 23a48373e7SDarrick J. Wong /* 24a48373e7SDarrick J. Wong * Reference count of this structure. The open healthmon fd holds one 25a48373e7SDarrick J. Wong * ref, the xfs_mount holds another ref if it points to this object, 26a48373e7SDarrick J. Wong * and running event handlers hold their own refs. 27a48373e7SDarrick J. Wong */ 28a48373e7SDarrick J. Wong refcount_t ref; 29b3a289a2SDarrick J. Wong 30b3a289a2SDarrick J. Wong /* lock for event list and event counters */ 31b3a289a2SDarrick J. Wong struct mutex lock; 32b3a289a2SDarrick J. Wong 33b3a289a2SDarrick J. Wong /* list of event objects */ 34b3a289a2SDarrick J. Wong struct xfs_healthmon_event *first_event; 35b3a289a2SDarrick J. Wong struct xfs_healthmon_event *last_event; 36b3a289a2SDarrick J. Wong 3725ca57faSDarrick J. Wong /* preallocated event for unmount */ 3825ca57faSDarrick J. Wong struct xfs_healthmon_event *unmount_event; 3925ca57faSDarrick J. Wong 40b3a289a2SDarrick J. Wong /* number of events in the list */ 41b3a289a2SDarrick J. Wong unsigned int events; 42b3a289a2SDarrick J. Wong 43b3a289a2SDarrick J. Wong /* do we want all events? */ 44b3a289a2SDarrick J. Wong bool verbose:1; 45b3a289a2SDarrick J. Wong 46b3a289a2SDarrick J. Wong /* waiter so read/poll can sleep until the arrival of events */ 47b3a289a2SDarrick J. Wong struct wait_queue_head wait; 48b3a289a2SDarrick J. Wong 49b3a289a2SDarrick J. Wong /* 50b3a289a2SDarrick J. Wong * Buffer for formatting events for a read_iter call. Events are 51b3a289a2SDarrick J. Wong * formatted into the buffer at bufhead, and buftail determines where 52b3a289a2SDarrick J. Wong * to start a copy_iter to get those events to userspace. All buffer 53b3a289a2SDarrick J. Wong * fields are protected by inode_lock. 54b3a289a2SDarrick J. Wong */ 55b3a289a2SDarrick J. Wong char *buffer; 56b3a289a2SDarrick J. Wong size_t bufsize; 57b3a289a2SDarrick J. Wong size_t bufhead; 58b3a289a2SDarrick J. Wong size_t buftail; 59b3a289a2SDarrick J. Wong 60b3a289a2SDarrick J. Wong /* did we lose previous events? */ 61b3a289a2SDarrick J. Wong unsigned long long lost_prev_event; 62b3a289a2SDarrick J. Wong 63b3a289a2SDarrick J. Wong /* total counts of events observed and lost events */ 64b3a289a2SDarrick J. Wong unsigned long long total_events; 65b3a289a2SDarrick J. Wong unsigned long long total_lost; 66a48373e7SDarrick J. Wong }; 67a48373e7SDarrick J. Wong 68a48373e7SDarrick J. Wong void xfs_healthmon_unmount(struct xfs_mount *mp); 69a48373e7SDarrick J. Wong 70b3a289a2SDarrick J. Wong enum xfs_healthmon_type { 71b3a289a2SDarrick J. Wong XFS_HEALTHMON_RUNNING, /* monitor running */ 72b3a289a2SDarrick J. Wong XFS_HEALTHMON_LOST, /* message lost */ 7325ca57faSDarrick J. Wong XFS_HEALTHMON_UNMOUNT, /* filesystem is unmounting */ 745eb4cb18SDarrick J. Wong 7574c4795eSDarrick J. Wong /* filesystem shutdown */ 7674c4795eSDarrick J. Wong XFS_HEALTHMON_SHUTDOWN, 7774c4795eSDarrick J. Wong 785eb4cb18SDarrick J. Wong /* metadata health events */ 795eb4cb18SDarrick J. Wong XFS_HEALTHMON_SICK, /* runtime corruption observed */ 805eb4cb18SDarrick J. Wong XFS_HEALTHMON_CORRUPT, /* fsck reported corruption */ 815eb4cb18SDarrick J. Wong XFS_HEALTHMON_HEALTHY, /* fsck reported healthy structure */ 82e76e0e3fSDarrick J. Wong 83e76e0e3fSDarrick J. Wong /* media errors */ 84e76e0e3fSDarrick J. Wong XFS_HEALTHMON_MEDIA_ERROR, 85*dfa8bad3SDarrick J. Wong 86*dfa8bad3SDarrick J. Wong /* file range events */ 87*dfa8bad3SDarrick J. Wong XFS_HEALTHMON_BUFREAD, 88*dfa8bad3SDarrick J. Wong XFS_HEALTHMON_BUFWRITE, 89*dfa8bad3SDarrick J. Wong XFS_HEALTHMON_DIOREAD, 90*dfa8bad3SDarrick J. Wong XFS_HEALTHMON_DIOWRITE, 91*dfa8bad3SDarrick J. Wong XFS_HEALTHMON_DATALOST, 92b3a289a2SDarrick J. Wong }; 93b3a289a2SDarrick J. Wong 94b3a289a2SDarrick J. Wong enum xfs_healthmon_domain { 95b3a289a2SDarrick J. Wong XFS_HEALTHMON_MOUNT, /* affects the whole fs */ 965eb4cb18SDarrick J. Wong 975eb4cb18SDarrick J. Wong /* metadata health events */ 985eb4cb18SDarrick J. Wong XFS_HEALTHMON_FS, /* main filesystem metadata */ 995eb4cb18SDarrick J. Wong XFS_HEALTHMON_AG, /* allocation group metadata */ 1005eb4cb18SDarrick J. Wong XFS_HEALTHMON_INODE, /* inode metadata */ 1015eb4cb18SDarrick J. Wong XFS_HEALTHMON_RTGROUP, /* realtime group metadata */ 102e76e0e3fSDarrick J. Wong 103e76e0e3fSDarrick J. Wong /* media errors */ 104e76e0e3fSDarrick J. Wong XFS_HEALTHMON_DATADEV, 105e76e0e3fSDarrick J. Wong XFS_HEALTHMON_RTDEV, 106e76e0e3fSDarrick J. Wong XFS_HEALTHMON_LOGDEV, 107*dfa8bad3SDarrick J. Wong 108*dfa8bad3SDarrick J. Wong /* file range events */ 109*dfa8bad3SDarrick J. Wong XFS_HEALTHMON_FILERANGE, 110b3a289a2SDarrick J. Wong }; 111b3a289a2SDarrick J. Wong 112b3a289a2SDarrick J. Wong struct xfs_healthmon_event { 113b3a289a2SDarrick J. Wong struct xfs_healthmon_event *next; 114b3a289a2SDarrick J. Wong 115b3a289a2SDarrick J. Wong enum xfs_healthmon_type type; 116b3a289a2SDarrick J. Wong enum xfs_healthmon_domain domain; 117b3a289a2SDarrick J. Wong 118b3a289a2SDarrick J. Wong uint64_t time_ns; 119b3a289a2SDarrick J. Wong 120b3a289a2SDarrick J. Wong union { 121b3a289a2SDarrick J. Wong /* lost events */ 122b3a289a2SDarrick J. Wong struct { 123b3a289a2SDarrick J. Wong uint64_t lostcount; 124b3a289a2SDarrick J. Wong }; 1255eb4cb18SDarrick J. Wong /* fs/rt metadata */ 1265eb4cb18SDarrick J. Wong struct { 1275eb4cb18SDarrick J. Wong /* XFS_SICK_* flags */ 1285eb4cb18SDarrick J. Wong unsigned int fsmask; 1295eb4cb18SDarrick J. Wong }; 1305eb4cb18SDarrick J. Wong /* ag/rtgroup metadata */ 1315eb4cb18SDarrick J. Wong struct { 1325eb4cb18SDarrick J. Wong /* XFS_SICK_(AG|RG)* flags */ 1335eb4cb18SDarrick J. Wong unsigned int grpmask; 1345eb4cb18SDarrick J. Wong unsigned int group; 1355eb4cb18SDarrick J. Wong }; 1365eb4cb18SDarrick J. Wong /* inode metadata */ 1375eb4cb18SDarrick J. Wong struct { 1385eb4cb18SDarrick J. Wong /* XFS_SICK_INO_* flags */ 1395eb4cb18SDarrick J. Wong unsigned int imask; 1405eb4cb18SDarrick J. Wong uint32_t gen; 1415eb4cb18SDarrick J. Wong xfs_ino_t ino; 142b3a289a2SDarrick J. Wong }; 14374c4795eSDarrick J. Wong /* shutdown */ 14474c4795eSDarrick J. Wong struct { 14574c4795eSDarrick J. Wong unsigned int flags; 14674c4795eSDarrick J. Wong }; 147e76e0e3fSDarrick J. Wong /* media errors */ 148e76e0e3fSDarrick J. Wong struct { 149e76e0e3fSDarrick J. Wong xfs_daddr_t daddr; 150e76e0e3fSDarrick J. Wong uint64_t bbcount; 151e76e0e3fSDarrick J. Wong }; 152*dfa8bad3SDarrick J. Wong /* file range events */ 153*dfa8bad3SDarrick J. Wong struct { 154*dfa8bad3SDarrick J. Wong xfs_ino_t fino; 155*dfa8bad3SDarrick J. Wong loff_t fpos; 156*dfa8bad3SDarrick J. Wong uint64_t flen; 157*dfa8bad3SDarrick J. Wong uint32_t fgen; 158*dfa8bad3SDarrick J. Wong int error; 159*dfa8bad3SDarrick J. Wong }; 160b3a289a2SDarrick J. Wong }; 1615eb4cb18SDarrick J. Wong }; 1625eb4cb18SDarrick J. Wong 1635eb4cb18SDarrick J. Wong void xfs_healthmon_report_fs(struct xfs_mount *mp, 1645eb4cb18SDarrick J. Wong enum xfs_healthmon_type type, unsigned int old_mask, 1655eb4cb18SDarrick J. Wong unsigned int new_mask); 1665eb4cb18SDarrick J. Wong void xfs_healthmon_report_group(struct xfs_group *xg, 1675eb4cb18SDarrick J. Wong enum xfs_healthmon_type type, unsigned int old_mask, 1685eb4cb18SDarrick J. Wong unsigned int new_mask); 1695eb4cb18SDarrick J. Wong void xfs_healthmon_report_inode(struct xfs_inode *ip, 1705eb4cb18SDarrick J. Wong enum xfs_healthmon_type type, unsigned int old_mask, 1715eb4cb18SDarrick J. Wong unsigned int new_mask); 172b3a289a2SDarrick J. Wong 17374c4795eSDarrick J. Wong void xfs_healthmon_report_shutdown(struct xfs_mount *mp, uint32_t flags); 17474c4795eSDarrick J. Wong 175e76e0e3fSDarrick J. Wong void xfs_healthmon_report_media(struct xfs_mount *mp, enum xfs_device fdev, 176e76e0e3fSDarrick J. Wong xfs_daddr_t daddr, uint64_t bbcount); 177e76e0e3fSDarrick J. Wong 178*dfa8bad3SDarrick J. Wong void xfs_healthmon_report_file_ioerror(struct xfs_inode *ip, 179*dfa8bad3SDarrick J. Wong const struct fserror_event *p); 180*dfa8bad3SDarrick J. Wong 181a48373e7SDarrick J. Wong long xfs_ioc_health_monitor(struct file *file, 182a48373e7SDarrick J. Wong struct xfs_health_monitor __user *arg); 183a48373e7SDarrick J. Wong 184a48373e7SDarrick J. Wong #endif /* __XFS_HEALTHMON_H__ */ 185