xfs: pass xfsstats structures to handlers and macros

This patch is the next step toward per-fs xfs stats. The patch makes
the show and clear routines able to handle any stats structure
associated with a kobject.

Instead of a single global xfsstats structure, add kobject and a pointer
to a per-cpu struct xfsstats. Modify the macros that manipulate the stats
accordingly: XFS_STATS_INC, XFS_STATS_DEC, and XFS_STATS_ADD now access
xfsstats->xs_stats.

The sysfs functions need to get from the kobject back to the xfsstats
structure which contains it, and pass the pointer to the ->xs_stats
percpu structure into the show & clear routines.

Signed-off-by: Bill O'Donnell <billodo@redhat.com>
Reviewed-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
This commit is contained in:
Bill O'Donnell 2015-10-12 05:19:45 +11:00 коммит произвёл Dave Chinner
Родитель a27c264009
Коммит 80529c45ab
6 изменённых файлов: 63 добавлений и 37 удалений

Просмотреть файл

@ -171,6 +171,13 @@ struct xfs_kobj {
struct completion complete; struct completion complete;
}; };
struct xstats {
struct xfsstats __percpu *xs_stats;
struct xfs_kobj xs_kobj;
};
extern struct xstats xfsstats;
/* Kernel uid/gid conversion. These are used to convert to/from the on disk /* Kernel uid/gid conversion. These are used to convert to/from the on disk
* uid_t/gid_t types to the kuid_t/kgid_t types that the kernel uses internally. * uid_t/gid_t types to the kuid_t/kgid_t types that the kernel uses internally.
* The conversion here is type only, the value will remain the same since we * The conversion here is type only, the value will remain the same since we

Просмотреть файл

@ -18,18 +18,18 @@
#include "xfs.h" #include "xfs.h"
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
DEFINE_PER_CPU(struct xfsstats, xfsstats); struct xstats xfsstats;
static int counter_val(int idx) static int counter_val(struct xfsstats __percpu *stats, int idx)
{ {
int val = 0, cpu; int val = 0, cpu;
for_each_possible_cpu(cpu) for_each_possible_cpu(cpu)
val += *(((__u32 *)&per_cpu(xfsstats, cpu) + idx)); val += *(((__u32 *)per_cpu_ptr(stats, cpu) + idx));
return val; return val;
} }
int xfs_stats_format(char *buf) int xfs_stats_format(struct xfsstats __percpu *stats, char *buf)
{ {
int i, j; int i, j;
int len = 0; int len = 0;
@ -73,14 +73,14 @@ int xfs_stats_format(char *buf)
/* inner loop does each group */ /* inner loop does each group */
for (; j < xstats[i].endpoint; j++) for (; j < xstats[i].endpoint; j++)
len += snprintf(buf + len, PATH_MAX - len, " %u", len += snprintf(buf + len, PATH_MAX - len, " %u",
counter_val(j)); counter_val(stats, j));
len += snprintf(buf + len, PATH_MAX - len, "\n"); len += snprintf(buf + len, PATH_MAX - len, "\n");
} }
/* extra precision counters */ /* extra precision counters */
for_each_possible_cpu(i) { for_each_possible_cpu(i) {
xs_xstrat_bytes += per_cpu(xfsstats, i).xs_xstrat_bytes; xs_xstrat_bytes += per_cpu_ptr(stats, i)->xs_xstrat_bytes;
xs_write_bytes += per_cpu(xfsstats, i).xs_write_bytes; xs_write_bytes += per_cpu_ptr(stats, i)->xs_write_bytes;
xs_read_bytes += per_cpu(xfsstats, i).xs_read_bytes; xs_read_bytes += per_cpu_ptr(stats, i)->xs_read_bytes;
} }
len += snprintf(buf + len, PATH_MAX-len, "xpc %Lu %Lu %Lu\n", len += snprintf(buf + len, PATH_MAX-len, "xpc %Lu %Lu %Lu\n",
@ -95,7 +95,7 @@ int xfs_stats_format(char *buf)
return len; return len;
} }
void xfs_stats_clearall(void) void xfs_stats_clearall(struct xfsstats __percpu *stats)
{ {
int c; int c;
__uint32_t vn_active; __uint32_t vn_active;
@ -104,9 +104,9 @@ void xfs_stats_clearall(void)
for_each_possible_cpu(c) { for_each_possible_cpu(c) {
preempt_disable(); preempt_disable();
/* save vn_active, it's a universal truth! */ /* save vn_active, it's a universal truth! */
vn_active = per_cpu(xfsstats, c).vn_active; vn_active = per_cpu_ptr(stats, c)->vn_active;
memset(&per_cpu(xfsstats, c), 0, sizeof(struct xfsstats)); memset(per_cpu_ptr(stats, c), 0, sizeof(*stats));
per_cpu(xfsstats, c).vn_active = vn_active; per_cpu_ptr(stats, c)->vn_active = vn_active;
preempt_enable(); preempt_enable();
} }
} }
@ -117,10 +117,8 @@ static int xqm_proc_show(struct seq_file *m, void *v)
{ {
/* maximum; incore; ratio free to inuse; freelist */ /* maximum; incore; ratio free to inuse; freelist */
seq_printf(m, "%d\t%d\t%d\t%u\n", seq_printf(m, "%d\t%d\t%d\t%u\n",
0, 0, counter_val(xfsstats.xs_stats, XFSSTAT_END_XQMSTAT),
counter_val(XFSSTAT_END_XQMSTAT), 0, counter_val(xfsstats.xs_stats, XFSSTAT_END_XQMSTAT + 1));
0,
counter_val(XFSSTAT_END_XQMSTAT + 1));
return 0; return 0;
} }
@ -144,7 +142,7 @@ static int xqmstat_proc_show(struct seq_file *m, void *v)
seq_printf(m, "qm"); seq_printf(m, "qm");
for (j = XFSSTAT_END_IBT_V2; j < XFSSTAT_END_XQMSTAT; j++) for (j = XFSSTAT_END_IBT_V2; j < XFSSTAT_END_XQMSTAT; j++)
seq_printf(m, " %u", counter_val(j)); seq_printf(m, " %u", counter_val(xfsstats.xs_stats, j));
seq_putc(m, '\n'); seq_putc(m, '\n');
return 0; return 0;
} }

Просмотреть файл

@ -18,9 +18,6 @@
#ifndef __XFS_STATS_H__ #ifndef __XFS_STATS_H__
#define __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) #if defined(CONFIG_PROC_FS) && !defined(XFS_STATS_OFF)
#include <linux/percpu.h> #include <linux/percpu.h>
@ -217,15 +214,18 @@ struct xfsstats {
__uint64_t xs_read_bytes; __uint64_t xs_read_bytes;
}; };
DECLARE_PER_CPU(struct xfsstats, xfsstats); int xfs_stats_format(struct xfsstats __percpu *stats, char *buf);
void xfs_stats_clearall(struct xfsstats __percpu *stats);
extern struct xstats xfsstats;
/* #define XFS_STATS_INC(v) \
* We don't disable preempt, not too worried about poking the (per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v++)
* wrong CPU's stat for now (also aggregated before reporting).
*/ #define XFS_STATS_DEC(v) \
#define XFS_STATS_INC(v) (per_cpu(xfsstats, current_cpu()).v++) (per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v--)
#define XFS_STATS_DEC(v) (per_cpu(xfsstats, current_cpu()).v--)
#define XFS_STATS_ADD(v, inc) (per_cpu(xfsstats, current_cpu()).v += (inc)) #define XFS_STATS_ADD(v, inc) \
(per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v += (inc))
extern int xfs_init_procfs(void); extern int xfs_init_procfs(void);
extern void xfs_cleanup_procfs(void); extern void xfs_cleanup_procfs(void);

Просмотреть файл

@ -61,7 +61,6 @@ static kmem_zone_t *xfs_ioend_zone;
mempool_t *xfs_ioend_pool; mempool_t *xfs_ioend_pool;
static struct kset *xfs_kset; /* top-level xfs sysfs dir */ static struct kset *xfs_kset; /* top-level xfs sysfs dir */
static struct xfs_kobj xfs_stats_kobj; /* global stats sysfs attrs */
#ifdef DEBUG #ifdef DEBUG
static struct xfs_kobj xfs_dbg_kobj; /* global debug sysfs attrs */ static struct xfs_kobj xfs_dbg_kobj; /* global debug sysfs attrs */
#endif #endif
@ -1842,11 +1841,18 @@ init_xfs_fs(void)
goto out_sysctl_unregister; goto out_sysctl_unregister;
} }
xfs_stats_kobj.kobject.kset = xfs_kset; xfsstats.xs_kobj.kobject.kset = xfs_kset;
error = xfs_sysfs_init(&xfs_stats_kobj, &xfs_stats_ktype, NULL,
xfsstats.xs_stats = alloc_percpu(struct xfsstats);
if (!xfsstats.xs_stats) {
error = -ENOMEM;
goto out_kset_unregister;
}
error = xfs_sysfs_init(&xfsstats.xs_kobj, &xfs_stats_ktype, NULL,
"stats"); "stats");
if (error) if (error)
goto out_kset_unregister; goto out_free_stats;
#ifdef DEBUG #ifdef DEBUG
xfs_dbg_kobj.kobject.kset = xfs_kset; xfs_dbg_kobj.kobject.kset = xfs_kset;
@ -1871,7 +1877,9 @@ init_xfs_fs(void)
xfs_sysfs_del(&xfs_dbg_kobj); xfs_sysfs_del(&xfs_dbg_kobj);
out_remove_stats_kobj: out_remove_stats_kobj:
#endif #endif
xfs_sysfs_del(&xfs_stats_kobj); xfs_sysfs_del(&xfsstats.xs_kobj);
out_free_stats:
free_percpu(xfsstats.xs_stats);
out_kset_unregister: out_kset_unregister:
kset_unregister(xfs_kset); kset_unregister(xfs_kset);
out_sysctl_unregister: out_sysctl_unregister:
@ -1898,7 +1906,8 @@ exit_xfs_fs(void)
#ifdef DEBUG #ifdef DEBUG
xfs_sysfs_del(&xfs_dbg_kobj); xfs_sysfs_del(&xfs_dbg_kobj);
#endif #endif
xfs_sysfs_del(&xfs_stats_kobj); xfs_sysfs_del(&xfsstats.xs_kobj);
free_percpu(xfsstats.xs_stats);
kset_unregister(xfs_kset); kset_unregister(xfs_kset);
xfs_sysctl_unregister(); xfs_sysctl_unregister();
xfs_cleanup_procfs(); xfs_cleanup_procfs();

Просмотреть файл

@ -37,7 +37,7 @@ xfs_stats_clear_proc_handler(
ret = proc_dointvec_minmax(ctl, write, buffer, lenp, ppos); ret = proc_dointvec_minmax(ctl, write, buffer, lenp, ppos);
if (!ret && write && *valp) { if (!ret && write && *valp) {
xfs_stats_clearall(); xfs_stats_clearall(xfsstats.xs_stats);
xfs_stats_clear = 0; xfs_stats_clear = 0;
} }

Просмотреть файл

@ -131,12 +131,22 @@ struct kobj_type xfs_dbg_ktype = {
/* stats */ /* stats */
static inline struct xstats *
to_xstats(struct kobject *kobject)
{
struct xfs_kobj *kobj = to_kobj(kobject);
return container_of(kobj, struct xstats, xs_kobj);
}
STATIC ssize_t STATIC ssize_t
stats_show( stats_show(
struct kobject *kobject, struct kobject *kobject,
char *buf) char *buf)
{ {
return xfs_stats_format(buf); struct xstats *stats = to_xstats(kobject);
return xfs_stats_format(stats->xs_stats, buf);
} }
XFS_SYSFS_ATTR_RO(stats); XFS_SYSFS_ATTR_RO(stats);
@ -148,6 +158,7 @@ stats_clear_store(
{ {
int ret; int ret;
int val; int val;
struct xstats *stats = to_xstats(kobject);
ret = kstrtoint(buf, 0, &val); ret = kstrtoint(buf, 0, &val);
if (ret) if (ret)
@ -155,7 +166,8 @@ stats_clear_store(
if (val != 1) if (val != 1)
return -EINVAL; return -EINVAL;
xfs_stats_clearall();
xfs_stats_clearall(stats->xs_stats);
return count; return count;
} }
XFS_SYSFS_ATTR_WO(stats_clear); XFS_SYSFS_ATTR_WO(stats_clear);