1 /* $OpenBSD: nfsstat.c,v 1.33 2009/10/27 23:59:40 deraadt 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 #include <sys/param.h> 37 #include <sys/mount.h> 38 #include <sys/sysctl.h> 39 #include <nfs/rpcv2.h> 40 #include <nfs/nfsproto.h> 41 #include <nfs/nfs.h> 42 #include <signal.h> 43 #include <fcntl.h> 44 #include <ctype.h> 45 #include <errno.h> 46 #include <kvm.h> 47 #include <nlist.h> 48 #include <unistd.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <limits.h> 53 #include <paths.h> 54 #include <err.h> 55 56 #define SHOW_SERVER 0x01 57 #define SHOW_CLIENT 0x02 58 #define SHOW_ALL (SHOW_SERVER | SHOW_CLIENT) 59 60 struct nlist nl[] = { 61 #define N_NFSSTAT 0 62 { "_nfsstats" }, 63 { "" }, 64 }; 65 kvm_t *kd; 66 volatile sig_atomic_t signalled; /* set if alarm goes off "early" */ 67 int nfs_id; 68 69 void getnfsstats(struct nfsstats *); 70 void printhdr(void); 71 void intpr(u_int); 72 void sidewaysintpr(u_int, u_int); 73 void usage(void); 74 void catchalarm(int); 75 76 int 77 main(int argc, char *argv[]) 78 { 79 u_int interval, display = SHOW_ALL; 80 extern int optind; 81 extern char *optarg; 82 char *memf, *nlistf; 83 const char *errstr; 84 int ch; 85 86 interval = 0; 87 memf = nlistf = NULL; 88 while ((ch = getopt(argc, argv, "cM:N:sw:")) != -1) 89 switch(ch) { 90 case 'M': 91 memf = optarg; 92 break; 93 case 'N': 94 nlistf = optarg; 95 break; 96 case 'w': 97 interval = (u_int)strtonum(optarg, 0, 1000, &errstr); 98 if (errstr) 99 errx(1, "invalid interval %s: %s", 100 optarg, errstr); 101 break; 102 case 's': 103 display = SHOW_SERVER; 104 break; 105 case 'c': 106 display = SHOW_CLIENT; 107 break; 108 case '?': 109 default: 110 usage(); 111 } 112 argc -= optind; 113 argv += optind; 114 115 #define BACKWARD_COMPATIBILITY 116 #ifdef BACKWARD_COMPATIBILITY 117 if (*argv) { 118 interval = (u_int)strtonum(*argv, 0, 1000, &errstr); 119 if (errstr) 120 errx(1, "invalid interval %s: %s", *argv, errstr); 121 if (*++argv) { 122 nlistf = *argv; 123 if (*++argv) 124 memf = *argv; 125 } 126 } 127 #endif 128 if (nlistf || memf) { 129 char errbuf[_POSIX2_LINE_MAX]; 130 131 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf)) == 0) 132 errx(1, "nfsstat: %s", errbuf); 133 if (kvm_nlist(kd, nl) != 0) 134 errx(1, "kvm_nlist: can't get names"); 135 } else { 136 int mib[4]; 137 size_t len; 138 139 mib[0] = CTL_VFS; 140 mib[1] = VFS_GENERIC; 141 mib[2] = VFS_MAXTYPENUM; 142 len = sizeof(nfs_id); 143 if (sysctl(mib, 3, &nfs_id, &len, NULL, 0)) 144 err(1, "sysctl: VFS_MAXTYPENUM"); 145 146 for (; nfs_id; nfs_id--) { 147 struct vfsconf vfsc; 148 149 mib[0] = CTL_VFS; 150 mib[1] = VFS_GENERIC; 151 mib[2] = VFS_CONF; 152 mib[3] = nfs_id; 153 154 len = sizeof(vfsc); 155 if (sysctl(mib, 4, &vfsc, &len, NULL, 0)) 156 continue; 157 158 if (!strcmp(vfsc.vfc_name, MOUNT_NFS)) 159 break; 160 } 161 if (nfs_id == 0) 162 errx(1, "cannot find nfs filesystem id"); 163 } 164 165 if (interval) 166 sidewaysintpr(interval, display); 167 else 168 intpr(display); 169 170 return 0; 171 } 172 173 void 174 getnfsstats(struct nfsstats *p) 175 { 176 if (kd) { 177 if (kvm_read(kd, nl[N_NFSSTAT].n_value, p, sizeof(*p)) != sizeof(*p)) 178 errx(1, "kvm_read failed"); 179 } else { 180 int mib[3]; 181 size_t len = sizeof(*p); 182 183 mib[0] = CTL_VFS; 184 mib[1] = nfs_id; /* 2 */ 185 mib[2] = NFS_NFSSTATS; 186 187 if (sysctl(mib, 3, p, &len, NULL, 0)) 188 err(1, "sysctl"); 189 } 190 } 191 192 /* 193 * Print a description of the nfs stats. 194 */ 195 void 196 intpr(u_int display) 197 { 198 struct nfsstats nfsstats; 199 200 getnfsstats(&nfsstats); 201 202 if (display & SHOW_CLIENT) { 203 printf("Client Info:\n"); 204 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 205 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 206 "Write", "Create", "Remove"); 207 printf("%9llu %9llu %9llu %9llu %9llu %9llu %9llu %9llu\n", 208 nfsstats.rpccnt[NFSPROC_GETATTR], 209 nfsstats.rpccnt[NFSPROC_SETATTR], 210 nfsstats.rpccnt[NFSPROC_LOOKUP], 211 nfsstats.rpccnt[NFSPROC_READLINK], 212 nfsstats.rpccnt[NFSPROC_READ], 213 nfsstats.rpccnt[NFSPROC_WRITE], 214 nfsstats.rpccnt[NFSPROC_CREATE], 215 nfsstats.rpccnt[NFSPROC_REMOVE]); 216 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 217 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 218 "Readdir", "RdirPlus", "Access"); 219 printf("%9llu %9llu %9llu %9llu %9llu %9llu %9llu %9llu\n", 220 nfsstats.rpccnt[NFSPROC_RENAME], 221 nfsstats.rpccnt[NFSPROC_LINK], 222 nfsstats.rpccnt[NFSPROC_SYMLINK], 223 nfsstats.rpccnt[NFSPROC_MKDIR], 224 nfsstats.rpccnt[NFSPROC_RMDIR], 225 nfsstats.rpccnt[NFSPROC_READDIR], 226 nfsstats.rpccnt[NFSPROC_READDIRPLUS], 227 nfsstats.rpccnt[NFSPROC_ACCESS]); 228 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 229 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit"); 230 printf("%9llu %9llu %9llu %9llu %9llu\n", 231 nfsstats.rpccnt[NFSPROC_MKNOD], 232 nfsstats.rpccnt[NFSPROC_FSSTAT], 233 nfsstats.rpccnt[NFSPROC_FSINFO], 234 nfsstats.rpccnt[NFSPROC_PATHCONF], 235 nfsstats.rpccnt[NFSPROC_COMMIT]); 236 printf("Rpc Info:\n"); 237 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 238 "TimedOut", "Invalid", "X Replies", "Retries", "Requests", 239 "FrcSync"); 240 printf("%9llu %9llu %9llu %9llu %9llu %9llu\n", 241 nfsstats.rpctimeouts, 242 nfsstats.rpcinvalid, 243 nfsstats.rpcunexpected, 244 nfsstats.rpcretries, 245 nfsstats.rpcrequests, 246 nfsstats.forcedsync); 247 printf("Cache Info:\n"); 248 printf("%9.9s %9.9s %9.9s %9.9s", 249 "Attr Hits", "Misses", "Lkup Hits", "Misses"); 250 printf(" %9.9s %9.9s %9.9s %9.9s\n", 251 "BioR Hits", "Misses", "BioW Hits", "Misses"); 252 printf("%9llu %9llu %9llu %9llu", 253 nfsstats.attrcache_hits, nfsstats.attrcache_misses, 254 nfsstats.lookupcache_hits, nfsstats.lookupcache_misses); 255 printf(" %9llu %9llu %9llu %9llu\n", 256 nfsstats.biocache_reads-nfsstats.read_bios, 257 nfsstats.read_bios, 258 nfsstats.biocache_writes-nfsstats.write_bios, 259 nfsstats.write_bios); 260 printf("%9.9s %9.9s %9.9s %9.9s", 261 "BioRLHits", "Misses", "BioD Hits", "Misses"); 262 printf(" %9.9s %9.9s\n", "DirE Hits", "Misses"); 263 printf("%9llu %9llu %9llu %9llu", 264 nfsstats.biocache_readlinks-nfsstats.readlink_bios, 265 nfsstats.readlink_bios, 266 nfsstats.biocache_readdirs-nfsstats.readdir_bios, 267 nfsstats.readdir_bios); 268 printf(" %9llu %9llu\n", 269 nfsstats.direofcache_hits, nfsstats.direofcache_misses); 270 } 271 272 if (display == SHOW_ALL) 273 printf("\n"); 274 275 if (display & SHOW_SERVER) { 276 printf("Server Info:\n"); 277 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 278 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 279 "Write", "Create", "Remove"); 280 printf("%9llu %9llu %9llu %9llu %9llu %9llu %9llu %9llu\n", 281 nfsstats.srvrpccnt[NFSPROC_GETATTR], 282 nfsstats.srvrpccnt[NFSPROC_SETATTR], 283 nfsstats.srvrpccnt[NFSPROC_LOOKUP], 284 nfsstats.srvrpccnt[NFSPROC_READLINK], 285 nfsstats.srvrpccnt[NFSPROC_READ], 286 nfsstats.srvrpccnt[NFSPROC_WRITE], 287 nfsstats.srvrpccnt[NFSPROC_CREATE], 288 nfsstats.srvrpccnt[NFSPROC_REMOVE]); 289 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 290 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 291 "Readdir", "RdirPlus", "Access"); 292 printf("%9llu %9llu %9llu %9llu %9llu %9llu %9llu %9llu\n", 293 nfsstats.srvrpccnt[NFSPROC_RENAME], 294 nfsstats.srvrpccnt[NFSPROC_LINK], 295 nfsstats.srvrpccnt[NFSPROC_SYMLINK], 296 nfsstats.srvrpccnt[NFSPROC_MKDIR], 297 nfsstats.srvrpccnt[NFSPROC_RMDIR], 298 nfsstats.srvrpccnt[NFSPROC_READDIR], 299 nfsstats.srvrpccnt[NFSPROC_READDIRPLUS], 300 nfsstats.srvrpccnt[NFSPROC_ACCESS]); 301 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 302 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit"); 303 printf("%9llu %9llu %9llu %9llu %9llu\n", 304 nfsstats.srvrpccnt[NFSPROC_MKNOD], 305 nfsstats.srvrpccnt[NFSPROC_FSSTAT], 306 nfsstats.srvrpccnt[NFSPROC_FSINFO], 307 nfsstats.srvrpccnt[NFSPROC_PATHCONF], 308 nfsstats.srvrpccnt[NFSPROC_COMMIT]); 309 printf("Server Ret-Failed\n"); 310 printf("%17llu\n", nfsstats.srvrpc_errs); 311 printf("Server Faults\n"); 312 printf("%13llu\n", nfsstats.srv_errs); 313 printf("Server Cache Stats:\n"); 314 printf("%9.9s %9.9s %9.9s %9.9s\n", 315 "Inprog", "Idem", "Non-idem", "Misses"); 316 printf("%9llu %9llu %9llu %9llu\n", 317 nfsstats.srvcache_inproghits, 318 nfsstats.srvcache_idemdonehits, 319 nfsstats.srvcache_nonidemdonehits, 320 nfsstats.srvcache_misses); 321 printf("Server Write Gathering:\n"); 322 printf("%9.9s %9.9s %9.9s\n", 323 "WriteOps", "WriteRPC", "Opsaved"); 324 printf("%9llu %9llu %9llu\n", 325 nfsstats.srvvop_writes, 326 nfsstats.srvrpccnt[NFSPROC_WRITE], 327 nfsstats.srvrpccnt[NFSPROC_WRITE] - nfsstats.srvvop_writes); 328 } 329 } 330 331 /* 332 * Print a running summary of nfs statistics. 333 * Repeat display every interval seconds, showing statistics 334 * collected over that interval. Assumes that interval is non-zero. 335 * First line printed at top of screen is always cumulative. 336 */ 337 void 338 sidewaysintpr(u_int interval, u_int display) 339 { 340 struct nfsstats nfsstats, lastst; 341 int hdrcnt; 342 sigset_t emptyset; 343 344 (void)signal(SIGALRM, catchalarm); 345 signalled = 0; 346 (void)alarm(interval); 347 bzero(&lastst, sizeof(lastst)); 348 349 for (hdrcnt = 1;;) { 350 if (!--hdrcnt) { 351 printhdr(); 352 hdrcnt = 20; 353 } 354 355 getnfsstats(&nfsstats); 356 357 if (display & SHOW_CLIENT) 358 printf("Client: " 359 "%8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu\n", 360 nfsstats.rpccnt[NFSPROC_GETATTR] - 361 lastst.rpccnt[NFSPROC_GETATTR], 362 nfsstats.rpccnt[NFSPROC_LOOKUP] - 363 lastst.rpccnt[NFSPROC_LOOKUP], 364 nfsstats.rpccnt[NFSPROC_READLINK] - 365 lastst.rpccnt[NFSPROC_READLINK], 366 nfsstats.rpccnt[NFSPROC_READ] - 367 lastst.rpccnt[NFSPROC_READ], 368 nfsstats.rpccnt[NFSPROC_WRITE] - 369 lastst.rpccnt[NFSPROC_WRITE], 370 nfsstats.rpccnt[NFSPROC_RENAME] - 371 lastst.rpccnt[NFSPROC_RENAME], 372 nfsstats.rpccnt[NFSPROC_ACCESS] - 373 lastst.rpccnt[NFSPROC_ACCESS], 374 (nfsstats.rpccnt[NFSPROC_READDIR] - 375 lastst.rpccnt[NFSPROC_READDIR]) + 376 (nfsstats.rpccnt[NFSPROC_READDIRPLUS] - 377 lastst.rpccnt[NFSPROC_READDIRPLUS])); 378 if (display & SHOW_SERVER) 379 printf("Server: " 380 "%8llu %8llu %8llu %8llu %8llu %8llu %8llu %8llu\n", 381 nfsstats.srvrpccnt[NFSPROC_GETATTR] - 382 lastst.srvrpccnt[NFSPROC_GETATTR], 383 nfsstats.srvrpccnt[NFSPROC_LOOKUP] - 384 lastst.srvrpccnt[NFSPROC_LOOKUP], 385 nfsstats.srvrpccnt[NFSPROC_READLINK] - 386 lastst.srvrpccnt[NFSPROC_READLINK], 387 nfsstats.srvrpccnt[NFSPROC_READ] - 388 lastst.srvrpccnt[NFSPROC_READ], 389 nfsstats.srvrpccnt[NFSPROC_WRITE] - 390 lastst.srvrpccnt[NFSPROC_WRITE], 391 nfsstats.srvrpccnt[NFSPROC_RENAME] - 392 lastst.srvrpccnt[NFSPROC_RENAME], 393 nfsstats.srvrpccnt[NFSPROC_ACCESS] - 394 lastst.srvrpccnt[NFSPROC_ACCESS], 395 (nfsstats.srvrpccnt[NFSPROC_READDIR] - 396 lastst.srvrpccnt[NFSPROC_READDIR]) + 397 (nfsstats.srvrpccnt[NFSPROC_READDIRPLUS] - 398 lastst.srvrpccnt[NFSPROC_READDIRPLUS])); 399 lastst = nfsstats; 400 fflush(stdout); 401 sigemptyset(&emptyset); 402 if (!signalled) 403 sigsuspend(&emptyset); 404 signalled = 0; 405 (void)alarm(interval); 406 } 407 /*NOTREACHED*/ 408 } 409 410 void 411 printhdr(void) 412 { 413 printf(" %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s\n", 414 "Getattr", "Lookup", "Readlink", "Read", "Write", "Rename", 415 "Access", "Readdir"); 416 fflush(stdout); 417 } 418 419 /* 420 * Called if an interval expires before sidewaysintpr has completed a loop. 421 * Sets a flag to not wait for the alarm. 422 */ 423 /* ARGSUSED */ 424 void 425 catchalarm(int signo) 426 { 427 signalled = 1; 428 } 429 430 void 431 usage(void) 432 { 433 extern char *__progname; 434 435 fprintf(stderr, "usage: %s [-cs] [-M core] [-N system] [-w wait]\n", 436 __progname); 437 exit(1); 438 } 439