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