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