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