forked from Minki/linux
e567b98ce9
nfsd stats counters can be updated by concurrent nfsd threads without any protection. Convert some nfsd_stats and nfsd_net struct members to use percpu counters. The longest_chain* members of struct nfsd_net remain unprotected. Signed-off-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
147 lines
3.5 KiB
C
147 lines
3.5 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* procfs-based user access to knfsd statistics
|
|
*
|
|
* /proc/net/rpc/nfsd
|
|
*
|
|
* Format:
|
|
* rc <hits> <misses> <nocache>
|
|
* Statistsics for the reply cache
|
|
* fh <stale> <deprecated filehandle cache stats>
|
|
* statistics for filehandle lookup
|
|
* io <bytes-read> <bytes-written>
|
|
* statistics for IO throughput
|
|
* th <threads> <deprecated thread usage histogram stats>
|
|
* number of threads
|
|
* ra <deprecated ra-cache stats>
|
|
*
|
|
* plus generic RPC stats (see net/sunrpc/stats.c)
|
|
*
|
|
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
|
|
*/
|
|
|
|
#include <linux/seq_file.h>
|
|
#include <linux/module.h>
|
|
#include <linux/sunrpc/stats.h>
|
|
#include <net/net_namespace.h>
|
|
|
|
#include "nfsd.h"
|
|
|
|
struct nfsd_stats nfsdstats;
|
|
struct svc_stat nfsd_svcstats = {
|
|
.program = &nfsd_program,
|
|
};
|
|
|
|
static int nfsd_proc_show(struct seq_file *seq, void *v)
|
|
{
|
|
int i;
|
|
|
|
seq_printf(seq, "rc %lld %lld %lld\nfh %lld 0 0 0 0\nio %lld %lld\n",
|
|
percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_RC_HITS]),
|
|
percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_RC_MISSES]),
|
|
percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_RC_NOCACHE]),
|
|
percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_FH_STALE]),
|
|
percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_IO_READ]),
|
|
percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_IO_WRITE]));
|
|
|
|
/* thread usage: */
|
|
seq_printf(seq, "th %u 0", nfsdstats.th_cnt);
|
|
|
|
/* deprecated thread usage histogram stats */
|
|
for (i = 0; i < 10; i++)
|
|
seq_puts(seq, " 0.000");
|
|
|
|
/* deprecated ra-cache stats */
|
|
seq_puts(seq, "\nra 0 0 0 0 0 0 0 0 0 0 0 0\n");
|
|
|
|
/* show my rpc info */
|
|
svc_seq_show(seq, &nfsd_svcstats);
|
|
|
|
#ifdef CONFIG_NFSD_V4
|
|
/* Show count for individual nfsv4 operations */
|
|
/* Writing operation numbers 0 1 2 also for maintaining uniformity */
|
|
seq_printf(seq,"proc4ops %u", LAST_NFS4_OP + 1);
|
|
for (i = 0; i <= LAST_NFS4_OP; i++) {
|
|
seq_printf(seq, " %lld",
|
|
percpu_counter_sum_positive(&nfsdstats.counter[NFSD_STATS_NFS4_OP(i)]));
|
|
}
|
|
|
|
seq_putc(seq, '\n');
|
|
#endif
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nfsd_proc_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, nfsd_proc_show, NULL);
|
|
}
|
|
|
|
static const struct proc_ops nfsd_proc_ops = {
|
|
.proc_open = nfsd_proc_open,
|
|
.proc_read = seq_read,
|
|
.proc_lseek = seq_lseek,
|
|
.proc_release = single_release,
|
|
};
|
|
|
|
int nfsd_percpu_counters_init(struct percpu_counter counters[], int num)
|
|
{
|
|
int i, err = 0;
|
|
|
|
for (i = 0; !err && i < num; i++)
|
|
err = percpu_counter_init(&counters[i], 0, GFP_KERNEL);
|
|
|
|
if (!err)
|
|
return 0;
|
|
|
|
for (; i > 0; i--)
|
|
percpu_counter_destroy(&counters[i-1]);
|
|
|
|
return err;
|
|
}
|
|
|
|
void nfsd_percpu_counters_reset(struct percpu_counter counters[], int num)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < num; i++)
|
|
percpu_counter_set(&counters[i], 0);
|
|
}
|
|
|
|
void nfsd_percpu_counters_destroy(struct percpu_counter counters[], int num)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < num; i++)
|
|
percpu_counter_destroy(&counters[i]);
|
|
}
|
|
|
|
static int nfsd_stat_counters_init(void)
|
|
{
|
|
return nfsd_percpu_counters_init(nfsdstats.counter, NFSD_STATS_COUNTERS_NUM);
|
|
}
|
|
|
|
static void nfsd_stat_counters_destroy(void)
|
|
{
|
|
nfsd_percpu_counters_destroy(nfsdstats.counter, NFSD_STATS_COUNTERS_NUM);
|
|
}
|
|
|
|
int nfsd_stat_init(void)
|
|
{
|
|
int err;
|
|
|
|
err = nfsd_stat_counters_init();
|
|
if (err)
|
|
return err;
|
|
|
|
svc_proc_register(&init_net, &nfsd_svcstats, &nfsd_proc_ops);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void nfsd_stat_shutdown(void)
|
|
{
|
|
nfsd_stat_counters_destroy();
|
|
svc_proc_unregister(&init_net, "nfsd");
|
|
}
|