1 /* $OpenBSD: nfsstat.c,v 1.32 2009/06/05 19:32:26 jasper Exp $ */ 2 /* $NetBSD: nfsstat.c,v 1.7 1996/03/03 17:21:30 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1983, 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Rick Macklem at The University of Guelph. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #ifndef lint 37 static char copyright[] = 38 "@(#) Copyright (c) 1983, 1989, 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"; 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "from: @(#)nfsstat.c 8.1 (Berkeley) 6/6/93"; 45 static char *rcsid = "$NetBSD: nfsstat.c,v 1.7 1996/03/03 17:21:30 thorpej Exp $"; 46 #else 47 static char *rcsid = "$OpenBSD: nfsstat.c,v 1.32 2009/06/05 19:32:26 jasper Exp $"; 48 #endif 49 #endif /* not lint */ 50 51 #include <sys/param.h> 52 #include <sys/mount.h> 53 #include <sys/sysctl.h> 54 #include <nfs/rpcv2.h> 55 #include <nfs/nfsproto.h> 56 #include <nfs/nfs.h> 57 #include <signal.h> 58 #include <fcntl.h> 59 #include <ctype.h> 60 #include <errno.h> 61 #include <kvm.h> 62 #include <nlist.h> 63 #include <unistd.h> 64 #include <stdio.h> 65 #include <stdlib.h> 66 #include <string.h> 67 #include <limits.h> 68 #include <paths.h> 69 #include <err.h> 70 71 #define SHOW_SERVER 0x01 72 #define SHOW_CLIENT 0x02 73 #define SHOW_ALL (SHOW_SERVER | SHOW_CLIENT) 74 75 struct nlist nl[] = { 76 #define N_NFSSTAT 0 77 { "_nfsstats" }, 78 { "" }, 79 }; 80 kvm_t *kd; 81 volatile sig_atomic_t signalled; /* set if alarm goes off "early" */ 82 int nfs_id; 83 84 void getnfsstats(struct nfsstats *); 85 void printhdr(void); 86 void intpr(u_int); 87 void sidewaysintpr(u_int, u_int); 88 void usage(void); 89 void catchalarm(int); 90 91 int 92 main(int argc, char *argv[]) 93 { 94 u_int interval, display = SHOW_ALL; 95 extern int optind; 96 extern char *optarg; 97 char *memf, *nlistf; 98 const char *errstr; 99 int ch; 100 101 interval = 0; 102 memf = nlistf = NULL; 103 while ((ch = getopt(argc, argv, "cM:N:sw:")) != -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 = (u_int)strtonum(optarg, 0, 1000, &errstr); 113 if (errstr) 114 errx(1, "invalid interval %s: %s", 115 optarg, errstr); 116 break; 117 case 's': 118 display = SHOW_SERVER; 119 break; 120 case 'c': 121 display = SHOW_CLIENT; 122 break; 123 case '?': 124 default: 125 usage(); 126 } 127 argc -= optind; 128 argv += optind; 129 130 #define BACKWARD_COMPATIBILITY 131 #ifdef BACKWARD_COMPATIBILITY 132 if (*argv) { 133 interval = (u_int)strtonum(*argv, 0, 1000, &errstr); 134 if (errstr) 135 errx(1, "invalid interval %s: %s", *argv, errstr); 136 if (*++argv) { 137 nlistf = *argv; 138 if (*++argv) 139 memf = *argv; 140 } 141 } 142 #endif 143 if (nlistf || memf) { 144 char errbuf[_POSIX2_LINE_MAX]; 145 146 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == 0) 147 errx(1, "nfsstat: %s", errbuf); 148 if (kvm_nlist(kd, nl) != 0) 149 errx(1, "kvm_nlist: can't get names"); 150 } else { 151 int mib[4]; 152 size_t len; 153 154 mib[0] = CTL_VFS; 155 mib[1] = VFS_GENERIC; 156 mib[2] = VFS_MAXTYPENUM; 157 len = sizeof(nfs_id); 158 if (sysctl(mib, 3, &nfs_id, &len, NULL, 0)) 159 err(1, "sysctl: VFS_MAXTYPENUM"); 160 161 for (; nfs_id; nfs_id--) { 162 struct vfsconf vfsc; 163 164 mib[0] = CTL_VFS; 165 mib[1] = VFS_GENERIC; 166 mib[2] = VFS_CONF; 167 mib[3] = nfs_id; 168 169 len = sizeof(vfsc); 170 if (sysctl(mib, 4, &vfsc, &len, NULL, 0)) 171 continue; 172 173 if (!strcmp(vfsc.vfc_name, MOUNT_NFS)) 174 break; 175 } 176 if (nfs_id == 0) 177 errx(1, "cannot find nfs filesystem id"); 178 } 179 180 if (interval) 181 sidewaysintpr(interval, display); 182 else 183 intpr(display); 184 185 return 0; 186 } 187 188 void 189 getnfsstats(struct nfsstats *p) 190 { 191 if (kd) { 192 if (kvm_read(kd, nl[N_NFSSTAT].n_value, p, sizeof(*p)) != sizeof(*p)) 193 errx(1, "kvm_read failed"); 194 } else { 195 int mib[3]; 196 size_t len = sizeof(*p); 197 198 mib[0] = CTL_VFS; 199 mib[1] = nfs_id; /* 2 */ 200 mib[2] = NFS_NFSSTATS; 201 202 if (sysctl(mib, 3, p, &len, NULL, 0)) 203 err(1, "sysctl"); 204 } 205 } 206 207 /* 208 * Print a description of the nfs stats. 209 */ 210 void 211 intpr(u_int display) 212 { 213 struct nfsstats nfsstats; 214 215 getnfsstats(&nfsstats); 216 217 if (display & SHOW_CLIENT) { 218 printf("Client Info:\n"); 219 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 220 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 221 "Write", "Create", "Remove"); 222 printf("%9llu %9llu %9llu %9llu %9llu %9llu %9llu %9llu\n", 223 nfsstats.rpccnt[NFSPROC_GETATTR], 224 nfsstats.rpccnt[NFSPROC_SETATTR], 225 nfsstats.rpccnt[NFSPROC_LOOKUP], 226 nfsstats.rpccnt[NFSPROC_READLINK], 227 nfsstats.rpccnt[NFSPROC_READ], 228 nfsstats.rpccnt[NFSPROC_WRITE], 229 nfsstats.rpccnt[NFSPROC_CREATE], 230 nfsstats.rpccnt[NFSPROC_REMOVE]); 231 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 232 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 233 "Readdir", "RdirPlus", "Access"); 234 printf("%9llu %9llu %9llu %9llu %9llu %9llu %9llu %9llu\n", 235 nfsstats.rpccnt[NFSPROC_RENAME], 236 nfsstats.rpccnt[NFSPROC_LINK], 237 nfsstats.rpccnt[NFSPROC_SYMLINK], 238 nfsstats.rpccnt[NFSPROC_MKDIR], 239 nfsstats.rpccnt[NFSPROC_RMDIR], 240 nfsstats.rpccnt[NFSPROC_READDIR], 241 nfsstats.rpccnt[NFSPROC_READDIRPLUS], 242 nfsstats.rpccnt[NFSPROC_ACCESS]); 243 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 244 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit"); 245 printf("%9llu %9llu %9llu %9llu %9llu\n", 246 nfsstats.rpccnt[NFSPROC_MKNOD], 247 nfsstats.rpccnt[NFSPROC_FSSTAT], 248 nfsstats.rpccnt[NFSPROC_FSINFO], 249 nfsstats.rpccnt[NFSPROC_PATHCONF], 250 nfsstats.rpccnt[NFSPROC_COMMIT]); 251 printf("Rpc Info:\n"); 252 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 253 "TimedOut", "Invalid", "X Replies", "Retries", "Requests", 254 "FrcSync"); 255 printf("%9llu %9llu %9llu %9llu %9llu %9llu\n", 256 nfsstats.rpctimeouts, 257 nfsstats.rpcinvalid, 258 nfsstats.rpcunexpected, 259 nfsstats.rpcretries, 260 nfsstats.rpcrequests, 261 nfsstats.forcedsync); 262 printf("Cache Info:\n"); 263 printf("%9.9s %9.9s %9.9s %9.9s", 264 "Attr Hits", "Misses", "Lkup Hits", "Misses"); 265 printf(" %9.9s %9.9s %9.9s %9.9s\n", 266 "BioR Hits", "Misses", "BioW Hits", "Misses"); 267 printf("%9llu %9llu %9llu %9llu", 268 nfsstats.attrcache_hits, nfsstats.attrcache_misses, 269 nfsstats.lookupcache_hits, nfsstats.lookupcache_misses); 270 printf(" %9llu %9llu %9llu %9llu\n", 271 nfsstats.biocache_reads-nfsstats.read_bios, 272 nfsstats.read_bios, 273 nfsstats.biocache_writes-nfsstats.write_bios, 274 nfsstats.write_bios); 275 printf("%9.9s %9.9s %9.9s %9.9s", 276 "BioRLHits", "Misses", "BioD Hits", "Misses"); 277 printf(" %9.9s %9.9s\n", "DirE Hits", "Misses"); 278 printf("%9llu %9llu %9llu %9llu", 279 nfsstats.biocache_readlinks-nfsstats.readlink_bios, 280 nfsstats.readlink_bios, 281 nfsstats.biocache_readdirs-nfsstats.readdir_bios, 282 nfsstats.readdir_bios); 283 printf(" %9llu %9llu\n", 284 nfsstats.direofcache_hits, nfsstats.direofcache_misses); 285 } 286 287 if (display == SHOW_ALL) 288 printf("\n"); 289 290 if (display & SHOW_SERVER) { 291 printf("Server Info:\n"); 292 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 293 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 294 "Write", "Create", "Remove"); 295 printf("%9llu %9llu %9llu %9llu %9llu %9llu %9llu %9llu\n", 296 nfsstats.srvrpccnt[NFSPROC_GETATTR], 297 nfsstats.srvrpccnt[NFSPROC_SETATTR], 298 nfsstats.srvrpccnt[NFSPROC_LOOKUP], 299 nfsstats.srvrpccnt[NFSPROC_READLINK], 300 nfsstats.srvrpccnt[NFSPROC_READ], 301 nfsstats.srvrpccnt[NFSPROC_WRITE], 302 nfsstats.srvrpccnt[NFSPROC_CREATE], 303 nfsstats.srvrpccnt[NFSPROC_REMOVE]); 304 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 305 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 306 "Readdir", "RdirPlus", "Access"); 307 printf("%9llu %9llu %9llu %9llu %9llu %9llu %9llu %9llu\n", 308 nfsstats.srvrpccnt[NFSPROC_RENAME], 309 nfsstats.srvrpccnt[NFSPROC_LINK], 310 nfsstats.srvrpccnt[NFSPROC_SYMLINK], 311 nfsstats.srvrpccnt[NFSPROC_MKDIR], 312 nfsstats.srvrpccnt[NFSPROC_RMDIR], 313 nfsstats.srvrpccnt[NFSPROC_READDIR], 314 nfsstats.srvrpccnt[NFSPROC_READDIRPLUS], 315 nfsstats.srvrpccnt[NFSPROC_ACCESS]); 316 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 317 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit"); 318 printf("%9llu %9llu %9llu %9llu %9llu\n", 319 nfsstats.srvrpccnt[NFSPROC_MKNOD], 320 nfsstats.srvrpccnt[NFSPROC_FSSTAT], 321 nfsstats.srvrpccnt[NFSPROC_FSINFO], 322 nfsstats.srvrpccnt[NFSPROC_PATHCONF], 323 nfsstats.srvrpccnt[NFSPROC_COMMIT]); 324 printf("Server Ret-Failed\n"); 325 printf("%17llu\n", nfsstats.srvrpc_errs); 326 printf("Server Faults\n"); 327 printf("%13llu\n", nfsstats.srv_errs); 328 printf("Server Cache Stats:\n"); 329 printf("%9.9s %9.9s %9.9s %9.9s\n", 330 "Inprog", "Idem", "Non-idem", "Misses"); 331 printf("%9llu %9llu %9llu %9llu\n", 332 nfsstats.srvcache_inproghits, 333 nfsstats.srvcache_idemdonehits, 334 nfsstats.srvcache_nonidemdonehits, 335 nfsstats.srvcache_misses); 336 printf("Server Write Gathering:\n"); 337 printf("%9.9s %9.9s %9.9s\n", 338 "WriteOps", "WriteRPC", "Opsaved"); 339 printf("%9llu %9llu %9llu\n", 340 nfsstats.srvvop_writes, 341 nfsstats.srvrpccnt[NFSPROC_WRITE], 342 nfsstats.srvrpccnt[NFSPROC_WRITE] - nfsstats.srvvop_writes); 343 } 344 } 345 346 /* 347 * Print a running summary of nfs statistics. 348 * Repeat display every interval seconds, showing statistics 349 * collected over that interval. Assumes that interval is non-zero. 350 * First line printed at top of screen is always cumulative. 351 */ 352 void 353 sidewaysintpr(u_int interval, u_int display) 354 { 355 struct nfsstats nfsstats, lastst; 356 int hdrcnt; 357 sigset_t emptyset; 358 359 (void)signal(SIGALRM, catchalarm); 360 signalled = 0; 361 (void)alarm(interval); 362 bzero(&lastst, sizeof(lastst)); 363 364 for (hdrcnt = 1;;) { 365 if (!--hdrcnt) { 366 printhdr(); 367 hdrcnt = 20; 368 } 369 370 getnfsstats(&nfsstats); 371 372 if (display & SHOW_CLIENT) 373 printf("Client: " 374 "%8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu\n", 375 nfsstats.rpccnt[NFSPROC_GETATTR] - 376 lastst.rpccnt[NFSPROC_GETATTR], 377 nfsstats.rpccnt[NFSPROC_LOOKUP] - 378 lastst.rpccnt[NFSPROC_LOOKUP], 379 nfsstats.rpccnt[NFSPROC_READLINK] - 380 lastst.rpccnt[NFSPROC_READLINK], 381 nfsstats.rpccnt[NFSPROC_READ] - 382 lastst.rpccnt[NFSPROC_READ], 383 nfsstats.rpccnt[NFSPROC_WRITE] - 384 lastst.rpccnt[NFSPROC_WRITE], 385 nfsstats.rpccnt[NFSPROC_RENAME] - 386 lastst.rpccnt[NFSPROC_RENAME], 387 nfsstats.rpccnt[NFSPROC_ACCESS] - 388 lastst.rpccnt[NFSPROC_ACCESS], 389 (nfsstats.rpccnt[NFSPROC_READDIR] - 390 lastst.rpccnt[NFSPROC_READDIR]) + 391 (nfsstats.rpccnt[NFSPROC_READDIRPLUS] - 392 lastst.rpccnt[NFSPROC_READDIRPLUS])); 393 if (display & SHOW_SERVER) 394 printf("Server: " 395 "%8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu\n", 396 nfsstats.srvrpccnt[NFSPROC_GETATTR] - 397 lastst.srvrpccnt[NFSPROC_GETATTR], 398 nfsstats.srvrpccnt[NFSPROC_LOOKUP] - 399 lastst.srvrpccnt[NFSPROC_LOOKUP], 400 nfsstats.srvrpccnt[NFSPROC_READLINK] - 401 lastst.srvrpccnt[NFSPROC_READLINK], 402 nfsstats.srvrpccnt[NFSPROC_READ] - 403 lastst.srvrpccnt[NFSPROC_READ], 404 nfsstats.srvrpccnt[NFSPROC_WRITE] - 405 lastst.srvrpccnt[NFSPROC_WRITE], 406 nfsstats.srvrpccnt[NFSPROC_RENAME] - 407 lastst.srvrpccnt[NFSPROC_RENAME], 408 nfsstats.srvrpccnt[NFSPROC_ACCESS] - 409 lastst.srvrpccnt[NFSPROC_ACCESS], 410 (nfsstats.srvrpccnt[NFSPROC_READDIR] - 411 lastst.srvrpccnt[NFSPROC_READDIR]) + 412 (nfsstats.srvrpccnt[NFSPROC_READDIRPLUS] - 413 lastst.srvrpccnt[NFSPROC_READDIRPLUS])); 414 lastst = nfsstats; 415 fflush(stdout); 416 sigemptyset(&emptyset); 417 if (!signalled) 418 sigsuspend(&emptyset); 419 signalled = 0; 420 (void)alarm(interval); 421 } 422 /*NOTREACHED*/ 423 } 424 425 void 426 printhdr(void) 427 { 428 printf(" %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s\n", 429 "Getattr", "Lookup", "Readlink", "Read", "Write", "Rename", 430 "Access", "Readdir"); 431 fflush(stdout); 432 } 433 434 /* 435 * Called if an interval expires before sidewaysintpr has completed a loop. 436 * Sets a flag to not wait for the alarm. 437 */ 438 /* ARGSUSED */ 439 void 440 catchalarm(int signo) 441 { 442 signalled = 1; 443 } 444 445 void 446 usage(void) 447 { 448 extern char *__progname; 449 450 fprintf(stderr, "usage: %s [-cs] [-M core] [-N system] [-w wait]\n", 451 __progname); 452 exit(1); 453 } 454