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