nfsstat.c revision 40627
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 38static 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 45static char sccsid[] = "@(#)nfsstat.c 8.2 (Berkeley) 3/31/95"; 46#endif 47static const char rcsid[] = 48 "$Id: nfsstat.c,v 1.10 1998/01/20 12:27:38 bde Exp $"; 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 71struct nlist nl[] = { 72#define N_NFSSTAT 0 73 { "_nfsstats" }, 74 "", 75}; 76kvm_t *kd; 77 78static int deadkernel = 0; 79 80void intpr __P((void)); 81void printhdr __P((void)); 82void sidewaysintpr __P((u_int)); 83void usage __P((void)); 84 85main(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 */ 155void 156readstats(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 size_t buflen = sizeof *stp; 166 167 if (sysctlbyname("vfs.nfs.nfsstats", stp, &buflen, (void *)0, (size_t)0) < 0) { 168 err(1, "sysctl"); 169 } 170 } 171} 172 173/* 174 * Print a description of the nfs stats. 175 */ 176void 177intpr() 178{ 179 struct nfsstats nfsstats; 180 181 readstats(&nfsstats); 182 183 printf("Client Info:\n"); 184 printf("Rpc Counts:\n"); 185 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 186 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 187 "Write", "Create", "Remove"); 188 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 189 nfsstats.rpccnt[NFSPROC_GETATTR], 190 nfsstats.rpccnt[NFSPROC_SETATTR], 191 nfsstats.rpccnt[NFSPROC_LOOKUP], 192 nfsstats.rpccnt[NFSPROC_READLINK], 193 nfsstats.rpccnt[NFSPROC_READ], 194 nfsstats.rpccnt[NFSPROC_WRITE], 195 nfsstats.rpccnt[NFSPROC_CREATE], 196 nfsstats.rpccnt[NFSPROC_REMOVE]); 197 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 198 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 199 "Readdir", "RdirPlus", "Access"); 200 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 201 nfsstats.rpccnt[NFSPROC_RENAME], 202 nfsstats.rpccnt[NFSPROC_LINK], 203 nfsstats.rpccnt[NFSPROC_SYMLINK], 204 nfsstats.rpccnt[NFSPROC_MKDIR], 205 nfsstats.rpccnt[NFSPROC_RMDIR], 206 nfsstats.rpccnt[NFSPROC_READDIR], 207 nfsstats.rpccnt[NFSPROC_READDIRPLUS], 208 nfsstats.rpccnt[NFSPROC_ACCESS]); 209 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 210 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit", 211 "GLease", "Vacate", "Evict"); 212 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 213 nfsstats.rpccnt[NFSPROC_MKNOD], 214 nfsstats.rpccnt[NFSPROC_FSSTAT], 215 nfsstats.rpccnt[NFSPROC_FSINFO], 216 nfsstats.rpccnt[NFSPROC_PATHCONF], 217 nfsstats.rpccnt[NFSPROC_COMMIT], 218 nfsstats.rpccnt[NQNFSPROC_GETLEASE], 219 nfsstats.rpccnt[NQNFSPROC_VACATED], 220 nfsstats.rpccnt[NQNFSPROC_EVICTED]); 221 printf("Rpc Info:\n"); 222 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 223 "TimedOut", "Invalid", "X Replies", "Retries", "Requests"); 224 printf("%9d %9d %9d %9d %9d\n", 225 nfsstats.rpctimeouts, 226 nfsstats.rpcinvalid, 227 nfsstats.rpcunexpected, 228 nfsstats.rpcretries, 229 nfsstats.rpcrequests); 230 printf("Cache Info:\n"); 231 printf("%9.9s %9.9s %9.9s %9.9s", 232 "Attr Hits", "Misses", "Lkup Hits", "Misses"); 233 printf(" %9.9s %9.9s %9.9s %9.9s\n", 234 "BioR Hits", "Misses", "BioW Hits", "Misses"); 235 printf("%9d %9d %9d %9d", 236 nfsstats.attrcache_hits, nfsstats.attrcache_misses, 237 nfsstats.lookupcache_hits, nfsstats.lookupcache_misses); 238 printf(" %9d %9d %9d %9d\n", 239 nfsstats.biocache_reads-nfsstats.read_bios, 240 nfsstats.read_bios, 241 nfsstats.biocache_writes-nfsstats.write_bios, 242 nfsstats.write_bios); 243 printf("%9.9s %9.9s %9.9s %9.9s", 244 "BioRLHits", "Misses", "BioD Hits", "Misses"); 245 printf(" %9.9s %9.9s\n", "DirE Hits", "Misses"); 246 printf("%9d %9d %9d %9d", 247 nfsstats.biocache_readlinks-nfsstats.readlink_bios, 248 nfsstats.readlink_bios, 249 nfsstats.biocache_readdirs-nfsstats.readdir_bios, 250 nfsstats.readdir_bios); 251 printf(" %9d %9d\n", 252 nfsstats.direofcache_hits, nfsstats.direofcache_misses); 253 printf("\nServer Info:\n"); 254 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 255 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 256 "Write", "Create", "Remove"); 257 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 258 nfsstats.srvrpccnt[NFSPROC_GETATTR], 259 nfsstats.srvrpccnt[NFSPROC_SETATTR], 260 nfsstats.srvrpccnt[NFSPROC_LOOKUP], 261 nfsstats.srvrpccnt[NFSPROC_READLINK], 262 nfsstats.srvrpccnt[NFSPROC_READ], 263 nfsstats.srvrpccnt[NFSPROC_WRITE], 264 nfsstats.srvrpccnt[NFSPROC_CREATE], 265 nfsstats.srvrpccnt[NFSPROC_REMOVE]); 266 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 267 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 268 "Readdir", "RdirPlus", "Access"); 269 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 270 nfsstats.srvrpccnt[NFSPROC_RENAME], 271 nfsstats.srvrpccnt[NFSPROC_LINK], 272 nfsstats.srvrpccnt[NFSPROC_SYMLINK], 273 nfsstats.srvrpccnt[NFSPROC_MKDIR], 274 nfsstats.srvrpccnt[NFSPROC_RMDIR], 275 nfsstats.srvrpccnt[NFSPROC_READDIR], 276 nfsstats.srvrpccnt[NFSPROC_READDIRPLUS], 277 nfsstats.srvrpccnt[NFSPROC_ACCESS]); 278 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 279 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit", 280 "GLease", "Vacate", "Evict"); 281 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 282 nfsstats.srvrpccnt[NFSPROC_MKNOD], 283 nfsstats.srvrpccnt[NFSPROC_FSSTAT], 284 nfsstats.srvrpccnt[NFSPROC_FSINFO], 285 nfsstats.srvrpccnt[NFSPROC_PATHCONF], 286 nfsstats.srvrpccnt[NFSPROC_COMMIT], 287 nfsstats.srvrpccnt[NQNFSPROC_GETLEASE], 288 nfsstats.srvrpccnt[NQNFSPROC_VACATED], 289 nfsstats.srvrpccnt[NQNFSPROC_EVICTED]); 290 printf("Server Ret-Failed\n"); 291 printf("%17d\n", nfsstats.srvrpc_errs); 292 printf("Server Faults\n"); 293 printf("%13d\n", nfsstats.srv_errs); 294 printf("Server Cache Stats:\n"); 295 printf("%9.9s %9.9s %9.9s %9.9s\n", 296 "Inprog", "Idem", "Non-idem", "Misses"); 297 printf("%9d %9d %9d %9d\n", 298 nfsstats.srvcache_inproghits, 299 nfsstats.srvcache_idemdonehits, 300 nfsstats.srvcache_nonidemdonehits, 301 nfsstats.srvcache_misses); 302 printf("Server Lease Stats:\n"); 303 printf("%9.9s %9.9s %9.9s\n", 304 "Leases", "PeakL", "GLeases"); 305 printf("%9d %9d %9d\n", 306 nfsstats.srvnqnfs_leases, 307 nfsstats.srvnqnfs_maxleases, 308 nfsstats.srvnqnfs_getleases); 309 printf("Server Write Gathering:\n"); 310 printf("%9.9s %9.9s %9.9s\n", 311 "WriteOps", "WriteRPC", "Opsaved"); 312 printf("%9d %9d %9d\n", 313 nfsstats.srvvop_writes, 314 nfsstats.srvrpccnt[NFSPROC_WRITE], 315 nfsstats.srvrpccnt[NFSPROC_WRITE] - nfsstats.srvvop_writes); 316} 317 318u_char signalled; /* set if alarm goes off "early" */ 319 320/* 321 * Print a running summary of nfs statistics. 322 * Repeat display every interval seconds, showing statistics 323 * collected over that interval. Assumes that interval is non-zero. 324 * First line printed at top of screen is always cumulative. 325 */ 326void 327sidewaysintpr(interval) 328 u_int interval; 329{ 330 struct nfsstats nfsstats, lastst; 331 int hdrcnt, oldmask; 332 void catchalarm(); 333 334 (void)signal(SIGALRM, catchalarm); 335 signalled = 0; 336 (void)alarm(interval); 337 bzero((caddr_t)&lastst, sizeof(lastst)); 338 339 for (hdrcnt = 1;;) { 340 if (!--hdrcnt) { 341 printhdr(); 342 hdrcnt = 20; 343 } 344 readstats(&nfsstats); 345 printf("Client: %8d %8d %8d %8d %8d %8d %8d %8d\n", 346 nfsstats.rpccnt[NFSPROC_GETATTR]-lastst.rpccnt[NFSPROC_GETATTR], 347 nfsstats.rpccnt[NFSPROC_LOOKUP]-lastst.rpccnt[NFSPROC_LOOKUP], 348 nfsstats.rpccnt[NFSPROC_READLINK]-lastst.rpccnt[NFSPROC_READLINK], 349 nfsstats.rpccnt[NFSPROC_READ]-lastst.rpccnt[NFSPROC_READ], 350 nfsstats.rpccnt[NFSPROC_WRITE]-lastst.rpccnt[NFSPROC_WRITE], 351 nfsstats.rpccnt[NFSPROC_RENAME]-lastst.rpccnt[NFSPROC_RENAME], 352 nfsstats.rpccnt[NFSPROC_ACCESS]-lastst.rpccnt[NFSPROC_ACCESS], 353 (nfsstats.rpccnt[NFSPROC_READDIR]-lastst.rpccnt[NFSPROC_READDIR]) 354 +(nfsstats.rpccnt[NFSPROC_READDIRPLUS]-lastst.rpccnt[NFSPROC_READDIRPLUS])); 355 printf("Server: %8d %8d %8d %8d %8d %8d %8d %8d\n", 356 nfsstats.srvrpccnt[NFSPROC_GETATTR]-lastst.srvrpccnt[NFSPROC_GETATTR], 357 nfsstats.srvrpccnt[NFSPROC_LOOKUP]-lastst.srvrpccnt[NFSPROC_LOOKUP], 358 nfsstats.srvrpccnt[NFSPROC_READLINK]-lastst.srvrpccnt[NFSPROC_READLINK], 359 nfsstats.srvrpccnt[NFSPROC_READ]-lastst.srvrpccnt[NFSPROC_READ], 360 nfsstats.srvrpccnt[NFSPROC_WRITE]-lastst.srvrpccnt[NFSPROC_WRITE], 361 nfsstats.srvrpccnt[NFSPROC_RENAME]-lastst.srvrpccnt[NFSPROC_RENAME], 362 nfsstats.srvrpccnt[NFSPROC_ACCESS]-lastst.srvrpccnt[NFSPROC_ACCESS], 363 (nfsstats.srvrpccnt[NFSPROC_READDIR]-lastst.srvrpccnt[NFSPROC_READDIR]) 364 +(nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]-lastst.srvrpccnt[NFSPROC_READDIRPLUS])); 365 lastst = nfsstats; 366 fflush(stdout); 367 oldmask = sigblock(sigmask(SIGALRM)); 368 if (!signalled) 369 sigpause(0); 370 sigsetmask(oldmask); 371 signalled = 0; 372 (void)alarm(interval); 373 } 374 /*NOTREACHED*/ 375} 376 377void 378printhdr() 379{ 380 printf(" %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s\n", 381 "Getattr", "Lookup", "Readlink", "Read", "Write", "Rename", 382 "Access", "Readdir"); 383 fflush(stdout); 384} 385 386/* 387 * Called if an interval expires before sidewaysintpr has completed a loop. 388 * Sets a flag to not wait for the alarm. 389 */ 390void 391catchalarm() 392{ 393 signalled = 1; 394} 395 396void 397usage() 398{ 399 (void)fprintf(stderr, 400 "usage: nfsstat [-M core] [-N system] [-w interval]\n"); 401 exit(1); 402} 403