xref: /openbmc/linux/net/sunrpc/stats.c (revision 55ae1aab)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * linux/net/sunrpc/stats.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * procfs-based user access to generic RPC statistics. The stats files
51da177e4SLinus Torvalds  * reside in /proc/net/rpc.
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * The read routines assume that the buffer passed in is just big enough.
81da177e4SLinus Torvalds  * If you implement an RPC service that has its own stats routine which
91da177e4SLinus Torvalds  * appends the generic RPC stats, make sure you don't exceed the PAGE_SIZE
101da177e4SLinus Torvalds  * limit.
111da177e4SLinus Torvalds  *
121da177e4SLinus Torvalds  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
151da177e4SLinus Torvalds #include <linux/module.h>
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds #include <linux/init.h>
181da177e4SLinus Torvalds #include <linux/kernel.h>
191da177e4SLinus Torvalds #include <linux/proc_fs.h>
201da177e4SLinus Torvalds #include <linux/seq_file.h>
211da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
221da177e4SLinus Torvalds #include <linux/sunrpc/svcsock.h>
2311c556b3SChuck Lever #include <linux/sunrpc/metrics.h>
24457c4cbcSEric W. Biederman #include <net/net_namespace.h>
251da177e4SLinus Torvalds 
261da177e4SLinus Torvalds #define RPCDBG_FACILITY	RPCDBG_MISC
271da177e4SLinus Torvalds 
281da177e4SLinus Torvalds struct proc_dir_entry	*proc_net_rpc = NULL;
291da177e4SLinus Torvalds 
301da177e4SLinus Torvalds /*
311da177e4SLinus Torvalds  * Get RPC client stats
321da177e4SLinus Torvalds  */
331da177e4SLinus Torvalds static int rpc_proc_show(struct seq_file *seq, void *v) {
341da177e4SLinus Torvalds 	const struct rpc_stat	*statp = seq->private;
351da177e4SLinus Torvalds 	const struct rpc_program *prog = statp->program;
36ea339d46SChuck Lever 	unsigned int i, j;
371da177e4SLinus Torvalds 
381da177e4SLinus Torvalds 	seq_printf(seq,
3949e31cbaSMax Kellermann 		"net %u %u %u %u\n",
401da177e4SLinus Torvalds 			statp->netcnt,
411da177e4SLinus Torvalds 			statp->netudpcnt,
421da177e4SLinus Torvalds 			statp->nettcpcnt,
431da177e4SLinus Torvalds 			statp->nettcpconn);
441da177e4SLinus Torvalds 	seq_printf(seq,
4549e31cbaSMax Kellermann 		"rpc %u %u %u\n",
461da177e4SLinus Torvalds 			statp->rpccnt,
471da177e4SLinus Torvalds 			statp->rpcretrans,
481da177e4SLinus Torvalds 			statp->rpcauthrefresh);
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds 	for (i = 0; i < prog->nrvers; i++) {
511da177e4SLinus Torvalds 		const struct rpc_version *vers = prog->version[i];
521da177e4SLinus Torvalds 		if (!vers)
531da177e4SLinus Torvalds 			continue;
5449e31cbaSMax Kellermann 		seq_printf(seq, "proc%u %u",
551da177e4SLinus Torvalds 					vers->number, vers->nrprocs);
561da177e4SLinus Torvalds 		for (j = 0; j < vers->nrprocs; j++)
5749e31cbaSMax Kellermann 			seq_printf(seq, " %u",
581da177e4SLinus Torvalds 					vers->procs[j].p_count);
591da177e4SLinus Torvalds 		seq_putc(seq, '\n');
601da177e4SLinus Torvalds 	}
611da177e4SLinus Torvalds 	return 0;
621da177e4SLinus Torvalds }
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds static int rpc_proc_open(struct inode *inode, struct file *file)
651da177e4SLinus Torvalds {
661da177e4SLinus Torvalds 	return single_open(file, rpc_proc_show, PDE(inode)->data);
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds 
69da7071d7SArjan van de Ven static const struct file_operations rpc_proc_fops = {
701da177e4SLinus Torvalds 	.owner = THIS_MODULE,
711da177e4SLinus Torvalds 	.open = rpc_proc_open,
721da177e4SLinus Torvalds 	.read  = seq_read,
731da177e4SLinus Torvalds 	.llseek = seq_lseek,
741da177e4SLinus Torvalds 	.release = single_release,
751da177e4SLinus Torvalds };
761da177e4SLinus Torvalds 
771da177e4SLinus Torvalds /*
781da177e4SLinus Torvalds  * Get RPC server stats
791da177e4SLinus Torvalds  */
801da177e4SLinus Torvalds void svc_seq_show(struct seq_file *seq, const struct svc_stat *statp) {
811da177e4SLinus Torvalds 	const struct svc_program *prog = statp->program;
821da177e4SLinus Torvalds 	const struct svc_procedure *proc;
831da177e4SLinus Torvalds 	const struct svc_version *vers;
84ea339d46SChuck Lever 	unsigned int i, j;
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	seq_printf(seq,
8749e31cbaSMax Kellermann 		"net %u %u %u %u\n",
881da177e4SLinus Torvalds 			statp->netcnt,
891da177e4SLinus Torvalds 			statp->netudpcnt,
901da177e4SLinus Torvalds 			statp->nettcpcnt,
911da177e4SLinus Torvalds 			statp->nettcpconn);
921da177e4SLinus Torvalds 	seq_printf(seq,
9349e31cbaSMax Kellermann 		"rpc %u %u %u %u %u\n",
941da177e4SLinus Torvalds 			statp->rpccnt,
951da177e4SLinus Torvalds 			statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
961da177e4SLinus Torvalds 			statp->rpcbadfmt,
971da177e4SLinus Torvalds 			statp->rpcbadauth,
981da177e4SLinus Torvalds 			statp->rpcbadclnt);
991da177e4SLinus Torvalds 
1001da177e4SLinus Torvalds 	for (i = 0; i < prog->pg_nvers; i++) {
1011da177e4SLinus Torvalds 		if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
1021da177e4SLinus Torvalds 			continue;
10349e31cbaSMax Kellermann 		seq_printf(seq, "proc%d %u", i, vers->vs_nproc);
1041da177e4SLinus Torvalds 		for (j = 0; j < vers->vs_nproc; j++, proc++)
10549e31cbaSMax Kellermann 			seq_printf(seq, " %u", proc->pc_count);
1061da177e4SLinus Torvalds 		seq_putc(seq, '\n');
1071da177e4SLinus Torvalds 	}
1081da177e4SLinus Torvalds }
10924c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_seq_show);
1101da177e4SLinus Torvalds 
11111c556b3SChuck Lever /**
11211c556b3SChuck Lever  * rpc_alloc_iostats - allocate an rpc_iostats structure
11311c556b3SChuck Lever  * @clnt: RPC program, version, and xprt
11411c556b3SChuck Lever  *
11511c556b3SChuck Lever  */
11611c556b3SChuck Lever struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
11711c556b3SChuck Lever {
11811c556b3SChuck Lever 	struct rpc_iostats *new;
1190da974f4SPanagiotis Issaris 	new = kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
12011c556b3SChuck Lever 	return new;
12111c556b3SChuck Lever }
122e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_alloc_iostats);
12311c556b3SChuck Lever 
12411c556b3SChuck Lever /**
12511c556b3SChuck Lever  * rpc_free_iostats - release an rpc_iostats structure
12611c556b3SChuck Lever  * @stats: doomed rpc_iostats structure
12711c556b3SChuck Lever  *
12811c556b3SChuck Lever  */
12911c556b3SChuck Lever void rpc_free_iostats(struct rpc_iostats *stats)
13011c556b3SChuck Lever {
13111c556b3SChuck Lever 	kfree(stats);
13211c556b3SChuck Lever }
133e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_free_iostats);
13411c556b3SChuck Lever 
13511c556b3SChuck Lever /**
13611c556b3SChuck Lever  * rpc_count_iostats - tally up per-task stats
13711c556b3SChuck Lever  * @task: completed rpc_task
13811c556b3SChuck Lever  *
13911c556b3SChuck Lever  * Relies on the caller for serialization.
14011c556b3SChuck Lever  */
14111c556b3SChuck Lever void rpc_count_iostats(struct rpc_task *task)
14211c556b3SChuck Lever {
14311c556b3SChuck Lever 	struct rpc_rqst *req = task->tk_rqstp;
144*55ae1aabSRicardo Labiaga 	struct rpc_iostats *stats;
14511c556b3SChuck Lever 	struct rpc_iostats *op_metrics;
14611c556b3SChuck Lever 	long rtt, execute, queue;
14711c556b3SChuck Lever 
148*55ae1aabSRicardo Labiaga 	if (!task->tk_client || !task->tk_client->cl_metrics || !req)
14911c556b3SChuck Lever 		return;
150*55ae1aabSRicardo Labiaga 
151*55ae1aabSRicardo Labiaga 	stats = task->tk_client->cl_metrics;
152cc0175c1SChuck Lever 	op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx];
15311c556b3SChuck Lever 
15411c556b3SChuck Lever 	op_metrics->om_ops++;
15511c556b3SChuck Lever 	op_metrics->om_ntrans += req->rq_ntrans;
15611c556b3SChuck Lever 	op_metrics->om_timeouts += task->tk_timeouts;
15711c556b3SChuck Lever 
15811c556b3SChuck Lever 	op_metrics->om_bytes_sent += task->tk_bytes_sent;
15911c556b3SChuck Lever 	op_metrics->om_bytes_recv += req->rq_received;
16011c556b3SChuck Lever 
16111c556b3SChuck Lever 	queue = (long)req->rq_xtime - task->tk_start;
16211c556b3SChuck Lever 	if (queue < 0)
16311c556b3SChuck Lever 		queue = -queue;
16411c556b3SChuck Lever 	op_metrics->om_queue += queue;
16511c556b3SChuck Lever 
16611c556b3SChuck Lever 	rtt = task->tk_rtt;
16711c556b3SChuck Lever 	if (rtt < 0)
16811c556b3SChuck Lever 		rtt = -rtt;
16911c556b3SChuck Lever 	op_metrics->om_rtt += rtt;
17011c556b3SChuck Lever 
17111c556b3SChuck Lever 	execute = (long)jiffies - task->tk_start;
17211c556b3SChuck Lever 	if (execute < 0)
17311c556b3SChuck Lever 		execute = -execute;
17411c556b3SChuck Lever 	op_metrics->om_execute += execute;
17511c556b3SChuck Lever }
17611c556b3SChuck Lever 
177ec535ce1SAdrian Bunk static void _print_name(struct seq_file *seq, unsigned int op,
178ec535ce1SAdrian Bunk 			struct rpc_procinfo *procs)
179cc0175c1SChuck Lever {
180cc0175c1SChuck Lever 	if (procs[op].p_name)
181cc0175c1SChuck Lever 		seq_printf(seq, "\t%12s: ", procs[op].p_name);
182cc0175c1SChuck Lever 	else if (op == 0)
183cc0175c1SChuck Lever 		seq_printf(seq, "\t        NULL: ");
184cc0175c1SChuck Lever 	else
185cc0175c1SChuck Lever 		seq_printf(seq, "\t%12u: ", op);
186cc0175c1SChuck Lever }
187cc0175c1SChuck Lever 
1885eb53f41SChuck Lever #define MILLISECS_PER_JIFFY	(1000 / HZ)
18911c556b3SChuck Lever 
19011c556b3SChuck Lever void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
19111c556b3SChuck Lever {
19211c556b3SChuck Lever 	struct rpc_iostats *stats = clnt->cl_metrics;
19311c556b3SChuck Lever 	struct rpc_xprt *xprt = clnt->cl_xprt;
19411c556b3SChuck Lever 	unsigned int op, maxproc = clnt->cl_maxproc;
19511c556b3SChuck Lever 
19611c556b3SChuck Lever 	if (!stats)
19711c556b3SChuck Lever 		return;
19811c556b3SChuck Lever 
19911c556b3SChuck Lever 	seq_printf(seq, "\tRPC iostats version: %s  ", RPC_IOSTATS_VERS);
20011c556b3SChuck Lever 	seq_printf(seq, "p/v: %u/%u (%s)\n",
20111c556b3SChuck Lever 			clnt->cl_prog, clnt->cl_vers, clnt->cl_protname);
20211c556b3SChuck Lever 
20311c556b3SChuck Lever 	if (xprt)
20411c556b3SChuck Lever 		xprt->ops->print_stats(xprt, seq);
20511c556b3SChuck Lever 
20611c556b3SChuck Lever 	seq_printf(seq, "\tper-op statistics\n");
20711c556b3SChuck Lever 	for (op = 0; op < maxproc; op++) {
20811c556b3SChuck Lever 		struct rpc_iostats *metrics = &stats[op];
209cc0175c1SChuck Lever 		_print_name(seq, op, clnt->cl_procinfo);
21011c556b3SChuck Lever 		seq_printf(seq, "%lu %lu %lu %Lu %Lu %Lu %Lu %Lu\n",
21111c556b3SChuck Lever 				metrics->om_ops,
21211c556b3SChuck Lever 				metrics->om_ntrans,
21311c556b3SChuck Lever 				metrics->om_timeouts,
21411c556b3SChuck Lever 				metrics->om_bytes_sent,
21511c556b3SChuck Lever 				metrics->om_bytes_recv,
21611c556b3SChuck Lever 				metrics->om_queue * MILLISECS_PER_JIFFY,
21711c556b3SChuck Lever 				metrics->om_rtt * MILLISECS_PER_JIFFY,
21811c556b3SChuck Lever 				metrics->om_execute * MILLISECS_PER_JIFFY);
21911c556b3SChuck Lever 	}
22011c556b3SChuck Lever }
221e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_print_iostats);
22211c556b3SChuck Lever 
2231da177e4SLinus Torvalds /*
2241da177e4SLinus Torvalds  * Register/unregister RPC proc files
2251da177e4SLinus Torvalds  */
2261da177e4SLinus Torvalds static inline struct proc_dir_entry *
22799ac48f5SArjan van de Ven do_register(const char *name, void *data, const struct file_operations *fops)
2281da177e4SLinus Torvalds {
2291da177e4SLinus Torvalds 	rpc_proc_init();
2301da177e4SLinus Torvalds 	dprintk("RPC:       registering /proc/net/rpc/%s\n", name);
2311da177e4SLinus Torvalds 
232e7fe2336SDenis V. Lunev 	return proc_create_data(name, 0, proc_net_rpc, fops, data);
2331da177e4SLinus Torvalds }
2341da177e4SLinus Torvalds 
2351da177e4SLinus Torvalds struct proc_dir_entry *
2361da177e4SLinus Torvalds rpc_proc_register(struct rpc_stat *statp)
2371da177e4SLinus Torvalds {
2381da177e4SLinus Torvalds 	return do_register(statp->program->name, statp, &rpc_proc_fops);
2391da177e4SLinus Torvalds }
240e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_proc_register);
2411da177e4SLinus Torvalds 
2421da177e4SLinus Torvalds void
2431da177e4SLinus Torvalds rpc_proc_unregister(const char *name)
2441da177e4SLinus Torvalds {
2451da177e4SLinus Torvalds 	remove_proc_entry(name, proc_net_rpc);
2461da177e4SLinus Torvalds }
247e8914c65STrond Myklebust EXPORT_SYMBOL_GPL(rpc_proc_unregister);
2481da177e4SLinus Torvalds 
2491da177e4SLinus Torvalds struct proc_dir_entry *
25099ac48f5SArjan van de Ven svc_proc_register(struct svc_stat *statp, const struct file_operations *fops)
2511da177e4SLinus Torvalds {
2521da177e4SLinus Torvalds 	return do_register(statp->program->pg_name, statp, fops);
2531da177e4SLinus Torvalds }
25424c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_proc_register);
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds void
2571da177e4SLinus Torvalds svc_proc_unregister(const char *name)
2581da177e4SLinus Torvalds {
2591da177e4SLinus Torvalds 	remove_proc_entry(name, proc_net_rpc);
2601da177e4SLinus Torvalds }
26124c3767eSTrond Myklebust EXPORT_SYMBOL_GPL(svc_proc_unregister);
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds void
2641da177e4SLinus Torvalds rpc_proc_init(void)
2651da177e4SLinus Torvalds {
2661da177e4SLinus Torvalds 	dprintk("RPC:       registering /proc/net/rpc\n");
26799b76233SAlexey Dobriyan 	if (!proc_net_rpc)
26899b76233SAlexey Dobriyan 		proc_net_rpc = proc_mkdir("rpc", init_net.proc_net);
2691da177e4SLinus Torvalds }
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds void
2721da177e4SLinus Torvalds rpc_proc_exit(void)
2731da177e4SLinus Torvalds {
2741da177e4SLinus Torvalds 	dprintk("RPC:       unregistering /proc/net/rpc\n");
2751da177e4SLinus Torvalds 	if (proc_net_rpc) {
2761da177e4SLinus Torvalds 		proc_net_rpc = NULL;
277457c4cbcSEric W. Biederman 		remove_proc_entry("rpc", init_net.proc_net);
2781da177e4SLinus Torvalds 	}
2791da177e4SLinus Torvalds }
2801da177e4SLinus Torvalds 
281