summaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_healthmon.h
blob: fa3deb187a2b313b1f062b7a6fea6ea23bfb1e02 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/* 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 list_head		event_list;

	/* 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 list_head		entry;

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