Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb230c12 authored by Bill O'Donnell's avatar Bill O'Donnell Committed by Dave Chinner
Browse files

xfs: create global stats and stats_clear in sysfs



Currently, xfs global stats are in procfs. This patch introduces
(replicates) the global stats in sysfs. Additionally a stats_clear file
is introduced in sysfs.

Signed-off-by: default avatarBill O'Donnell <billodo@redhat.com>
Reviewed-by: default avatarEric Sandeen <sandeen@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 1f93e4a9
Loading
Loading
Loading
Loading
+82 −0
Original line number Diff line number Diff line
@@ -29,6 +29,88 @@ static int counter_val(int idx)
	return val;
}

int xfs_stats_format(char *buf)
{
	int		i, j;
	int		len = 0;
	__uint64_t	xs_xstrat_bytes = 0;
	__uint64_t	xs_write_bytes = 0;
	__uint64_t	xs_read_bytes = 0;

	static const struct xstats_entry {
		char	*desc;
		int	endpoint;
	} xstats[] = {
		{ "extent_alloc",	XFSSTAT_END_EXTENT_ALLOC	},
		{ "abt",		XFSSTAT_END_ALLOC_BTREE		},
		{ "blk_map",		XFSSTAT_END_BLOCK_MAPPING	},
		{ "bmbt",		XFSSTAT_END_BLOCK_MAP_BTREE	},
		{ "dir",		XFSSTAT_END_DIRECTORY_OPS	},
		{ "trans",		XFSSTAT_END_TRANSACTIONS	},
		{ "ig",			XFSSTAT_END_INODE_OPS		},
		{ "log",		XFSSTAT_END_LOG_OPS		},
		{ "push_ail",		XFSSTAT_END_TAIL_PUSHING	},
		{ "xstrat",		XFSSTAT_END_WRITE_CONVERT	},
		{ "rw",			XFSSTAT_END_READ_WRITE_OPS	},
		{ "attr",		XFSSTAT_END_ATTRIBUTE_OPS	},
		{ "icluster",		XFSSTAT_END_INODE_CLUSTER	},
		{ "vnodes",		XFSSTAT_END_VNODE_OPS		},
		{ "buf",		XFSSTAT_END_BUF			},
		{ "abtb2",		XFSSTAT_END_ABTB_V2		},
		{ "abtc2",		XFSSTAT_END_ABTC_V2		},
		{ "bmbt2",		XFSSTAT_END_BMBT_V2		},
		{ "ibt2",		XFSSTAT_END_IBT_V2		},
		{ "fibt2",		XFSSTAT_END_FIBT_V2		},
		/* we print both series of quota information together */
		{ "qm",			XFSSTAT_END_QM			},
	};

	/* Loop over all stats groups */

	for (i = j = 0; i < ARRAY_SIZE(xstats); i++) {
		len += snprintf(buf + len, PATH_MAX - len, "%s",
				xstats[i].desc);
		/* inner loop does each group */
		for (; j < xstats[i].endpoint; j++)
			len += snprintf(buf + len, PATH_MAX - len, " %u",
					counter_val(j));
		len += snprintf(buf + len, PATH_MAX - len, "\n");
	}
	/* extra precision counters */
	for_each_possible_cpu(i) {
		xs_xstrat_bytes += per_cpu(xfsstats, i).xs_xstrat_bytes;
		xs_write_bytes += per_cpu(xfsstats, i).xs_write_bytes;
		xs_read_bytes += per_cpu(xfsstats, i).xs_read_bytes;
	}

	len += snprintf(buf + len, PATH_MAX-len, "xpc %Lu %Lu %Lu\n",
			xs_xstrat_bytes, xs_write_bytes, xs_read_bytes);
	len += snprintf(buf + len, PATH_MAX-len, "debug %u\n",
#if defined(DEBUG)
		1);
#else
		0);
#endif

	return len;
}

void xfs_stats_clearall(void)
{
	int		c;
	__uint32_t	vn_active;

	xfs_notice(NULL, "Clearing xfsstats");
	for_each_possible_cpu(c) {
		preempt_disable();
		/* save vn_active, it's a universal truth! */
		vn_active = per_cpu(xfsstats, c).vn_active;
		memset(&per_cpu(xfsstats, c), 0, sizeof(struct xfsstats));
		per_cpu(xfsstats, c).vn_active = vn_active;
		preempt_enable();
	}
}

static int xfs_stat_proc_show(struct seq_file *m, void *v)
{
	int		i, j;
+2 −0
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@
#ifndef __XFS_STATS_H__
#define __XFS_STATS_H__

int xfs_stats_format(char *buf);
void xfs_stats_clearall(void);

#if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)

+15 −5
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ static kmem_zone_t *xfs_ioend_zone;
mempool_t *xfs_ioend_pool;

static struct kset *xfs_kset;		/* top-level xfs sysfs dir */
static struct xfs_kobj xfs_stats_kobj;	/* global stats sysfs attrs */
#ifdef DEBUG
static struct xfs_kobj xfs_dbg_kobj;	/* global debug sysfs attrs */
#endif
@@ -1838,19 +1839,25 @@ init_xfs_fs(void)
	xfs_kset = kset_create_and_add("xfs", NULL, fs_kobj);
	if (!xfs_kset) {
		error = -ENOMEM;
		goto out_sysctl_unregister;;
		goto out_sysctl_unregister;
	}

	xfs_stats_kobj.kobject.kset = xfs_kset;
	error = xfs_sysfs_init(&xfs_stats_kobj, &xfs_stats_ktype, NULL,
			       "stats");
	if (error)
		goto out_kset_unregister;

#ifdef DEBUG
	xfs_dbg_kobj.kobject.kset = xfs_kset;
	error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug");
	if (error)
		goto out_kset_unregister;
		goto out_remove_stats_kobj;
#endif

	error = xfs_qm_init();
	if (error)
		goto out_remove_kobj;
		goto out_remove_dbg_kobj;

	error = register_filesystem(&xfs_fs_type);
	if (error)
@@ -1859,11 +1866,13 @@ init_xfs_fs(void)

 out_qm_exit:
	xfs_qm_exit();
 out_remove_kobj:
 out_remove_dbg_kobj:
#ifdef DEBUG
	xfs_sysfs_del(&xfs_dbg_kobj);
 out_kset_unregister:
 out_remove_stats_kobj:
#endif
	xfs_sysfs_del(&xfs_stats_kobj);
 out_kset_unregister:
	kset_unregister(xfs_kset);
 out_sysctl_unregister:
	xfs_sysctl_unregister();
@@ -1889,6 +1898,7 @@ exit_xfs_fs(void)
#ifdef DEBUG
	xfs_sysfs_del(&xfs_dbg_kobj);
#endif
	xfs_sysfs_del(&xfs_stats_kobj);
	kset_unregister(xfs_kset);
	xfs_sysctl_unregister();
	xfs_cleanup_procfs();
+3 −12
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include "xfs_error.h"
#include "xfs_stats.h"

static struct ctl_table_header *xfs_table_header;

@@ -31,22 +32,12 @@ xfs_stats_clear_proc_handler(
	size_t			*lenp,
	loff_t			*ppos)
{
	int		c, ret, *valp = ctl->data;
	__uint32_t	vn_active;
	int		ret, *valp = ctl->data;

	ret = proc_dointvec_minmax(ctl, write, buffer, lenp, ppos);

	if (!ret && write && *valp) {
		xfs_notice(NULL, "Clearing xfsstats");
		for_each_possible_cpu(c) {
			preempt_disable();
			/* save vn_active, it's a universal truth! */
			vn_active = per_cpu(xfsstats, c).vn_active;
			memset(&per_cpu(xfsstats, c), 0,
			       sizeof(struct xfsstats));
			per_cpu(xfsstats, c).vn_active = vn_active;
			preempt_enable();
		}
		xfs_stats_clearall();
		xfs_stats_clear = 0;
	}

+75 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include "xfs_log_format.h"
#include "xfs_log.h"
#include "xfs_log_priv.h"
#include "xfs_stats.h"

struct xfs_sysfs_attr {
	struct attribute attr;
@@ -38,6 +39,8 @@ to_attr(struct attribute *attr)
	static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RW(name)
#define XFS_SYSFS_ATTR_RO(name) \
	static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RO(name)
#define XFS_SYSFS_ATTR_WO(name) \
	static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_WO(name)

#define ATTR_LIST(name) &xfs_sysfs_attr_##name.attr

@@ -125,6 +128,78 @@ struct kobj_type xfs_dbg_ktype = {

#endif /* DEBUG */


/* stats */

STATIC ssize_t
stats_show(
	char	*buf,
	void	*data)
{
	return xfs_stats_format(buf);
}
XFS_SYSFS_ATTR_RO(stats);

STATIC ssize_t
stats_clear_store(
	const char	*buf,
	size_t		count,
	void		*data)
{
	int		ret;
	int		val;

	ret = kstrtoint(buf, 0, &val);
	if (ret)
		return ret;

	if (val != 1)
		return -EINVAL;
	xfs_stats_clearall();
	return count;
}
XFS_SYSFS_ATTR_WO(stats_clear);

static struct attribute *xfs_stats_attrs[] = {
	ATTR_LIST(stats),
	ATTR_LIST(stats_clear),
	NULL,
};

STATIC ssize_t
xfs_stats_show(
	struct kobject		*kobject,
	struct attribute	*attr,
	char			*buf)
{
	struct xfs_sysfs_attr *xfs_attr = to_attr(attr);

	return xfs_attr->show ? xfs_attr->show(buf, NULL) : 0;
}

STATIC ssize_t
xfs_stats_store(
	struct kobject		*kobject,
	struct attribute	*attr,
	const char		*buf,
	size_t			count)
{
	struct xfs_sysfs_attr *xfs_attr = to_attr(attr);

	return xfs_attr->store ? xfs_attr->store(buf, count, NULL) : 0;
}

static struct sysfs_ops xfs_stats_ops = {
	.show = xfs_stats_show,
	.store = xfs_stats_store,
};

struct kobj_type xfs_stats_ktype = {
	.release = xfs_sysfs_release,
	.sysfs_ops = &xfs_stats_ops,
	.default_attrs = xfs_stats_attrs,
};

/* xlog */

STATIC ssize_t
Loading