xref: /openbmc/linux/fs/xfs/scrub/stats.c (revision 6c71a0574249f5e5a45fe055ab5f837023d5eeca)
1d7a74cadSDarrick J. Wong // SPDX-License-Identifier: GPL-2.0-or-later
2d7a74cadSDarrick J. Wong /*
3d7a74cadSDarrick J. Wong  * Copyright (C) 2023 Oracle.  All Rights Reserved.
4d7a74cadSDarrick J. Wong  * Author: Darrick J. Wong <djwong@kernel.org>
5d7a74cadSDarrick J. Wong  */
6d7a74cadSDarrick J. Wong #include "xfs.h"
7d7a74cadSDarrick J. Wong #include "xfs_fs.h"
8d7a74cadSDarrick J. Wong #include "xfs_shared.h"
9d7a74cadSDarrick J. Wong #include "xfs_format.h"
10d7a74cadSDarrick J. Wong #include "xfs_trans_resv.h"
11d7a74cadSDarrick J. Wong #include "xfs_mount.h"
12d7a74cadSDarrick J. Wong #include "xfs_sysfs.h"
13d7a74cadSDarrick J. Wong #include "xfs_btree.h"
14d7a74cadSDarrick J. Wong #include "xfs_super.h"
15d7a74cadSDarrick J. Wong #include "scrub/scrub.h"
16d7a74cadSDarrick J. Wong #include "scrub/stats.h"
17d7a74cadSDarrick J. Wong #include "scrub/trace.h"
18d7a74cadSDarrick J. Wong 
19d7a74cadSDarrick J. Wong struct xchk_scrub_stats {
20d7a74cadSDarrick J. Wong 	/* all 32-bit counters here */
21d7a74cadSDarrick J. Wong 
22d7a74cadSDarrick J. Wong 	/* checking stats */
23d7a74cadSDarrick J. Wong 	uint32_t		invocations;
24d7a74cadSDarrick J. Wong 	uint32_t		clean;
25d7a74cadSDarrick J. Wong 	uint32_t		corrupt;
26d7a74cadSDarrick J. Wong 	uint32_t		preen;
27d7a74cadSDarrick J. Wong 	uint32_t		xfail;
28d7a74cadSDarrick J. Wong 	uint32_t		xcorrupt;
29d7a74cadSDarrick J. Wong 	uint32_t		incomplete;
30d7a74cadSDarrick J. Wong 	uint32_t		warning;
31d7a74cadSDarrick J. Wong 	uint32_t		retries;
32d7a74cadSDarrick J. Wong 
33d7a74cadSDarrick J. Wong 	/* repair stats */
34d7a74cadSDarrick J. Wong 	uint32_t		repair_invocations;
35d7a74cadSDarrick J. Wong 	uint32_t		repair_success;
36d7a74cadSDarrick J. Wong 
37d7a74cadSDarrick J. Wong 	/* all 64-bit items here */
38d7a74cadSDarrick J. Wong 
39d7a74cadSDarrick J. Wong 	/* runtimes */
40d7a74cadSDarrick J. Wong 	uint64_t		checktime_us;
41d7a74cadSDarrick J. Wong 	uint64_t		repairtime_us;
42d7a74cadSDarrick J. Wong 
43d7a74cadSDarrick J. Wong 	/* non-counter state must go at the end for clearall */
44d7a74cadSDarrick J. Wong 	spinlock_t		css_lock;
45d7a74cadSDarrick J. Wong };
46d7a74cadSDarrick J. Wong 
47d7a74cadSDarrick J. Wong struct xchk_stats {
48d7a74cadSDarrick J. Wong 	struct dentry		*cs_debugfs;
49d7a74cadSDarrick J. Wong 	struct xchk_scrub_stats	cs_stats[XFS_SCRUB_TYPE_NR];
50d7a74cadSDarrick J. Wong };
51d7a74cadSDarrick J. Wong 
52d7a74cadSDarrick J. Wong 
53d7a74cadSDarrick J. Wong static struct xchk_stats	global_stats;
54d7a74cadSDarrick J. Wong 
55d7a74cadSDarrick J. Wong static const char *name_map[XFS_SCRUB_TYPE_NR] = {
56d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_SB]		= "sb",
57d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_AGF]		= "agf",
58d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_AGFL]		= "agfl",
59d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_AGI]		= "agi",
60d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_BNOBT]		= "bnobt",
61d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_CNTBT]		= "cntbt",
62d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_INOBT]		= "inobt",
63d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_FINOBT]		= "finobt",
64d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_RMAPBT]		= "rmapbt",
65d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_REFCNTBT]	= "refcountbt",
66d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_INODE]		= "inode",
67d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_BMBTD]		= "bmapbtd",
68d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_BMBTA]		= "bmapbta",
69d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_BMBTC]		= "bmapbtc",
70d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_DIR]		= "directory",
71d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_XATTR]		= "xattr",
72d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_SYMLINK]	= "symlink",
73d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_PARENT]		= "parent",
74d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_RTBITMAP]	= "rtbitmap",
75d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_RTSUM]		= "rtsummary",
76d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_UQUOTA]		= "usrquota",
77d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_GQUOTA]		= "grpquota",
78d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_PQUOTA]		= "prjquota",
79d7a74cadSDarrick J. Wong 	[XFS_SCRUB_TYPE_FSCOUNTERS]	= "fscounters",
80d7a74cadSDarrick J. Wong };
81d7a74cadSDarrick J. Wong 
82d7a74cadSDarrick J. Wong /* Format the scrub stats into a text buffer, similar to pcp style. */
83d7a74cadSDarrick J. Wong STATIC ssize_t
xchk_stats_format(struct xchk_stats * cs,char * buf,size_t remaining)84d7a74cadSDarrick J. Wong xchk_stats_format(
85d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs,
86d7a74cadSDarrick J. Wong 	char			*buf,
87d7a74cadSDarrick J. Wong 	size_t			remaining)
88d7a74cadSDarrick J. Wong {
89d7a74cadSDarrick J. Wong 	struct xchk_scrub_stats	*css = &cs->cs_stats[0];
90d7a74cadSDarrick J. Wong 	unsigned int		i;
91d7a74cadSDarrick J. Wong 	ssize_t			copied = 0;
92d7a74cadSDarrick J. Wong 	int			ret = 0;
93d7a74cadSDarrick J. Wong 
94d7a74cadSDarrick J. Wong 	for (i = 0; i < XFS_SCRUB_TYPE_NR; i++, css++) {
95d7a74cadSDarrick J. Wong 		if (!name_map[i])
96d7a74cadSDarrick J. Wong 			continue;
97d7a74cadSDarrick J. Wong 
98d7a74cadSDarrick J. Wong 		ret = scnprintf(buf, remaining,
99d7a74cadSDarrick J. Wong  "%s %u %u %u %u %u %u %u %u %u %llu %u %u %llu\n",
100d7a74cadSDarrick J. Wong 				name_map[i],
101d7a74cadSDarrick J. Wong 				(unsigned int)css->invocations,
102d7a74cadSDarrick J. Wong 				(unsigned int)css->clean,
103d7a74cadSDarrick J. Wong 				(unsigned int)css->corrupt,
104d7a74cadSDarrick J. Wong 				(unsigned int)css->preen,
105d7a74cadSDarrick J. Wong 				(unsigned int)css->xfail,
106d7a74cadSDarrick J. Wong 				(unsigned int)css->xcorrupt,
107d7a74cadSDarrick J. Wong 				(unsigned int)css->incomplete,
108d7a74cadSDarrick J. Wong 				(unsigned int)css->warning,
109d7a74cadSDarrick J. Wong 				(unsigned int)css->retries,
110d7a74cadSDarrick J. Wong 				(unsigned long long)css->checktime_us,
111d7a74cadSDarrick J. Wong 				(unsigned int)css->repair_invocations,
112d7a74cadSDarrick J. Wong 				(unsigned int)css->repair_success,
113d7a74cadSDarrick J. Wong 				(unsigned long long)css->repairtime_us);
114d7a74cadSDarrick J. Wong 		if (ret <= 0)
115d7a74cadSDarrick J. Wong 			break;
116d7a74cadSDarrick J. Wong 
117d7a74cadSDarrick J. Wong 		remaining -= ret;
118d7a74cadSDarrick J. Wong 		copied += ret;
119d7a74cadSDarrick J. Wong 		buf +=  ret;
120d7a74cadSDarrick J. Wong 	}
121d7a74cadSDarrick J. Wong 
122d7a74cadSDarrick J. Wong 	return copied > 0 ? copied : ret;
123d7a74cadSDarrick J. Wong }
124d7a74cadSDarrick J. Wong 
125d7a74cadSDarrick J. Wong /* Estimate the worst case buffer size required to hold the whole report. */
126d7a74cadSDarrick J. Wong STATIC size_t
xchk_stats_estimate_bufsize(struct xchk_stats * cs)127d7a74cadSDarrick J. Wong xchk_stats_estimate_bufsize(
128d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs)
129d7a74cadSDarrick J. Wong {
130d7a74cadSDarrick J. Wong 	struct xchk_scrub_stats	*css = &cs->cs_stats[0];
131d7a74cadSDarrick J. Wong 	unsigned int		i;
132d7a74cadSDarrick J. Wong 	size_t			field_width;
133d7a74cadSDarrick J. Wong 	size_t			ret = 0;
134d7a74cadSDarrick J. Wong 
135d7a74cadSDarrick J. Wong 	/* 4294967296 plus one space for each u32 field */
136d7a74cadSDarrick J. Wong 	field_width = 11 * (offsetof(struct xchk_scrub_stats, checktime_us) /
137d7a74cadSDarrick J. Wong 			    sizeof(uint32_t));
138d7a74cadSDarrick J. Wong 
139d7a74cadSDarrick J. Wong 	/* 18446744073709551615 plus one space for each u64 field */
140d7a74cadSDarrick J. Wong 	field_width += 21 * ((offsetof(struct xchk_scrub_stats, css_lock) -
141d7a74cadSDarrick J. Wong 			      offsetof(struct xchk_scrub_stats, checktime_us)) /
142d7a74cadSDarrick J. Wong 			     sizeof(uint64_t));
143d7a74cadSDarrick J. Wong 
144d7a74cadSDarrick J. Wong 	for (i = 0; i < XFS_SCRUB_TYPE_NR; i++, css++) {
145d7a74cadSDarrick J. Wong 		if (!name_map[i])
146d7a74cadSDarrick J. Wong 			continue;
147d7a74cadSDarrick J. Wong 
148d7a74cadSDarrick J. Wong 		/* name plus one space */
149d7a74cadSDarrick J. Wong 		ret += 1 + strlen(name_map[i]);
150d7a74cadSDarrick J. Wong 
151d7a74cadSDarrick J. Wong 		/* all fields, plus newline */
152d7a74cadSDarrick J. Wong 		ret += field_width + 1;
153d7a74cadSDarrick J. Wong 	}
154d7a74cadSDarrick J. Wong 
155d7a74cadSDarrick J. Wong 	return ret;
156d7a74cadSDarrick J. Wong }
157d7a74cadSDarrick J. Wong 
158d7a74cadSDarrick J. Wong /* Clear all counters. */
159d7a74cadSDarrick J. Wong STATIC void
xchk_stats_clearall(struct xchk_stats * cs)160d7a74cadSDarrick J. Wong xchk_stats_clearall(
161d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs)
162d7a74cadSDarrick J. Wong {
163d7a74cadSDarrick J. Wong 	struct xchk_scrub_stats	*css = &cs->cs_stats[0];
164d7a74cadSDarrick J. Wong 	unsigned int		i;
165d7a74cadSDarrick J. Wong 
166d7a74cadSDarrick J. Wong 	for (i = 0; i < XFS_SCRUB_TYPE_NR; i++, css++) {
167d7a74cadSDarrick J. Wong 		spin_lock(&css->css_lock);
168d7a74cadSDarrick J. Wong 		memset(css, 0, offsetof(struct xchk_scrub_stats, css_lock));
169d7a74cadSDarrick J. Wong 		spin_unlock(&css->css_lock);
170d7a74cadSDarrick J. Wong 	}
171d7a74cadSDarrick J. Wong }
172d7a74cadSDarrick J. Wong 
173d7a74cadSDarrick J. Wong #define XFS_SCRUB_OFLAG_UNCLEAN	(XFS_SCRUB_OFLAG_CORRUPT | \
174d7a74cadSDarrick J. Wong 				 XFS_SCRUB_OFLAG_PREEN | \
175d7a74cadSDarrick J. Wong 				 XFS_SCRUB_OFLAG_XFAIL | \
176d7a74cadSDarrick J. Wong 				 XFS_SCRUB_OFLAG_XCORRUPT | \
177d7a74cadSDarrick J. Wong 				 XFS_SCRUB_OFLAG_INCOMPLETE | \
178d7a74cadSDarrick J. Wong 				 XFS_SCRUB_OFLAG_WARNING)
179d7a74cadSDarrick J. Wong 
180d7a74cadSDarrick J. Wong STATIC void
xchk_stats_merge_one(struct xchk_stats * cs,const struct xfs_scrub_metadata * sm,const struct xchk_stats_run * run)181d7a74cadSDarrick J. Wong xchk_stats_merge_one(
182d7a74cadSDarrick J. Wong 	struct xchk_stats		*cs,
183d7a74cadSDarrick J. Wong 	const struct xfs_scrub_metadata	*sm,
184d7a74cadSDarrick J. Wong 	const struct xchk_stats_run	*run)
185d7a74cadSDarrick J. Wong {
186d7a74cadSDarrick J. Wong 	struct xchk_scrub_stats		*css;
187d7a74cadSDarrick J. Wong 
188e0319282SDarrick J. Wong 	if (sm->sm_type >= XFS_SCRUB_TYPE_NR) {
189d7a74cadSDarrick J. Wong 		ASSERT(sm->sm_type < XFS_SCRUB_TYPE_NR);
190e0319282SDarrick J. Wong 		return;
191e0319282SDarrick J. Wong 	}
192d7a74cadSDarrick J. Wong 
193d7a74cadSDarrick J. Wong 	css = &cs->cs_stats[sm->sm_type];
194d7a74cadSDarrick J. Wong 	spin_lock(&css->css_lock);
195d7a74cadSDarrick J. Wong 	css->invocations++;
196d7a74cadSDarrick J. Wong 	if (!(sm->sm_flags & XFS_SCRUB_OFLAG_UNCLEAN))
197d7a74cadSDarrick J. Wong 		css->clean++;
198d7a74cadSDarrick J. Wong 	if (sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)
199d7a74cadSDarrick J. Wong 		css->corrupt++;
200d7a74cadSDarrick J. Wong 	if (sm->sm_flags & XFS_SCRUB_OFLAG_PREEN)
201d7a74cadSDarrick J. Wong 		css->preen++;
202d7a74cadSDarrick J. Wong 	if (sm->sm_flags & XFS_SCRUB_OFLAG_XFAIL)
203d7a74cadSDarrick J. Wong 		css->xfail++;
204d7a74cadSDarrick J. Wong 	if (sm->sm_flags & XFS_SCRUB_OFLAG_XCORRUPT)
205d7a74cadSDarrick J. Wong 		css->xcorrupt++;
206d7a74cadSDarrick J. Wong 	if (sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE)
207d7a74cadSDarrick J. Wong 		css->incomplete++;
208d7a74cadSDarrick J. Wong 	if (sm->sm_flags & XFS_SCRUB_OFLAG_WARNING)
209d7a74cadSDarrick J. Wong 		css->warning++;
210d7a74cadSDarrick J. Wong 	css->retries += run->retries;
211d7a74cadSDarrick J. Wong 	css->checktime_us += howmany_64(run->scrub_ns, NSEC_PER_USEC);
212d7a74cadSDarrick J. Wong 
213d7a74cadSDarrick J. Wong 	if (run->repair_attempted)
214d7a74cadSDarrick J. Wong 		css->repair_invocations++;
215d7a74cadSDarrick J. Wong 	if (run->repair_succeeded)
216d7a74cadSDarrick J. Wong 		css->repair_success++;
217d7a74cadSDarrick J. Wong 	css->repairtime_us += howmany_64(run->repair_ns, NSEC_PER_USEC);
218d7a74cadSDarrick J. Wong 	spin_unlock(&css->css_lock);
219d7a74cadSDarrick J. Wong }
220d7a74cadSDarrick J. Wong 
221d7a74cadSDarrick J. Wong /* Merge these scrub-run stats into the global and mount stat data. */
222d7a74cadSDarrick J. Wong void
xchk_stats_merge(struct xfs_mount * mp,const struct xfs_scrub_metadata * sm,const struct xchk_stats_run * run)223d7a74cadSDarrick J. Wong xchk_stats_merge(
224d7a74cadSDarrick J. Wong 	struct xfs_mount		*mp,
225d7a74cadSDarrick J. Wong 	const struct xfs_scrub_metadata	*sm,
226d7a74cadSDarrick J. Wong 	const struct xchk_stats_run	*run)
227d7a74cadSDarrick J. Wong {
228d7a74cadSDarrick J. Wong 	xchk_stats_merge_one(&global_stats, sm, run);
229d7a74cadSDarrick J. Wong 	xchk_stats_merge_one(mp->m_scrub_stats, sm, run);
230d7a74cadSDarrick J. Wong }
231d7a74cadSDarrick J. Wong 
232d7a74cadSDarrick J. Wong /* debugfs boilerplate */
233d7a74cadSDarrick J. Wong 
234d7a74cadSDarrick J. Wong static ssize_t
xchk_scrub_stats_read(struct file * file,char __user * ubuf,size_t count,loff_t * ppos)235d7a74cadSDarrick J. Wong xchk_scrub_stats_read(
236d7a74cadSDarrick J. Wong 	struct file		*file,
237d7a74cadSDarrick J. Wong 	char __user		*ubuf,
238d7a74cadSDarrick J. Wong 	size_t			count,
239d7a74cadSDarrick J. Wong 	loff_t			*ppos)
240d7a74cadSDarrick J. Wong {
241d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs = file->private_data;
242d7a74cadSDarrick J. Wong 	char			*buf;
243d7a74cadSDarrick J. Wong 	size_t			bufsize;
244d7a74cadSDarrick J. Wong 	ssize_t			avail, ret;
245d7a74cadSDarrick J. Wong 
246d7a74cadSDarrick J. Wong 	/*
247d7a74cadSDarrick J. Wong 	 * This generates stringly snapshot of all the scrub counters, so we
248d7a74cadSDarrick J. Wong 	 * do not want userspace to receive garbled text from multiple calls.
249d7a74cadSDarrick J. Wong 	 * If the file position is greater than 0, return a short read.
250d7a74cadSDarrick J. Wong 	 */
251d7a74cadSDarrick J. Wong 	if (*ppos > 0)
252d7a74cadSDarrick J. Wong 		return 0;
253d7a74cadSDarrick J. Wong 
254d7a74cadSDarrick J. Wong 	bufsize = xchk_stats_estimate_bufsize(cs);
255d7a74cadSDarrick J. Wong 
256d7a74cadSDarrick J. Wong 	buf = kvmalloc(bufsize, XCHK_GFP_FLAGS);
257d7a74cadSDarrick J. Wong 	if (!buf)
258d7a74cadSDarrick J. Wong 		return -ENOMEM;
259d7a74cadSDarrick J. Wong 
260d7a74cadSDarrick J. Wong 	avail = xchk_stats_format(cs, buf, bufsize);
261d7a74cadSDarrick J. Wong 	if (avail < 0) {
262d7a74cadSDarrick J. Wong 		ret = avail;
263d7a74cadSDarrick J. Wong 		goto out;
264d7a74cadSDarrick J. Wong 	}
265d7a74cadSDarrick J. Wong 
266d7a74cadSDarrick J. Wong 	ret = simple_read_from_buffer(ubuf, count, ppos, buf, avail);
267d7a74cadSDarrick J. Wong out:
268d7a74cadSDarrick J. Wong 	kvfree(buf);
269d7a74cadSDarrick J. Wong 	return ret;
270d7a74cadSDarrick J. Wong }
271d7a74cadSDarrick J. Wong 
272d7a74cadSDarrick J. Wong static const struct file_operations scrub_stats_fops = {
273d7a74cadSDarrick J. Wong 	.open			= simple_open,
274d7a74cadSDarrick J. Wong 	.read			= xchk_scrub_stats_read,
275d7a74cadSDarrick J. Wong };
276d7a74cadSDarrick J. Wong 
277d7a74cadSDarrick J. Wong static ssize_t
xchk_clear_scrub_stats_write(struct file * file,const char __user * ubuf,size_t count,loff_t * ppos)278d7a74cadSDarrick J. Wong xchk_clear_scrub_stats_write(
279d7a74cadSDarrick J. Wong 	struct file		*file,
280d7a74cadSDarrick J. Wong 	const char __user	*ubuf,
281d7a74cadSDarrick J. Wong 	size_t			count,
282d7a74cadSDarrick J. Wong 	loff_t			*ppos)
283d7a74cadSDarrick J. Wong {
284d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs = file->private_data;
285d7a74cadSDarrick J. Wong 	unsigned int		val;
286d7a74cadSDarrick J. Wong 	int			ret;
287d7a74cadSDarrick J. Wong 
288d7a74cadSDarrick J. Wong 	ret = kstrtouint_from_user(ubuf, count, 0, &val);
289d7a74cadSDarrick J. Wong 	if (ret)
290d7a74cadSDarrick J. Wong 		return ret;
291d7a74cadSDarrick J. Wong 
292d7a74cadSDarrick J. Wong 	if (val != 1)
293d7a74cadSDarrick J. Wong 		return -EINVAL;
294d7a74cadSDarrick J. Wong 
295d7a74cadSDarrick J. Wong 	xchk_stats_clearall(cs);
296d7a74cadSDarrick J. Wong 	return count;
297d7a74cadSDarrick J. Wong }
298d7a74cadSDarrick J. Wong 
299d7a74cadSDarrick J. Wong static const struct file_operations clear_scrub_stats_fops = {
300d7a74cadSDarrick J. Wong 	.open			= simple_open,
301d7a74cadSDarrick J. Wong 	.write			= xchk_clear_scrub_stats_write,
302d7a74cadSDarrick J. Wong };
303d7a74cadSDarrick J. Wong 
304d7a74cadSDarrick J. Wong /* Initialize the stats object. */
305d7a74cadSDarrick J. Wong STATIC int
xchk_stats_init(struct xchk_stats * cs,struct xfs_mount * mp)306d7a74cadSDarrick J. Wong xchk_stats_init(
307d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs,
308d7a74cadSDarrick J. Wong 	struct xfs_mount	*mp)
309d7a74cadSDarrick J. Wong {
310d7a74cadSDarrick J. Wong 	struct xchk_scrub_stats	*css = &cs->cs_stats[0];
311d7a74cadSDarrick J. Wong 	unsigned int		i;
312d7a74cadSDarrick J. Wong 
313d7a74cadSDarrick J. Wong 	for (i = 0; i < XFS_SCRUB_TYPE_NR; i++, css++)
314d7a74cadSDarrick J. Wong 		spin_lock_init(&css->css_lock);
315d7a74cadSDarrick J. Wong 
316d7a74cadSDarrick J. Wong 	return 0;
317d7a74cadSDarrick J. Wong }
318d7a74cadSDarrick J. Wong 
319d7a74cadSDarrick J. Wong /* Connect the stats object to debugfs. */
320d7a74cadSDarrick J. Wong void
xchk_stats_register(struct xchk_stats * cs,struct dentry * parent)321d7a74cadSDarrick J. Wong xchk_stats_register(
322d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs,
323d7a74cadSDarrick J. Wong 	struct dentry		*parent)
324d7a74cadSDarrick J. Wong {
325d7a74cadSDarrick J. Wong 	if (!parent)
326d7a74cadSDarrick J. Wong 		return;
327d7a74cadSDarrick J. Wong 
328d7a74cadSDarrick J. Wong 	cs->cs_debugfs = xfs_debugfs_mkdir("scrub", parent);
329d7a74cadSDarrick J. Wong 	if (!cs->cs_debugfs)
330d7a74cadSDarrick J. Wong 		return;
331d7a74cadSDarrick J. Wong 
332*7f0e5af2SDarrick J. Wong 	debugfs_create_file("stats", 0444, cs->cs_debugfs, cs,
333d7a74cadSDarrick J. Wong 			&scrub_stats_fops);
334*7f0e5af2SDarrick J. Wong 	debugfs_create_file("clear_stats", 0200, cs->cs_debugfs, cs,
335d7a74cadSDarrick J. Wong 			&clear_scrub_stats_fops);
336d7a74cadSDarrick J. Wong }
337d7a74cadSDarrick J. Wong 
338d7a74cadSDarrick J. Wong /* Free all resources related to the stats object. */
339d7a74cadSDarrick J. Wong STATIC int
xchk_stats_teardown(struct xchk_stats * cs)340d7a74cadSDarrick J. Wong xchk_stats_teardown(
341d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs)
342d7a74cadSDarrick J. Wong {
343d7a74cadSDarrick J. Wong 	return 0;
344d7a74cadSDarrick J. Wong }
345d7a74cadSDarrick J. Wong 
346d7a74cadSDarrick J. Wong /* Disconnect the stats object from debugfs. */
347d7a74cadSDarrick J. Wong void
xchk_stats_unregister(struct xchk_stats * cs)348d7a74cadSDarrick J. Wong xchk_stats_unregister(
349d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs)
350d7a74cadSDarrick J. Wong {
351d7a74cadSDarrick J. Wong 	debugfs_remove(cs->cs_debugfs);
352d7a74cadSDarrick J. Wong }
353d7a74cadSDarrick J. Wong 
354d7a74cadSDarrick J. Wong /* Initialize global stats and register them */
355d7a74cadSDarrick J. Wong int __init
xchk_global_stats_setup(struct dentry * parent)356d7a74cadSDarrick J. Wong xchk_global_stats_setup(
357d7a74cadSDarrick J. Wong 	struct dentry		*parent)
358d7a74cadSDarrick J. Wong {
359d7a74cadSDarrick J. Wong 	int			error;
360d7a74cadSDarrick J. Wong 
361d7a74cadSDarrick J. Wong 	error = xchk_stats_init(&global_stats, NULL);
362d7a74cadSDarrick J. Wong 	if (error)
363d7a74cadSDarrick J. Wong 		return error;
364d7a74cadSDarrick J. Wong 
365d7a74cadSDarrick J. Wong 	xchk_stats_register(&global_stats, parent);
366d7a74cadSDarrick J. Wong 	return 0;
367d7a74cadSDarrick J. Wong }
368d7a74cadSDarrick J. Wong 
369d7a74cadSDarrick J. Wong /* Unregister global stats and tear them down */
370d7a74cadSDarrick J. Wong void
xchk_global_stats_teardown(void)371d7a74cadSDarrick J. Wong xchk_global_stats_teardown(void)
372d7a74cadSDarrick J. Wong {
373d7a74cadSDarrick J. Wong 	xchk_stats_unregister(&global_stats);
374d7a74cadSDarrick J. Wong 	xchk_stats_teardown(&global_stats);
375d7a74cadSDarrick J. Wong }
376d7a74cadSDarrick J. Wong 
377d7a74cadSDarrick J. Wong /* Allocate per-mount stats */
378d7a74cadSDarrick J. Wong int
xchk_mount_stats_alloc(struct xfs_mount * mp)379d7a74cadSDarrick J. Wong xchk_mount_stats_alloc(
380d7a74cadSDarrick J. Wong 	struct xfs_mount	*mp)
381d7a74cadSDarrick J. Wong {
382d7a74cadSDarrick J. Wong 	struct xchk_stats	*cs;
383d7a74cadSDarrick J. Wong 	int			error;
384d7a74cadSDarrick J. Wong 
385d7a74cadSDarrick J. Wong 	cs = kvzalloc(sizeof(struct xchk_stats), GFP_KERNEL);
386d7a74cadSDarrick J. Wong 	if (!cs)
387d7a74cadSDarrick J. Wong 		return -ENOMEM;
388d7a74cadSDarrick J. Wong 
389d7a74cadSDarrick J. Wong 	error = xchk_stats_init(cs, mp);
390d7a74cadSDarrick J. Wong 	if (error)
391d7a74cadSDarrick J. Wong 		goto out_free;
392d7a74cadSDarrick J. Wong 
393d7a74cadSDarrick J. Wong 	mp->m_scrub_stats = cs;
394d7a74cadSDarrick J. Wong 	return 0;
395d7a74cadSDarrick J. Wong out_free:
396d7a74cadSDarrick J. Wong 	kvfree(cs);
397d7a74cadSDarrick J. Wong 	return error;
398d7a74cadSDarrick J. Wong }
399d7a74cadSDarrick J. Wong 
400d7a74cadSDarrick J. Wong /* Free per-mount stats */
401d7a74cadSDarrick J. Wong void
xchk_mount_stats_free(struct xfs_mount * mp)402d7a74cadSDarrick J. Wong xchk_mount_stats_free(
403d7a74cadSDarrick J. Wong 	struct xfs_mount	*mp)
404d7a74cadSDarrick J. Wong {
405d7a74cadSDarrick J. Wong 	xchk_stats_teardown(mp->m_scrub_stats);
406d7a74cadSDarrick J. Wong 	kvfree(mp->m_scrub_stats);
407d7a74cadSDarrick J. Wong 	mp->m_scrub_stats = NULL;
408d7a74cadSDarrick J. Wong }
409