nfsstat.c revision 292686
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
34static 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
41static char sccsid[] = "@(#)nfsstat.c	8.2 (Berkeley) 3/31/95";
42#endif
43static const char rcsid[] =
44  "$FreeBSD: head/usr.bin/nfsstat/nfsstat.c 292686 2015-12-24 11:41:21Z bapt $";
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
72static int widemode = 0;
73static int zflag = 0;
74static int printtitle = 1;
75static struct ext_nfsstats ext_nfsstats;
76static int extra_output = 0;
77
78static void intpr(int, int);
79static void printhdr(int, int);
80static void usage(void);
81static char *sperc1(int, int);
82static char *sperc2(int, int);
83static void exp_intpr(int, int);
84static void exp_sidewaysintpr(u_int, int, int);
85
86#define DELTA(field)	(nfsstats.field - lastst.field)
87
88int
89main(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 */
189static void
190intpr(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
340static void
341printhdr(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
354static void
355usage(void)
356{
357	(void)fprintf(stderr,
358	    "usage: nfsstat [-cemszW] [-M core] [-N system] [-w wait]\n");
359	exit(1);
360}
361
362static char SPBuf[64][8];
363static int SPIndex;
364
365static char *
366sperc1(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
380static char *
381sperc2(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 */
398static void
399exp_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 */
654static void
655exp_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