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