162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2023 Oracle. All Rights Reserved. 462306a36Sopenharmony_ci * Author: Darrick J. Wong <djwong@kernel.org> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "xfs.h" 762306a36Sopenharmony_ci#include "xfs_fs.h" 862306a36Sopenharmony_ci#include "xfs_shared.h" 962306a36Sopenharmony_ci#include "xfs_format.h" 1062306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1162306a36Sopenharmony_ci#include "xfs_mount.h" 1262306a36Sopenharmony_ci#include "xfs_sysfs.h" 1362306a36Sopenharmony_ci#include "xfs_btree.h" 1462306a36Sopenharmony_ci#include "xfs_super.h" 1562306a36Sopenharmony_ci#include "scrub/scrub.h" 1662306a36Sopenharmony_ci#include "scrub/stats.h" 1762306a36Sopenharmony_ci#include "scrub/trace.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistruct xchk_scrub_stats { 2062306a36Sopenharmony_ci /* all 32-bit counters here */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci /* checking stats */ 2362306a36Sopenharmony_ci uint32_t invocations; 2462306a36Sopenharmony_ci uint32_t clean; 2562306a36Sopenharmony_ci uint32_t corrupt; 2662306a36Sopenharmony_ci uint32_t preen; 2762306a36Sopenharmony_ci uint32_t xfail; 2862306a36Sopenharmony_ci uint32_t xcorrupt; 2962306a36Sopenharmony_ci uint32_t incomplete; 3062306a36Sopenharmony_ci uint32_t warning; 3162306a36Sopenharmony_ci uint32_t retries; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci /* repair stats */ 3462306a36Sopenharmony_ci uint32_t repair_invocations; 3562306a36Sopenharmony_ci uint32_t repair_success; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci /* all 64-bit items here */ 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci /* runtimes */ 4062306a36Sopenharmony_ci uint64_t checktime_us; 4162306a36Sopenharmony_ci uint64_t repairtime_us; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* non-counter state must go at the end for clearall */ 4462306a36Sopenharmony_ci spinlock_t css_lock; 4562306a36Sopenharmony_ci}; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct xchk_stats { 4862306a36Sopenharmony_ci struct dentry *cs_debugfs; 4962306a36Sopenharmony_ci struct xchk_scrub_stats cs_stats[XFS_SCRUB_TYPE_NR]; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic struct xchk_stats global_stats; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic const char *name_map[XFS_SCRUB_TYPE_NR] = { 5662306a36Sopenharmony_ci [XFS_SCRUB_TYPE_SB] = "sb", 5762306a36Sopenharmony_ci [XFS_SCRUB_TYPE_AGF] = "agf", 5862306a36Sopenharmony_ci [XFS_SCRUB_TYPE_AGFL] = "agfl", 5962306a36Sopenharmony_ci [XFS_SCRUB_TYPE_AGI] = "agi", 6062306a36Sopenharmony_ci [XFS_SCRUB_TYPE_BNOBT] = "bnobt", 6162306a36Sopenharmony_ci [XFS_SCRUB_TYPE_CNTBT] = "cntbt", 6262306a36Sopenharmony_ci [XFS_SCRUB_TYPE_INOBT] = "inobt", 6362306a36Sopenharmony_ci [XFS_SCRUB_TYPE_FINOBT] = "finobt", 6462306a36Sopenharmony_ci [XFS_SCRUB_TYPE_RMAPBT] = "rmapbt", 6562306a36Sopenharmony_ci [XFS_SCRUB_TYPE_REFCNTBT] = "refcountbt", 6662306a36Sopenharmony_ci [XFS_SCRUB_TYPE_INODE] = "inode", 6762306a36Sopenharmony_ci [XFS_SCRUB_TYPE_BMBTD] = "bmapbtd", 6862306a36Sopenharmony_ci [XFS_SCRUB_TYPE_BMBTA] = "bmapbta", 6962306a36Sopenharmony_ci [XFS_SCRUB_TYPE_BMBTC] = "bmapbtc", 7062306a36Sopenharmony_ci [XFS_SCRUB_TYPE_DIR] = "directory", 7162306a36Sopenharmony_ci [XFS_SCRUB_TYPE_XATTR] = "xattr", 7262306a36Sopenharmony_ci [XFS_SCRUB_TYPE_SYMLINK] = "symlink", 7362306a36Sopenharmony_ci [XFS_SCRUB_TYPE_PARENT] = "parent", 7462306a36Sopenharmony_ci [XFS_SCRUB_TYPE_RTBITMAP] = "rtbitmap", 7562306a36Sopenharmony_ci [XFS_SCRUB_TYPE_RTSUM] = "rtsummary", 7662306a36Sopenharmony_ci [XFS_SCRUB_TYPE_UQUOTA] = "usrquota", 7762306a36Sopenharmony_ci [XFS_SCRUB_TYPE_GQUOTA] = "grpquota", 7862306a36Sopenharmony_ci [XFS_SCRUB_TYPE_PQUOTA] = "prjquota", 7962306a36Sopenharmony_ci [XFS_SCRUB_TYPE_FSCOUNTERS] = "fscounters", 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* Format the scrub stats into a text buffer, similar to pcp style. */ 8362306a36Sopenharmony_ciSTATIC ssize_t 8462306a36Sopenharmony_cixchk_stats_format( 8562306a36Sopenharmony_ci struct xchk_stats *cs, 8662306a36Sopenharmony_ci char *buf, 8762306a36Sopenharmony_ci size_t remaining) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct xchk_scrub_stats *css = &cs->cs_stats[0]; 9062306a36Sopenharmony_ci unsigned int i; 9162306a36Sopenharmony_ci ssize_t copied = 0; 9262306a36Sopenharmony_ci int ret = 0; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci for (i = 0; i < XFS_SCRUB_TYPE_NR; i++, css++) { 9562306a36Sopenharmony_ci if (!name_map[i]) 9662306a36Sopenharmony_ci continue; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ret = scnprintf(buf, remaining, 9962306a36Sopenharmony_ci "%s %u %u %u %u %u %u %u %u %u %llu %u %u %llu\n", 10062306a36Sopenharmony_ci name_map[i], 10162306a36Sopenharmony_ci (unsigned int)css->invocations, 10262306a36Sopenharmony_ci (unsigned int)css->clean, 10362306a36Sopenharmony_ci (unsigned int)css->corrupt, 10462306a36Sopenharmony_ci (unsigned int)css->preen, 10562306a36Sopenharmony_ci (unsigned int)css->xfail, 10662306a36Sopenharmony_ci (unsigned int)css->xcorrupt, 10762306a36Sopenharmony_ci (unsigned int)css->incomplete, 10862306a36Sopenharmony_ci (unsigned int)css->warning, 10962306a36Sopenharmony_ci (unsigned int)css->retries, 11062306a36Sopenharmony_ci (unsigned long long)css->checktime_us, 11162306a36Sopenharmony_ci (unsigned int)css->repair_invocations, 11262306a36Sopenharmony_ci (unsigned int)css->repair_success, 11362306a36Sopenharmony_ci (unsigned long long)css->repairtime_us); 11462306a36Sopenharmony_ci if (ret <= 0) 11562306a36Sopenharmony_ci break; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci remaining -= ret; 11862306a36Sopenharmony_ci copied += ret; 11962306a36Sopenharmony_ci buf += ret; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci return copied > 0 ? copied : ret; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* Estimate the worst case buffer size required to hold the whole report. */ 12662306a36Sopenharmony_ciSTATIC size_t 12762306a36Sopenharmony_cixchk_stats_estimate_bufsize( 12862306a36Sopenharmony_ci struct xchk_stats *cs) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct xchk_scrub_stats *css = &cs->cs_stats[0]; 13162306a36Sopenharmony_ci unsigned int i; 13262306a36Sopenharmony_ci size_t field_width; 13362306a36Sopenharmony_ci size_t ret = 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci /* 4294967296 plus one space for each u32 field */ 13662306a36Sopenharmony_ci field_width = 11 * (offsetof(struct xchk_scrub_stats, checktime_us) / 13762306a36Sopenharmony_ci sizeof(uint32_t)); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* 18446744073709551615 plus one space for each u64 field */ 14062306a36Sopenharmony_ci field_width += 21 * ((offsetof(struct xchk_scrub_stats, css_lock) - 14162306a36Sopenharmony_ci offsetof(struct xchk_scrub_stats, checktime_us)) / 14262306a36Sopenharmony_ci sizeof(uint64_t)); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci for (i = 0; i < XFS_SCRUB_TYPE_NR; i++, css++) { 14562306a36Sopenharmony_ci if (!name_map[i]) 14662306a36Sopenharmony_ci continue; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci /* name plus one space */ 14962306a36Sopenharmony_ci ret += 1 + strlen(name_map[i]); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci /* all fields, plus newline */ 15262306a36Sopenharmony_ci ret += field_width + 1; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return ret; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* Clear all counters. */ 15962306a36Sopenharmony_ciSTATIC void 16062306a36Sopenharmony_cixchk_stats_clearall( 16162306a36Sopenharmony_ci struct xchk_stats *cs) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct xchk_scrub_stats *css = &cs->cs_stats[0]; 16462306a36Sopenharmony_ci unsigned int i; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci for (i = 0; i < XFS_SCRUB_TYPE_NR; i++, css++) { 16762306a36Sopenharmony_ci spin_lock(&css->css_lock); 16862306a36Sopenharmony_ci memset(css, 0, offsetof(struct xchk_scrub_stats, css_lock)); 16962306a36Sopenharmony_ci spin_unlock(&css->css_lock); 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci#define XFS_SCRUB_OFLAG_UNCLEAN (XFS_SCRUB_OFLAG_CORRUPT | \ 17462306a36Sopenharmony_ci XFS_SCRUB_OFLAG_PREEN | \ 17562306a36Sopenharmony_ci XFS_SCRUB_OFLAG_XFAIL | \ 17662306a36Sopenharmony_ci XFS_SCRUB_OFLAG_XCORRUPT | \ 17762306a36Sopenharmony_ci XFS_SCRUB_OFLAG_INCOMPLETE | \ 17862306a36Sopenharmony_ci XFS_SCRUB_OFLAG_WARNING) 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ciSTATIC void 18162306a36Sopenharmony_cixchk_stats_merge_one( 18262306a36Sopenharmony_ci struct xchk_stats *cs, 18362306a36Sopenharmony_ci const struct xfs_scrub_metadata *sm, 18462306a36Sopenharmony_ci const struct xchk_stats_run *run) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct xchk_scrub_stats *css; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci if (sm->sm_type >= XFS_SCRUB_TYPE_NR) { 18962306a36Sopenharmony_ci ASSERT(sm->sm_type < XFS_SCRUB_TYPE_NR); 19062306a36Sopenharmony_ci return; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci css = &cs->cs_stats[sm->sm_type]; 19462306a36Sopenharmony_ci spin_lock(&css->css_lock); 19562306a36Sopenharmony_ci css->invocations++; 19662306a36Sopenharmony_ci if (!(sm->sm_flags & XFS_SCRUB_OFLAG_UNCLEAN)) 19762306a36Sopenharmony_ci css->clean++; 19862306a36Sopenharmony_ci if (sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT) 19962306a36Sopenharmony_ci css->corrupt++; 20062306a36Sopenharmony_ci if (sm->sm_flags & XFS_SCRUB_OFLAG_PREEN) 20162306a36Sopenharmony_ci css->preen++; 20262306a36Sopenharmony_ci if (sm->sm_flags & XFS_SCRUB_OFLAG_XFAIL) 20362306a36Sopenharmony_ci css->xfail++; 20462306a36Sopenharmony_ci if (sm->sm_flags & XFS_SCRUB_OFLAG_XCORRUPT) 20562306a36Sopenharmony_ci css->xcorrupt++; 20662306a36Sopenharmony_ci if (sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE) 20762306a36Sopenharmony_ci css->incomplete++; 20862306a36Sopenharmony_ci if (sm->sm_flags & XFS_SCRUB_OFLAG_WARNING) 20962306a36Sopenharmony_ci css->warning++; 21062306a36Sopenharmony_ci css->retries += run->retries; 21162306a36Sopenharmony_ci css->checktime_us += howmany_64(run->scrub_ns, NSEC_PER_USEC); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci if (run->repair_attempted) 21462306a36Sopenharmony_ci css->repair_invocations++; 21562306a36Sopenharmony_ci if (run->repair_succeeded) 21662306a36Sopenharmony_ci css->repair_success++; 21762306a36Sopenharmony_ci css->repairtime_us += howmany_64(run->repair_ns, NSEC_PER_USEC); 21862306a36Sopenharmony_ci spin_unlock(&css->css_lock); 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci/* Merge these scrub-run stats into the global and mount stat data. */ 22262306a36Sopenharmony_civoid 22362306a36Sopenharmony_cixchk_stats_merge( 22462306a36Sopenharmony_ci struct xfs_mount *mp, 22562306a36Sopenharmony_ci const struct xfs_scrub_metadata *sm, 22662306a36Sopenharmony_ci const struct xchk_stats_run *run) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci xchk_stats_merge_one(&global_stats, sm, run); 22962306a36Sopenharmony_ci xchk_stats_merge_one(mp->m_scrub_stats, sm, run); 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci/* debugfs boilerplate */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic ssize_t 23562306a36Sopenharmony_cixchk_scrub_stats_read( 23662306a36Sopenharmony_ci struct file *file, 23762306a36Sopenharmony_ci char __user *ubuf, 23862306a36Sopenharmony_ci size_t count, 23962306a36Sopenharmony_ci loff_t *ppos) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci struct xchk_stats *cs = file->private_data; 24262306a36Sopenharmony_ci char *buf; 24362306a36Sopenharmony_ci size_t bufsize; 24462306a36Sopenharmony_ci ssize_t avail, ret; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * This generates stringly snapshot of all the scrub counters, so we 24862306a36Sopenharmony_ci * do not want userspace to receive garbled text from multiple calls. 24962306a36Sopenharmony_ci * If the file position is greater than 0, return a short read. 25062306a36Sopenharmony_ci */ 25162306a36Sopenharmony_ci if (*ppos > 0) 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci bufsize = xchk_stats_estimate_bufsize(cs); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci buf = kvmalloc(bufsize, XCHK_GFP_FLAGS); 25762306a36Sopenharmony_ci if (!buf) 25862306a36Sopenharmony_ci return -ENOMEM; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci avail = xchk_stats_format(cs, buf, bufsize); 26162306a36Sopenharmony_ci if (avail < 0) { 26262306a36Sopenharmony_ci ret = avail; 26362306a36Sopenharmony_ci goto out; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci ret = simple_read_from_buffer(ubuf, count, ppos, buf, avail); 26762306a36Sopenharmony_ciout: 26862306a36Sopenharmony_ci kvfree(buf); 26962306a36Sopenharmony_ci return ret; 27062306a36Sopenharmony_ci} 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_cistatic const struct file_operations scrub_stats_fops = { 27362306a36Sopenharmony_ci .open = simple_open, 27462306a36Sopenharmony_ci .read = xchk_scrub_stats_read, 27562306a36Sopenharmony_ci}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic ssize_t 27862306a36Sopenharmony_cixchk_clear_scrub_stats_write( 27962306a36Sopenharmony_ci struct file *file, 28062306a36Sopenharmony_ci const char __user *ubuf, 28162306a36Sopenharmony_ci size_t count, 28262306a36Sopenharmony_ci loff_t *ppos) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci struct xchk_stats *cs = file->private_data; 28562306a36Sopenharmony_ci unsigned int val; 28662306a36Sopenharmony_ci int ret; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ret = kstrtouint_from_user(ubuf, count, 0, &val); 28962306a36Sopenharmony_ci if (ret) 29062306a36Sopenharmony_ci return ret; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (val != 1) 29362306a36Sopenharmony_ci return -EINVAL; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci xchk_stats_clearall(cs); 29662306a36Sopenharmony_ci return count; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic const struct file_operations clear_scrub_stats_fops = { 30062306a36Sopenharmony_ci .open = simple_open, 30162306a36Sopenharmony_ci .write = xchk_clear_scrub_stats_write, 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci/* Initialize the stats object. */ 30562306a36Sopenharmony_ciSTATIC int 30662306a36Sopenharmony_cixchk_stats_init( 30762306a36Sopenharmony_ci struct xchk_stats *cs, 30862306a36Sopenharmony_ci struct xfs_mount *mp) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct xchk_scrub_stats *css = &cs->cs_stats[0]; 31162306a36Sopenharmony_ci unsigned int i; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci for (i = 0; i < XFS_SCRUB_TYPE_NR; i++, css++) 31462306a36Sopenharmony_ci spin_lock_init(&css->css_lock); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return 0; 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci/* Connect the stats object to debugfs. */ 32062306a36Sopenharmony_civoid 32162306a36Sopenharmony_cixchk_stats_register( 32262306a36Sopenharmony_ci struct xchk_stats *cs, 32362306a36Sopenharmony_ci struct dentry *parent) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci if (!parent) 32662306a36Sopenharmony_ci return; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci cs->cs_debugfs = xfs_debugfs_mkdir("scrub", parent); 32962306a36Sopenharmony_ci if (!cs->cs_debugfs) 33062306a36Sopenharmony_ci return; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci debugfs_create_file("stats", 0644, cs->cs_debugfs, cs, 33362306a36Sopenharmony_ci &scrub_stats_fops); 33462306a36Sopenharmony_ci debugfs_create_file("clear_stats", 0400, cs->cs_debugfs, cs, 33562306a36Sopenharmony_ci &clear_scrub_stats_fops); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci/* Free all resources related to the stats object. */ 33962306a36Sopenharmony_ciSTATIC int 34062306a36Sopenharmony_cixchk_stats_teardown( 34162306a36Sopenharmony_ci struct xchk_stats *cs) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/* Disconnect the stats object from debugfs. */ 34762306a36Sopenharmony_civoid 34862306a36Sopenharmony_cixchk_stats_unregister( 34962306a36Sopenharmony_ci struct xchk_stats *cs) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci debugfs_remove(cs->cs_debugfs); 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci/* Initialize global stats and register them */ 35562306a36Sopenharmony_ciint __init 35662306a36Sopenharmony_cixchk_global_stats_setup( 35762306a36Sopenharmony_ci struct dentry *parent) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci int error; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci error = xchk_stats_init(&global_stats, NULL); 36262306a36Sopenharmony_ci if (error) 36362306a36Sopenharmony_ci return error; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci xchk_stats_register(&global_stats, parent); 36662306a36Sopenharmony_ci return 0; 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci/* Unregister global stats and tear them down */ 37062306a36Sopenharmony_civoid 37162306a36Sopenharmony_cixchk_global_stats_teardown(void) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci xchk_stats_unregister(&global_stats); 37462306a36Sopenharmony_ci xchk_stats_teardown(&global_stats); 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci/* Allocate per-mount stats */ 37862306a36Sopenharmony_ciint 37962306a36Sopenharmony_cixchk_mount_stats_alloc( 38062306a36Sopenharmony_ci struct xfs_mount *mp) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct xchk_stats *cs; 38362306a36Sopenharmony_ci int error; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci cs = kvzalloc(sizeof(struct xchk_stats), GFP_KERNEL); 38662306a36Sopenharmony_ci if (!cs) 38762306a36Sopenharmony_ci return -ENOMEM; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci error = xchk_stats_init(cs, mp); 39062306a36Sopenharmony_ci if (error) 39162306a36Sopenharmony_ci goto out_free; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci mp->m_scrub_stats = cs; 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ciout_free: 39662306a36Sopenharmony_ci kvfree(cs); 39762306a36Sopenharmony_ci return error; 39862306a36Sopenharmony_ci} 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci/* Free per-mount stats */ 40162306a36Sopenharmony_civoid 40262306a36Sopenharmony_cixchk_mount_stats_free( 40362306a36Sopenharmony_ci struct xfs_mount *mp) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci xchk_stats_teardown(mp->m_scrub_stats); 40662306a36Sopenharmony_ci kvfree(mp->m_scrub_stats); 40762306a36Sopenharmony_ci mp->m_scrub_stats = NULL; 40862306a36Sopenharmony_ci} 409