nfsstat.c revision 9336
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/*static char sccsid[] = "From: @(#)nfsstat.c 8.1 (Berkeley) 6/6/93";*/ 45static const char rcsid[] = 46 "$Id: nfsstat.c,v 1.2 1994/10/23 23:25:43 wollman Exp $"; 47#endif /* not lint */ 48 49#include <sys/param.h> 50#include <sys/mount.h> 51#include <sys/sysctl.h> 52#include <nfs/rpcv2.h> 53#include <nfs/nfsproto.h> 54#include <nfs/nfs.h> 55#include <signal.h> 56#include <fcntl.h> 57#include <ctype.h> 58#include <errno.h> 59#include <kvm.h> 60#include <nlist.h> 61#include <unistd.h> 62#include <stdio.h> 63#include <stdlib.h> 64#include <string.h> 65#include <paths.h> 66#include <err.h> 67 68struct nlist nl[] = { 69#define N_NFSSTAT 0 70 { "_nfsstats" }, 71 "", 72}; 73kvm_t *kd; 74 75static int deadkernel = 0; 76 77void intpr __P((void)); 78void printhdr __P((void)); 79void sidewaysintpr __P((u_int)); 80void usage __P((void)); 81 82main(argc, argv) 83 int argc; 84 char **argv; 85{ 86 extern int optind; 87 extern char *optarg; 88 u_int interval; 89 int ch; 90 char *memf, *nlistf; 91 char errbuf[80]; 92 93 interval = 0; 94 memf = nlistf = NULL; 95 while ((ch = getopt(argc, argv, "M:N:w:")) != EOF) 96 switch(ch) { 97 case 'M': 98 memf = optarg; 99 break; 100 case 'N': 101 nlistf = optarg; 102 break; 103 case 'w': 104 interval = atoi(optarg); 105 break; 106 case '?': 107 default: 108 usage(); 109 } 110 argc -= optind; 111 argv += optind; 112 113#define BACKWARD_COMPATIBILITY 114#ifdef BACKWARD_COMPATIBILITY 115 if (*argv) { 116 interval = atoi(*argv); 117 if (*++argv) { 118 nlistf = *argv; 119 if (*++argv) 120 memf = *argv; 121 } 122 } 123#endif 124 /* 125 * Discard setgid privileges if not the running kernel so that bad 126 * guys can't print interesting stuff from kernel memory. 127 */ 128 if (nlistf != NULL || memf != NULL) { 129 setgid(getgid()); 130 deadkernel = 1; 131 132 if ((kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, 133 errbuf)) == 0) { 134 errx(1, "kvm_openfiles: %s", errbuf); 135 } 136 if (kvm_nlist(kd, nl) != 0) { 137 errx(1, "kvm_nlist: can't get names"); 138 } 139 } 140 141 if (interval) 142 sidewaysintpr(interval); 143 else 144 intpr(); 145 exit(0); 146} 147 148/* 149 * Read the nfs stats using sysctl(3) for live kernels, or kvm_read 150 * for dead ones. 151 */ 152void 153readstats(stp) 154 struct nfsstats *stp; 155{ 156 if(deadkernel) { 157 if(kvm_read(kd, (u_long)nl[N_NFSSTAT].n_value, stp, 158 sizeof *stp) < 0) { 159 err(1, "kvm_read"); 160 } 161 } else { 162 int name[3]; 163 size_t buflen = sizeof *stp; 164 165 name[0] = CTL_FS; 166 name[1] = MOUNT_NFS; 167 name[2] = NFS_NFSSTATS; 168 169 if(sysctl(name, 3, stp, &buflen, (void *)0, (size_t)0) < 0) { 170 err(1, "sysctl"); 171 } 172 } 173} 174 175/* 176 * Print a description of the nfs stats. 177 */ 178void 179intpr() 180{ 181 struct nfsstats nfsstats; 182 183 readstats(&nfsstats); 184 185 printf("Client Info:\n"); 186 printf("Rpc Counts:\n"); 187 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 188 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 189 "Write", "Create", "Remove"); 190 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 191 nfsstats.rpccnt[NFSPROC_GETATTR], 192 nfsstats.rpccnt[NFSPROC_SETATTR], 193 nfsstats.rpccnt[NFSPROC_LOOKUP], 194 nfsstats.rpccnt[NFSPROC_READLINK], 195 nfsstats.rpccnt[NFSPROC_READ], 196 nfsstats.rpccnt[NFSPROC_WRITE], 197 nfsstats.rpccnt[NFSPROC_CREATE], 198 nfsstats.rpccnt[NFSPROC_REMOVE]); 199 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 200 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 201 "Readdir", "RdirPlus", "Access"); 202 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 203 nfsstats.rpccnt[NFSPROC_RENAME], 204 nfsstats.rpccnt[NFSPROC_LINK], 205 nfsstats.rpccnt[NFSPROC_SYMLINK], 206 nfsstats.rpccnt[NFSPROC_MKDIR], 207 nfsstats.rpccnt[NFSPROC_RMDIR], 208 nfsstats.rpccnt[NFSPROC_READDIR], 209 nfsstats.rpccnt[NFSPROC_READDIRPLUS], 210 nfsstats.rpccnt[NFSPROC_ACCESS]); 211 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 212 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit", 213 "GLease", "Vacate", "Evict"); 214 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 215 nfsstats.rpccnt[NFSPROC_MKNOD], 216 nfsstats.rpccnt[NFSPROC_FSSTAT], 217 nfsstats.rpccnt[NFSPROC_FSINFO], 218 nfsstats.rpccnt[NFSPROC_PATHCONF], 219 nfsstats.rpccnt[NFSPROC_COMMIT], 220 nfsstats.rpccnt[NQNFSPROC_GETLEASE], 221 nfsstats.rpccnt[NQNFSPROC_VACATED], 222 nfsstats.rpccnt[NQNFSPROC_EVICTED]); 223 printf("Rpc Info:\n"); 224 printf("%9.9s %9.9s %9.9s %9.9s %9.9s\n", 225 "TimedOut", "Invalid", "X Replies", "Retries", "Requests"); 226 printf("%9d %9d %9d %9d %9d\n", 227 nfsstats.rpctimeouts, 228 nfsstats.rpcinvalid, 229 nfsstats.rpcunexpected, 230 nfsstats.rpcretries, 231 nfsstats.rpcrequests); 232 printf("Cache Info:\n"); 233 printf("%9.9s %9.9s %9.9s %9.9s", 234 "Attr Hits", "Misses", "Lkup Hits", "Misses"); 235 printf(" %9.9s %9.9s %9.9s %9.9s\n", 236 "BioR Hits", "Misses", "BioW Hits", "Misses"); 237 printf("%9d %9d %9d %9d", 238 nfsstats.attrcache_hits, nfsstats.attrcache_misses, 239 nfsstats.lookupcache_hits, nfsstats.lookupcache_misses); 240 printf(" %9d %9d %9d %9d\n", 241 nfsstats.biocache_reads-nfsstats.read_bios, 242 nfsstats.read_bios, 243 nfsstats.biocache_writes-nfsstats.write_bios, 244 nfsstats.write_bios); 245 printf("%9.9s %9.9s %9.9s %9.9s", 246 "BioRLHits", "Misses", "BioD Hits", "Misses"); 247 printf(" %9.9s %9.9s\n", "DirE Hits", "Misses"); 248 printf("%9d %9d %9d %9d", 249 nfsstats.biocache_readlinks-nfsstats.readlink_bios, 250 nfsstats.readlink_bios, 251 nfsstats.biocache_readdirs-nfsstats.readdir_bios, 252 nfsstats.readdir_bios); 253 printf(" %9d %9d\n", 254 nfsstats.direofcache_hits, nfsstats.direofcache_misses); 255 printf("\nServer Info:\n"); 256 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 257 "Getattr", "Setattr", "Lookup", "Readlink", "Read", 258 "Write", "Create", "Remove"); 259 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 260 nfsstats.srvrpccnt[NFSPROC_GETATTR], 261 nfsstats.srvrpccnt[NFSPROC_SETATTR], 262 nfsstats.srvrpccnt[NFSPROC_LOOKUP], 263 nfsstats.srvrpccnt[NFSPROC_READLINK], 264 nfsstats.srvrpccnt[NFSPROC_READ], 265 nfsstats.srvrpccnt[NFSPROC_WRITE], 266 nfsstats.srvrpccnt[NFSPROC_CREATE], 267 nfsstats.srvrpccnt[NFSPROC_REMOVE]); 268 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 269 "Rename", "Link", "Symlink", "Mkdir", "Rmdir", 270 "Readdir", "RdirPlus", "Access"); 271 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 272 nfsstats.srvrpccnt[NFSPROC_RENAME], 273 nfsstats.srvrpccnt[NFSPROC_LINK], 274 nfsstats.srvrpccnt[NFSPROC_SYMLINK], 275 nfsstats.srvrpccnt[NFSPROC_MKDIR], 276 nfsstats.srvrpccnt[NFSPROC_RMDIR], 277 nfsstats.srvrpccnt[NFSPROC_READDIR], 278 nfsstats.srvrpccnt[NFSPROC_READDIRPLUS], 279 nfsstats.srvrpccnt[NFSPROC_ACCESS]); 280 printf("%9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s %9.9s\n", 281 "Mknod", "Fsstat", "Fsinfo", "PathConf", "Commit", 282 "GLease", "Vacate", "Evict"); 283 printf("%9d %9d %9d %9d %9d %9d %9d %9d\n", 284 nfsstats.srvrpccnt[NFSPROC_MKNOD], 285 nfsstats.srvrpccnt[NFSPROC_FSSTAT], 286 nfsstats.srvrpccnt[NFSPROC_FSINFO], 287 nfsstats.srvrpccnt[NFSPROC_PATHCONF], 288 nfsstats.srvrpccnt[NFSPROC_COMMIT], 289 nfsstats.srvrpccnt[NQNFSPROC_GETLEASE], 290 nfsstats.srvrpccnt[NQNFSPROC_VACATED], 291 nfsstats.srvrpccnt[NQNFSPROC_EVICTED]); 292 printf("Server Ret-Failed\n"); 293 printf("%17d\n", nfsstats.srvrpc_errs); 294 printf("Server Faults\n"); 295 printf("%13d\n", nfsstats.srv_errs); 296 printf("Server Cache Stats:\n"); 297 printf("%9.9s %9.9s %9.9s %9.9s\n", 298 "Inprog", "Idem", "Non-idem", "Misses"); 299 printf("%9d %9d %9d %9d\n", 300 nfsstats.srvcache_inproghits, 301 nfsstats.srvcache_idemdonehits, 302 nfsstats.srvcache_nonidemdonehits, 303 nfsstats.srvcache_misses); 304 printf("Server Lease Stats:\n"); 305 printf("%9.9s %9.9s %9.9s\n", 306 "Leases", "PeakL", "GLeases"); 307 printf("%9d %9d %9d\n", 308 nfsstats.srvnqnfs_leases, 309 nfsstats.srvnqnfs_maxleases, 310 nfsstats.srvnqnfs_getleases); 311 printf("Server Write Gathering:\n"); 312 printf("%9.9s %9.9s %9.9s\n", 313 "WriteOps", "WriteRPC", "Opsaved"); 314 printf("%9d %9d %9d\n", 315 nfsstats.srvvop_writes, 316 nfsstats.srvrpccnt[NFSPROC_WRITE], 317 nfsstats.srvrpccnt[NFSPROC_WRITE] - nfsstats.srvvop_writes); 318} 319 320u_char signalled; /* set if alarm goes off "early" */ 321 322/* 323 * Print a running summary of nfs statistics. 324 * Repeat display every interval seconds, showing statistics 325 * collected over that interval. Assumes that interval is non-zero. 326 * First line printed at top of screen is always cumulative. 327 */ 328void 329sidewaysintpr(interval) 330 u_int interval; 331{ 332 struct nfsstats nfsstats, lastst; 333 int hdrcnt, oldmask; 334 void catchalarm(); 335 336 (void)signal(SIGALRM, catchalarm); 337 signalled = 0; 338 (void)alarm(interval); 339 bzero((caddr_t)&lastst, sizeof(lastst)); 340 341 for (hdrcnt = 1;;) { 342 if (!--hdrcnt) { 343 printhdr(); 344 hdrcnt = 20; 345 } 346 readstats(&nfsstats); 347 printf("Client: %8d %8d %8d %8d %8d %8d %8d %8d\n", 348 nfsstats.rpccnt[NFSPROC_GETATTR]-lastst.rpccnt[NFSPROC_GETATTR], 349 nfsstats.rpccnt[NFSPROC_LOOKUP]-lastst.rpccnt[NFSPROC_LOOKUP], 350 nfsstats.rpccnt[NFSPROC_READLINK]-lastst.rpccnt[NFSPROC_READLINK], 351 nfsstats.rpccnt[NFSPROC_READ]-lastst.rpccnt[NFSPROC_READ], 352 nfsstats.rpccnt[NFSPROC_WRITE]-lastst.rpccnt[NFSPROC_WRITE], 353 nfsstats.rpccnt[NFSPROC_RENAME]-lastst.rpccnt[NFSPROC_RENAME], 354 nfsstats.rpccnt[NFSPROC_ACCESS]-lastst.rpccnt[NFSPROC_ACCESS], 355 (nfsstats.rpccnt[NFSPROC_READDIR]-lastst.rpccnt[NFSPROC_READDIR]) 356 +(nfsstats.rpccnt[NFSPROC_READDIRPLUS]-lastst.rpccnt[NFSPROC_READDIRPLUS])); 357 printf("Server: %8d %8d %8d %8d %8d %8d %8d %8d\n", 358 nfsstats.srvrpccnt[NFSPROC_GETATTR]-lastst.srvrpccnt[NFSPROC_GETATTR], 359 nfsstats.srvrpccnt[NFSPROC_LOOKUP]-lastst.srvrpccnt[NFSPROC_LOOKUP], 360 nfsstats.srvrpccnt[NFSPROC_READLINK]-lastst.srvrpccnt[NFSPROC_READLINK], 361 nfsstats.srvrpccnt[NFSPROC_READ]-lastst.srvrpccnt[NFSPROC_READ], 362 nfsstats.srvrpccnt[NFSPROC_WRITE]-lastst.srvrpccnt[NFSPROC_WRITE], 363 nfsstats.srvrpccnt[NFSPROC_RENAME]-lastst.srvrpccnt[NFSPROC_RENAME], 364 nfsstats.srvrpccnt[NFSPROC_ACCESS]-lastst.srvrpccnt[NFSPROC_ACCESS], 365 (nfsstats.srvrpccnt[NFSPROC_READDIR]-lastst.srvrpccnt[NFSPROC_READDIR]) 366 +(nfsstats.srvrpccnt[NFSPROC_READDIRPLUS]-lastst.srvrpccnt[NFSPROC_READDIRPLUS])); 367 lastst = nfsstats; 368 fflush(stdout); 369 oldmask = sigblock(sigmask(SIGALRM)); 370 if (!signalled) 371 sigpause(0); 372 sigsetmask(oldmask); 373 signalled = 0; 374 (void)alarm(interval); 375 } 376 /*NOTREACHED*/ 377} 378 379void 380printhdr() 381{ 382 printf(" %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s %8.8s\n", 383 "Getattr", "Lookup", "Readlink", "Read", "Write", "Rename", 384 "Access", "Readdir"); 385 fflush(stdout); 386} 387 388/* 389 * Called if an interval expires before sidewaysintpr has completed a loop. 390 * Sets a flag to not wait for the alarm. 391 */ 392void 393catchalarm() 394{ 395 signalled = 1; 396} 397 398void 399usage() 400{ 401 (void)fprintf(stderr, 402 "usage: nfsstat [-M core] [-N system] [-w interval]\n"); 403 exit(1); 404} 405