162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc.
462306a36Sopenharmony_ci * All Rights Reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "xfs.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_cistruct xstats xfsstats;
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistatic int counter_val(struct xfsstats __percpu *stats, int idx)
1162306a36Sopenharmony_ci{
1262306a36Sopenharmony_ci	int val = 0, cpu;
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci	for_each_possible_cpu(cpu)
1562306a36Sopenharmony_ci		val += *(((__u32 *)per_cpu_ptr(stats, cpu) + idx));
1662306a36Sopenharmony_ci	return val;
1762306a36Sopenharmony_ci}
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ciint xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	int		i, j;
2262306a36Sopenharmony_ci	int		len = 0;
2362306a36Sopenharmony_ci	uint64_t	xs_xstrat_bytes = 0;
2462306a36Sopenharmony_ci	uint64_t	xs_write_bytes = 0;
2562306a36Sopenharmony_ci	uint64_t	xs_read_bytes = 0;
2662306a36Sopenharmony_ci	uint64_t	defer_relog = 0;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	static const struct xstats_entry {
2962306a36Sopenharmony_ci		char	*desc;
3062306a36Sopenharmony_ci		int	endpoint;
3162306a36Sopenharmony_ci	} xstats[] = {
3262306a36Sopenharmony_ci		{ "extent_alloc",	xfsstats_offset(xs_abt_lookup)	},
3362306a36Sopenharmony_ci		{ "abt",		xfsstats_offset(xs_blk_mapr)	},
3462306a36Sopenharmony_ci		{ "blk_map",		xfsstats_offset(xs_bmbt_lookup)	},
3562306a36Sopenharmony_ci		{ "bmbt",		xfsstats_offset(xs_dir_lookup)	},
3662306a36Sopenharmony_ci		{ "dir",		xfsstats_offset(xs_trans_sync)	},
3762306a36Sopenharmony_ci		{ "trans",		xfsstats_offset(xs_ig_attempts)	},
3862306a36Sopenharmony_ci		{ "ig",			xfsstats_offset(xs_log_writes)	},
3962306a36Sopenharmony_ci		{ "log",		xfsstats_offset(xs_try_logspace)},
4062306a36Sopenharmony_ci		{ "push_ail",		xfsstats_offset(xs_xstrat_quick)},
4162306a36Sopenharmony_ci		{ "xstrat",		xfsstats_offset(xs_write_calls)	},
4262306a36Sopenharmony_ci		{ "rw",			xfsstats_offset(xs_attr_get)	},
4362306a36Sopenharmony_ci		{ "attr",		xfsstats_offset(xs_iflush_count)},
4462306a36Sopenharmony_ci		{ "icluster",		xfsstats_offset(vn_active)	},
4562306a36Sopenharmony_ci		{ "vnodes",		xfsstats_offset(xb_get)		},
4662306a36Sopenharmony_ci		{ "buf",		xfsstats_offset(xs_abtb_2)	},
4762306a36Sopenharmony_ci		{ "abtb2",		xfsstats_offset(xs_abtc_2)	},
4862306a36Sopenharmony_ci		{ "abtc2",		xfsstats_offset(xs_bmbt_2)	},
4962306a36Sopenharmony_ci		{ "bmbt2",		xfsstats_offset(xs_ibt_2)	},
5062306a36Sopenharmony_ci		{ "ibt2",		xfsstats_offset(xs_fibt_2)	},
5162306a36Sopenharmony_ci		{ "fibt2",		xfsstats_offset(xs_rmap_2)	},
5262306a36Sopenharmony_ci		{ "rmapbt",		xfsstats_offset(xs_refcbt_2)	},
5362306a36Sopenharmony_ci		{ "refcntbt",		xfsstats_offset(xs_qm_dqreclaims)},
5462306a36Sopenharmony_ci		/* we print both series of quota information together */
5562306a36Sopenharmony_ci		{ "qm",			xfsstats_offset(xs_xstrat_bytes)},
5662306a36Sopenharmony_ci	};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	/* Loop over all stats groups */
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	for (i = j = 0; i < ARRAY_SIZE(xstats); i++) {
6162306a36Sopenharmony_ci		len += scnprintf(buf + len, PATH_MAX - len, "%s",
6262306a36Sopenharmony_ci				xstats[i].desc);
6362306a36Sopenharmony_ci		/* inner loop does each group */
6462306a36Sopenharmony_ci		for (; j < xstats[i].endpoint; j++)
6562306a36Sopenharmony_ci			len += scnprintf(buf + len, PATH_MAX - len, " %u",
6662306a36Sopenharmony_ci					counter_val(stats, j));
6762306a36Sopenharmony_ci		len += scnprintf(buf + len, PATH_MAX - len, "\n");
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci	/* extra precision counters */
7062306a36Sopenharmony_ci	for_each_possible_cpu(i) {
7162306a36Sopenharmony_ci		xs_xstrat_bytes += per_cpu_ptr(stats, i)->s.xs_xstrat_bytes;
7262306a36Sopenharmony_ci		xs_write_bytes += per_cpu_ptr(stats, i)->s.xs_write_bytes;
7362306a36Sopenharmony_ci		xs_read_bytes += per_cpu_ptr(stats, i)->s.xs_read_bytes;
7462306a36Sopenharmony_ci		defer_relog += per_cpu_ptr(stats, i)->s.defer_relog;
7562306a36Sopenharmony_ci	}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	len += scnprintf(buf + len, PATH_MAX-len, "xpc %llu %llu %llu\n",
7862306a36Sopenharmony_ci			xs_xstrat_bytes, xs_write_bytes, xs_read_bytes);
7962306a36Sopenharmony_ci	len += scnprintf(buf + len, PATH_MAX-len, "defer_relog %llu\n",
8062306a36Sopenharmony_ci			defer_relog);
8162306a36Sopenharmony_ci	len += scnprintf(buf + len, PATH_MAX-len, "debug %u\n",
8262306a36Sopenharmony_ci#if defined(DEBUG)
8362306a36Sopenharmony_ci		1);
8462306a36Sopenharmony_ci#else
8562306a36Sopenharmony_ci		0);
8662306a36Sopenharmony_ci#endif
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	return len;
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_civoid xfs_stats_clearall(struct xfsstats __percpu *stats)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	int		c;
9462306a36Sopenharmony_ci	uint32_t	vn_active;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	xfs_notice(NULL, "Clearing xfsstats");
9762306a36Sopenharmony_ci	for_each_possible_cpu(c) {
9862306a36Sopenharmony_ci		preempt_disable();
9962306a36Sopenharmony_ci		/* save vn_active, it's a universal truth! */
10062306a36Sopenharmony_ci		vn_active = per_cpu_ptr(stats, c)->s.vn_active;
10162306a36Sopenharmony_ci		memset(per_cpu_ptr(stats, c), 0, sizeof(*stats));
10262306a36Sopenharmony_ci		per_cpu_ptr(stats, c)->s.vn_active = vn_active;
10362306a36Sopenharmony_ci		preempt_enable();
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS
10862306a36Sopenharmony_ci/* legacy quota interfaces */
10962306a36Sopenharmony_ci#ifdef CONFIG_XFS_QUOTA
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci#define XFSSTAT_START_XQMSTAT xfsstats_offset(xs_qm_dqreclaims)
11262306a36Sopenharmony_ci#define XFSSTAT_END_XQMSTAT xfsstats_offset(xs_qm_dquot)
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic int xqm_proc_show(struct seq_file *m, void *v)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci	/* maximum; incore; ratio free to inuse; freelist */
11762306a36Sopenharmony_ci	seq_printf(m, "%d\t%d\t%d\t%u\n",
11862306a36Sopenharmony_ci		   0, counter_val(xfsstats.xs_stats, XFSSTAT_END_XQMSTAT),
11962306a36Sopenharmony_ci		   0, counter_val(xfsstats.xs_stats, XFSSTAT_END_XQMSTAT + 1));
12062306a36Sopenharmony_ci	return 0;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci/* legacy quota stats interface no 2 */
12462306a36Sopenharmony_cistatic int xqmstat_proc_show(struct seq_file *m, void *v)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	int j;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	seq_puts(m, "qm");
12962306a36Sopenharmony_ci	for (j = XFSSTAT_START_XQMSTAT; j < XFSSTAT_END_XQMSTAT; j++)
13062306a36Sopenharmony_ci		seq_printf(m, " %u", counter_val(xfsstats.xs_stats, j));
13162306a36Sopenharmony_ci	seq_putc(m, '\n');
13262306a36Sopenharmony_ci	return 0;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci#endif /* CONFIG_XFS_QUOTA */
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ciint
13762306a36Sopenharmony_cixfs_init_procfs(void)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	if (!proc_mkdir("fs/xfs", NULL))
14062306a36Sopenharmony_ci		return -ENOMEM;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (!proc_symlink("fs/xfs/stat", NULL,
14362306a36Sopenharmony_ci			  "/sys/fs/xfs/stats/stats"))
14462306a36Sopenharmony_ci		goto out;
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci#ifdef CONFIG_XFS_QUOTA
14762306a36Sopenharmony_ci	if (!proc_create_single("fs/xfs/xqmstat", 0, NULL, xqmstat_proc_show))
14862306a36Sopenharmony_ci		goto out;
14962306a36Sopenharmony_ci	if (!proc_create_single("fs/xfs/xqm", 0, NULL, xqm_proc_show))
15062306a36Sopenharmony_ci		goto out;
15162306a36Sopenharmony_ci#endif
15262306a36Sopenharmony_ci	return 0;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciout:
15562306a36Sopenharmony_ci	remove_proc_subtree("fs/xfs", NULL);
15662306a36Sopenharmony_ci	return -ENOMEM;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_civoid
16062306a36Sopenharmony_cixfs_cleanup_procfs(void)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	remove_proc_subtree("fs/xfs", NULL);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci#endif /* CONFIG_PROC_FS */
165