1 /* $OpenBSD: nfs.c,v 1.10 2024/05/18 09:02:34 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2009 Jasper Lievisse Adriaanse <jasper@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 *
18 */
19
20 #include <sys/types.h>
21 #include <sys/mount.h>
22 #include <sys/signal.h>
23 #include <sys/sysctl.h>
24 #include <nfs/rpcv2.h>
25 #include <nfs/nfsproto.h>
26 #include <nfs/nfs.h>
27
28 #include <err.h>
29 #include <errno.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "systat.h"
35
36 int select_client(void);
37 int select_server(void);
38 int read_nfs(void);
39 void print_client(void);
40 void print_server(void);
41
42 struct nfsstats nfsstats;
43 int num_client = 0;
44 int num_server = 0;
45
46 field_def fields_nfs[] = {
47 /* Client */
48 {"RPC COUNTS", 10, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
49 {"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
50 {"RPC INFO", 14, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
51 {"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
52 {"CACHE INFO", 10, 12, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
53 {"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
54
55 /* Server */
56 {"RPC COUNTS", 10, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
57 {"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
58 {"CACHE STATS", 14, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
59 {"", 12, 14, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
60 {"WRITES", 10, 12, 1, FLD_ALIGN_LEFT, -1, 0, 0, 0},
61 {"", 10, 12, 1, FLD_ALIGN_RIGHT, -1, 0, 0, 0},
62 };
63
64 /* _V suffixed fields indicate a value column. */
65 /* Client */
66 #define FLD_NFS_C_RPC_COUNTS FIELD_ADDR(fields_nfs,0)
67 #define FLD_NFS_C_RPC_COUNTS_V FIELD_ADDR(fields_nfs,1)
68 #define FLD_NFS_C_RPC_INFO FIELD_ADDR(fields_nfs,2)
69 #define FLD_NFS_C_RPC_INFO_V FIELD_ADDR(fields_nfs,3)
70 #define FLD_NFS_C_CACHE_INFO FIELD_ADDR(fields_nfs,4)
71 #define FLD_NFS_C_CACHE_V FIELD_ADDR(fields_nfs,5)
72
73 /* Server */
74 #define FLD_NFS_S_RPC_COUNTS FIELD_ADDR(fields_nfs,6)
75 #define FLD_NFS_S_RPC_COUNTS_V FIELD_ADDR(fields_nfs,7)
76 #define FLD_NFS_S_CACHE_STATS FIELD_ADDR(fields_nfs,8)
77 #define FLD_NFS_S_CACHE_STATS_V FIELD_ADDR(fields_nfs,9)
78 #define FLD_NFS_S_WRITES FIELD_ADDR(fields_nfs,10)
79 #define FLD_NFS_S_WRITES_V FIELD_ADDR(fields_nfs,11)
80
81 /* Define views */
82 field_def *view_nfs_0[] = {
83 FLD_NFS_C_RPC_COUNTS, FLD_NFS_C_RPC_COUNTS_V, FLD_NFS_C_RPC_INFO,
84 FLD_NFS_C_RPC_INFO_V, FLD_NFS_C_CACHE_INFO, FLD_NFS_C_CACHE_V ,NULL
85 };
86
87 field_def *view_nfs_1[] = {
88 FLD_NFS_S_RPC_COUNTS, FLD_NFS_S_RPC_COUNTS_V, FLD_NFS_S_CACHE_STATS,
89 FLD_NFS_S_CACHE_STATS_V, FLD_NFS_S_WRITES, FLD_NFS_S_WRITES_V, NULL
90 };
91
92 /* Define view managers */
93 struct view_manager nfs_client_mgr = {
94 "Client", select_client, read_nfs, NULL, print_header,
95 print_client, keyboard_callback, NULL, NULL
96 };
97
98 struct view_manager nfs_server_mgr = {
99 "Server", select_server, read_nfs, NULL, print_header,
100 print_server, keyboard_callback, NULL, NULL
101 };
102
103 field_view views_nfs[] = {
104 {view_nfs_0, "nfsclient", '8', &nfs_client_mgr},
105 {view_nfs_1, "nfsserver", '9', &nfs_server_mgr},
106 {NULL, NULL, 0, NULL}
107 };
108
109 int
select_client(void)110 select_client(void)
111 {
112 num_disp = num_client;
113 return(0);
114 }
115
116 int
select_server(void)117 select_server(void)
118 {
119 num_disp = num_server;
120 return(0);
121 }
122
123 int
initnfs(void)124 initnfs(void)
125 {
126 field_view *v;
127
128 for (v = views_nfs; v->name != NULL; v++)
129 add_view(v);
130
131 read_nfs();
132
133 return(0);
134 }
135
136 /*
137 * We get all the information in one go and don't care about
138 * server or client fields (those will be '0' if not applicable).
139 */
140 int
read_nfs(void)141 read_nfs(void)
142 {
143 struct nfsstats *p = &nfsstats;
144 int mib[3];
145 size_t len = sizeof(*p);
146
147 mib[0] = CTL_VFS;
148 mib[1] = 2; /* NETDEV */
149 mib[2] = NFS_NFSSTATS;
150
151 if (sysctl(mib, 3, p, &len, NULL, 0) == -1)
152 return(-1);
153 else
154 return(0);
155 }
156
157
158 /*
159 * As we want a view with multiple columns, mixed with labels and values,
160 * we can't use the regular dance and have to use our own (looong) dance
161 * to build the layout.
162 */
163 void
print_client(void)164 print_client(void)
165 {
166 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Getattr");
167 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
168 nfsstats.rpccnt[NFSPROC_GETATTR]);
169 print_fld_str(FLD_NFS_C_RPC_INFO, "TimedOut");
170 print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpctimeouts);
171 print_fld_str(FLD_NFS_C_CACHE_INFO, "Attr Hits ");
172 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.attrcache_hits);
173 end_line();
174
175 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Setattr");
176 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
177 nfsstats.rpccnt[NFSPROC_SETATTR]);
178 print_fld_str(FLD_NFS_C_RPC_INFO, "Invalid");
179 print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpcinvalid);
180 print_fld_str(FLD_NFS_C_CACHE_INFO, "Attr Misses");
181 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.attrcache_misses);
182 end_line();
183
184 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Lookup");
185 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
186 nfsstats.rpccnt[NFSPROC_LOOKUP]);
187 print_fld_str(FLD_NFS_C_RPC_INFO, "X Replies");
188 print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpcunexpected);
189 print_fld_str(FLD_NFS_C_CACHE_INFO, "Lkup Hits ");
190 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.lookupcache_hits);
191 end_line();
192
193 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Readlink");
194 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
195 nfsstats.rpccnt[NFSPROC_READLINK]);
196 print_fld_str(FLD_NFS_C_RPC_INFO, "Retries");
197 print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpcretries);
198 print_fld_str(FLD_NFS_C_CACHE_INFO, "Lkup Misses ");
199 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.lookupcache_misses);
200 end_line();
201
202 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Read");
203 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
204 nfsstats.rpccnt[NFSPROC_READ]);
205 print_fld_str(FLD_NFS_C_RPC_INFO, "Requests");
206 print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.rpcrequests);
207 print_fld_str(FLD_NFS_C_CACHE_INFO, "BioR Hits ");
208 print_fld_ssize(FLD_NFS_C_CACHE_V,
209 nfsstats.biocache_reads-nfsstats.read_bios);
210 end_line();
211
212 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Write");
213 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_WRITE]);
214 print_fld_str(FLD_NFS_C_RPC_INFO, "FrcSync");
215 print_fld_ssize(FLD_NFS_C_RPC_INFO_V, nfsstats.forcedsync);
216 print_fld_str(FLD_NFS_C_CACHE_INFO, "BioR Misses");
217 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.read_bios);
218 end_line();
219
220 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Create");
221 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
222 nfsstats.rpccnt[NFSPROC_CREATE]);
223 print_fld_str(FLD_NFS_C_CACHE_INFO, "BioW Hits ");
224 print_fld_ssize(FLD_NFS_C_CACHE_V,
225 nfsstats.biocache_writes-nfsstats.write_bios);
226 end_line();
227
228 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Remove");
229 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
230 nfsstats.rpccnt[NFSPROC_REMOVE]);
231 print_fld_str(FLD_NFS_C_CACHE_INFO, "BioW Misses");
232 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.write_bios);
233 end_line();
234
235 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Rename");
236 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
237 nfsstats.rpccnt[NFSPROC_RENAME]);
238 print_fld_str(FLD_NFS_C_CACHE_INFO, "BioRL Hits ");
239 print_fld_ssize(FLD_NFS_C_CACHE_V,
240 nfsstats.biocache_readlinks-nfsstats.readlink_bios);
241 end_line();
242
243 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Link");
244 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_LINK]);
245 print_fld_str(FLD_NFS_C_CACHE_INFO, "BioRL Misses");
246 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.readlink_bios);
247 end_line();
248
249 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Symlink");
250 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
251 nfsstats.rpccnt[NFSPROC_SYMLINK]);
252 print_fld_str(FLD_NFS_C_CACHE_INFO, "BioD Hits ");
253 print_fld_ssize(FLD_NFS_C_CACHE_V,
254 nfsstats.biocache_readdirs-nfsstats.readdir_bios);
255 end_line();
256
257 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Mkdir");
258 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_MKDIR]);
259 print_fld_str(FLD_NFS_C_CACHE_INFO, "BioD Misses");
260 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.readdir_bios);
261 end_line();
262
263 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Rmdir");
264 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_RMDIR]);
265 print_fld_str(FLD_NFS_C_CACHE_INFO, "DirE Hits ");
266 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.direofcache_hits);
267 end_line();
268
269 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Readdir");
270 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
271 nfsstats.rpccnt[NFSPROC_READDIR]);
272 print_fld_str(FLD_NFS_C_CACHE_INFO, "DirE Misses");
273 print_fld_ssize(FLD_NFS_C_CACHE_V, nfsstats.direofcache_misses);
274 end_line();
275
276 print_fld_str(FLD_NFS_C_RPC_COUNTS, "RdirPlus");
277 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
278 nfsstats.rpccnt[NFSPROC_READDIRPLUS]);
279 end_line();
280
281 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Access");
282 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
283 nfsstats.rpccnt[NFSPROC_ACCESS]);
284 end_line();
285
286 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Mknod");
287 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V, nfsstats.rpccnt[NFSPROC_MKNOD]);
288 end_line();
289
290 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Fsstat");
291 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
292 nfsstats.rpccnt[NFSPROC_FSSTAT]);
293 end_line();
294
295 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Fsinfo");
296 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
297 nfsstats.rpccnt[NFSPROC_FSINFO]);
298 end_line();
299
300 print_fld_str(FLD_NFS_C_RPC_COUNTS, "PathConf");
301 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
302 nfsstats.rpccnt[NFSPROC_PATHCONF]);
303 end_line();
304
305 print_fld_str(FLD_NFS_C_RPC_COUNTS, "Commit");
306 print_fld_ssize(FLD_NFS_C_RPC_COUNTS_V,
307 nfsstats.rpccnt[NFSPROC_COMMIT]);
308 end_line();
309 }
310
311 void
print_server(void)312 print_server(void)
313 {
314 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Getattr");
315 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
316 nfsstats.srvrpccnt[NFSPROC_GETATTR]);
317 print_fld_str(FLD_NFS_S_CACHE_STATS, "Inprog");
318 print_fld_ssize(FLD_NFS_S_CACHE_STATS_V, nfsstats.srvcache_inproghits);
319 print_fld_str(FLD_NFS_S_WRITES, "WriteOps");
320 print_fld_ssize(FLD_NFS_S_WRITES_V, nfsstats.srvvop_writes);
321 end_line();
322
323 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Setattr");
324 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
325 nfsstats.srvrpccnt[NFSPROC_SETATTR]);
326 print_fld_str(FLD_NFS_S_CACHE_STATS, "Idem");
327 print_fld_ssize(FLD_NFS_S_CACHE_STATS_V,
328 nfsstats.srvcache_idemdonehits);
329 print_fld_str(FLD_NFS_S_WRITES, "WriteRPC");
330 print_fld_ssize(FLD_NFS_S_WRITES_V, nfsstats.srvrpccnt[NFSPROC_WRITE]);
331 end_line();
332
333 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Lookup");
334 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
335 nfsstats.srvrpccnt[NFSPROC_LOOKUP]);
336 print_fld_str(FLD_NFS_S_CACHE_STATS, "Non-idem");
337 print_fld_ssize(FLD_NFS_S_CACHE_STATS_V,
338 nfsstats.srvcache_nonidemdonehits);
339 print_fld_str(FLD_NFS_S_WRITES, "Opsaved");
340 print_fld_ssize(FLD_NFS_S_WRITES_V,
341 nfsstats.srvrpccnt[NFSPROC_WRITE] - nfsstats.srvvop_writes);
342 end_line();
343
344 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Readlink");
345 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
346 nfsstats.srvrpccnt[NFSPROC_READLINK]);
347 print_fld_str(FLD_NFS_S_CACHE_STATS, "Misses");
348 print_fld_ssize(FLD_NFS_S_CACHE_STATS_V, nfsstats.srvcache_misses);
349 end_line();
350
351 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Read");
352 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
353 nfsstats.srvrpccnt[NFSPROC_READ]);
354 end_line();
355
356 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Write");
357 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
358 nfsstats.srvrpccnt[NFSPROC_WRITE]);
359 end_line();
360
361 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Create");
362 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
363 nfsstats.srvrpccnt[NFSPROC_CREATE]);
364 end_line();
365
366 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Remove");
367 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
368 nfsstats.srvrpccnt[NFSPROC_REMOVE]);
369 end_line();
370
371 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Rename");
372 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
373 nfsstats.srvrpccnt[NFSPROC_RENAME]);
374 end_line();
375
376 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Link");
377 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
378 nfsstats.srvrpccnt[NFSPROC_LINK]);
379 end_line();
380
381 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Symlink");
382 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
383 nfsstats.srvrpccnt[NFSPROC_SYMLINK]);
384 end_line();
385
386 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Mkdir");
387 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
388 nfsstats.srvrpccnt[NFSPROC_MKDIR]);
389 end_line();
390
391 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Rmdir");
392 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
393 nfsstats.srvrpccnt[NFSPROC_RMDIR]);
394 end_line();
395
396 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Readdir");
397 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
398 nfsstats.srvrpccnt[NFSPROC_READDIR]);
399 end_line();
400
401 print_fld_str(FLD_NFS_S_RPC_COUNTS, "RdirPlus");
402 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
403 nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]);
404 end_line();
405
406 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Access");
407 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
408 nfsstats.srvrpccnt[NFSPROC_ACCESS]);
409 end_line();
410
411 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Mknod");
412 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
413 nfsstats.srvrpccnt[NFSPROC_MKNOD]);
414 end_line();
415
416 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Fsstat");
417 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
418 nfsstats.srvrpccnt[NFSPROC_FSSTAT]);
419 end_line();
420
421 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Fsinfo");
422 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
423 nfsstats.srvrpccnt[NFSPROC_FSINFO]);
424 end_line();
425
426 print_fld_str(FLD_NFS_S_RPC_COUNTS, "PathConf");
427 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
428 nfsstats.srvrpccnt[NFSPROC_PATHCONF]);
429 end_line();
430
431 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Commit");
432 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V,
433 nfsstats.srvrpccnt[NFSPROC_COMMIT]);
434 end_line();
435
436 /* This creates an empty space on screen to separate the two blocks */
437 print_fld_str(FLD_NFS_S_RPC_COUNTS, "");
438 end_line();
439
440 print_fld_str(FLD_NFS_S_RPC_COUNTS, "Ret-Failed");
441 print_fld_ssize(FLD_NFS_S_RPC_COUNTS_V, nfsstats.srvrpc_errs);
442 print_fld_str(FLD_NFS_S_CACHE_STATS, "Faults");
443 print_fld_ssize(FLD_NFS_S_CACHE_STATS_V, nfsstats.srv_errs);
444 end_line();
445 }
446