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