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 38 static 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 45 static char sccsid[] = "@(#)nfsstat.c 8.2 (Berkeley) 3/31/95"; 46 #endif 47 static const char rcsid[] = 48 "$FreeBSD$"; 49 #endif /* not lint */ 50 51 #include <sys/param.h> 52 #include <sys/mount.h> 53 #include <sys/time.h> 54 #include <sys/sysctl.h> 55 #include <nfs/rpcv2.h> 56 #include <nfs/nfsproto.h> 57 #include <nfsclient/nfs.h> 58 #include <nfsserver/nfs.h> 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 73 struct nlist nl[] = { 74 #define N_NFSSTAT 0 75 { "nfsstats" }, 76 #define N_NFSRVSTAT 1 77 { "nfsrvstats" }, 78 "", 79 }; 80 kvm_t *kd; 81 82 static int deadkernel = 0; 83 static int widemode = 0; 84 85 void intpr(int, int); 86 void printhdr(int, int); 87 void sidewaysintpr(u_int, int, int); 88 void usage(void); 89 char *sperc1(int, int); 90 char *sperc2(int, int); 91 92 #define DELTA(field) (nfsstats.field - lastst.field) 93 94 int 95 main(argc, argv) 96 int argc; 97 char **argv; 98 { 99 u_int interval; 100 int clientOnly = -1; 101 int serverOnly = -1; 102 int ch; 103 char *memf, *nlistf; 104 char errbuf[_POSIX2_LINE_MAX]; 105 106 interval = 0; 107 memf = nlistf = NULL; 108 while ((ch = getopt(argc, argv, "csWM:N:w:")) != -1) 109 switch(ch) { 110 case 'M': 111 memf = optarg; 112 break; 113 case 'N': 114 nlistf = optarg; 115 break; 116 case 'W': 117 widemode = 1; 118 break; 119 case 'w': 120 interval = atoi(optarg); 121 break; 122 case 'c': 123 clientOnly = 1; 124 if (serverOnly < 0) 125 serverOnly = 0; 126 break; 127 case 's': 128 serverOnly = 1; 129 if (clientOnly < 0) 130 clientOnly = 0; 131 break; 132 case '?': 133 default: 134 usage(); 135 } 136 argc -= optind; 137 argv += optind; 138 139 #define BACKWARD_COMPATIBILITY 140 #ifdef BACKWARD_COMPATIBILITY 141 if (*argv) { 142 interval = atoi(*argv); 143 if (*++argv) { 144 nlistf = *argv; 145 if (*++argv) 146 memf = *argv; 147 } 148 } 149 #endif 150 if (nlistf != NULL || memf != NULL) { 151 deadkernel = 1; 152 153 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, 154 errbuf)) == 0) { 155 errx(1, "kvm_openfiles: %s", errbuf); 156 } 157 if (kvm_nlist(kd, nl) != 0) { 158 errx(1, "kvm_nlist: can't get names"); 159 } 160 } 161 162 if (interval) 163 sidewaysintpr(interval, clientOnly, serverOnly); 164 else 165 intpr(clientOnly, serverOnly); 166 exit(0); 167 } 168 169 /* 170 * Read the nfs stats using sysctl(3) for live kernels, or kvm_read 171 * for dead ones. 172 */ 173 void 174 readstats(stp, srvstp) 175 struct nfsstats **stp; 176 struct nfsrvstats **srvstp; 177 { 178 size_t buflen; 179 180 if (deadkernel) { 181 if (kvm_read(kd, (u_long)nl[N_NFSSTAT].n_value, *stp, 182 sizeof(struct nfsstats)) < 0) { 183 *stp = NULL; 184 } 185 if (kvm_read(kd, (u_long)nl[N_NFSRVSTAT].n_value, *srvstp, 186 sizeof(struct nfsrvstats)) < 0) { 187 *srvstp = NULL; 188 } 189 } else { 190 buflen = sizeof(struct nfsstats); 191 if (sysctlbyname("vfs.nfs.nfsstats", *stp, &buflen, 192 (void *)0, (size_t)0) < 0) { 193 *stp = NULL; 194 } 195 buflen = sizeof(struct nfsrvstats); 196 if (sysctlbyname("vfs.nfsrv.nfsrvstats", *srvstp, &buflen, 197 (void *)0, (size_t)0) < 0) { 198 *srvstp = NULL; 199 } 200 } 201 } 202 203 /* 204 * Print a description of the nfs stats. 205 */ 206 void 207 intpr(int clientOnly, int serverOnly) 208 { 209 struct nfsstats nfsstats, *nfsstatsp; 210 struct nfsrvstats nfsrvstats, *nfsrvstatsp; 211 212 nfsstatsp = &nfsstats; 213 nfsrvstatsp = &nfsrvstats; 214 215 readstats(&nfsstatsp, &nfsrvstatsp); 216 217 if (clientOnly && !nfsstatsp) { 218 printf("Client not present!\n"); 219 clientOnly = 0; 220 } 221 if (clientOnly) { 222 printf("Client Info:\n"); 223 printf("Rpc Counts:\n"); 224 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 225 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 226 "Write", "Create", "Remove"); 227 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 228 nfsstats.rpccnt[NFSPROC_GETATTR], 229 nfsstats.rpccnt[NFSPROC_SETATTR], 230 nfsstats.rpccnt[NFSPROC_LOOKUP], 231 nfsstats.rpccnt[NFSPROC_READLINK], 232 nfsstats.rpccnt[NFSPROC_READ], 233 nfsstats.rpccnt[NFSPROC_WRITE], 234 nfsstats.rpccnt[NFSPROC_CREATE], 235 nfsstats.rpccnt[NFSPROC_REMOVE]); 236 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 237 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 238 "Readdir", "RdirPlus", "Access"); 239 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 240 nfsstats.rpccnt[NFSPROC_RENAME], 241 nfsstats.rpccnt[NFSPROC_LINK], 242 nfsstats.rpccnt[NFSPROC_SYMLINK], 243 nfsstats.rpccnt[NFSPROC_MKDIR], 244 nfsstats.rpccnt[NFSPROC_RMDIR], 245 nfsstats.rpccnt[NFSPROC_READDIR], 246 nfsstats.rpccnt[NFSPROC_READDIRPLUS], 247 nfsstats.rpccnt[NFSPROC_ACCESS]); 248 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 249 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit"); 250 printf("%9d %9d %9d %9d %9d\n", 251 nfsstats.rpccnt[NFSPROC_MKNOD], 252 nfsstats.rpccnt[NFSPROC_FSSTAT], 253 nfsstats.rpccnt[NFSPROC_FSINFO], 254 nfsstats.rpccnt[NFSPROC_PATHCONF], 255 nfsstats.rpccnt[NFSPROC_COMMIT]); 256 printf("Rpc Info:\n"); 257 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 258 "TimedOut", "Invalid", "X Replies", "Retries", 259 "Requests"); 260 printf("%9d %9d %9d %9d %9d\n", 261 nfsstats.rpctimeouts, 262 nfsstats.rpcinvalid, 263 nfsstats.rpcunexpected, 264 nfsstats.rpcretries, 265 nfsstats.rpcrequests); 266 printf("Cache Info:\n"); 267 printf("%9.9s %9.9s %9.9s %9.9s", 268 "Attr Hits", "Misses", "Lkup Hits", "Misses"); 269 printf(" %9.9s %9.9s %9.9s %9.9s\n", 270 "BioR Hits", "Misses", "BioW Hits", "Misses"); 271 printf("%9d %9d %9d %9d", 272 nfsstats.attrcache_hits, nfsstats.attrcache_misses, 273 nfsstats.lookupcache_hits, nfsstats.lookupcache_misses); 274 printf(" %9d %9d %9d %9d\n", 275 nfsstats.biocache_reads-nfsstats.read_bios, 276 nfsstats.read_bios, 277 nfsstats.biocache_writes-nfsstats.write_bios, 278 nfsstats.write_bios); 279 printf("%9.9s %9.9s %9.9s %9.9s", 280 "BioRLHits", "Misses", "BioD Hits", "Misses"); 281 printf(" %9.9s %9.9s\n", "DirE Hits", "Misses"); 282 printf("%9d %9d %9d %9d", 283 nfsstats.biocache_readlinks-nfsstats.readlink_bios, 284 nfsstats.readlink_bios, 285 nfsstats.biocache_readdirs-nfsstats.readdir_bios, 286 nfsstats.readdir_bios); 287 printf(" %9d %9d\n", 288 nfsstats.direofcache_hits, nfsstats.direofcache_misses); 289 } 290 if (serverOnly && !nfsrvstatsp) { 291 printf("Server not present!\n"); 292 serverOnly = 0; 293 } 294 if (serverOnly) { 295 printf("\nServer Info:\n"); 296 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 297 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 298 "Write", "Create", "Remove"); 299 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 300 nfsrvstats.srvrpccnt[NFSPROC_GETATTR], 301 nfsrvstats.srvrpccnt[NFSPROC_SETATTR], 302 nfsrvstats.srvrpccnt[NFSPROC_LOOKUP], 303 nfsrvstats.srvrpccnt[NFSPROC_READLINK], 304 nfsrvstats.srvrpccnt[NFSPROC_READ], 305 nfsrvstats.srvrpccnt[NFSPROC_WRITE], 306 nfsrvstats.srvrpccnt[NFSPROC_CREATE], 307 nfsrvstats.srvrpccnt[NFSPROC_REMOVE]); 308 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 309 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 310 "Readdir", "RdirPlus", "Access"); 311 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 312 nfsrvstats.srvrpccnt[NFSPROC_RENAME], 313 nfsrvstats.srvrpccnt[NFSPROC_LINK], 314 nfsrvstats.srvrpccnt[NFSPROC_SYMLINK], 315 nfsrvstats.srvrpccnt[NFSPROC_MKDIR], 316 nfsrvstats.srvrpccnt[NFSPROC_RMDIR], 317 nfsrvstats.srvrpccnt[NFSPROC_READDIR], 318 nfsrvstats.srvrpccnt[NFSPROC_READDIRPLUS], 319 nfsrvstats.srvrpccnt[NFSPROC_ACCESS]); 320 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 321 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit"); 322 printf("%9d %9d %9d %9d %9d\n", 323 nfsrvstats.srvrpccnt[NFSPROC_MKNOD], 324 nfsrvstats.srvrpccnt[NFSPROC_FSSTAT], 325 nfsrvstats.srvrpccnt[NFSPROC_FSINFO], 326 nfsrvstats.srvrpccnt[NFSPROC_PATHCONF], 327 nfsrvstats.srvrpccnt[NFSPROC_COMMIT]); 328 printf("Server Ret-Failed\n"); 329 printf("%17d\n", nfsrvstats.srvrpc_errs); 330 printf("Server Faults\n"); 331 printf("%13d\n", nfsrvstats.srv_errs); 332 printf("Server Cache Stats:\n"); 333 printf("%9.9s %9.9s %9.9s %9.9s\n", 334 "Inprog", "Idem", "Non-idem", "Misses"); 335 printf("%9d %9d %9d %9d\n", 336 nfsrvstats.srvcache_inproghits, 337 nfsrvstats.srvcache_idemdonehits, 338 nfsrvstats.srvcache_nonidemdonehits, 339 nfsrvstats.srvcache_misses); 340 printf("Server Write Gathering:\n"); 341 printf("%9.9s %9.9s %9.9s\n", 342 "WriteOps", "WriteRPC", "Opsaved"); 343 printf("%9d %9d %9d\n", 344 nfsrvstats.srvvop_writes, 345 nfsrvstats.srvrpccnt[NFSPROC_WRITE], 346 nfsrvstats.srvrpccnt[NFSPROC_WRITE] - 347 nfsrvstats.srvvop_writes); 348 } 349 } 350 351 u_char signalled; /* set if alarm goes off "early" */ 352 353 /* 354 * Print a running summary of nfs statistics. 355 * Repeat display every interval seconds, showing statistics 356 * collected over that interval. Assumes that interval is non-zero. 357 * First line printed at top of screen is always cumulative. 358 */ 359 void 360 sidewaysintpr(u_int interval, int clientOnly, int serverOnly) 361 { 362 struct nfsstats nfsstats, lastst, *nfsstatsp; 363 struct nfsrvstats nfsrvstats, lastsrvst, *nfsrvstatsp; 364 int hdrcnt = 1; 365 366 nfsstatsp = &lastst; 367 nfsrvstatsp = &lastsrvst; 368 readstats(&nfsstatsp, &nfsrvstatsp); 369 if (clientOnly && !nfsstatsp) { 370 printf("Client not present!\n"); 371 clientOnly = 0; 372 } 373 if (serverOnly && !nfsrvstatsp) { 374 printf("Server not present!\n"); 375 serverOnly = 0; 376 } 377 sleep(interval); 378 379 for (;;) { 380 nfsstatsp = &nfsstats; 381 nfsrvstatsp = &nfsrvstats; 382 readstats(&nfsstatsp, &nfsrvstatsp); 383 384 if (--hdrcnt == 0) { 385 printhdr(clientOnly, serverOnly); 386 if (clientOnly && serverOnly) 387 hdrcnt = 10; 388 else 389 hdrcnt = 20; 390 } 391 if (clientOnly) { 392 printf("%s %6d %6d %6d %6d %6d %6d %6d %6d", 393 ((clientOnly && serverOnly) ? "Client:" : ""), 394 DELTA(attrcache_hits) + DELTA(attrcache_misses), 395 DELTA(lookupcache_hits) + DELTA(lookupcache_misses), 396 DELTA(biocache_readlinks), 397 DELTA(biocache_reads), 398 DELTA(biocache_writes), 399 nfsstats.rpccnt[NFSPROC_RENAME]-lastst.rpccnt[NFSPROC_RENAME], 400 DELTA(accesscache_hits) + DELTA(accesscache_misses), 401 DELTA(biocache_readdirs) 402 ); 403 if (widemode) { 404 printf(" %s %s %s %s %s %s", 405 sperc1(DELTA(attrcache_hits), 406 DELTA(attrcache_misses)), 407 sperc1(DELTA(lookupcache_hits), 408 DELTA(lookupcache_misses)), 409 sperc2(DELTA(biocache_reads), 410 DELTA(read_bios)), 411 sperc2(DELTA(biocache_writes), 412 DELTA(write_bios)), 413 sperc1(DELTA(accesscache_hits), 414 DELTA(accesscache_misses)), 415 sperc2(DELTA(biocache_readdirs), 416 DELTA(readdir_bios)) 417 ); 418 } 419 printf("\n"); 420 lastst = nfsstats; 421 } 422 if (serverOnly) { 423 printf("%s %6d %6d %6d %6d %6d %6d %6d %6d", 424 ((clientOnly && serverOnly) ? "Server:" : ""), 425 nfsrvstats.srvrpccnt[NFSPROC_GETATTR]-lastsrvst.srvrpccnt[NFSPROC_GETATTR], 426 nfsrvstats.srvrpccnt[NFSPROC_LOOKUP]-lastsrvst.srvrpccnt[NFSPROC_LOOKUP], 427 nfsrvstats.srvrpccnt[NFSPROC_READLINK]-lastsrvst.srvrpccnt[NFSPROC_READLINK], 428 nfsrvstats.srvrpccnt[NFSPROC_READ]-lastsrvst.srvrpccnt[NFSPROC_READ], 429 nfsrvstats.srvrpccnt[NFSPROC_WRITE]-lastsrvst.srvrpccnt[NFSPROC_WRITE], 430 nfsrvstats.srvrpccnt[NFSPROC_RENAME]-lastsrvst.srvrpccnt[NFSPROC_RENAME], 431 nfsrvstats.srvrpccnt[NFSPROC_ACCESS]-lastsrvst.srvrpccnt[NFSPROC_ACCESS], 432 (nfsrvstats.srvrpccnt[NFSPROC_READDIR]-lastsrvst.srvrpccnt[NFSPROC_READDIR]) 433 +(nfsrvstats.srvrpccnt[NFSPROC_READDIRPLUS]-lastsrvst.srvrpccnt[NFSPROC_READDIRPLUS])); 434 printf("\n"); 435 lastsrvst = nfsrvstats; 436 } 437 fflush(stdout); 438 sleep(interval); 439 } 440 /*NOTREACHED*/ 441 } 442 443 void 444 printhdr(int clientOnly, int serverOnly) 445 { 446 printf("%s%6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s %6.6s", 447 ((serverOnly && clientOnly) ? " " : " "), 448 "GtAttr", "Lookup", "Rdlink", "Read", "Write", "Rename", 449 "Access", "Rddir"); 450 if (widemode && clientOnly) { 451 printf(" Attr Lkup BioR BioW Accs BioD"); 452 } 453 printf("\n"); 454 fflush(stdout); 455 } 456 457 void 458 usage() 459 { 460 (void)fprintf(stderr, 461 "usage: nfsstat [-csW] [-M core] [-N system] [-w interval]\n"); 462 exit(1); 463 } 464 465 static char SPBuf[64][8]; 466 static int SPIndex; 467 468 char * 469 sperc1(int hits, int misses) 470 { 471 char *p = SPBuf[SPIndex]; 472 473 if (hits + misses) { 474 sprintf(p, "%3d%%", 475 (int)(char)((quad_t)hits * 100 / (hits + misses))); 476 } else { 477 sprintf(p, " -"); 478 } 479 SPIndex = (SPIndex + 1) & 63; 480 return(p); 481 } 482 483 char * 484 sperc2(int ttl, int misses) 485 { 486 char *p = SPBuf[SPIndex]; 487 488 if (ttl) { 489 sprintf(p, "%3d%%", 490 (int)(char)((quad_t)(ttl - misses) * 100 / ttl)); 491 } else { 492 sprintf(p, " -"); 493 } 494 SPIndex = (SPIndex + 1) & 63; 495 return(p); 496 } 497 498