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