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