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