/*
|
/*
|
* linux/net/sunrpc/stats.c
|
* linux/net/sunrpc/stats.c
|
*
|
*
|
* procfs-based user access to generic RPC statistics. The stats files
|
* procfs-based user access to generic RPC statistics. The stats files
|
* reside in /proc/net/rpc.
|
* reside in /proc/net/rpc.
|
*
|
*
|
* The read routines assume that the buffer passed in is just big enough.
|
* The read routines assume that the buffer passed in is just big enough.
|
* If you implement an RPC service that has its own stats routine which
|
* If you implement an RPC service that has its own stats routine which
|
* appends the generic RPC stats, make sure you don't exceed the PAGE_SIZE
|
* appends the generic RPC stats, make sure you don't exceed the PAGE_SIZE
|
* limit.
|
* limit.
|
*
|
*
|
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
|
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
|
*/
|
*/
|
|
|
#include <linux/module.h>
|
#include <linux/module.h>
|
|
|
#include <linux/init.h>
|
#include <linux/init.h>
|
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
#include <linux/sched.h>
|
#include <linux/sched.h>
|
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/clnt.h>
|
#include <linux/sunrpc/svcsock.h>
|
#include <linux/sunrpc/svcsock.h>
|
#include <linux/init.h>
|
#include <linux/init.h>
|
|
|
#define RPCDBG_FACILITY RPCDBG_MISC
|
#define RPCDBG_FACILITY RPCDBG_MISC
|
|
|
static struct proc_dir_entry *proc_net_rpc = NULL;
|
static struct proc_dir_entry *proc_net_rpc = NULL;
|
|
|
/*
|
/*
|
* Get RPC client stats
|
* Get RPC client stats
|
*/
|
*/
|
int
|
int
|
rpc_proc_read(char *buffer, char **start, off_t offset, int count,
|
rpc_proc_read(char *buffer, char **start, off_t offset, int count,
|
int *eof, void *data)
|
int *eof, void *data)
|
{
|
{
|
struct rpc_stat *statp = (struct rpc_stat *) data;
|
struct rpc_stat *statp = (struct rpc_stat *) data;
|
struct rpc_program *prog = statp->program;
|
struct rpc_program *prog = statp->program;
|
struct rpc_version *vers;
|
struct rpc_version *vers;
|
int len, i, j;
|
int len, i, j;
|
|
|
len = sprintf(buffer,
|
len = sprintf(buffer,
|
"net %d %d %d %d\n",
|
"net %d %d %d %d\n",
|
statp->netcnt,
|
statp->netcnt,
|
statp->netudpcnt,
|
statp->netudpcnt,
|
statp->nettcpcnt,
|
statp->nettcpcnt,
|
statp->nettcpconn);
|
statp->nettcpconn);
|
len += sprintf(buffer + len,
|
len += sprintf(buffer + len,
|
"rpc %d %d %d\n",
|
"rpc %d %d %d\n",
|
statp->rpccnt,
|
statp->rpccnt,
|
statp->rpcretrans,
|
statp->rpcretrans,
|
statp->rpcauthrefresh);
|
statp->rpcauthrefresh);
|
|
|
for (i = 0; i < prog->nrvers; i++) {
|
for (i = 0; i < prog->nrvers; i++) {
|
if (!(vers = prog->version[i]))
|
if (!(vers = prog->version[i]))
|
continue;
|
continue;
|
len += sprintf(buffer + len, "proc%d %d",
|
len += sprintf(buffer + len, "proc%d %d",
|
vers->number, vers->nrprocs);
|
vers->number, vers->nrprocs);
|
for (j = 0; j < vers->nrprocs; j++)
|
for (j = 0; j < vers->nrprocs; j++)
|
len += sprintf(buffer + len, " %d",
|
len += sprintf(buffer + len, " %d",
|
vers->procs[j].p_count);
|
vers->procs[j].p_count);
|
buffer[len++] = '\n';
|
buffer[len++] = '\n';
|
}
|
}
|
|
|
if (offset >= len) {
|
if (offset >= len) {
|
*start = buffer;
|
*start = buffer;
|
*eof = 1;
|
*eof = 1;
|
return 0;
|
return 0;
|
}
|
}
|
*start = buffer + offset;
|
*start = buffer + offset;
|
if ((len -= offset) > count)
|
if ((len -= offset) > count)
|
return count;
|
return count;
|
*eof = 1;
|
*eof = 1;
|
return len;
|
return len;
|
}
|
}
|
|
|
/*
|
/*
|
* Get RPC server stats
|
* Get RPC server stats
|
*/
|
*/
|
int
|
int
|
svc_proc_read(char *buffer, char **start, off_t offset, int count,
|
svc_proc_read(char *buffer, char **start, off_t offset, int count,
|
int *eof, void *data)
|
int *eof, void *data)
|
{
|
{
|
struct svc_stat *statp = (struct svc_stat *) data;
|
struct svc_stat *statp = (struct svc_stat *) data;
|
struct svc_program *prog = statp->program;
|
struct svc_program *prog = statp->program;
|
struct svc_procedure *proc;
|
struct svc_procedure *proc;
|
struct svc_version *vers;
|
struct svc_version *vers;
|
int len, i, j;
|
int len, i, j;
|
|
|
len = sprintf(buffer,
|
len = sprintf(buffer,
|
"net %d %d %d %d\n",
|
"net %d %d %d %d\n",
|
statp->netcnt,
|
statp->netcnt,
|
statp->netudpcnt,
|
statp->netudpcnt,
|
statp->nettcpcnt,
|
statp->nettcpcnt,
|
statp->nettcpconn);
|
statp->nettcpconn);
|
len += sprintf(buffer + len,
|
len += sprintf(buffer + len,
|
"rpc %d %d %d %d %d\n",
|
"rpc %d %d %d %d %d\n",
|
statp->rpccnt,
|
statp->rpccnt,
|
statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
|
statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
|
statp->rpcbadfmt,
|
statp->rpcbadfmt,
|
statp->rpcbadauth,
|
statp->rpcbadauth,
|
statp->rpcbadclnt);
|
statp->rpcbadclnt);
|
|
|
for (i = 0; i < prog->pg_nvers; i++) {
|
for (i = 0; i < prog->pg_nvers; i++) {
|
if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
|
if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
|
continue;
|
continue;
|
len += sprintf(buffer + len, "proc%d %d", i, vers->vs_nproc);
|
len += sprintf(buffer + len, "proc%d %d", i, vers->vs_nproc);
|
for (j = 0; j < vers->vs_nproc; j++, proc++)
|
for (j = 0; j < vers->vs_nproc; j++, proc++)
|
len += sprintf(buffer + len, " %d", proc->pc_count);
|
len += sprintf(buffer + len, " %d", proc->pc_count);
|
buffer[len++] = '\n';
|
buffer[len++] = '\n';
|
}
|
}
|
|
|
if (offset >= len) {
|
if (offset >= len) {
|
*start = buffer;
|
*start = buffer;
|
*eof = 1;
|
*eof = 1;
|
return 0;
|
return 0;
|
}
|
}
|
*start = buffer + offset;
|
*start = buffer + offset;
|
if ((len -= offset) > count)
|
if ((len -= offset) > count)
|
return count;
|
return count;
|
*eof = 1;
|
*eof = 1;
|
return len;
|
return len;
|
}
|
}
|
|
|
/*
|
/*
|
* Register/unregister RPC proc files
|
* Register/unregister RPC proc files
|
*/
|
*/
|
static inline struct proc_dir_entry *
|
static inline struct proc_dir_entry *
|
do_register(const char *name, void *data, int issvc)
|
do_register(const char *name, void *data, int issvc)
|
{
|
{
|
rpc_proc_init();
|
rpc_proc_init();
|
dprintk("RPC: registering /proc/net/rpc/%s\n", name);
|
dprintk("RPC: registering /proc/net/rpc/%s\n", name);
|
return create_proc_read_entry(name, 0, proc_net_rpc,
|
return create_proc_read_entry(name, 0, proc_net_rpc,
|
issvc? svc_proc_read : rpc_proc_read,
|
issvc? svc_proc_read : rpc_proc_read,
|
data);
|
data);
|
}
|
}
|
|
|
struct proc_dir_entry *
|
struct proc_dir_entry *
|
rpc_proc_register(struct rpc_stat *statp)
|
rpc_proc_register(struct rpc_stat *statp)
|
{
|
{
|
return do_register(statp->program->name, statp, 0);
|
return do_register(statp->program->name, statp, 0);
|
}
|
}
|
|
|
void
|
void
|
rpc_proc_unregister(const char *name)
|
rpc_proc_unregister(const char *name)
|
{
|
{
|
remove_proc_entry(name, proc_net_rpc);
|
remove_proc_entry(name, proc_net_rpc);
|
}
|
}
|
|
|
struct proc_dir_entry *
|
struct proc_dir_entry *
|
svc_proc_register(struct svc_stat *statp)
|
svc_proc_register(struct svc_stat *statp)
|
{
|
{
|
return do_register(statp->program->pg_name, statp, 1);
|
return do_register(statp->program->pg_name, statp, 1);
|
}
|
}
|
|
|
void
|
void
|
svc_proc_unregister(const char *name)
|
svc_proc_unregister(const char *name)
|
{
|
{
|
remove_proc_entry(name, proc_net_rpc);
|
remove_proc_entry(name, proc_net_rpc);
|
}
|
}
|
|
|
void
|
void
|
rpc_proc_init(void)
|
rpc_proc_init(void)
|
{
|
{
|
dprintk("RPC: registering /proc/net/rpc\n");
|
dprintk("RPC: registering /proc/net/rpc\n");
|
if (!proc_net_rpc) {
|
if (!proc_net_rpc) {
|
struct proc_dir_entry *ent;
|
struct proc_dir_entry *ent;
|
ent = proc_mkdir("net/rpc", 0);
|
ent = proc_mkdir("net/rpc", 0);
|
if (ent) {
|
if (ent) {
|
ent->owner = THIS_MODULE;
|
ent->owner = THIS_MODULE;
|
proc_net_rpc = ent;
|
proc_net_rpc = ent;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
void
|
void
|
rpc_proc_exit(void)
|
rpc_proc_exit(void)
|
{
|
{
|
dprintk("RPC: unregistering /proc/net/rpc\n");
|
dprintk("RPC: unregistering /proc/net/rpc\n");
|
if (proc_net_rpc) {
|
if (proc_net_rpc) {
|
proc_net_rpc = NULL;
|
proc_net_rpc = NULL;
|
remove_proc_entry("net/rpc", 0);
|
remove_proc_entry("net/rpc", 0);
|
}
|
}
|
}
|
}
|
|
|
|
|
static int __init
|
static int __init
|
init_sunrpc(void)
|
init_sunrpc(void)
|
{
|
{
|
#ifdef RPC_DEBUG
|
#ifdef RPC_DEBUG
|
rpc_register_sysctl();
|
rpc_register_sysctl();
|
#endif
|
#endif
|
rpc_proc_init();
|
rpc_proc_init();
|
return 0;
|
return 0;
|
}
|
}
|
|
|
static void __exit
|
static void __exit
|
cleanup_sunrpc(void)
|
cleanup_sunrpc(void)
|
{
|
{
|
#ifdef RPC_DEBUG
|
#ifdef RPC_DEBUG
|
rpc_unregister_sysctl();
|
rpc_unregister_sysctl();
|
#endif
|
#endif
|
rpc_proc_exit();
|
rpc_proc_exit();
|
}
|
}
|
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
module_init(init_sunrpc);
|
module_init(init_sunrpc);
|
module_exit(cleanup_sunrpc);
|
module_exit(cleanup_sunrpc);
|
|
|