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