xref: /original-bsd/usr.bin/nfsstat/nfsstat.c (revision ba762ddc)
1 /*
2  * Copyright (c) 1983, 1989 Regents of the University of California.
3  * 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  * %sccs.include.redist.c%
9  */
10 
11 #ifndef lint
12 char copyright[] =
13 "@(#) Copyright (c) 1983, 1989 Regents of the University of California.\n\
14  All rights reserved.\n";
15 #endif /* not lint */
16 
17 #ifndef lint
18 static char sccsid[] = "@(#)nfsstat.c	5.8 (Berkeley) 04/23/91";
19 #endif /* not lint */
20 
21 #include <sys/param.h>
22 #include <sys/vmmac.h>
23 #include <machine/pte.h>
24 #include <sys/namei.h>
25 #include <sys/mount.h>
26 #include <nfs/nfsv2.h>
27 #include <nfs/nfs.h>
28 #include <signal.h>
29 #include <fcntl.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <nlist.h>
33 #include <unistd.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <paths.h>
38 
39 struct nlist nl[] = {
40 #define	N_NFSSTAT	0
41 	{ "_nfsstats" },
42 #define	N_SYSMAP	1
43 	{ "_Sysmap" },
44 #define	N_SYSSIZE	2
45 	{ "_Syssize" },
46 	"",
47 };
48 
49 struct pte *Sysmap;
50 
51 int kflag, kmem;
52 char *kernel = _PATH_UNIX;
53 char *kmemf = _PATH_KMEM;
54 
55 off_t klseek();
56 void intpr(), printhdr(), sidewaysintpr(), usage();
57 
58 main(argc, argv)
59 	int argc;
60 	char **argv;
61 {
62 	extern int optind;
63 	extern char *optarg;
64 	u_int interval;
65 	int ch;
66 
67 	interval = 0;
68 	while ((ch = getopt(argc, argv, "M:N:w:")) != EOF)
69 		switch(ch) {
70 		case 'M':
71 			kmemf = optarg;
72 			kflag = 1;
73 			break;
74 		case 'N':
75 			kernel = optarg;
76 			break;
77 		case 'w':
78 			interval = atoi(optarg);
79 			break;
80 		case '?':
81 		default:
82 			usage();
83 		}
84 	argc -= optind;
85 	argv += optind;
86 
87 #define	BACKWARD_COMPATIBILITY
88 #ifdef	BACKWARD_COMPATIBILITY
89 	if (*argv) {
90 		kernel = *++argv;
91 		if (*++argv) {
92 			kmemf = *argv;
93 			kflag = 1;
94 		}
95 	}
96 #endif
97 	if (nlist(kernel, nl) < 0 || nl[0].n_type == 0) {
98 		(void)fprintf(stderr, "nfsstate: %s: no namelist\n", kernel);
99 		exit(1);
100 	}
101 	kmem = open(kmemf, O_RDONLY);
102 	if (kmem < 0) {
103 		(void)fprintf(stderr,
104 		    "nfsstat: %s: %s\n", kmemf, strerror(errno));
105 		exit(1);
106 	}
107 	if (kflag) {
108 		off_t off;
109 
110 		Sysmap = (struct pte *)
111 		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
112 		if (!Sysmap) {
113 			(void)fprintf(stderr, "nfsstat: %s\n", strerror(errno));
114 			exit(1);
115 		}
116 		off = nl[N_SYSMAP].n_value & ~KERNBASE;
117 		(void)lseek(kmem, off, L_SET);
118 		(void)read(kmem, (char *)Sysmap,
119 		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
120 	}
121 
122 	if (!nl[N_NFSSTAT].n_value) {
123 		(void)fprintf(stderr, "nfsstat: nfsstats symbol not defined\n");
124 		exit(1);
125 	}
126 	if (interval)
127 		sidewaysintpr(interval, nl[N_NFSSTAT].n_value);
128 	else
129 		intpr(nl[N_NFSSTAT].n_value);
130 	exit(0);
131 }
132 
133 /*
134  * Print a description of the network interfaces.
135  */
136 void
137 intpr(nfsstataddr)
138 	off_t nfsstataddr;
139 {
140 	struct nfsstats nfsstats;
141 
142 	klseek(kmem, nfsstataddr, 0L);
143 	read(kmem, (char *)&nfsstats, sizeof(struct nfsstats));
144 	printf("Client Info:\n");
145 	printf("Rpc Counts:\n");
146 	printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
147 		"Getattr", "Setattr", "Lookup", "Readlink", "Read",
148 		"Write", "Create", "Remove");
149 	printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
150 		nfsstats.rpccnt[1],
151 		nfsstats.rpccnt[2],
152 		nfsstats.rpccnt[4],
153 		nfsstats.rpccnt[5],
154 		nfsstats.rpccnt[6],
155 		nfsstats.rpccnt[8],
156 		nfsstats.rpccnt[9],
157 		nfsstats.rpccnt[10]);
158 	printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
159 		"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
160 		"Readdir", "Statfs");
161 	printf("%9d %9d %9d %9d %9d %9d %9d\n",
162 		nfsstats.rpccnt[11],
163 		nfsstats.rpccnt[12],
164 		nfsstats.rpccnt[13],
165 		nfsstats.rpccnt[14],
166 		nfsstats.rpccnt[15],
167 		nfsstats.rpccnt[16],
168 		nfsstats.rpccnt[17]);
169 	printf("Rpc Info:\n");
170 	printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n",
171 		"TimedOut", "Invalid", "X Replies", "Retries", "Requests");
172 	printf("%9d %9d %9d %9d %9d\n",
173 		nfsstats.rpctimeouts,
174 		nfsstats.rpcinvalid,
175 		nfsstats.rpcunexpected,
176 		nfsstats.rpcretries,
177 		nfsstats.rpcrequests);
178 	printf("Cache Info:\n");
179 	printf("%9.9s %9.9s %9.9s %9.9s",
180 		"Attr Hits", "Misses", "Lkup Hits", "Misses");
181 	printf(" %9.9s %9.9s %9.9s %9.9s\n",
182 		"BioR Hits", "Misses", "BioW Hits", "Misses");
183 	printf("%9d %9d %9d %9d",
184 		nfsstats.attrcache_hits, nfsstats.attrcache_misses,
185 		nfsstats.lookupcache_hits, nfsstats.lookupcache_misses);
186 	printf(" %9d %9d %9d %9d\n",
187 		nfsstats.biocache_reads-nfsstats.read_bios,
188 		nfsstats.read_bios,
189 		nfsstats.biocache_writes-nfsstats.write_bios,
190 		nfsstats.write_bios);
191 	printf("%9.9s %9.9s %9.9s %9.9s",
192 		"BioRLHits", "Misses", "BioD Hits", "Misses");
193 	printf(" %9.9s %9.9s\n", "DirE Hits", "Misses");
194 	printf("%9d %9d %9d %9d",
195 		nfsstats.biocache_readlinks-nfsstats.readlink_bios,
196 		nfsstats.readlink_bios,
197 		nfsstats.biocache_readdirs-nfsstats.readdir_bios,
198 		nfsstats.readdir_bios);
199 	printf(" %9d %9d\n",
200 		nfsstats.direofcache_hits, nfsstats.direofcache_misses);
201 	printf("\nServer Info:\n");
202 	printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
203 		"Getattr", "Setattr", "Lookup", "Readlink", "Read",
204 		"Write", "Create", "Remove");
205 	printf("%9d %9d %9d %9d %9d %9d %9d %9d\n",
206 		nfsstats.srvrpccnt[1],
207 		nfsstats.srvrpccnt[2],
208 		nfsstats.srvrpccnt[4],
209 		nfsstats.srvrpccnt[5],
210 		nfsstats.srvrpccnt[6],
211 		nfsstats.srvrpccnt[8],
212 		nfsstats.srvrpccnt[9],
213 		nfsstats.srvrpccnt[10]);
214 	printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n",
215 		"Rename", "Link", "Symlink", "Mkdir", "Rmdir",
216 		"Readdir", "Statfs");
217 	printf("%9d %9d %9d %9d %9d %9d %9d\n",
218 		nfsstats.srvrpccnt[11],
219 		nfsstats.srvrpccnt[12],
220 		nfsstats.srvrpccnt[13],
221 		nfsstats.srvrpccnt[14],
222 		nfsstats.srvrpccnt[15],
223 		nfsstats.srvrpccnt[16],
224 		nfsstats.srvrpccnt[17]);
225 	printf("Server Ret-Failed\n");
226 	printf("%17d\n", nfsstats.srvrpc_errs);
227 	printf("Server Faults\n");
228 	printf("%13d\n", nfsstats.srv_errs);
229 	printf("Server Cache Stats:\n");
230 	printf("%9.9s %9.9s %9.9s %9.9s\n",
231 		"Inprog", "Idem", "Non-idem", "Misses");
232 	printf("%9d %9d %9d %9d\n",
233 		nfsstats.srvcache_inproghits,
234 		nfsstats.srvcache_idemdonehits,
235 		nfsstats.srvcache_nonidemdonehits,
236 		nfsstats.srvcache_misses);
237 }
238 
239 u_char	signalled;			/* set if alarm goes off "early" */
240 
241 /*
242  * Print a running summary of nfs statistics.
243  * Repeat display every interval seconds, showing statistics
244  * collected over that interval.  Assumes that interval is non-zero.
245  * First line printed at top of screen is always cumulative.
246  */
247 void
248 sidewaysintpr(interval, off)
249 	u_int interval;
250 	off_t off;
251 {
252 	struct nfsstats nfsstats, lastst;
253 	int hdrcnt, oldmask;
254 	void catchalarm();
255 
256 	klseek(kmem, off, 0L);
257 
258 	(void)signal(SIGALRM, catchalarm);
259 	signalled = 0;
260 	(void)alarm(interval);
261 	bzero((caddr_t)&lastst, sizeof(lastst));
262 
263 	for (hdrcnt = 1;;) {
264 		if (!--hdrcnt) {
265 			printhdr();
266 			hdrcnt = 20;
267 		}
268 		klseek(kmem, off, 0L);
269 		read(kmem, (char *)&nfsstats, sizeof nfsstats);
270 		printf("Client: %8d %8d %8d %8d %8d %8d %8d %8d\n",
271 		    nfsstats.rpccnt[1]-lastst.rpccnt[1],
272 		    nfsstats.rpccnt[4]-lastst.rpccnt[4],
273 		    nfsstats.rpccnt[5]-lastst.rpccnt[5],
274 		    nfsstats.rpccnt[6]-lastst.rpccnt[6],
275 		    nfsstats.rpccnt[8]-lastst.rpccnt[8],
276 		    nfsstats.rpccnt[11]-lastst.rpccnt[11],
277 		    nfsstats.rpccnt[12]-lastst.rpccnt[12],
278 		    nfsstats.rpccnt[16]-lastst.rpccnt[16]);
279 		printf("Server: %8d %8d %8d %8d %8d %8d %8d %8d\n",
280 		    nfsstats.srvrpccnt[1]-lastst.srvrpccnt[1],
281 		    nfsstats.srvrpccnt[4]-lastst.srvrpccnt[4],
282 		    nfsstats.srvrpccnt[5]-lastst.srvrpccnt[5],
283 		    nfsstats.srvrpccnt[6]-lastst.srvrpccnt[6],
284 		    nfsstats.srvrpccnt[8]-lastst.srvrpccnt[8],
285 		    nfsstats.srvrpccnt[11]-lastst.srvrpccnt[11],
286 		    nfsstats.srvrpccnt[12]-lastst.srvrpccnt[12],
287 		    nfsstats.srvrpccnt[16]-lastst.srvrpccnt[16]);
288 		lastst = nfsstats;
289 		fflush(stdout);
290 		oldmask = sigblock(sigmask(SIGALRM));
291 		if (!signalled)
292 			sigpause(0);
293 		sigsetmask(oldmask);
294 		signalled = 0;
295 		(void)alarm(interval);
296 	}
297 	/*NOTREACHED*/
298 }
299 
300 void
301 printhdr()
302 {
303 	printf("        %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s\n",
304 	    "Getattr", "Lookup", "Readlink", "Read", "Write", "Rename",
305 	    "Link", "Readdir");
306 	fflush(stdout);
307 }
308 
309 /*
310  * Called if an interval expires before sidewaysintpr has completed a loop.
311  * Sets a flag to not wait for the alarm.
312  */
313 void
314 catchalarm()
315 {
316 	signalled = 1;
317 }
318 
319 /*
320  * Seek into the kernel for a value.
321  */
322 off_t
323 klseek(fd, base, off)
324 	int fd, off;
325 	off_t base;
326 {
327 	if (kflag) {
328 		/* get kernel pte */
329 		base &= ~KERNBASE;
330 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
331 	}
332 	return (lseek(fd, base, off));
333 }
334 
335 void
336 usage()
337 {
338 	(void)fprintf(stderr,
339 	    "usage: nfsstat [-M core] [-N system] [-w interval]\n");
340 	exit(1);
341 }
342