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