67a13170c6d7f579573d2147fdfe08ebc73019ea
[linux-flexiantxendom0-3.2.10.git] / net / sunrpc / stats.c
1 /*
2  * linux/net/sunrpc/stats.c
3  *
4  * procfs-based user access to generic RPC statistics. The stats files
5  * reside in /proc/net/rpc.
6  *
7  * The read routines assume that the buffer passed in is just big enough.
8  * If you implement an RPC service that has its own stats routine which
9  * appends the generic RPC stats, make sure you don't exceed the PAGE_SIZE
10  * limit.
11  *
12  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
13  */
14
15 #include <linux/module.h>
16
17 #include <linux/init.h>
18 #include <linux/kernel.h>
19 #include <linux/sched.h>
20 #include <linux/proc_fs.h>
21 #include <linux/sunrpc/clnt.h>
22 #include <linux/sunrpc/svcsock.h>
23
24 #define RPCDBG_FACILITY RPCDBG_MISC
25
26 struct proc_dir_entry   *proc_net_rpc = NULL;
27
28 /*
29  * Get RPC client stats
30  */
31 int
32 rpc_proc_read(char *buffer, char **start, off_t offset, int count,
33                                 int *eof, void *data)
34 {
35         struct rpc_stat *statp = (struct rpc_stat *) data;
36         struct rpc_program *prog = statp->program;
37         struct rpc_version *vers;
38         int             len, i, j;
39
40         len = sprintf(buffer,
41                 "net %d %d %d %d\n",
42                         statp->netcnt,
43                         statp->netudpcnt,
44                         statp->nettcpcnt,
45                         statp->nettcpconn);
46         len += sprintf(buffer + len,
47                 "rpc %d %d %d\n",
48                         statp->rpccnt,
49                         statp->rpcretrans,
50                         statp->rpcauthrefresh);
51
52         for (i = 0; i < prog->nrvers; i++) {
53                 if (!(vers = prog->version[i]))
54                         continue;
55                 len += sprintf(buffer + len, "proc%d %d",
56                                         vers->number, vers->nrprocs);
57                 for (j = 0; j < vers->nrprocs; j++)
58                         len += sprintf(buffer + len, " %d",
59                                         vers->procs[j].p_count);
60                 buffer[len++] = '\n';
61         }
62
63         if (offset >= len) {
64                 *start = buffer;
65                 *eof = 1;
66                 return 0;
67         }
68         *start = buffer + offset;
69         if ((len -= offset) > count)
70                 return count;
71         *eof = 1;
72         return len;
73 }
74
75 /*
76  * Get RPC server stats
77  */
78 int
79 svc_proc_read(char *buffer, char **start, off_t offset, int count,
80                                 int *eof, void *data)
81 {
82         struct svc_stat *statp  = (struct svc_stat *) data;
83         struct svc_program *prog = statp->program;
84         struct svc_procedure *proc;
85         struct svc_version *vers;
86         int             len, i, j;
87
88         len = sprintf(buffer,
89                 "net %d %d %d %d\n",
90                         statp->netcnt,
91                         statp->netudpcnt,
92                         statp->nettcpcnt,
93                         statp->nettcpconn);
94         len += sprintf(buffer + len,
95                 "rpc %d %d %d %d %d\n",
96                         statp->rpccnt,
97                         statp->rpcbadfmt+statp->rpcbadauth+statp->rpcbadclnt,
98                         statp->rpcbadfmt,
99                         statp->rpcbadauth,
100                         statp->rpcbadclnt);
101
102         for (i = 0; i < prog->pg_nvers; i++) {
103                 if (!(vers = prog->pg_vers[i]) || !(proc = vers->vs_proc))
104                         continue;
105                 len += sprintf(buffer + len, "proc%d %d", i, vers->vs_nproc);
106                 for (j = 0; j < vers->vs_nproc; j++, proc++)
107                         len += sprintf(buffer + len, " %d", proc->pc_count);
108                 buffer[len++] = '\n';
109         }
110
111         if (offset >= len) {
112                 *start = buffer;
113                 *eof = 1;
114                 return 0;
115         }
116         *start = buffer + offset;
117         if ((len -= offset) > count)
118                 return count;
119         *eof = 1;
120         return len;
121 }
122
123 /*
124  * Register/unregister RPC proc files
125  */
126 static inline struct proc_dir_entry *
127 do_register(const char *name, void *data, int issvc)
128 {
129         rpc_proc_init();
130         dprintk("RPC: registering /proc/net/rpc/%s\n", name);
131         return create_proc_read_entry(name, 0, proc_net_rpc, 
132                                       issvc? svc_proc_read : rpc_proc_read,
133                                       data);
134 }
135
136 struct proc_dir_entry *
137 rpc_proc_register(struct rpc_stat *statp)
138 {
139         return do_register(statp->program->name, statp, 0);
140 }
141
142 void
143 rpc_proc_unregister(const char *name)
144 {
145         remove_proc_entry(name, proc_net_rpc);
146 }
147
148 struct proc_dir_entry *
149 svc_proc_register(struct svc_stat *statp)
150 {
151         return do_register(statp->program->pg_name, statp, 1);
152 }
153
154 void
155 svc_proc_unregister(const char *name)
156 {
157         remove_proc_entry(name, proc_net_rpc);
158 }
159
160 void
161 rpc_proc_init(void)
162 {
163         dprintk("RPC: registering /proc/net/rpc\n");
164         if (!proc_net_rpc) {
165                 struct proc_dir_entry *ent;
166                 ent = proc_mkdir("net/rpc", 0);
167                 if (ent) {
168                         ent->owner = THIS_MODULE;
169                         proc_net_rpc = ent;
170                 }
171         }
172 }
173
174 void
175 rpc_proc_exit(void)
176 {
177         dprintk("RPC: unregistering /proc/net/rpc\n");
178         if (proc_net_rpc) {
179                 proc_net_rpc = NULL;
180                 remove_proc_entry("net/rpc", 0);
181         }
182 }
183