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/sched.h> 201da177e4SLinus Torvalds #include <linux/proc_fs.h> 211da177e4SLinus Torvalds #include <linux/seq_file.h> 221da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h> 231da177e4SLinus Torvalds #include <linux/sunrpc/svcsock.h> 2411c556b3SChuck Lever #include <linux/sunrpc/metrics.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; 361da177e4SLinus Torvalds 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 691da177e4SLinus Torvalds static 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; 841da177e4SLinus Torvalds 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 } 1091da177e4SLinus Torvalds 11011c556b3SChuck Lever /** 11111c556b3SChuck Lever * rpc_alloc_iostats - allocate an rpc_iostats structure 11211c556b3SChuck Lever * @clnt: RPC program, version, and xprt 11311c556b3SChuck Lever * 11411c556b3SChuck Lever */ 11511c556b3SChuck Lever struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt) 11611c556b3SChuck Lever { 11711c556b3SChuck Lever unsigned int ops = clnt->cl_maxproc; 11811c556b3SChuck Lever size_t size = ops * sizeof(struct rpc_iostats); 11911c556b3SChuck Lever struct rpc_iostats *new; 12011c556b3SChuck Lever 12111c556b3SChuck Lever new = kmalloc(size, GFP_KERNEL); 12211c556b3SChuck Lever if (new) 12311c556b3SChuck Lever memset(new, 0 , size); 12411c556b3SChuck Lever return new; 12511c556b3SChuck Lever } 12611c556b3SChuck Lever EXPORT_SYMBOL(rpc_alloc_iostats); 12711c556b3SChuck Lever 12811c556b3SChuck Lever /** 12911c556b3SChuck Lever * rpc_free_iostats - release an rpc_iostats structure 13011c556b3SChuck Lever * @stats: doomed rpc_iostats structure 13111c556b3SChuck Lever * 13211c556b3SChuck Lever */ 13311c556b3SChuck Lever void rpc_free_iostats(struct rpc_iostats *stats) 13411c556b3SChuck Lever { 13511c556b3SChuck Lever kfree(stats); 13611c556b3SChuck Lever } 13711c556b3SChuck Lever EXPORT_SYMBOL(rpc_free_iostats); 13811c556b3SChuck Lever 13911c556b3SChuck Lever /** 14011c556b3SChuck Lever * rpc_count_iostats - tally up per-task stats 14111c556b3SChuck Lever * @task: completed rpc_task 14211c556b3SChuck Lever * 14311c556b3SChuck Lever * Relies on the caller for serialization. 14411c556b3SChuck Lever */ 14511c556b3SChuck Lever void rpc_count_iostats(struct rpc_task *task) 14611c556b3SChuck Lever { 14711c556b3SChuck Lever struct rpc_rqst *req = task->tk_rqstp; 14811c556b3SChuck Lever struct rpc_iostats *stats = task->tk_client->cl_metrics; 14911c556b3SChuck Lever struct rpc_iostats *op_metrics; 15011c556b3SChuck Lever long rtt, execute, queue; 15111c556b3SChuck Lever 15211c556b3SChuck Lever if (!stats || !req) 15311c556b3SChuck Lever return; 154cc0175c1SChuck Lever op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx]; 15511c556b3SChuck Lever 15611c556b3SChuck Lever op_metrics->om_ops++; 15711c556b3SChuck Lever op_metrics->om_ntrans += req->rq_ntrans; 15811c556b3SChuck Lever op_metrics->om_timeouts += task->tk_timeouts; 15911c556b3SChuck Lever 16011c556b3SChuck Lever op_metrics->om_bytes_sent += task->tk_bytes_sent; 16111c556b3SChuck Lever op_metrics->om_bytes_recv += req->rq_received; 16211c556b3SChuck Lever 16311c556b3SChuck Lever queue = (long)req->rq_xtime - task->tk_start; 16411c556b3SChuck Lever if (queue < 0) 16511c556b3SChuck Lever queue = -queue; 16611c556b3SChuck Lever op_metrics->om_queue += queue; 16711c556b3SChuck Lever 16811c556b3SChuck Lever rtt = task->tk_rtt; 16911c556b3SChuck Lever if (rtt < 0) 17011c556b3SChuck Lever rtt = -rtt; 17111c556b3SChuck Lever op_metrics->om_rtt += rtt; 17211c556b3SChuck Lever 17311c556b3SChuck Lever execute = (long)jiffies - task->tk_start; 17411c556b3SChuck Lever if (execute < 0) 17511c556b3SChuck Lever execute = -execute; 17611c556b3SChuck Lever op_metrics->om_execute += execute; 17711c556b3SChuck Lever } 17811c556b3SChuck Lever 179cc0175c1SChuck Lever void _print_name(struct seq_file *seq, unsigned int op, struct rpc_procinfo *procs) 180cc0175c1SChuck Lever { 181cc0175c1SChuck Lever if (procs[op].p_name) 182cc0175c1SChuck Lever seq_printf(seq, "\t%12s: ", procs[op].p_name); 183cc0175c1SChuck Lever else if (op == 0) 184cc0175c1SChuck Lever seq_printf(seq, "\t NULL: "); 185cc0175c1SChuck Lever else 186cc0175c1SChuck Lever seq_printf(seq, "\t%12u: ", op); 187cc0175c1SChuck Lever } 188cc0175c1SChuck Lever 189*5eb53f41SChuck Lever #define MILLISECS_PER_JIFFY (1000 / HZ) 19011c556b3SChuck Lever 19111c556b3SChuck Lever void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) 19211c556b3SChuck Lever { 19311c556b3SChuck Lever struct rpc_iostats *stats = clnt->cl_metrics; 19411c556b3SChuck Lever struct rpc_xprt *xprt = clnt->cl_xprt; 19511c556b3SChuck Lever unsigned int op, maxproc = clnt->cl_maxproc; 19611c556b3SChuck Lever 19711c556b3SChuck Lever if (!stats) 19811c556b3SChuck Lever return; 19911c556b3SChuck Lever 20011c556b3SChuck Lever seq_printf(seq, "\tRPC iostats version: %s ", RPC_IOSTATS_VERS); 20111c556b3SChuck Lever seq_printf(seq, "p/v: %u/%u (%s)\n", 20211c556b3SChuck Lever clnt->cl_prog, clnt->cl_vers, clnt->cl_protname); 20311c556b3SChuck Lever 20411c556b3SChuck Lever if (xprt) 20511c556b3SChuck Lever xprt->ops->print_stats(xprt, seq); 20611c556b3SChuck Lever 20711c556b3SChuck Lever seq_printf(seq, "\tper-op statistics\n"); 20811c556b3SChuck Lever for (op = 0; op < maxproc; op++) { 20911c556b3SChuck Lever struct rpc_iostats *metrics = &stats[op]; 210cc0175c1SChuck Lever _print_name(seq, op, clnt->cl_procinfo); 21111c556b3SChuck Lever seq_printf(seq, "%lu %lu %lu %Lu %Lu %Lu %Lu %Lu\n", 21211c556b3SChuck Lever metrics->om_ops, 21311c556b3SChuck Lever metrics->om_ntrans, 21411c556b3SChuck Lever metrics->om_timeouts, 21511c556b3SChuck Lever metrics->om_bytes_sent, 21611c556b3SChuck Lever metrics->om_bytes_recv, 21711c556b3SChuck Lever metrics->om_queue * MILLISECS_PER_JIFFY, 21811c556b3SChuck Lever metrics->om_rtt * MILLISECS_PER_JIFFY, 21911c556b3SChuck Lever metrics->om_execute * MILLISECS_PER_JIFFY); 22011c556b3SChuck Lever } 22111c556b3SChuck Lever } 22211c556b3SChuck Lever EXPORT_SYMBOL(rpc_print_iostats); 22311c556b3SChuck Lever 2241da177e4SLinus Torvalds /* 2251da177e4SLinus Torvalds * Register/unregister RPC proc files 2261da177e4SLinus Torvalds */ 2271da177e4SLinus Torvalds static inline struct proc_dir_entry * 2281da177e4SLinus Torvalds do_register(const char *name, void *data, struct file_operations *fops) 2291da177e4SLinus Torvalds { 2301da177e4SLinus Torvalds struct proc_dir_entry *ent; 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds rpc_proc_init(); 2331da177e4SLinus Torvalds dprintk("RPC: registering /proc/net/rpc/%s\n", name); 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds ent = create_proc_entry(name, 0, proc_net_rpc); 2361da177e4SLinus Torvalds if (ent) { 2371da177e4SLinus Torvalds ent->proc_fops = fops; 2381da177e4SLinus Torvalds ent->data = data; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds return ent; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds struct proc_dir_entry * 2441da177e4SLinus Torvalds rpc_proc_register(struct rpc_stat *statp) 2451da177e4SLinus Torvalds { 2461da177e4SLinus Torvalds return do_register(statp->program->name, statp, &rpc_proc_fops); 2471da177e4SLinus Torvalds } 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds void 2501da177e4SLinus Torvalds rpc_proc_unregister(const char *name) 2511da177e4SLinus Torvalds { 2521da177e4SLinus Torvalds remove_proc_entry(name, proc_net_rpc); 2531da177e4SLinus Torvalds } 2541da177e4SLinus Torvalds 2551da177e4SLinus Torvalds struct proc_dir_entry * 2561da177e4SLinus Torvalds svc_proc_register(struct svc_stat *statp, struct file_operations *fops) 2571da177e4SLinus Torvalds { 2581da177e4SLinus Torvalds return do_register(statp->program->pg_name, statp, fops); 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds void 2621da177e4SLinus Torvalds svc_proc_unregister(const char *name) 2631da177e4SLinus Torvalds { 2641da177e4SLinus Torvalds remove_proc_entry(name, proc_net_rpc); 2651da177e4SLinus Torvalds } 2661da177e4SLinus Torvalds 2671da177e4SLinus Torvalds void 2681da177e4SLinus Torvalds rpc_proc_init(void) 2691da177e4SLinus Torvalds { 2701da177e4SLinus Torvalds dprintk("RPC: registering /proc/net/rpc\n"); 2711da177e4SLinus Torvalds if (!proc_net_rpc) { 2721da177e4SLinus Torvalds struct proc_dir_entry *ent; 2731da177e4SLinus Torvalds ent = proc_mkdir("rpc", proc_net); 2741da177e4SLinus Torvalds if (ent) { 2751da177e4SLinus Torvalds ent->owner = THIS_MODULE; 2761da177e4SLinus Torvalds proc_net_rpc = ent; 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds void 2821da177e4SLinus Torvalds rpc_proc_exit(void) 2831da177e4SLinus Torvalds { 2841da177e4SLinus Torvalds dprintk("RPC: unregistering /proc/net/rpc\n"); 2851da177e4SLinus Torvalds if (proc_net_rpc) { 2861da177e4SLinus Torvalds proc_net_rpc = NULL; 2871da177e4SLinus Torvalds remove_proc_entry("net/rpc", NULL); 2881da177e4SLinus Torvalds } 2891da177e4SLinus Torvalds } 2901da177e4SLinus Torvalds 291