3 * Copyright (C) 2005,2006 Jason Pepas
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.
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.
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
20 * Jason Pepas <cell at ices.utexas.edu>
21 * Florian octo Forster <octo at verplant.org>
28 #define MODULE_NAME "nfs"
30 /* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
32 # define NFS_HAVE_READ 1
34 # define NFS_HAVE_READ 0
37 static char *nfs2_procedures_file = "nfs2_procedures-%s.rrd";
38 static char *nfs3_procedures_file = "nfs3_procedures-%s.rrd";
42 see http://www.missioncriticallinux.com/orph/NFS-Statistics
45 rpc_stat.netcnt Not used; always zero.
46 rpc_stat.netudpcnt Not used; always zero.
47 rpc_stat.nettcpcnt Not used; always zero.
48 rpc_stat.nettcpconn Not used; always zero.
51 rpc_stat.rpccnt The number of RPC calls.
52 rpc_stat.rpcretrans The number of retransmitted RPC calls.
53 rpc_stat.rpcauthrefresh The number of credential refreshes.
58 Procedure NFS Version NFS Version 3
59 Number Procedures Procedures
85 static char *nfs2_procedures_ds_def[] =
87 "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
88 "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
89 "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
90 "DS:root:COUNTER:"COLLECTD_HEARTBEAT":0:U",
91 "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
92 "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
93 "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
94 "DS:wrcache:COUNTER:"COLLECTD_HEARTBEAT":0:U",
95 "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
96 "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
97 "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
98 "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
99 "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
100 "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
101 "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
102 "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
103 "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
104 "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
107 static int nfs2_procedures_ds_num = 18;
109 static char *nfs3_procedures_ds_def[] =
111 "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
112 "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
113 "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
114 "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
115 "DS:access:COUNTER:"COLLECTD_HEARTBEAT":0:U",
116 "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
117 "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
118 "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
119 "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
120 "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
121 "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
122 "DS:mknod:COUNTER:"COLLECTD_HEARTBEAT":0:U",
123 "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
124 "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
125 "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
126 "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
127 "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
128 "DS:readdirplus:COUNTER:"COLLECTD_HEARTBEAT":0:U",
129 "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
130 "DS:fsinfo:COUNTER:"COLLECTD_HEARTBEAT":0:U",
131 "DS:pathconf:COUNTER:"COLLECTD_HEARTBEAT":0:U",
132 "DS:commit:COUNTER:"COLLECTD_HEARTBEAT":0:U",
135 static int nfs3_procedures_ds_num = 22;
137 #if HAVE_LIBKSTAT && 0
138 extern kstat_ctl_t *kc;
139 static kstat_t *nfs2_ksp_client;
140 static kstat_t *nfs2_ksp_server;
141 static kstat_t *nfs3_ksp_client;
142 static kstat_t *nfs3_ksp_server;
143 static kstat_t *nfs4_ksp_client;
144 static kstat_t *nfs4_ksp_server;
147 /* Possibly TODO: NFSv4 statistics */
149 static void nfs_init (void)
151 #if HAVE_LIBKSTAT && 0
154 nfs2_ksp_client = NULL;
155 nfs2_ksp_server = NULL;
156 nfs3_ksp_client = NULL;
157 nfs3_ksp_server = NULL;
158 nfs4_ksp_client = NULL;
159 nfs4_ksp_server = NULL;
164 for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
165 ksp_chain = ksp_chain->ks_next)
167 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
169 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
170 nfs2_ksp_server = ksp_chain;
171 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
172 nfs3_ksp_server = ksp_chain;
173 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
174 nfs4_ksp_server = ksp_chain;
175 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
176 nfs2_ksp_client = ksp_chain;
177 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
178 nfs3_ksp_client = ksp_chain;
179 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
180 nfs4_ksp_client = ksp_chain;
188 static void nfs2_procedures_write (char *host, char *inst, char *val)
190 char filename[BUFSIZE];
192 if (snprintf (filename, BUFSIZE, nfs2_procedures_file, inst) > BUFSIZE)
195 rrd_update_file (host, filename, val, nfs2_procedures_ds_def,
196 nfs2_procedures_ds_num);
199 static void nfs3_procedures_write (char *host, char *inst, char *val)
201 char filename[BUFSIZE];
203 if (snprintf (filename, BUFSIZE, nfs3_procedures_file, inst) > BUFSIZE)
206 rrd_update_file (host, filename, val, nfs3_procedures_ds_def,
207 nfs3_procedures_ds_num);
211 static void nfs2_procedures_submit (unsigned long long *val, char *inst)
216 retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
217 "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
218 "%llu:%llu:%llu", /* 18x %llu */
219 (unsigned int) curtime,
220 val[0], val[1], val[2], val[3], val[4], val[5], val[6],
221 val[7], val[8], val[9], val[10], val[11], val[12],
222 val[13], val[14], val[15], val[16], val[17]);
225 if (retval >= BUFSIZE)
229 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
233 plugin_submit ("nfs2_procedures", inst, buf);
236 static void nfs3_procedures_submit (unsigned long long *val, char *inst)
241 retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
242 "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
243 "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
244 (unsigned int) curtime,
245 val[0], val[1], val[2], val[3], val[4], val[5], val[6],
246 val[7], val[8], val[9], val[10], val[11], val[12],
247 val[13], val[14], val[15], val[16], val[17], val[18],
248 val[19], val[20], val[21]);
250 if (retval >= BUFSIZE)
254 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
258 plugin_submit("nfs3_procedures", inst, buf);
260 #endif /* NFS_HAVE_READ */
263 static void nfs_read_stats_file (FILE *fh, char *inst)
265 char buffer[BUFSIZE];
273 while (fgets (buffer, BUFSIZE, fh) != NULL)
275 numfields = strsplit (buffer, fields, 48);
280 if (strncmp (fields[0], "proc2", 5) == 0)
283 unsigned long long *values;
285 if (numfields - 2 != nfs2_procedures_ds_num)
287 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
291 if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
293 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
297 for (i = 0; i < nfs2_procedures_ds_num; i++)
298 values[i] = atoll (fields[i + 2]);
300 nfs2_procedures_submit (values, inst);
304 else if (strncmp (fields[0], "proc3", 5) == 0)
307 unsigned long long *values;
309 if (numfields - 2 != nfs3_procedures_ds_num)
311 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
315 if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
317 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
321 for (i = 0; i < nfs3_procedures_ds_num; i++)
322 values[i] = atoll (fields[i + 2]);
324 nfs3_procedures_submit (values, inst);
330 #endif /* defined(KERNEL_LINUX) */
333 #if HAVE_LIBKSTAT && 0
334 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
336 unsigned long long values[18];
338 values[0] = get_kstat_value (ksp, "null");
339 values[1] = get_kstat_value (ksp, "getattr");
340 values[2] = get_kstat_value (ksp, "setattr");
341 values[3] = get_kstat_value (ksp, "root");
342 values[4] = get_kstat_value (ksp, "lookup");
343 values[5] = get_kstat_value (ksp, "readlink");
344 values[6] = get_kstat_value (ksp, "read");
345 values[7] = get_kstat_value (ksp, "wrcache");
346 values[8] = get_kstat_value (ksp, "write");
347 values[9] = get_kstat_value (ksp, "create");
348 values[10] = get_kstat_value (ksp, "remove");
349 values[11] = get_kstat_value (ksp, "rename");
350 values[12] = get_kstat_value (ksp, "link");
351 values[13] = get_kstat_value (ksp, "symlink");
352 values[14] = get_kstat_value (ksp, "mkdir");
353 values[15] = get_kstat_value (ksp, "rmdir");
354 values[16] = get_kstat_value (ksp, "readdir");
355 values[17] = get_kstat_value (ksp, "statfs");
357 nfs2_procedures_submit (values, inst);
362 static void nfs_read (void)
367 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
369 nfs_read_stats_file (fh, "client");
373 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
375 nfs_read_stats_file (fh, "server");
379 /* #endif defined(KERNEL_LINUX) */
381 #elif HAVE_LIBKSTAT && 0
382 if (nfs2_ksp_client != NULL)
383 nfs2_read_kstat (nfs2_ksp_client, "client");
384 if (nfs2_ksp_server != NULL)
385 nfs2_read_kstat (nfs2_ksp_server, "server");
386 #endif /* defined(HAVE_LIBKSTAT) */
389 # define nfs_read NULL
390 #endif /* NFS_HAVE_READ */
392 void module_register (void)
394 plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
395 plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
396 plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);