xref: /freebsd/usr.bin/nfsstat/nfsstat.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
1 /*
2  * Copyright (c) 1983, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 4. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 #ifndef lint
34 static const char copyright[] =
35 "@(#) Copyright (c) 1983, 1989, 1993\n\
36 	The Regents of the University of California.  All rights reserved.\n";
37 #endif /* not lint */
38 
39 #ifndef lint
40 #if 0
41 static char sccsid[] = "@(#)nfsstat.c	8.2 (Berkeley) 3/31/95";
42 #endif
43 static const char rcsid[] =
44   "$FreeBSD$";
45 #endif /* not lint */
46 
47 #include <sys/param.h>
48 #include <sys/module.h>
49 #include <sys/mount.h>
50 #include <sys/time.h>
51 #include <sys/sysctl.h>
52 #include <nfs/nfsproto.h>
53 #include <nfsclient/nfs.h>
54 #include <nfsserver/nfs.h>
55 #include <nfs/nfssvc.h>
56 
57 #include <fs/nfs/nfsport.h>
58 
59 #include <signal.h>
60 #include <fcntl.h>
61 #include <ctype.h>
62 #include <errno.h>
63 #include <limits.h>
64 #include <nlist.h>
65 #include <unistd.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <paths.h>
70 #include <err.h>
71 
72 static int widemode = 0;
73 static int zflag = 0;
74 static int printtitle = 1;
75 static struct ext_nfsstats ext_nfsstats;
76 static int extra_output = 0;
77 
78 static void intpr(int, int);
79 static void printhdr(int, int);
80 static void usage(void);
81 static char *sperc1(int, int);
82 static char *sperc2(int, int);
83 static void exp_intpr(int, int);
84 static void exp_sidewaysintpr(u_int, int, int);
85 
86 #define DELTA(field)	(nfsstats.field - lastst.field)
87 
88 int
89 main(int argc, char **argv)
90 {
91 	u_int interval;
92 	int clientOnly = -1;
93 	int serverOnly = -1;
94 	int ch;
95 	char *memf, *nlistf;
96 	int mntlen, i;
97 	char buf[1024];
98 	struct statfs *mntbuf;
99 	struct nfscl_dumpmntopts dumpmntopts;
100 
101 	interval = 0;
102 	memf = nlistf = NULL;
103 	while ((ch = getopt(argc, argv, "cesWM:mN:w:z")) != -1)
104 		switch(ch) {
105 		case 'M':
106 			memf = optarg;
107 			break;
108 		case 'm':
109 			/* Display mount options for NFS mount points. */
110 			mntlen = getmntinfo(&mntbuf, MNT_NOWAIT);
111 			for (i = 0; i < mntlen; i++) {
112 				if (strcmp(mntbuf->f_fstypename, "nfs") == 0) {
113 					dumpmntopts.ndmnt_fname =
114 					    mntbuf->f_mntonname;
115 					dumpmntopts.ndmnt_buf = buf;
116 					dumpmntopts.ndmnt_blen = sizeof(buf);
117 					if (nfssvc(NFSSVC_DUMPMNTOPTS,
118 					    &dumpmntopts) >= 0)
119 						printf("%s on %s\n%s\n",
120 						    mntbuf->f_mntfromname,
121 						    mntbuf->f_mntonname, buf);
122 					else if (errno == EPERM)
123 						errx(1, "Only priviledged users"
124 						    " can use the -m option");
125 				}
126 				mntbuf++;
127 			}
128 			exit(0);
129 		case 'N':
130 			nlistf = optarg;
131 			break;
132 		case 'W':
133 			widemode = 1;
134 			break;
135 		case 'w':
136 			interval = atoi(optarg);
137 			break;
138 		case 'c':
139 			clientOnly = 1;
140 			if (serverOnly < 0)
141 				serverOnly = 0;
142 			break;
143 		case 's':
144 			serverOnly = 1;
145 			if (clientOnly < 0)
146 				clientOnly = 0;
147 			break;
148 		case 'z':
149 			zflag = 1;
150 			break;
151 		case 'e':
152 			extra_output = 1;
153 			break;
154 		case '?':
155 		default:
156 			usage();
157 		}
158 	argc -= optind;
159 	argv += optind;
160 
161 #define	BACKWARD_COMPATIBILITY
162 #ifdef	BACKWARD_COMPATIBILITY
163 	if (*argv) {
164 		interval = atoi(*argv);
165 		if (*++argv) {
166 			nlistf = *argv;
167 			if (*++argv)
168 				memf = *argv;
169 		}
170 	}
171 #endif
172 	if (modfind("nfscommon") < 0)
173 		errx(1, "NFS client/server not loaded");
174 
175 	if (interval) {
176 		exp_sidewaysintpr(interval, clientOnly, serverOnly);
177 	} else {
178 		if (extra_output != 0)
179 			exp_intpr(clientOnly, serverOnly);
180 		else
181 			intpr(clientOnly, serverOnly);
182 	}
183 	exit(0);
184 }
185 
186 /*
187  * Print a description of the nfs stats.
188  */
189 static void
190 intpr(int clientOnly, int serverOnly)
191 {
192 	int nfssvc_flag;
193 
194 	nfssvc_flag = NFSSVC_GETSTATS;
195 	if (zflag != 0) {
196 		if (clientOnly != 0)
197 			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
198 		if (serverOnly != 0)
199 			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
200 	}
201 	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
202 		err(1, "Can't get stats");
203 	if (clientOnly) {
204 		printf("Client Info:\n");
205 		printf("Rpc Counts:\n");
206 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
207 			"Getattr", "Setattr", "Lookup", "Readlink", "Read",
208 			"Write", "Create", "Remove");
209 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
210 			ext_nfsstats.rpccnt[NFSPROC_GETATTR],
211 			ext_nfsstats.rpccnt[NFSPROC_SETATTR],
212 			ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
213 			ext_nfsstats.rpccnt[NFSPROC_READLINK],
214 			ext_nfsstats.rpccnt[NFSPROC_READ],
215 			ext_nfsstats.rpccnt[NFSPROC_WRITE],
216 			ext_nfsstats.rpccnt[NFSPROC_CREATE],
217 			ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
218 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
219 			"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
220 			"Readdir", "RdirPlus", "Access");
221 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
222 			ext_nfsstats.rpccnt[NFSPROC_RENAME],
223 			ext_nfsstats.rpccnt[NFSPROC_LINK],
224 			ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
225 			ext_nfsstats.rpccnt[NFSPROC_MKDIR],
226 			ext_nfsstats.rpccnt[NFSPROC_RMDIR],
227 			ext_nfsstats.rpccnt[NFSPROC_READDIR],
228 			ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
229 			ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
230 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
231 			"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
232 		printf("%9d %9d %9d %9d %9d\n",
233 			ext_nfsstats.rpccnt[NFSPROC_MKNOD],
234 			ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
235 			ext_nfsstats.rpccnt[NFSPROC_FSINFO],
236 			ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
237 			ext_nfsstats.rpccnt[NFSPROC_COMMIT]);
238 		printf("Rpc Info:\n");
239 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
240 			"TimedOut", "Invalid", "X Replies", "Retries",
241 			"Requests");
242 		printf("%9d %9d %9d %9d %9d\n",
243 			ext_nfsstats.rpctimeouts,
244 			ext_nfsstats.rpcinvalid,
245 			ext_nfsstats.rpcunexpected,
246 			ext_nfsstats.rpcretries,
247 			ext_nfsstats.rpcrequests);
248 		printf("Cache Info:\n");
249 		printf("%9.9s %9.9s %9.9s %9.9s",
250 			"Attr Hits", "Misses", "Lkup Hits", "Misses");
251 		printf(" %9.9s %9.9s %9.9s %9.9s\n",
252 			"BioR Hits", "Misses", "BioW Hits", "Misses");
253 		printf("%9d %9d %9d %9d",
254 			ext_nfsstats.attrcache_hits,
255 			ext_nfsstats.attrcache_misses,
256 			ext_nfsstats.lookupcache_hits,
257 			ext_nfsstats.lookupcache_misses);
258 		printf(" %9d %9d %9d %9d\n",
259 			ext_nfsstats.biocache_reads -
260 			ext_nfsstats.read_bios,
261 			ext_nfsstats.read_bios,
262 			ext_nfsstats.biocache_writes -
263 			ext_nfsstats.write_bios,
264 			ext_nfsstats.write_bios);
265 		printf("%9.9s %9.9s %9.9s %9.9s",
266 			"BioRLHits", "Misses", "BioD Hits", "Misses");
267 		printf(" %9.9s %9.9s %9.9s %9.9s\n", "DirE Hits", "Misses", "Accs Hits", "Misses");
268 		printf("%9d %9d %9d %9d",
269 			ext_nfsstats.biocache_readlinks -
270 			ext_nfsstats.readlink_bios,
271 			ext_nfsstats.readlink_bios,
272 			ext_nfsstats.biocache_readdirs -
273 			ext_nfsstats.readdir_bios,
274 			ext_nfsstats.readdir_bios);
275 		printf(" %9d %9d %9d %9d\n",
276 			ext_nfsstats.direofcache_hits,
277 			ext_nfsstats.direofcache_misses,
278 			ext_nfsstats.accesscache_hits,
279 			ext_nfsstats.accesscache_misses);
280 	}
281 	if (serverOnly) {
282 		printf("\nServer Info:\n");
283 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
284 			"Getattr", "Setattr", "Lookup", "Readlink", "Read",
285 			"Write", "Create", "Remove");
286 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
287 			ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
288 			ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
289 			ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
290 			ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
291 			ext_nfsstats.srvrpccnt[NFSV4OP_READ],
292 			ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
293 			ext_nfsstats.srvrpccnt[NFSV4OP_CREATE],
294 			ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
295 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
296 			"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
297 			"Readdir", "RdirPlus", "Access");
298 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
299 			ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
300 			ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
301 			ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
302 			ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
303 			ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
304 			ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
305 			ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
306 			ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
307 		printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
308 			"Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit");
309 		printf("%9d %9d %9d %9d %9d\n",
310 			ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
311 			ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
312 			ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
313 			ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
314 			ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT]);
315 		printf("Server Ret-Failed\n");
316 		printf("%17d\n", ext_nfsstats.srvrpc_errs);
317 		printf("Server Faults\n");
318 		printf("%13d\n", ext_nfsstats.srv_errs);
319 		printf("Server Cache Stats:\n");
320 		printf("%9.9s %9.9s %9.9s %9.9s\n",
321 			"Inprog", "Idem", "Non-idem", "Misses");
322 		printf("%9d %9d %9d %9d\n",
323 			ext_nfsstats.srvcache_inproghits,
324 			ext_nfsstats.srvcache_idemdonehits,
325 			ext_nfsstats.srvcache_nonidemdonehits,
326 			ext_nfsstats.srvcache_misses);
327 		printf("Server Write Gathering:\n");
328 		printf("%9.9s %9.9s %9.9s\n",
329 			"WriteOps", "WriteRPC", "Opsaved");
330 		/*
331 		 * The new client doesn't do write gathering. It was
332 		 * only useful for NFSv2.
333 		 */
334 		printf("%9d %9d %9d\n",
335 			ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
336 			ext_nfsstats.srvrpccnt[NFSV4OP_WRITE], 0);
337 	}
338 }
339 
340 static void
341 printhdr(int clientOnly, int serverOnly)
342 {
343 	printf("%s%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s",
344 	    ((serverOnly && clientOnly) ? "        " : " "),
345 	    "GtAttr", "Lookup", "Rdlink", "Read", "Write", "Rename",
346 	    "Access", "Rddir");
347 	if (widemode && clientOnly) {
348 		printf(" Attr Lkup BioR BioW Accs BioD");
349 	}
350 	printf("\n");
351 	fflush(stdout);
352 }
353 
354 static void
355 usage(void)
356 {
357 	(void)fprintf(stderr,
358 	    "usage: nfsstat [-cemszW] [-M core] [-N system] [-w wait]\n");
359 	exit(1);
360 }
361 
362 static char SPBuf[64][8];
363 static int SPIndex;
364 
365 static char *
366 sperc1(int hits, int misses)
367 {
368 	char *p = SPBuf[SPIndex];
369 
370 	if (hits + misses) {
371 		sprintf(p, "%3d%%",
372 		    (int)(char)((quad_t)hits * 100 / (hits + misses)));
373 	} else {
374 		sprintf(p, "   -");
375 	}
376 	SPIndex = (SPIndex + 1) & 63;
377 	return(p);
378 }
379 
380 static char *
381 sperc2(int ttl, int misses)
382 {
383 	char *p = SPBuf[SPIndex];
384 
385 	if (ttl) {
386 		sprintf(p, "%3d%%",
387 		    (int)(char)((quad_t)(ttl - misses) * 100 / ttl));
388 	} else {
389 		sprintf(p, "   -");
390 	}
391 	SPIndex = (SPIndex + 1) & 63;
392 	return(p);
393 }
394 
395 /*
396  * Print a description of the nfs stats for the experimental client/server.
397  */
398 static void
399 exp_intpr(int clientOnly, int serverOnly)
400 {
401 	int nfssvc_flag;
402 
403 	nfssvc_flag = NFSSVC_GETSTATS;
404 	if (zflag != 0) {
405 		if (clientOnly != 0)
406 			nfssvc_flag |= NFSSVC_ZEROCLTSTATS;
407 		if (serverOnly != 0)
408 			nfssvc_flag |= NFSSVC_ZEROSRVSTATS;
409 	}
410 	if (nfssvc(nfssvc_flag, &ext_nfsstats) < 0)
411 		err(1, "Can't get stats");
412 	if (clientOnly != 0) {
413 		if (printtitle) {
414 			printf("Client Info:\n");
415 			printf("Rpc Counts:\n");
416 			printf(
417 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
418 			    , "Getattr", "Setattr", "Lookup", "Readlink",
419 			    "Read", "Write", "Create", "Remove");
420 		}
421 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
422 		    ext_nfsstats.rpccnt[NFSPROC_GETATTR],
423 		    ext_nfsstats.rpccnt[NFSPROC_SETATTR],
424 		    ext_nfsstats.rpccnt[NFSPROC_LOOKUP],
425 		    ext_nfsstats.rpccnt[NFSPROC_READLINK],
426 		    ext_nfsstats.rpccnt[NFSPROC_READ],
427 		    ext_nfsstats.rpccnt[NFSPROC_WRITE],
428 		    ext_nfsstats.rpccnt[NFSPROC_CREATE],
429 		    ext_nfsstats.rpccnt[NFSPROC_REMOVE]);
430 		if (printtitle)
431 			printf(
432 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
433 			    , "Rename", "Link", "Symlink", "Mkdir", "Rmdir",
434 			    "Readdir", "RdirPlus", "Access");
435 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
436 		    ext_nfsstats.rpccnt[NFSPROC_RENAME],
437 		    ext_nfsstats.rpccnt[NFSPROC_LINK],
438 		    ext_nfsstats.rpccnt[NFSPROC_SYMLINK],
439 		    ext_nfsstats.rpccnt[NFSPROC_MKDIR],
440 		    ext_nfsstats.rpccnt[NFSPROC_RMDIR],
441 		    ext_nfsstats.rpccnt[NFSPROC_READDIR],
442 		    ext_nfsstats.rpccnt[NFSPROC_READDIRPLUS],
443 		    ext_nfsstats.rpccnt[NFSPROC_ACCESS]);
444 		if (printtitle)
445 			printf(
446 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
447 			    , "Mknod", "Fsstat", "Fsinfo", "PathConf",
448 			    "Commit", "SetClId", "SetClIdCf", "Lock");
449 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
450 		    ext_nfsstats.rpccnt[NFSPROC_MKNOD],
451 		    ext_nfsstats.rpccnt[NFSPROC_FSSTAT],
452 		    ext_nfsstats.rpccnt[NFSPROC_FSINFO],
453 		    ext_nfsstats.rpccnt[NFSPROC_PATHCONF],
454 		    ext_nfsstats.rpccnt[NFSPROC_COMMIT],
455 		    ext_nfsstats.rpccnt[NFSPROC_SETCLIENTID],
456 		    ext_nfsstats.rpccnt[NFSPROC_SETCLIENTIDCFRM],
457 		    ext_nfsstats.rpccnt[NFSPROC_LOCK]);
458 		if (printtitle)
459 			printf("%9.9s %9.9s %9.9s %9.9s\n",
460 			    "LockT", "LockU", "Open", "OpenCfr");
461 		printf("%9d %9d %9d %9d\n",
462 		    ext_nfsstats.rpccnt[NFSPROC_LOCKT],
463 		    ext_nfsstats.rpccnt[NFSPROC_LOCKU],
464 		    ext_nfsstats.rpccnt[NFSPROC_OPEN],
465 		    ext_nfsstats.rpccnt[NFSPROC_OPENCONFIRM]);
466 		if (printtitle)
467 			printf(
468 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
469 			    , "OpenOwner", "Opens", "LockOwner",
470 			    "Locks", "Delegs", "LocalOwn",
471 			    "LocalOpen", "LocalLOwn");
472 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
473 		    ext_nfsstats.clopenowners,
474 		    ext_nfsstats.clopens,
475 		    ext_nfsstats.cllockowners,
476 		    ext_nfsstats.cllocks,
477 		    ext_nfsstats.cldelegates,
478 		    ext_nfsstats.cllocalopenowners,
479 		    ext_nfsstats.cllocalopens,
480 		    ext_nfsstats.cllocallockowners);
481 		if (printtitle)
482 			printf("%9.9s\n", "LocalLock");
483 		printf("%9d\n", ext_nfsstats.cllocallocks);
484 		if (printtitle) {
485 			printf("Rpc Info:\n");
486 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
487 			    "TimedOut", "Invalid", "X Replies", "Retries",
488 			    "Requests");
489 		}
490 		printf("%9d %9d %9d %9d %9d\n",
491 		    ext_nfsstats.rpctimeouts,
492 		    ext_nfsstats.rpcinvalid,
493 		    ext_nfsstats.rpcunexpected,
494 		    ext_nfsstats.rpcretries,
495 		    ext_nfsstats.rpcrequests);
496 		if (printtitle) {
497 			printf("Cache Info:\n");
498 			printf("%9.9s %9.9s %9.9s %9.9s",
499 			    "Attr Hits", "Misses", "Lkup Hits", "Misses");
500 			printf(" %9.9s %9.9s %9.9s %9.9s\n",
501 			    "BioR Hits", "Misses", "BioW Hits", "Misses");
502 		}
503 		printf("%9d %9d %9d %9d",
504 		    ext_nfsstats.attrcache_hits,
505 		    ext_nfsstats.attrcache_misses,
506 		    ext_nfsstats.lookupcache_hits,
507 		    ext_nfsstats.lookupcache_misses);
508 		printf(" %9d %9d %9d %9d\n",
509 		    ext_nfsstats.biocache_reads - ext_nfsstats.read_bios,
510 		    ext_nfsstats.read_bios,
511 		    ext_nfsstats.biocache_writes - ext_nfsstats.write_bios,
512 		    ext_nfsstats.write_bios);
513 		if (printtitle) {
514 			printf("%9.9s %9.9s %9.9s %9.9s",
515 			    "BioRLHits", "Misses", "BioD Hits", "Misses");
516 			printf(" %9.9s %9.9s\n", "DirE Hits", "Misses");
517 		}
518 		printf("%9d %9d %9d %9d",
519 		    ext_nfsstats.biocache_readlinks -
520 		    ext_nfsstats.readlink_bios,
521 		    ext_nfsstats.readlink_bios,
522 		    ext_nfsstats.biocache_readdirs -
523 		    ext_nfsstats.readdir_bios,
524 		    ext_nfsstats.readdir_bios);
525 		printf(" %9d %9d\n",
526 		    ext_nfsstats.direofcache_hits,
527 		    ext_nfsstats.direofcache_misses);
528 	}
529 	if (serverOnly != 0) {
530 		if (printtitle) {
531 			printf("\nServer Info:\n");
532 			printf(
533 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
534 			    , "Getattr", "Setattr", "Lookup", "Readlink",
535 			    "Read", "Write", "Create", "Remove");
536 		}
537 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
538 		    ext_nfsstats.srvrpccnt[NFSV4OP_GETATTR],
539 		    ext_nfsstats.srvrpccnt[NFSV4OP_SETATTR],
540 		    ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUP],
541 		    ext_nfsstats.srvrpccnt[NFSV4OP_READLINK],
542 		    ext_nfsstats.srvrpccnt[NFSV4OP_READ],
543 		    ext_nfsstats.srvrpccnt[NFSV4OP_WRITE],
544 		    ext_nfsstats.srvrpccnt[NFSV4OP_V3CREATE],
545 		    ext_nfsstats.srvrpccnt[NFSV4OP_REMOVE]);
546 		if (printtitle)
547 			printf(
548 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
549 			    , "Rename", "Link", "Symlink", "Mkdir", "Rmdir",
550 			    "Readdir", "RdirPlus", "Access");
551 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
552 		    ext_nfsstats.srvrpccnt[NFSV4OP_RENAME],
553 		    ext_nfsstats.srvrpccnt[NFSV4OP_LINK],
554 		    ext_nfsstats.srvrpccnt[NFSV4OP_SYMLINK],
555 		    ext_nfsstats.srvrpccnt[NFSV4OP_MKDIR],
556 		    ext_nfsstats.srvrpccnt[NFSV4OP_RMDIR],
557 		    ext_nfsstats.srvrpccnt[NFSV4OP_READDIR],
558 		    ext_nfsstats.srvrpccnt[NFSV4OP_READDIRPLUS],
559 		    ext_nfsstats.srvrpccnt[NFSV4OP_ACCESS]);
560 		if (printtitle)
561 			printf(
562 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
563 			    , "Mknod", "Fsstat", "Fsinfo", "PathConf",
564 			    "Commit", "LookupP", "SetClId", "SetClIdCf");
565 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
566 		    ext_nfsstats.srvrpccnt[NFSV4OP_MKNOD],
567 		    ext_nfsstats.srvrpccnt[NFSV4OP_FSSTAT],
568 		    ext_nfsstats.srvrpccnt[NFSV4OP_FSINFO],
569 		    ext_nfsstats.srvrpccnt[NFSV4OP_PATHCONF],
570 		    ext_nfsstats.srvrpccnt[NFSV4OP_COMMIT],
571 		    ext_nfsstats.srvrpccnt[NFSV4OP_LOOKUPP],
572 		    ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTID],
573 		    ext_nfsstats.srvrpccnt[NFSV4OP_SETCLIENTIDCFRM]);
574 		if (printtitle)
575 			printf(
576 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
577 			    , "Open", "OpenAttr", "OpenDwnGr", "OpenCfrm",
578 			    "DelePurge", "DeleRet", "GetFH", "Lock");
579 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
580 		    ext_nfsstats.srvrpccnt[NFSV4OP_OPEN],
581 		    ext_nfsstats.srvrpccnt[NFSV4OP_OPENATTR],
582 		    ext_nfsstats.srvrpccnt[NFSV4OP_OPENDOWNGRADE],
583 		    ext_nfsstats.srvrpccnt[NFSV4OP_OPENCONFIRM],
584 		    ext_nfsstats.srvrpccnt[NFSV4OP_DELEGPURGE],
585 		    ext_nfsstats.srvrpccnt[NFSV4OP_DELEGRETURN],
586 		    ext_nfsstats.srvrpccnt[NFSV4OP_GETFH],
587 		    ext_nfsstats.srvrpccnt[NFSV4OP_LOCK]);
588 		if (printtitle)
589 			printf(
590 			    "%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n"
591 			    , "LockT", "LockU", "Close", "Verify", "NVerify",
592 			    "PutFH", "PutPubFH", "PutRootFH");
593 		printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
594 		    ext_nfsstats.srvrpccnt[NFSV4OP_LOCKT],
595 		    ext_nfsstats.srvrpccnt[NFSV4OP_LOCKU],
596 		    ext_nfsstats.srvrpccnt[NFSV4OP_CLOSE],
597 		    ext_nfsstats.srvrpccnt[NFSV4OP_VERIFY],
598 		    ext_nfsstats.srvrpccnt[NFSV4OP_NVERIFY],
599 		    ext_nfsstats.srvrpccnt[NFSV4OP_PUTFH],
600 		    ext_nfsstats.srvrpccnt[NFSV4OP_PUTPUBFH],
601 		    ext_nfsstats.srvrpccnt[NFSV4OP_PUTROOTFH]);
602 		if (printtitle)
603 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
604 			    "Renew", "RestoreFH", "SaveFH", "Secinfo",
605 			    "RelLckOwn", "V4Create");
606 		printf("%9d %9d %9d %9d %9d %9d\n",
607 		    ext_nfsstats.srvrpccnt[NFSV4OP_RENEW],
608 		    ext_nfsstats.srvrpccnt[NFSV4OP_RESTOREFH],
609 		    ext_nfsstats.srvrpccnt[NFSV4OP_SAVEFH],
610 		    ext_nfsstats.srvrpccnt[NFSV4OP_SECINFO],
611 		    ext_nfsstats.srvrpccnt[NFSV4OP_RELEASELCKOWN],
612 		    ext_nfsstats.srvrpccnt[NFSV4OP_CREATE]);
613 		if (printtitle) {
614 			printf("Server:\n");
615 			printf("%9.9s %9.9s %9.9s\n",
616 			    "Retfailed", "Faults", "Clients");
617 		}
618 		printf("%9d %9d %9d\n",
619 		    ext_nfsstats.srv_errs, ext_nfsstats.srvrpc_errs,
620 		    ext_nfsstats.srvclients);
621 		if (printtitle)
622 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s \n",
623 			    "OpenOwner", "Opens", "LockOwner",
624 			    "Locks", "Delegs");
625 		printf("%9d %9d %9d %9d %9d \n",
626 		    ext_nfsstats.srvopenowners,
627 		    ext_nfsstats.srvopens,
628 		    ext_nfsstats.srvlockowners,
629 		    ext_nfsstats.srvlocks,
630 		    ext_nfsstats.srvdelegates);
631 		if (printtitle) {
632 			printf("Server Cache Stats:\n");
633 			printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
634 			    "Inprog", "Idem", "Non-idem", "Misses",
635 			    "CacheSize", "TCPPeak");
636 		}
637 		printf("%9d %9d %9d %9d %9d %9d\n",
638 		    ext_nfsstats.srvcache_inproghits,
639 		    ext_nfsstats.srvcache_idemdonehits,
640 		    ext_nfsstats.srvcache_nonidemdonehits,
641 		    ext_nfsstats.srvcache_misses,
642 		    ext_nfsstats.srvcache_size,
643 		    ext_nfsstats.srvcache_tcppeak);
644 	}
645 }
646 
647 /*
648  * Print a running summary of nfs statistics for the experimental client and/or
649  * server.
650  * Repeat display every interval seconds, showing statistics
651  * collected over that interval.  Assumes that interval is non-zero.
652  * First line printed at top of screen is always cumulative.
653  */
654 static void
655 exp_sidewaysintpr(u_int interval, int clientOnly, int serverOnly)
656 {
657 	struct ext_nfsstats nfsstats, lastst, *ext_nfsstatsp;
658 	int hdrcnt = 1;
659 
660 	ext_nfsstatsp = &lastst;
661 	if (nfssvc(NFSSVC_GETSTATS, ext_nfsstatsp) < 0)
662 		err(1, "Can't get stats");
663 	sleep(interval);
664 
665 	for (;;) {
666 		ext_nfsstatsp = &nfsstats;
667 		if (nfssvc(NFSSVC_GETSTATS, ext_nfsstatsp) < 0)
668 			err(1, "Can't get stats");
669 
670 		if (--hdrcnt == 0) {
671 			printhdr(clientOnly, serverOnly);
672 			if (clientOnly && serverOnly)
673 				hdrcnt = 10;
674 			else
675 				hdrcnt = 20;
676 		}
677 		if (clientOnly) {
678 		    printf("%s %6d %6d %6d %6d %6d %6d %6d %6d",
679 			((clientOnly && serverOnly) ? "Client:" : ""),
680 			DELTA(rpccnt[NFSPROC_GETATTR]),
681 			DELTA(rpccnt[NFSPROC_LOOKUP]),
682 			DELTA(rpccnt[NFSPROC_READLINK]),
683 			DELTA(rpccnt[NFSPROC_READ]),
684 			DELTA(rpccnt[NFSPROC_WRITE]),
685 			DELTA(rpccnt[NFSPROC_RENAME]),
686 			DELTA(rpccnt[NFSPROC_ACCESS]),
687 			DELTA(rpccnt[NFSPROC_READDIR]) +
688 			DELTA(rpccnt[NFSPROC_READDIRPLUS])
689 		    );
690 		    if (widemode) {
691 			    printf(" %s %s %s %s %s %s",
692 				sperc1(DELTA(attrcache_hits),
693 				    DELTA(attrcache_misses)),
694 				sperc1(DELTA(lookupcache_hits),
695 				    DELTA(lookupcache_misses)),
696 				sperc2(DELTA(biocache_reads),
697 				    DELTA(read_bios)),
698 				sperc2(DELTA(biocache_writes),
699 				    DELTA(write_bios)),
700 				sperc1(DELTA(accesscache_hits),
701 				    DELTA(accesscache_misses)),
702 				sperc2(DELTA(biocache_readdirs),
703 				    DELTA(readdir_bios))
704 			    );
705 		    }
706 		    printf("\n");
707 		}
708 		if (serverOnly) {
709 		    printf("%s %6d %6d %6d %6d %6d %6d %6d %6d",
710 			((clientOnly && serverOnly) ? "Server:" : ""),
711 			DELTA(srvrpccnt[NFSV4OP_GETATTR]),
712 			DELTA(srvrpccnt[NFSV4OP_LOOKUP]),
713 			DELTA(srvrpccnt[NFSV4OP_READLINK]),
714 			DELTA(srvrpccnt[NFSV4OP_READ]),
715 			DELTA(srvrpccnt[NFSV4OP_WRITE]),
716 			DELTA(srvrpccnt[NFSV4OP_RENAME]),
717 			DELTA(srvrpccnt[NFSV4OP_ACCESS]),
718 			DELTA(srvrpccnt[NFSV4OP_READDIR]) +
719 			DELTA(srvrpccnt[NFSV4OP_READDIRPLUS]));
720 		    printf("\n");
721 		}
722 		lastst = nfsstats;
723 		fflush(stdout);
724 		sleep(interval);
725 	}
726 	/*NOTREACHED*/
727 }
728