Applied pidfile patch
[collectd.git] / src / nfs.c
1 /**
2  * collectd - src/nfs.c
3  * Copyright (C) 2005  Jason Pepas
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Jason Pepas <cell at ices.utexas.edu>
21  *   Florian octo Forster <octo at verplant.org>
22  **/
23
24 #include "nfs.h"
25
26 #if COLLECT_NFS
27 #define MODULE_NAME "nfs"
28
29 #include "plugin.h"
30 #include "common.h"
31
32 static char *nfs2_procedures_file  = "nfs2_procedures-%s.rrd";
33 static char *nfs3_procedures_file  = "nfs3_procedures-%s.rrd";
34
35 /*
36 see /proc/net/rpc/nfs
37 see http://www.missioncriticallinux.com/orph/NFS-Statistics
38
39 net x x x x
40 rpc_stat.netcnt         Not used; always zero.
41 rpc_stat.netudpcnt      Not used; always zero.
42 rpc_stat.nettcpcnt      Not used; always zero.
43 rpc_stat.nettcpconn     Not used; always zero.
44
45 rpc x x x
46 rpc_stat.rpccnt             The number of RPC calls.
47 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
48 rpc_stat.rpcauthrefresh     The number of credential refreshes.
49
50 proc2 x x x...
51 proc3 x x x...
52
53 Procedure   NFS Version NFS Version 3
54 Number      Procedures  Procedures
55
56 0           null        null
57 1           getattr     getattr
58 2           setattr     setattr
59 3           root        lookup
60 4           lookup      access
61 5           readlink    readlink
62 6           read        read
63 7           wrcache     write
64 8           write       create
65 9           create      mkdir
66 10          remove      symlink
67 11          rename      mknod
68 12          link        remove
69 13          symlink     rmdir
70 14          mkdir       rename
71 15          rmdir       link
72 16          readdir     readdir
73 17          fsstat      readdirplus
74 18                      fsstat
75 19                      fsinfo
76 20                      pathconf
77 21                      commit
78 */
79
80 static char *nfs2_procedures_ds_def[] =
81 {
82         "DS:null:COUNTER:25:0:U",
83         "DS:getattr:COUNTER:25:0:U",
84         "DS:setattr:COUNTER:25:0:U",
85         "DS:root:COUNTER:25:0:U",
86         "DS:lookup:COUNTER:25:0:U",
87         "DS:readlink:COUNTER:25:0:U",
88         "DS:read:COUNTER:25:0:U",
89         "DS:wrcache:COUNTER:25:0:U",
90         "DS:write:COUNTER:25:0:U",
91         "DS:create:COUNTER:25:0:U",
92         "DS:remove:COUNTER:25:0:U",
93         "DS:rename:COUNTER:25:0:U",
94         "DS:link:COUNTER:25:0:U",
95         "DS:symlink:COUNTER:25:0:U",
96         "DS:mkdir:COUNTER:25:0:U",
97         "DS:rmdir:COUNTER:25:0:U",
98         "DS:readdir:COUNTER:25:0:U",
99         "DS:fsstat:COUNTER:25:0:U",
100         NULL
101 };
102 static int nfs2_procedures_ds_num = 18;
103
104 static char *nfs3_procedures_ds_def[] =
105 {
106         "DS:null:COUNTER:25:0:U",
107         "DS:getattr:COUNTER:25:0:U",
108         "DS:setattr:COUNTER:25:0:U",
109         "DS:lookup:COUNTER:25:0:U",
110         "DS:access:COUNTER:25:0:U",
111         "DS:readlink:COUNTER:25:0:U",
112         "DS:read:COUNTER:25:0:U",
113         "DS:write:COUNTER:25:0:U",
114         "DS:create:COUNTER:25:0:U",
115         "DS:mkdir:COUNTER:25:0:U",
116         "DS:symlink:COUNTER:25:0:U",
117         "DS:mknod:COUNTER:25:0:U",
118         "DS:remove:COUNTER:25:0:U",
119         "DS:rmdir:COUNTER:25:0:U",
120         "DS:rename:COUNTER:25:0:U",
121         "DS:link:COUNTER:25:0:U",
122         "DS:readdir:COUNTER:25:0:U",
123         "DS:readdirplus:COUNTER:25:0:U",
124         "DS:fsstat:COUNTER:25:0:U",
125         "DS:fsinfo:COUNTER:25:0:U",
126         "DS:pathconf:COUNTER:25:0:U",
127         "DS:commit:COUNTER:25:0:U",
128         NULL
129 };
130 static int nfs3_procedures_ds_num = 22;
131
132 #ifdef HAVE_LIBKSTAT
133 extern kstat_ctl_t *kc;
134 static kstat_t *nfs2_ksp_client;
135 static kstat_t *nfs2_ksp_server;
136 static kstat_t *nfs3_ksp_client;
137 static kstat_t *nfs3_ksp_server;
138 static kstat_t *nfs4_ksp_client;
139 static kstat_t *nfs4_ksp_server;
140 #endif
141
142 /* Possibly TODO: NFSv4 statistics */
143
144 void nfs_init (void)
145 {
146 #ifdef HAVE_LIBKSTAT
147         kstat_t *ksp_chain;
148
149         nfs2_ksp_client = NULL;
150         nfs2_ksp_server = NULL;
151         nfs3_ksp_client = NULL;
152         nfs3_ksp_server = NULL;
153         nfs4_ksp_client = NULL;
154         nfs4_ksp_server = NULL;
155         
156         if (kc == NULL)
157                 return;
158
159         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
160                         ksp_chain = ksp_chain->ks_next)
161         {
162                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
163                         continue;
164                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
165                         nfs2_ksp_server = ksp_chain;
166                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
167                         nfs3_ksp_server = ksp_chain;
168                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
169                         nfs4_ksp_server = ksp_chain;
170                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
171                         nfs2_ksp_client = ksp_chain;
172                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
173                         nfs3_ksp_client = ksp_chain;
174                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
175                         nfs4_ksp_client = ksp_chain;
176         }
177 #endif
178
179         return;
180 }
181
182 #define BUFSIZE 1024
183 void nfs2_procedures_write (char *host, char *inst, char *val)
184 {
185         char filename[BUFSIZE];
186
187         if (snprintf (filename, BUFSIZE, nfs2_procedures_file, inst) > BUFSIZE)
188                 return;
189
190         rrd_update_file (host, filename, val, nfs2_procedures_ds_def,
191                         nfs2_procedures_ds_num);
192 }
193
194 void nfs3_procedures_write (char *host, char *inst, char *val)
195 {
196         char filename[BUFSIZE];
197
198         if (snprintf (filename, BUFSIZE, nfs3_procedures_file, inst) > BUFSIZE)
199                 return;
200
201         rrd_update_file (host, filename, val, nfs3_procedures_ds_def,
202                         nfs3_procedures_ds_num);
203 }
204
205 void nfs2_procedures_submit (unsigned long long *val, char *inst)
206 {
207         char buf[BUFSIZE];
208         int retval = 0;
209
210         retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
211                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
212                         "%llu:%llu:%llu", /* 18x %llu */
213                         (unsigned int) curtime,
214                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
215                         val[7], val[8], val[9], val[10], val[11], val[12],
216                         val[13], val[14], val[15], val[16], val[17]);
217
218
219         if (retval >= BUFSIZE)
220                 return;
221         else if (retval < 0)
222         {
223                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
224                 return;
225         }
226
227         plugin_submit ("nfs2_procedures", inst, buf);
228 }
229
230 void nfs3_procedures_submit (unsigned long long *val, char *inst)
231 {
232         char buf[BUFSIZE];
233         int retval = 0;
234
235         retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
236                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
237                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
238                         (unsigned int) curtime,
239                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
240                         val[7], val[8], val[9], val[10], val[11], val[12],
241                         val[13], val[14], val[15], val[16], val[17], val[18],
242                         val[19], val[20], val[21]);
243
244         if (retval >= BUFSIZE)
245                 return;
246         else if (retval < 0)
247         {
248                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
249                 return;
250         }
251
252         plugin_submit("nfs3_procedures", inst, buf);
253 }
254
255 #if defined(KERNEL_LINUX)
256 void nfs_read_stats_file (FILE *fh, char *inst)
257 {
258         char buffer[BUFSIZE];
259
260         char *fields[48];
261         int numfields = 0;
262
263         if (fh == NULL)
264                 return;
265
266         while (fgets (buffer, BUFSIZE, fh) != NULL)
267         {
268                 numfields = strsplit (buffer, fields, 48);
269
270                 if (numfields < 2)
271                         continue;
272
273                 if (strncmp (fields[0], "proc2", 5) == 0)
274                 {
275                         int i;
276                         unsigned long long *values;
277
278                         if (numfields - 2 != nfs2_procedures_ds_num)
279                         {
280                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
281                                 continue;
282                         }
283
284                         if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
285                         {
286                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
287                                 continue;
288                         }
289
290                         for (i = 0; i < nfs2_procedures_ds_num; i++)
291                                 values[i] = atoll (fields[i + 2]);
292
293                         nfs2_procedures_submit (values, inst);
294
295                         free (values);
296                 }
297                 else if (strncmp (fields[0], "proc3", 5) == 0)
298                 {
299                         int i;
300                         unsigned long long *values;
301
302                         if (numfields - 2 != nfs3_procedures_ds_num)
303                         {
304                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
305                                 continue;
306                         }
307
308                         if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
309                         {
310                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
311                                 continue;
312                         }
313
314                         for (i = 0; i < nfs3_procedures_ds_num; i++)
315                                 values[i] = atoll (fields[i + 2]);
316
317                         nfs3_procedures_submit (values, inst);
318
319                         free (values);
320                 }
321         }
322 }
323 #endif /* defined(KERNEL_LINUX) */
324 #undef BUFSIZE
325
326 #ifdef HAVE_LIBKSTAT
327 void nfs2_read_kstat (kstat_t *ksp, char *inst)
328 {
329         unsigned long long values[18];
330
331         values[0] = get_kstat_value (ksp, "null");
332         values[1] = get_kstat_value (ksp, "getattr");
333         values[2] = get_kstat_value (ksp, "setattr");
334         values[3] = get_kstat_value (ksp, "root");
335         values[4] = get_kstat_value (ksp, "lookup");
336         values[5] = get_kstat_value (ksp, "readlink");
337         values[6] = get_kstat_value (ksp, "read");
338         values[7] = get_kstat_value (ksp, "wrcache");
339         values[8] = get_kstat_value (ksp, "write");
340         values[9] = get_kstat_value (ksp, "create");
341         values[10] = get_kstat_value (ksp, "remove");
342         values[11] = get_kstat_value (ksp, "rename");
343         values[12] = get_kstat_value (ksp, "link");
344         values[13] = get_kstat_value (ksp, "symlink");
345         values[14] = get_kstat_value (ksp, "mkdir");
346         values[15] = get_kstat_value (ksp, "rmdir");
347         values[16] = get_kstat_value (ksp, "readdir");
348         values[17] = get_kstat_value (ksp, "statfs");
349
350         nfs2_procedures_submit (values, inst);
351 }
352 #endif
353
354 void nfs_read (void)
355 {
356 #if defined(KERNEL_LINUX)
357         FILE *fh;
358
359         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
360         {
361                 nfs_read_stats_file (fh, "client");
362                 fclose (fh);
363         }
364
365         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
366         {
367                 nfs_read_stats_file (fh, "server");
368                 fclose (fh);
369         }
370
371 /* #endif defined(KERNEL_LINUX) */
372
373 #elif defined(HAVE_LIBKSTAT)
374         if (nfs2_ksp_client != NULL)
375                 nfs2_read_kstat (nfs2_ksp_client, "client");
376         if (nfs2_ksp_server != NULL)
377                 nfs2_read_kstat (nfs2_ksp_server, "server");
378 #endif /* defined(HAVE_LIBKSTAT) */
379 }
380
381 void module_register (void)
382 {
383     plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
384     plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
385     plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);
386 }
387
388 #undef MODULE_NAME
389 #endif /* COLLECT_LOAD */