1 /* $NetBSD: nfsstat.c,v 1.17 2001/03/19 05:45:30 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Rick Macklem at The University of Guelph. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #ifndef lint 41 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993\n\ 42 The Regents of the University of California. All rights reserved.\n"); 43 #endif /* not lint */ 44 45 #ifndef lint 46 #if 0 47 static char sccsid[] = "from: @(#)nfsstat.c 8.1 (Berkeley) 6/6/93"; 48 #else 49 __RCSID("$NetBSD: nfsstat.c,v 1.17 2001/03/19 05:45:30 lukem Exp $"); 50 #endif 51 #endif /* not lint */ 52 53 #include <sys/param.h> 54 #include <sys/mount.h> 55 #include <sys/sysctl.h> 56 57 #include <nfs/rpcv2.h> 58 #include <nfs/nfsproto.h> 59 #include <nfs/nfs.h> 60 61 #include <ctype.h> 62 #include <err.h> 63 #include <errno.h> 64 #include <fcntl.h> 65 #include <kvm.h> 66 #include <limits.h> 67 #include <nlist.h> 68 #include <paths.h> 69 #include <signal.h> 70 #include <stdlib.h> 71 #include <stdio.h> 72 #include <string.h> 73 #include <unistd.h> 74 75 struct nlist nl[] = { 76 #define N_NFSSTAT 0 77 { "_nfsstats" }, 78 { "" }, 79 }; 80 81 82 void catchalarm __P((int)); 83 void getstats __P((struct nfsstats *)); 84 void intpr __P((void)); 85 int main __P((int, char **)); 86 void printhdr __P((void)); 87 void sidewaysintpr __P((u_int)); 88 void usage __P((void)); 89 90 kvm_t *kd; 91 int printall, clientinfo, serverinfo; 92 u_long nfsstataddr; 93 94 int 95 main(argc, argv) 96 int argc; 97 char **argv; 98 { 99 u_int interval; 100 int ch; 101 char *memf, *nlistf; 102 char errbuf[_POSIX2_LINE_MAX]; 103 104 interval = 0; 105 memf = nlistf = NULL; 106 printall = 1; 107 while ((ch = getopt(argc, argv, "M:N:w:cs")) != -1) 108 switch(ch) { 109 case 'M': 110 memf = optarg; 111 break; 112 case 'N': 113 nlistf = optarg; 114 break; 115 case 'w': 116 interval = atoi(optarg); 117 break; 118 case 's': 119 serverinfo = 1; 120 printall = 0; 121 break; 122 case 'c': 123 clientinfo = 1; 124 printall = 0; 125 break; 126 case '?': 127 default: 128 usage(); 129 } 130 argc -= optind; 131 argv += optind; 132 133 #define BACKWARD_COMPATIBILITY 134 #ifdef BACKWARD_COMPATIBILITY 135 if (*argv) { 136 interval = atoi(*argv); 137 if (*++argv) { 138 nlistf = *argv; 139 if (*++argv) 140 memf = *argv; 141 } 142 } 143 #endif 144 if (nlistf || memf) { 145 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) 146 == 0) 147 errx(1, "kvm_openfiles: %s", errbuf); 148 149 if (kvm_nlist(kd, nl) != 0) 150 errx(1, "kvm_nlist: can't get names"); 151 nfsstataddr = nl[N_NFSSTAT].n_value; 152 } else { 153 kd = NULL; 154 } 155 156 if (interval) 157 sidewaysintpr(interval); 158 else 159 intpr(); 160 exit(0); 161 } 162 163 void 164 getstats(ns) 165 struct nfsstats *ns; 166 { 167 size_t size; 168 int mib[3]; 169 170 if (kd) { 171 if (kvm_read(kd, (u_long)nfsstataddr, ns, sizeof(*ns)) 172 != sizeof(*ns)) 173 errx(1, "kvm_read failed"); 174 } else { 175 mib[0] = CTL_VFS; 176 mib[1] = 2; /* XXX from CTL_VFS_NAMES in <sys/mount.h> */ 177 mib[2] = NFS_NFSSTATS; 178 179 size = sizeof(*ns); 180 if (sysctl(mib, 3, ns, &size, NULL, 0) == -1) 181 err(1, "sysctl(NFS_NFSSTATS) failed"); 182 } 183 } 184 185 /* 186 * Print a description of the nfs stats. 187 */ 188 void 189 intpr() 190 { 191 struct nfsstats nfsstats; 192 int64_t total; 193 int i; 194 195 #define PCT(x,y) ((y) == 0 ? 0 : (int)((int64_t)(x) * 100 / (y))) 196 #define NUMPCT(x,y) (x), PCT(x, (x)+(y)) 197 #define RPCSTAT(x) (x), PCT(x, total) 198 199 getstats(&nfsstats); 200 201 if (printall || clientinfo) { 202 total = 0; 203 for (i = 0; i < NFS_NPROCS; i++) 204 total += nfsstats.rpccnt[i]; 205 printf("Client Info:\n"); 206 printf("RPC Counts: (%lld call%s)\n", (long long)total, 207 total == 1 ? "" : "s"); 208 209 printf("%10s %14s %14s %14s %14s\n", 210 "null", "getattr", "setattr", "lookup", "access"); 211 printf( 212 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 213 RPCSTAT(nfsstats.rpccnt[NFSPROC_NULL]), 214 RPCSTAT(nfsstats.rpccnt[NFSPROC_GETATTR]), 215 RPCSTAT(nfsstats.rpccnt[NFSPROC_SETATTR]), 216 RPCSTAT(nfsstats.rpccnt[NFSPROC_LOOKUP]), 217 RPCSTAT(nfsstats.rpccnt[NFSPROC_ACCESS])); 218 printf("%10s %14s %14s %14s %14s\n", 219 "readlink", "read", "write", "create", "mkdir"); 220 printf( 221 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 222 RPCSTAT(nfsstats.rpccnt[NFSPROC_READLINK]), 223 RPCSTAT(nfsstats.rpccnt[NFSPROC_READ]), 224 RPCSTAT(nfsstats.rpccnt[NFSPROC_WRITE]), 225 RPCSTAT(nfsstats.rpccnt[NFSPROC_CREATE]), 226 RPCSTAT(nfsstats.rpccnt[NFSPROC_MKDIR])); 227 printf("%10s %14s %14s %14s %14s\n", 228 "symlink", "mknod", "remove", "rmdir", "rename"); 229 printf( 230 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 231 RPCSTAT(nfsstats.rpccnt[NFSPROC_SYMLINK]), 232 RPCSTAT(nfsstats.rpccnt[NFSPROC_MKNOD]), 233 RPCSTAT(nfsstats.rpccnt[NFSPROC_REMOVE]), 234 RPCSTAT(nfsstats.rpccnt[NFSPROC_RMDIR]), 235 RPCSTAT(nfsstats.rpccnt[NFSPROC_RENAME])); 236 printf("%10s %14s %14s %14s %14s\n", 237 "link", "readdir", "readdirplus", "fsstat", "fsinfo"); 238 printf( 239 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 240 RPCSTAT(nfsstats.rpccnt[NFSPROC_LINK]), 241 RPCSTAT(nfsstats.rpccnt[NFSPROC_READDIR]), 242 RPCSTAT(nfsstats.rpccnt[NFSPROC_READDIRPLUS]), 243 RPCSTAT(nfsstats.rpccnt[NFSPROC_FSSTAT]), 244 RPCSTAT(nfsstats.rpccnt[NFSPROC_FSINFO])); 245 printf("%10s %14s %14s %14s %14s\n", 246 "pathconf", "commit", "getlease", "vacated", "evicted"); 247 printf( 248 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 249 RPCSTAT(nfsstats.rpccnt[NFSPROC_PATHCONF]), 250 RPCSTAT(nfsstats.rpccnt[NFSPROC_COMMIT]), 251 RPCSTAT(nfsstats.rpccnt[NQNFSPROC_GETLEASE]), 252 RPCSTAT(nfsstats.rpccnt[NQNFSPROC_VACATED]), 253 RPCSTAT(nfsstats.rpccnt[NQNFSPROC_EVICTED])); 254 printf("%10s\n", "noop"); 255 printf("%10d %2d%%\n", 256 RPCSTAT(nfsstats.rpccnt[NFSPROC_NOOP])); 257 258 printf("RPC Info:\n"); 259 printf("%10s %14s %14s %14s %14s\n", 260 "timeout", "invalid", "unexpected", "retries", "requests"); 261 printf("%10d %14d %14d %14d %14d\n", 262 nfsstats.rpctimeouts, 263 nfsstats.rpcinvalid, 264 nfsstats.rpcunexpected, 265 nfsstats.rpcretries, 266 nfsstats.rpcrequests); 267 268 printf("Cache Info:\n"); 269 printf("%10s %14s %14s %14s %14s\n", 270 "attrcache", "lookupcache", "read", "write", "readlink"); 271 printf( 272 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 273 NUMPCT(nfsstats.attrcache_hits, 274 nfsstats.attrcache_misses), 275 NUMPCT(nfsstats.lookupcache_hits, 276 nfsstats.lookupcache_misses), 277 NUMPCT(nfsstats.biocache_reads - nfsstats.read_bios, 278 nfsstats.read_bios), 279 NUMPCT(nfsstats.biocache_writes - nfsstats.write_bios, 280 nfsstats.write_bios), 281 NUMPCT(nfsstats.biocache_readlinks - nfsstats.readlink_bios, 282 nfsstats.readlink_bios)); 283 printf("%10s %14s\n", 284 "readdir", "direofcache"); 285 printf("%10d %2d%% %10d %2d%%\n", 286 NUMPCT(nfsstats.biocache_readdirs - nfsstats.readdir_bios, 287 nfsstats.readdir_bios), 288 NUMPCT(nfsstats.direofcache_hits, 289 nfsstats.direofcache_misses)); 290 } 291 292 if (printall || (clientinfo && serverinfo)) 293 printf("\n"); 294 295 if (printall || serverinfo) { 296 total = 0; 297 for (i = 0; i < NFS_NPROCS; i++) 298 total += nfsstats.srvrpccnt[i]; 299 printf("Server Info:\n"); 300 printf("RPC Counts: (%lld call%s)\n", (long long)total, 301 total == 1 ? "" : "s"); 302 303 printf("%10s %14s %14s %14s %14s\n", 304 "null", "getattr", "setattr", "lookup", "access"); 305 printf( 306 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 307 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_NULL]), 308 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_GETATTR]), 309 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SETATTR]), 310 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LOOKUP]), 311 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_ACCESS])); 312 printf("%10s %14s %14s %14s %14s\n", 313 "readlink", "read", "write", "create", "mkdir"); 314 printf( 315 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 316 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READLINK]), 317 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READ]), 318 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_WRITE]), 319 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_CREATE]), 320 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKDIR])); 321 printf("%10s %14s %14s %14s %14s\n", 322 "symlink", "mknod", "remove", "rmdir", "rename"); 323 printf( 324 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 325 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_SYMLINK]), 326 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_MKNOD]), 327 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_REMOVE]), 328 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RMDIR]), 329 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_RENAME])); 330 printf("%10s %14s %14s %14s %14s\n", 331 "link", "readdir", "readdirplus", "fsstat", "fsinfo"); 332 printf( 333 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 334 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_LINK]), 335 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIR]), 336 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]), 337 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSSTAT]), 338 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_FSINFO])); 339 printf("%10s %14s %14s %14s %14s\n", 340 "pathconf", "commit", "getlease", "vacated", "evicted"); 341 printf( 342 "%10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%% %10d %2d%%\n", 343 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_PATHCONF]), 344 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_COMMIT]), 345 RPCSTAT(nfsstats.srvrpccnt[NQNFSPROC_GETLEASE]), 346 RPCSTAT(nfsstats.srvrpccnt[NQNFSPROC_VACATED]), 347 RPCSTAT(nfsstats.srvrpccnt[NQNFSPROC_EVICTED])); 348 printf("%10s\n", "noop"); 349 printf("%10d %2d%%\n", 350 RPCSTAT(nfsstats.srvrpccnt[NFSPROC_NOOP])); 351 352 printf("Server Errors:\n"); 353 printf("%10s %14s\n", 354 "RPC errors", "faults"); 355 printf("%10d %14d\n", 356 nfsstats.srvrpc_errs, 357 nfsstats.srv_errs); 358 printf("Server Cache Stats:\n"); 359 printf("%10s %14s %14s %14s\n", 360 "inprogress", "idem", "non-idem", "misses"); 361 printf("%10d %14d %14d %14d\n", 362 nfsstats.srvcache_inproghits, 363 nfsstats.srvcache_idemdonehits, 364 nfsstats.srvcache_nonidemdonehits, 365 nfsstats.srvcache_misses); 366 printf("Server Lease Stats:\n"); 367 printf("%10s %14s %14s\n", 368 "leases", "maxleases", "getleases"); 369 printf("%10d %14d %14d\n", 370 nfsstats.srvnqnfs_leases, 371 nfsstats.srvnqnfs_maxleases, 372 nfsstats.srvnqnfs_getleases); 373 printf("Server Write Gathering:\n"); 374 printf("%10s %14s %14s\n", 375 "writes", "write RPC", "OPs saved"); 376 printf("%10d %14d %14d %2d%%\n", 377 nfsstats.srvvop_writes, 378 nfsstats.srvrpccnt[NFSPROC_WRITE], 379 NUMPCT( 380 nfsstats.srvrpccnt[NFSPROC_WRITE]-nfsstats.srvvop_writes, 381 nfsstats.srvrpccnt[NFSPROC_WRITE])); 382 } 383 } 384 385 u_char signalled; /* set if alarm goes off "early" */ 386 387 /* 388 * Print a running summary of nfs statistics. 389 * Repeat display every interval seconds, showing statistics 390 * collected over that interval. Assumes that interval is non-zero. 391 * First line printed at top of screen is always cumulative. 392 */ 393 void 394 sidewaysintpr(interval) 395 u_int interval; 396 { 397 struct nfsstats nfsstats, lastst; 398 int hdrcnt, oldmask; 399 400 (void)signal(SIGALRM, catchalarm); 401 signalled = 0; 402 (void)alarm(interval); 403 memset((caddr_t)&lastst, 0, sizeof(lastst)); 404 405 for (hdrcnt = 1;;) { 406 if (!--hdrcnt) { 407 printhdr(); 408 hdrcnt = 20; 409 } 410 getstats(&nfsstats); 411 if (printall || clientinfo) 412 printf("Client: %8d %8d %8d %8d %8d %8d %8d %8d\n", 413 nfsstats.rpccnt[NFSPROC_GETATTR] - 414 lastst.rpccnt[NFSPROC_GETATTR], 415 nfsstats.rpccnt[NFSPROC_LOOKUP] - 416 lastst.rpccnt[NFSPROC_LOOKUP], 417 nfsstats.rpccnt[NFSPROC_READLINK] - 418 lastst.rpccnt[NFSPROC_READLINK], 419 nfsstats.rpccnt[NFSPROC_READ] - 420 lastst.rpccnt[NFSPROC_READ], 421 nfsstats.rpccnt[NFSPROC_WRITE] - 422 lastst.rpccnt[NFSPROC_WRITE], 423 nfsstats.rpccnt[NFSPROC_RENAME] - 424 lastst.rpccnt[NFSPROC_RENAME], 425 nfsstats.rpccnt[NFSPROC_ACCESS] - 426 lastst.rpccnt[NFSPROC_ACCESS], 427 (nfsstats.rpccnt[NFSPROC_READDIR] - 428 lastst.rpccnt[NFSPROC_READDIR]) + 429 (nfsstats.rpccnt[NFSPROC_READDIRPLUS] - 430 lastst.rpccnt[NFSPROC_READDIRPLUS])); 431 if (printall || serverinfo) 432 printf("Server: %8d %8d %8d %8d %8d %8d %8d %8d\n", 433 nfsstats.srvrpccnt[NFSPROC_GETATTR] - 434 lastst.srvrpccnt[NFSPROC_GETATTR], 435 nfsstats.srvrpccnt[NFSPROC_LOOKUP] - 436 lastst.srvrpccnt[NFSPROC_LOOKUP], 437 nfsstats.srvrpccnt[NFSPROC_READLINK] - 438 lastst.srvrpccnt[NFSPROC_READLINK], 439 nfsstats.srvrpccnt[NFSPROC_READ] - 440 lastst.srvrpccnt[NFSPROC_READ], 441 nfsstats.srvrpccnt[NFSPROC_WRITE] - 442 lastst.srvrpccnt[NFSPROC_WRITE], 443 nfsstats.srvrpccnt[NFSPROC_RENAME] - 444 lastst.srvrpccnt[NFSPROC_RENAME], 445 nfsstats.srvrpccnt[NFSPROC_ACCESS] - 446 lastst.srvrpccnt[NFSPROC_ACCESS], 447 (nfsstats.srvrpccnt[NFSPROC_READDIR] - 448 lastst.srvrpccnt[NFSPROC_READDIR]) + 449 (nfsstats.srvrpccnt[NFSPROC_READDIRPLUS] - 450 lastst.srvrpccnt[NFSPROC_READDIRPLUS])); 451 lastst = nfsstats; 452 fflush(stdout); 453 oldmask = sigblock(sigmask(SIGALRM)); 454 if (!signalled) 455 sigpause(0); 456 sigsetmask(oldmask); 457 signalled = 0; 458 (void)alarm(interval); 459 } 460 /*NOTREACHED*/ 461 } 462 463 void 464 printhdr() 465 { 466 467 printf(" %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s\n", 468 "Getattr", "Lookup", "Readlink", "Read", "Write", "Rename", 469 "Access", "Readdir"); 470 fflush(stdout); 471 } 472 473 /* 474 * Called if an interval expires before sidewaysintpr has completed a loop. 475 * Sets a flag to not wait for the alarm. 476 */ 477 void 478 catchalarm(dummy) 479 int dummy; 480 { 481 482 signalled = 1; 483 } 484 485 void 486 usage() 487 { 488 489 (void)fprintf(stderr, 490 "usage: nfsstat [-cs] [-M core] [-N system] [-w interval]\n"); 491 exit(1); 492 } 493