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