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