1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* LINTLIBRARY */ 23 /* PROTOLIB1 */ 24 25 /* 26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 /* 31 * nfsstat: Network File System statistics 32 * 33 */ 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <stdarg.h> 39 #include <string.h> 40 #include <errno.h> 41 #include <fcntl.h> 42 #include <kvm.h> 43 #include <kstat.h> 44 #include <sys/param.h> 45 #include <sys/types.h> 46 #include <sys/t_lock.h> 47 #include <sys/tiuser.h> 48 #include <sys/statvfs.h> 49 #include <sys/mntent.h> 50 #include <sys/mnttab.h> 51 #include <sys/sysmacros.h> 52 #include <sys/mkdev.h> 53 #include <rpc/types.h> 54 #include <rpc/xdr.h> 55 #include <rpc/auth.h> 56 #include <rpc/clnt.h> 57 #include <nfs/nfs.h> 58 #include <nfs/nfs_clnt.h> 59 #include <nfs/nfs_sec.h> 60 #include <inttypes.h> 61 #include <signal.h> 62 #include <time.h> 63 #include <sys/time.h> 64 #include <strings.h> 65 #include <ctype.h> 66 #include <locale.h> 67 68 #include "statcommon.h" 69 70 static kstat_ctl_t *kc = NULL; /* libkstat cookie */ 71 static kstat_t *rpc_clts_client_kstat, *rpc_clts_server_kstat; 72 static kstat_t *rpc_cots_client_kstat, *rpc_cots_server_kstat; 73 static kstat_t *rpc_rdma_client_kstat, *rpc_rdma_server_kstat; 74 static kstat_t *nfs_client_kstat, *nfs_server_v2_kstat, *nfs_server_v3_kstat; 75 static kstat_t *nfs4_client_kstat, *nfs_server_v4_kstat; 76 static kstat_t *rfsproccnt_v2_kstat, *rfsproccnt_v3_kstat, *rfsproccnt_v4_kstat; 77 static kstat_t *rfsreqcnt_v2_kstat, *rfsreqcnt_v3_kstat, *rfsreqcnt_v4_kstat; 78 static kstat_t *aclproccnt_v2_kstat, *aclproccnt_v3_kstat; 79 static kstat_t *aclreqcnt_v2_kstat, *aclreqcnt_v3_kstat; 80 static kstat_t *ksum_kstat; 81 82 static void handle_sig(int); 83 static int getstats_rpc(void); 84 static int getstats_nfs(void); 85 static int getstats_rfsproc(int); 86 static int getstats_rfsreq(int); 87 static int getstats_aclproc(void); 88 static int getstats_aclreq(void); 89 static void putstats(void); 90 static void setup(void); 91 static void cr_print(int); 92 static void sr_print(int); 93 static void cn_print(int, int); 94 static void sn_print(int, int); 95 static void ca_print(int, int); 96 static void sa_print(int, int); 97 static void req_print(kstat_t *, kstat_t *, int, int, int); 98 static void req_print_v4(kstat_t *, kstat_t *, int, int); 99 static void stat_print(const char *, kstat_t *, kstat_t *, int, int); 100 static void nfsstat_kstat_sum(kstat_t *, kstat_t *, kstat_t *); 101 static void stats_timer(int); 102 static void safe_zalloc(void **, uint_t, int); 103 static int safe_strtoi(char const *, char *); 104 105 106 static void nfsstat_kstat_copy(kstat_t *, kstat_t *, int); 107 static kid_t safe_kstat_read(kstat_ctl_t *, kstat_t *, void *); 108 static kid_t safe_kstat_write(kstat_ctl_t *, kstat_t *, void *); 109 110 static void usage(void); 111 static void mi_print(void); 112 static int ignore(char *); 113 static int interval; /* interval between stats */ 114 static int count; /* number of iterations the stat is printed */ 115 #define MAX_COLUMNS 80 116 #define MAX_PATHS 50 /* max paths that can be taken by -m */ 117 118 /* 119 * MI4_MIRRORMOUNT is canonically defined in nfs4_clnt.h, but we cannot 120 * include that file here. Same with MI4_REFERRAL. 121 */ 122 #define MI4_MIRRORMOUNT 0x4000 123 #define MI4_REFERRAL 0x8000 124 #define NFS_V4 4 125 126 static int req_width(kstat_t *, int); 127 static int stat_width(kstat_t *, int); 128 static char *path [MAX_PATHS] = {NULL}; /* array to store the multiple paths */ 129 130 /* 131 * Struct holds the previous kstat values so 132 * we can compute deltas when using the -i flag 133 */ 134 typedef struct old_kstat 135 { 136 kstat_t kst; 137 int tot; 138 } old_kstat_t; 139 140 static old_kstat_t old_rpc_clts_client_kstat, old_rpc_clts_server_kstat; 141 static old_kstat_t old_rpc_cots_client_kstat, old_rpc_cots_server_kstat; 142 static old_kstat_t old_rpc_rdma_client_kstat, old_rpc_rdma_server_kstat; 143 static old_kstat_t old_nfs_client_kstat, old_nfs_server_v2_kstat; 144 static old_kstat_t old_nfs_server_v3_kstat, old_ksum_kstat; 145 static old_kstat_t old_nfs4_client_kstat, old_nfs_server_v4_kstat; 146 static old_kstat_t old_rfsproccnt_v2_kstat, old_rfsproccnt_v3_kstat; 147 static old_kstat_t old_rfsproccnt_v4_kstat, old_rfsreqcnt_v2_kstat; 148 static old_kstat_t old_rfsreqcnt_v3_kstat, old_rfsreqcnt_v4_kstat; 149 static old_kstat_t old_aclproccnt_v2_kstat, old_aclproccnt_v3_kstat; 150 static old_kstat_t old_aclreqcnt_v2_kstat, old_aclreqcnt_v3_kstat; 151 152 static uint_t timestamp_fmt = NODATE; 153 154 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 155 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't */ 156 #endif 157 158 int 159 main(int argc, char *argv[]) 160 { 161 int c, go_forever, j; 162 int cflag = 0; /* client stats */ 163 int sflag = 0; /* server stats */ 164 int nflag = 0; /* nfs stats */ 165 int rflag = 0; /* rpc stats */ 166 int mflag = 0; /* mount table stats */ 167 int aflag = 0; /* print acl statistics */ 168 int vflag = 0; /* version specified, 0 specifies all */ 169 int zflag = 0; /* zero stats after printing */ 170 char *split_line = "*******************************************" 171 "*************************************"; 172 173 interval = 0; 174 count = 0; 175 go_forever = 0; 176 177 (void) setlocale(LC_ALL, ""); 178 (void) textdomain(TEXT_DOMAIN); 179 180 while ((c = getopt(argc, argv, "cnrsmzav:T:")) != EOF) { 181 switch (c) { 182 case 'c': 183 cflag++; 184 break; 185 case 'n': 186 nflag++; 187 break; 188 case 'r': 189 rflag++; 190 break; 191 case 's': 192 sflag++; 193 break; 194 case 'm': 195 mflag++; 196 break; 197 case 'z': 198 if (geteuid()) 199 fail(0, "Must be root for z flag\n"); 200 zflag++; 201 break; 202 case 'a': 203 aflag++; 204 break; 205 case 'v': 206 vflag = atoi(optarg); 207 if ((vflag < 2) || (vflag > 4)) 208 fail(0, "Invalid version number\n"); 209 break; 210 case 'T': 211 if (optarg) { 212 if (*optarg == 'u') 213 timestamp_fmt = UDATE; 214 else if (*optarg == 'd') 215 timestamp_fmt = DDATE; 216 else 217 usage(); 218 } else { 219 usage(); 220 } 221 break; 222 case '?': 223 default: 224 usage(); 225 } 226 } 227 228 if (((argc - optind) > 0) && !mflag) { 229 230 interval = safe_strtoi(argv[optind], "invalid interval"); 231 if (interval < 1) 232 fail(0, "invalid interval\n"); 233 optind++; 234 235 if ((argc - optind) > 0) { 236 count = safe_strtoi(argv[optind], "invalid count"); 237 if ((count <= 0) || (count == NULL)) 238 fail(0, "invalid count\n"); 239 } 240 optind++; 241 242 if ((argc - optind) > 0) 243 usage(); 244 245 /* 246 * no count number was set, so we will loop infinitely 247 * at interval specified 248 */ 249 if (!count) 250 go_forever = 1; 251 stats_timer(interval); 252 } else if (mflag) { 253 254 if (cflag || rflag || sflag || zflag || nflag || aflag || vflag) 255 fail(0, 256 "The -m flag may not be used with any other flags"); 257 258 for (j = 0; (argc - optind > 0) && (j < (MAX_PATHS - 1)); j++) { 259 path[j] = argv[optind]; 260 if (*path[j] != '/') 261 fail(0, "Please fully qualify your pathname " 262 "with a leading '/'"); 263 optind++; 264 } 265 path[j] = NULL; 266 if (argc - optind > 0) 267 fprintf(stderr, "Only the first 50 paths " 268 "will be searched for\n"); 269 } 270 271 setup(); 272 273 do { 274 if (mflag) { 275 mi_print(); 276 } else { 277 if (timestamp_fmt != NODATE) 278 print_timestamp(timestamp_fmt); 279 280 if (sflag && 281 (rpc_clts_server_kstat == NULL || 282 nfs_server_v4_kstat == NULL)) { 283 fprintf(stderr, 284 "nfsstat: kernel is not configured with " 285 "the server nfs and rpc code.\n"); 286 } 287 288 /* if s and nothing else, all 3 prints are called */ 289 if (sflag || (!sflag && !cflag)) { 290 if (rflag || (!rflag && !nflag && !aflag)) 291 sr_print(zflag); 292 if (nflag || (!rflag && !nflag && !aflag)) 293 sn_print(zflag, vflag); 294 if (aflag || (!rflag && !nflag && !aflag)) 295 sa_print(zflag, vflag); 296 } 297 if (cflag && 298 (rpc_clts_client_kstat == NULL || 299 nfs_client_kstat == NULL)) { 300 fprintf(stderr, 301 "nfsstat: kernel is not configured with" 302 " the client nfs and rpc code.\n"); 303 } 304 if (cflag || (!sflag && !cflag)) { 305 if (rflag || (!rflag && !nflag && !aflag)) 306 cr_print(zflag); 307 if (nflag || (!rflag && !nflag && !aflag)) 308 cn_print(zflag, vflag); 309 if (aflag || (!rflag && !nflag && !aflag)) 310 ca_print(zflag, vflag); 311 } 312 } 313 314 if (zflag) 315 putstats(); 316 if (interval) 317 printf("%s\n", split_line); 318 319 if (interval > 0) 320 (void) pause(); 321 } while ((--count > 0) || go_forever); 322 323 kstat_close(kc); 324 free(ksum_kstat); 325 return (0); 326 } 327 328 329 static int 330 getstats_rpc(void) 331 { 332 int field_width = 0; 333 334 if (rpc_clts_client_kstat != NULL) { 335 safe_kstat_read(kc, rpc_clts_client_kstat, NULL); 336 field_width = stat_width(rpc_clts_client_kstat, field_width); 337 } 338 339 if (rpc_cots_client_kstat != NULL) { 340 safe_kstat_read(kc, rpc_cots_client_kstat, NULL); 341 field_width = stat_width(rpc_cots_client_kstat, field_width); 342 } 343 344 if (rpc_rdma_client_kstat != NULL) { 345 safe_kstat_read(kc, rpc_rdma_client_kstat, NULL); 346 field_width = stat_width(rpc_rdma_client_kstat, field_width); 347 } 348 349 if (rpc_clts_server_kstat != NULL) { 350 safe_kstat_read(kc, rpc_clts_server_kstat, NULL); 351 field_width = stat_width(rpc_clts_server_kstat, field_width); 352 } 353 if (rpc_cots_server_kstat != NULL) { 354 safe_kstat_read(kc, rpc_cots_server_kstat, NULL); 355 field_width = stat_width(rpc_cots_server_kstat, field_width); 356 } 357 if (rpc_rdma_server_kstat != NULL) { 358 safe_kstat_read(kc, rpc_rdma_server_kstat, NULL); 359 field_width = stat_width(rpc_rdma_server_kstat, field_width); 360 } 361 return (field_width); 362 } 363 364 static int 365 getstats_nfs(void) 366 { 367 int field_width = 0; 368 369 if (nfs_client_kstat != NULL) { 370 safe_kstat_read(kc, nfs_client_kstat, NULL); 371 field_width = stat_width(nfs_client_kstat, field_width); 372 } 373 if (nfs4_client_kstat != NULL) { 374 safe_kstat_read(kc, nfs4_client_kstat, NULL); 375 field_width = stat_width(nfs4_client_kstat, field_width); 376 } 377 if (nfs_server_v2_kstat != NULL) { 378 safe_kstat_read(kc, nfs_server_v2_kstat, NULL); 379 field_width = stat_width(nfs_server_v2_kstat, field_width); 380 } 381 if (nfs_server_v3_kstat != NULL) { 382 safe_kstat_read(kc, nfs_server_v3_kstat, NULL); 383 field_width = stat_width(nfs_server_v3_kstat, field_width); 384 } 385 if (nfs_server_v4_kstat != NULL) { 386 safe_kstat_read(kc, nfs_server_v4_kstat, NULL); 387 field_width = stat_width(nfs_server_v4_kstat, field_width); 388 } 389 return (field_width); 390 } 391 392 static int 393 getstats_rfsproc(int ver) 394 { 395 int field_width = 0; 396 397 if ((ver == 2) && (rfsproccnt_v2_kstat != NULL)) { 398 safe_kstat_read(kc, rfsproccnt_v2_kstat, NULL); 399 field_width = req_width(rfsproccnt_v2_kstat, field_width); 400 } 401 if ((ver == 3) && (rfsproccnt_v3_kstat != NULL)) { 402 safe_kstat_read(kc, rfsproccnt_v3_kstat, NULL); 403 field_width = req_width(rfsproccnt_v3_kstat, field_width); 404 } 405 if ((ver == 4) && (rfsproccnt_v4_kstat != NULL)) { 406 safe_kstat_read(kc, rfsproccnt_v4_kstat, NULL); 407 field_width = req_width(rfsproccnt_v4_kstat, field_width); 408 } 409 return (field_width); 410 } 411 412 static int 413 getstats_rfsreq(int ver) 414 { 415 int field_width = 0; 416 if ((ver == 2) && (rfsreqcnt_v2_kstat != NULL)) { 417 safe_kstat_read(kc, rfsreqcnt_v2_kstat, NULL); 418 field_width = req_width(rfsreqcnt_v2_kstat, field_width); 419 } 420 if ((ver == 3) && (rfsreqcnt_v3_kstat != NULL)) { 421 safe_kstat_read(kc, rfsreqcnt_v3_kstat, NULL); 422 field_width = req_width(rfsreqcnt_v3_kstat, field_width); 423 } 424 if ((ver == 4) && (rfsreqcnt_v4_kstat != NULL)) { 425 safe_kstat_read(kc, rfsreqcnt_v4_kstat, NULL); 426 field_width = req_width(rfsreqcnt_v4_kstat, field_width); 427 } 428 return (field_width); 429 } 430 431 static int 432 getstats_aclproc(void) 433 { 434 int field_width = 0; 435 if (aclproccnt_v2_kstat != NULL) { 436 safe_kstat_read(kc, aclproccnt_v2_kstat, NULL); 437 field_width = req_width(aclproccnt_v2_kstat, field_width); 438 } 439 if (aclproccnt_v3_kstat != NULL) { 440 safe_kstat_read(kc, aclproccnt_v3_kstat, NULL); 441 field_width = req_width(aclproccnt_v3_kstat, field_width); 442 } 443 return (field_width); 444 } 445 446 static int 447 getstats_aclreq(void) 448 { 449 int field_width = 0; 450 if (aclreqcnt_v2_kstat != NULL) { 451 safe_kstat_read(kc, aclreqcnt_v2_kstat, NULL); 452 field_width = req_width(aclreqcnt_v2_kstat, field_width); 453 } 454 if (aclreqcnt_v3_kstat != NULL) { 455 safe_kstat_read(kc, aclreqcnt_v3_kstat, NULL); 456 field_width = req_width(aclreqcnt_v3_kstat, field_width); 457 } 458 return (field_width); 459 } 460 461 static void 462 putstats(void) 463 { 464 if (rpc_clts_client_kstat != NULL) 465 safe_kstat_write(kc, rpc_clts_client_kstat, NULL); 466 if (rpc_cots_client_kstat != NULL) 467 safe_kstat_write(kc, rpc_cots_client_kstat, NULL); 468 if (rpc_rdma_client_kstat != NULL) 469 safe_kstat_write(kc, rpc_rdma_client_kstat, NULL); 470 if (nfs_client_kstat != NULL) 471 safe_kstat_write(kc, nfs_client_kstat, NULL); 472 if (nfs4_client_kstat != NULL) 473 safe_kstat_write(kc, nfs4_client_kstat, NULL); 474 if (rpc_clts_server_kstat != NULL) 475 safe_kstat_write(kc, rpc_clts_server_kstat, NULL); 476 if (rpc_cots_server_kstat != NULL) 477 safe_kstat_write(kc, rpc_cots_server_kstat, NULL); 478 if (rpc_rdma_server_kstat != NULL) 479 safe_kstat_write(kc, rpc_rdma_server_kstat, NULL); 480 if (nfs_server_v2_kstat != NULL) 481 safe_kstat_write(kc, nfs_server_v2_kstat, NULL); 482 if (nfs_server_v3_kstat != NULL) 483 safe_kstat_write(kc, nfs_server_v3_kstat, NULL); 484 if (nfs_server_v4_kstat != NULL) 485 safe_kstat_write(kc, nfs_server_v4_kstat, NULL); 486 if (rfsproccnt_v2_kstat != NULL) 487 safe_kstat_write(kc, rfsproccnt_v2_kstat, NULL); 488 if (rfsproccnt_v3_kstat != NULL) 489 safe_kstat_write(kc, rfsproccnt_v3_kstat, NULL); 490 if (rfsproccnt_v4_kstat != NULL) 491 safe_kstat_write(kc, rfsproccnt_v4_kstat, NULL); 492 if (rfsreqcnt_v2_kstat != NULL) 493 safe_kstat_write(kc, rfsreqcnt_v2_kstat, NULL); 494 if (rfsreqcnt_v3_kstat != NULL) 495 safe_kstat_write(kc, rfsreqcnt_v3_kstat, NULL); 496 if (rfsreqcnt_v4_kstat != NULL) 497 safe_kstat_write(kc, rfsreqcnt_v4_kstat, NULL); 498 if (aclproccnt_v2_kstat != NULL) 499 safe_kstat_write(kc, aclproccnt_v2_kstat, NULL); 500 if (aclproccnt_v3_kstat != NULL) 501 safe_kstat_write(kc, aclproccnt_v3_kstat, NULL); 502 if (aclreqcnt_v2_kstat != NULL) 503 safe_kstat_write(kc, aclreqcnt_v2_kstat, NULL); 504 if (aclreqcnt_v3_kstat != NULL) 505 safe_kstat_write(kc, aclreqcnt_v3_kstat, NULL); 506 } 507 508 static void 509 setup(void) 510 { 511 if ((kc = kstat_open()) == NULL) 512 fail(1, "kstat_open(): can't open /dev/kstat"); 513 514 /* alloc space for our temporary kstat */ 515 safe_zalloc((void **)&ksum_kstat, sizeof (kstat_t), 0); 516 rpc_clts_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_client"); 517 rpc_clts_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_clts_server"); 518 rpc_cots_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_client"); 519 rpc_cots_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_cots_server"); 520 rpc_rdma_client_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_client"); 521 rpc_rdma_server_kstat = kstat_lookup(kc, "unix", 0, "rpc_rdma_server"); 522 nfs_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs_client"); 523 nfs4_client_kstat = kstat_lookup(kc, "nfs", 0, "nfs4_client"); 524 nfs_server_v2_kstat = kstat_lookup(kc, "nfs", 2, "nfs_server"); 525 nfs_server_v3_kstat = kstat_lookup(kc, "nfs", 3, "nfs_server"); 526 nfs_server_v4_kstat = kstat_lookup(kc, "nfs", 4, "nfs_server"); 527 rfsproccnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v2"); 528 rfsproccnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v3"); 529 rfsproccnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsproccnt_v4"); 530 rfsreqcnt_v2_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v2"); 531 rfsreqcnt_v3_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v3"); 532 rfsreqcnt_v4_kstat = kstat_lookup(kc, "nfs", 0, "rfsreqcnt_v4"); 533 aclproccnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v2"); 534 aclproccnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclproccnt_v3"); 535 aclreqcnt_v2_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v2"); 536 aclreqcnt_v3_kstat = kstat_lookup(kc, "nfs_acl", 0, "aclreqcnt_v3"); 537 if (rpc_clts_client_kstat == NULL && rpc_cots_server_kstat == NULL && 538 rfsproccnt_v2_kstat == NULL && rfsreqcnt_v3_kstat == NULL) 539 fail(0, "Multiple kstat lookups failed." 540 "Your kernel module may not be loaded\n"); 541 } 542 543 static int 544 req_width(kstat_t *req, int field_width) 545 { 546 int i, nreq, per, len; 547 char fixlen[128]; 548 kstat_named_t *knp; 549 uint64_t tot; 550 551 tot = 0; 552 knp = KSTAT_NAMED_PTR(req); 553 for (i = 0; i < req->ks_ndata; i++) 554 tot += knp[i].value.ui64; 555 556 knp = kstat_data_lookup(req, "null"); 557 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 558 559 for (i = 0; i < nreq; i++) { 560 len = strlen(knp[i].name) + 1; 561 if (field_width < len) 562 field_width = len; 563 if (tot) 564 per = (int)(knp[i].value.ui64 * 100 / tot); 565 else 566 per = 0; 567 (void) sprintf(fixlen, "%" PRIu64 " %d%%", 568 knp[i].value.ui64, per); 569 len = strlen(fixlen) + 1; 570 if (field_width < len) 571 field_width = len; 572 } 573 return (field_width); 574 } 575 576 static int 577 stat_width(kstat_t *req, int field_width) 578 { 579 int i, nreq, len; 580 char fixlen[128]; 581 kstat_named_t *knp; 582 583 knp = KSTAT_NAMED_PTR(req); 584 nreq = req->ks_ndata; 585 586 for (i = 0; i < nreq; i++) { 587 len = strlen(knp[i].name) + 1; 588 if (field_width < len) 589 field_width = len; 590 (void) sprintf(fixlen, "%" PRIu64, knp[i].value.ui64); 591 len = strlen(fixlen) + 1; 592 if (field_width < len) 593 field_width = len; 594 } 595 return (field_width); 596 } 597 598 static void 599 cr_print(int zflag) 600 { 601 int field_width; 602 603 field_width = getstats_rpc(); 604 if (field_width == 0) 605 return; 606 607 stat_print("\nClient rpc:\nConnection oriented:", 608 rpc_cots_client_kstat, 609 &old_rpc_cots_client_kstat.kst, field_width, zflag); 610 stat_print("Connectionless:", rpc_clts_client_kstat, 611 &old_rpc_clts_client_kstat.kst, field_width, zflag); 612 stat_print("RDMA based:", rpc_rdma_client_kstat, 613 &old_rpc_rdma_client_kstat.kst, field_width, zflag); 614 } 615 616 static void 617 sr_print(int zflag) 618 { 619 int field_width; 620 621 field_width = getstats_rpc(); 622 if (field_width == 0) 623 return; 624 625 stat_print("\nServer rpc:\nConnection oriented:", rpc_cots_server_kstat, 626 &old_rpc_cots_server_kstat.kst, field_width, zflag); 627 stat_print("Connectionless:", rpc_clts_server_kstat, 628 &old_rpc_clts_server_kstat.kst, field_width, zflag); 629 stat_print("RDMA based:", rpc_rdma_server_kstat, 630 &old_rpc_rdma_server_kstat.kst, field_width, zflag); 631 } 632 633 static void 634 cn_print(int zflag, int vflag) 635 { 636 int field_width; 637 638 field_width = getstats_nfs(); 639 if (field_width == 0) 640 return; 641 642 if (vflag == 0) { 643 nfsstat_kstat_sum(nfs_client_kstat, nfs4_client_kstat, 644 ksum_kstat); 645 stat_print("\nClient nfs:", ksum_kstat, &old_ksum_kstat.kst, 646 field_width, zflag); 647 } 648 649 if (vflag == 2 || vflag == 3) { 650 stat_print("\nClient nfs:", nfs_client_kstat, 651 &old_nfs_client_kstat.kst, field_width, zflag); 652 } 653 654 if (vflag == 4) { 655 stat_print("\nClient nfs:", nfs4_client_kstat, 656 &old_nfs4_client_kstat.kst, field_width, zflag); 657 } 658 659 if (vflag == 2 || vflag == 0) { 660 field_width = getstats_rfsreq(2); 661 req_print(rfsreqcnt_v2_kstat, &old_rfsreqcnt_v2_kstat.kst, 662 2, field_width, zflag); 663 } 664 665 if (vflag == 3 || vflag == 0) { 666 field_width = getstats_rfsreq(3); 667 req_print(rfsreqcnt_v3_kstat, &old_rfsreqcnt_v3_kstat.kst, 3, 668 field_width, zflag); 669 } 670 671 if (vflag == 4 || vflag == 0) { 672 field_width = getstats_rfsreq(4); 673 req_print_v4(rfsreqcnt_v4_kstat, &old_rfsreqcnt_v4_kstat.kst, 674 field_width, zflag); 675 } 676 } 677 678 static void 679 sn_print(int zflag, int vflag) 680 { 681 int field_width; 682 683 field_width = getstats_nfs(); 684 if (field_width == 0) 685 return; 686 687 if (vflag == 2 || vflag == 0) { 688 stat_print("\nServer NFSv2:", nfs_server_v2_kstat, 689 &old_nfs_server_v2_kstat.kst, field_width, zflag); 690 } 691 692 if (vflag == 3 || vflag == 0) { 693 stat_print("\nServer NFSv3:", nfs_server_v3_kstat, 694 &old_nfs_server_v3_kstat.kst, field_width, zflag); 695 } 696 697 if (vflag == 4 || vflag == 0) { 698 stat_print("\nServer NFSv4:", nfs_server_v4_kstat, 699 &old_nfs_server_v4_kstat.kst, field_width, zflag); 700 } 701 702 if (vflag == 2 || vflag == 0) { 703 field_width = getstats_rfsproc(2); 704 req_print(rfsproccnt_v2_kstat, &old_rfsproccnt_v2_kstat.kst, 705 2, field_width, zflag); 706 } 707 708 if (vflag == 3 || vflag == 0) { 709 field_width = getstats_rfsproc(3); 710 req_print(rfsproccnt_v3_kstat, &old_rfsproccnt_v3_kstat.kst, 711 3, field_width, zflag); 712 } 713 714 if (vflag == 4 || vflag == 0) { 715 field_width = getstats_rfsproc(4); 716 req_print_v4(rfsproccnt_v4_kstat, &old_rfsproccnt_v4_kstat.kst, 717 field_width, zflag); 718 } 719 } 720 721 static void 722 ca_print(int zflag, int vflag) 723 { 724 int field_width; 725 726 field_width = getstats_aclreq(); 727 if (field_width == 0) 728 return; 729 730 printf("\nClient nfs_acl:\n"); 731 732 if (vflag == 2 || vflag == 0) { 733 req_print(aclreqcnt_v2_kstat, &old_aclreqcnt_v2_kstat.kst, 2, 734 field_width, zflag); 735 } 736 737 if (vflag == 3 || vflag == 0) { 738 req_print(aclreqcnt_v3_kstat, &old_aclreqcnt_v3_kstat.kst, 739 3, field_width, zflag); 740 } 741 } 742 743 static void 744 sa_print(int zflag, int vflag) 745 { 746 int field_width; 747 748 field_width = getstats_aclproc(); 749 if (field_width == 0) 750 return; 751 752 printf("\nServer nfs_acl:\n"); 753 754 if (vflag == 2 || vflag == 0) { 755 req_print(aclproccnt_v2_kstat, &old_aclproccnt_v2_kstat.kst, 756 2, field_width, zflag); 757 } 758 759 if (vflag == 3 || vflag == 0) { 760 req_print(aclproccnt_v3_kstat, &old_aclproccnt_v3_kstat.kst, 761 3, field_width, zflag); 762 } 763 } 764 765 #define MIN(a, b) ((a) < (b) ? (a) : (b)) 766 767 static void 768 req_print(kstat_t *req, kstat_t *req_old, int ver, int field_width, 769 int zflag) 770 { 771 int i, j, nreq, per, ncolumns; 772 uint64_t tot, old_tot; 773 char fixlen[128]; 774 kstat_named_t *knp; 775 kstat_named_t *kptr; 776 kstat_named_t *knp_old; 777 778 if (req == NULL) 779 return; 780 781 if (field_width == 0) 782 return; 783 784 ncolumns = (MAX_COLUMNS -1)/field_width; 785 knp = kstat_data_lookup(req, "null"); 786 knp_old = KSTAT_NAMED_PTR(req_old); 787 788 kptr = KSTAT_NAMED_PTR(req); 789 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 790 791 tot = 0; 792 old_tot = 0; 793 794 if (knp_old == NULL) { 795 old_tot = 0; 796 } 797 798 for (i = 0; i < req->ks_ndata; i++) 799 tot += kptr[i].value.ui64; 800 801 if (interval && knp_old != NULL) { 802 for (i = 0; i < req_old->ks_ndata; i++) 803 old_tot += knp_old[i].value.ui64; 804 tot -= old_tot; 805 } 806 807 printf("Version %d: (%" PRIu64 " calls)\n", ver, tot); 808 809 for (i = 0; i < nreq; i += ncolumns) { 810 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 811 printf("%-*s", field_width, knp[j].name); 812 } 813 printf("\n"); 814 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 815 if (tot && interval && knp_old != NULL) 816 per = (int)((knp[j].value.ui64 - 817 knp_old[j].value.ui64) * 100 / tot); 818 else if (tot) 819 per = (int)(knp[j].value.ui64 * 100 / tot); 820 else 821 per = 0; 822 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 823 ((interval && knp_old != NULL) ? 824 (knp[j].value.ui64 - knp_old[j].value.ui64) 825 : knp[j].value.ui64), per); 826 printf("%-*s", field_width, fixlen); 827 } 828 printf("\n"); 829 } 830 if (zflag) { 831 for (i = 0; i < req->ks_ndata; i++) 832 knp[i].value.ui64 = 0; 833 } 834 if (knp_old != NULL) 835 nfsstat_kstat_copy(req, req_old, 1); 836 else 837 nfsstat_kstat_copy(req, req_old, 0); 838 } 839 840 /* 841 * Separate version of the req_print() to deal with V4 and its use of 842 * procedures and operations. It looks odd to have the counts for 843 * both of those lumped into the same set of statistics so this 844 * function (copy of req_print() does the separation and titles). 845 */ 846 847 #define COUNT 2 848 849 static void 850 req_print_v4(kstat_t *req, kstat_t *req_old, int field_width, int zflag) 851 { 852 int i, j, nreq, per, ncolumns; 853 uint64_t tot, tot_ops, old_tot, old_tot_ops; 854 char fixlen[128]; 855 kstat_named_t *kptr; 856 kstat_named_t *knp; 857 kstat_named_t *kptr_old; 858 859 if (req == NULL) 860 return; 861 862 if (field_width == 0) 863 return; 864 865 ncolumns = (MAX_COLUMNS)/field_width; 866 kptr = KSTAT_NAMED_PTR(req); 867 kptr_old = KSTAT_NAMED_PTR(req_old); 868 869 if (kptr_old == NULL) { 870 old_tot_ops = 0; 871 old_tot = 0; 872 } else { 873 old_tot = kptr_old[0].value.ui64 + kptr_old[1].value.ui64; 874 for (i = 2, old_tot_ops = 0; i < req_old->ks_ndata; i++) 875 old_tot_ops += kptr_old[i].value.ui64; 876 } 877 878 /* Count the number of operations sent */ 879 for (i = 2, tot_ops = 0; i < req->ks_ndata; i++) 880 tot_ops += kptr[i].value.ui64; 881 /* For v4 NULL/COMPOUND are the only procedures */ 882 tot = kptr[0].value.ui64 + kptr[1].value.ui64; 883 884 if (interval) { 885 tot -= old_tot; 886 tot_ops -= old_tot_ops; 887 } 888 889 printf("Version 4: (%" PRIu64 " calls)\n", tot); 890 891 knp = kstat_data_lookup(req, "null"); 892 nreq = req->ks_ndata - (knp - KSTAT_NAMED_PTR(req)); 893 894 for (i = 0; i < COUNT; i += ncolumns) { 895 for (j = i; j < MIN(i + ncolumns, 2); j++) { 896 printf("%-*s", field_width, knp[j].name); 897 } 898 printf("\n"); 899 for (j = i; j < MIN(i + ncolumns, 2); j++) { 900 if (tot && interval && kptr_old != NULL) 901 per = (int)((knp[j].value.ui64 - 902 kptr_old[j].value.ui64) * 100 / tot); 903 else if (tot) 904 per = (int)(knp[j].value.ui64 * 100 / tot); 905 else 906 per = 0; 907 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 908 ((interval && kptr_old != NULL) ? 909 (knp[j].value.ui64 - kptr_old[j].value.ui64) 910 : knp[j].value.ui64), per); 911 printf("%-*s", field_width, fixlen); 912 } 913 printf("\n"); 914 } 915 916 printf("Version 4: (%" PRIu64 " operations)\n", tot_ops); 917 for (i = 2; i < nreq; i += ncolumns) { 918 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 919 printf("%-*s", field_width, knp[j].name); 920 } 921 printf("\n"); 922 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 923 if (tot_ops && interval && kptr_old != NULL) 924 per = (int)((knp[j].value.ui64 - 925 kptr_old[j].value.ui64) * 100 / tot_ops); 926 else if (tot_ops) 927 per = (int)(knp[j].value.ui64 * 100 / tot_ops); 928 else 929 per = 0; 930 (void) sprintf(fixlen, "%" PRIu64 " %d%% ", 931 ((interval && kptr_old != NULL) ? 932 (knp[j].value.ui64 - kptr_old[j].value.ui64) 933 : knp[j].value.ui64), per); 934 printf("%-*s", field_width, fixlen); 935 } 936 printf("\n"); 937 } 938 if (zflag) { 939 for (i = 0; i < req->ks_ndata; i++) 940 kptr[i].value.ui64 = 0; 941 } 942 if (kptr_old != NULL) 943 nfsstat_kstat_copy(req, req_old, 1); 944 else 945 nfsstat_kstat_copy(req, req_old, 0); 946 } 947 948 static void 949 stat_print(const char *title_string, kstat_t *req, kstat_t *req_old, 950 int field_width, int zflag) 951 { 952 int i, j, nreq, ncolumns; 953 char fixlen[128]; 954 kstat_named_t *knp; 955 kstat_named_t *knp_old; 956 957 if (req == NULL) 958 return; 959 960 if (field_width == 0) 961 return; 962 963 printf("%s\n", title_string); 964 ncolumns = (MAX_COLUMNS -1)/field_width; 965 966 /* MEANS knp = (kstat_named_t *)req->ks_data */ 967 knp = KSTAT_NAMED_PTR(req); 968 nreq = req->ks_ndata; 969 knp_old = KSTAT_NAMED_PTR(req_old); 970 971 for (i = 0; i < nreq; i += ncolumns) { 972 /* prints out the titles of the columns */ 973 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 974 printf("%-*s", field_width, knp[j].name); 975 } 976 printf("\n"); 977 /* prints out the stat numbers */ 978 for (j = i; j < MIN(i + ncolumns, nreq); j++) { 979 (void) sprintf(fixlen, "%" PRIu64 " ", 980 (interval && knp_old != NULL) ? 981 (knp[j].value.ui64 - knp_old[j].value.ui64) 982 : knp[j].value.ui64); 983 printf("%-*s", field_width, fixlen); 984 } 985 printf("\n"); 986 987 } 988 if (zflag) { 989 for (i = 0; i < req->ks_ndata; i++) 990 knp[i].value.ui64 = 0; 991 } 992 993 if (knp_old != NULL) 994 nfsstat_kstat_copy(req, req_old, 1); 995 else 996 nfsstat_kstat_copy(req, req_old, 0); 997 } 998 999 static void 1000 nfsstat_kstat_sum(kstat_t *kstat1, kstat_t *kstat2, kstat_t *sum) 1001 { 1002 int i; 1003 kstat_named_t *knp1, *knp2, *knpsum; 1004 if (kstat1 == NULL || kstat2 == NULL) 1005 return; 1006 1007 knp1 = KSTAT_NAMED_PTR(kstat1); 1008 knp2 = KSTAT_NAMED_PTR(kstat2); 1009 if (sum->ks_data == NULL) 1010 nfsstat_kstat_copy(kstat1, sum, 0); 1011 knpsum = KSTAT_NAMED_PTR(sum); 1012 1013 for (i = 0; i < (kstat1->ks_ndata); i++) 1014 knpsum[i].value.ui64 = knp1[i].value.ui64 + knp2[i].value.ui64; 1015 } 1016 1017 /* 1018 * my_dir and my_path could be pointers 1019 */ 1020 struct myrec { 1021 ulong_t my_fsid; 1022 char my_dir[MAXPATHLEN]; 1023 char *my_path; 1024 char *ig_path; 1025 struct myrec *next; 1026 }; 1027 1028 /* 1029 * Print the mount table info 1030 */ 1031 static void 1032 mi_print(void) 1033 { 1034 FILE *mt; 1035 struct extmnttab m; 1036 struct myrec *list, *mrp, *pmrp; 1037 char *flavor; 1038 int ignored = 0; 1039 seconfig_t nfs_sec; 1040 kstat_t *ksp; 1041 struct mntinfo_kstat mik; 1042 int transport_flag = 0; 1043 int path_count; 1044 int found; 1045 char *timer_name[] = { 1046 "Lookups", 1047 "Reads", 1048 "Writes", 1049 "All" 1050 }; 1051 1052 mt = fopen(MNTTAB, "r"); 1053 if (mt == NULL) { 1054 perror(MNTTAB); 1055 exit(0); 1056 } 1057 1058 list = NULL; 1059 resetmnttab(mt); 1060 1061 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) { 1062 /* ignore non "nfs" and save the "ignore" entries */ 1063 if (strcmp(m.mnt_fstype, MNTTYPE_NFS) != 0) 1064 continue; 1065 /* 1066 * Check to see here if user gave a path(s) to 1067 * only show the mount point they wanted 1068 * Iterate through the list of paths the user gave and see 1069 * if any of them match our current nfs mount 1070 */ 1071 if (path[0] != NULL) { 1072 found = 0; 1073 for (path_count = 0; path[path_count] != NULL; 1074 path_count++) { 1075 if (strcmp(path[path_count], m.mnt_mountp) 1076 == 0) { 1077 found = 1; 1078 break; 1079 } 1080 } 1081 if (!found) 1082 continue; 1083 } 1084 1085 if ((mrp = malloc(sizeof (struct myrec))) == 0) { 1086 fprintf(stderr, "nfsstat: not enough memory\n"); 1087 exit(1); 1088 } 1089 mrp->my_fsid = makedev(m.mnt_major, m.mnt_minor); 1090 if (ignore(m.mnt_mntopts)) { 1091 /* 1092 * ignored entries cannot be ignored for this 1093 * option. We have to display the info for this 1094 * nfs mount. The ignore is an indication 1095 * that the actual mount point is different and 1096 * something is in between the nfs mount. 1097 * So save the mount point now 1098 */ 1099 if ((mrp->ig_path = malloc( 1100 strlen(m.mnt_mountp) + 1)) == 0) { 1101 fprintf(stderr, "nfsstat: not enough memory\n"); 1102 exit(1); 1103 } 1104 (void) strcpy(mrp->ig_path, m.mnt_mountp); 1105 ignored++; 1106 } else { 1107 mrp->ig_path = 0; 1108 (void) strcpy(mrp->my_dir, m.mnt_mountp); 1109 } 1110 if ((mrp->my_path = strdup(m.mnt_special)) == NULL) { 1111 fprintf(stderr, "nfsstat: not enough memory\n"); 1112 exit(1); 1113 } 1114 mrp->next = list; 1115 list = mrp; 1116 } 1117 1118 /* 1119 * If something got ignored, go to the beginning of the mnttab 1120 * and look for the cachefs entries since they are the one 1121 * causing this. The mount point saved for the ignored entries 1122 * is matched against the special to get the actual mount point. 1123 * We are interested in the acutal mount point so that the output 1124 * look nice too. 1125 */ 1126 if (ignored) { 1127 rewind(mt); 1128 resetmnttab(mt); 1129 while (getextmntent(mt, &m, sizeof (struct extmnttab)) == 0) { 1130 1131 /* ignore non "cachefs" */ 1132 if (strcmp(m.mnt_fstype, MNTTYPE_CACHEFS) != 0) 1133 continue; 1134 1135 for (mrp = list; mrp; mrp = mrp->next) { 1136 if (mrp->ig_path == 0) 1137 continue; 1138 if (strcmp(mrp->ig_path, m.mnt_special) == 0) { 1139 mrp->ig_path = 0; 1140 (void) strcpy(mrp->my_dir, 1141 m.mnt_mountp); 1142 } 1143 } 1144 } 1145 /* 1146 * Now ignored entries which do not have 1147 * the my_dir initialized are really ignored; This never 1148 * happens unless the mnttab is corrupted. 1149 */ 1150 for (pmrp = 0, mrp = list; mrp; mrp = mrp->next) { 1151 if (mrp->ig_path == 0) 1152 pmrp = mrp; 1153 else if (pmrp) 1154 pmrp->next = mrp->next; 1155 else 1156 list = mrp->next; 1157 } 1158 } 1159 1160 (void) fclose(mt); 1161 1162 1163 for (ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) { 1164 int i; 1165 1166 if (ksp->ks_type != KSTAT_TYPE_RAW) 1167 continue; 1168 if (strcmp(ksp->ks_module, "nfs") != 0) 1169 continue; 1170 if (strcmp(ksp->ks_name, "mntinfo") != 0) 1171 continue; 1172 1173 for (mrp = list; mrp; mrp = mrp->next) { 1174 if ((mrp->my_fsid & MAXMIN) == ksp->ks_instance) 1175 break; 1176 } 1177 if (mrp == 0) 1178 continue; 1179 1180 if (safe_kstat_read(kc, ksp, &mik) == -1) 1181 continue; 1182 1183 printf("%s from %s\n", mrp->my_dir, mrp->my_path); 1184 1185 /* 1186 * for printing rdma transport and provider string. 1187 * This way we avoid modifying the kernel mntinfo_kstat 1188 * struct for protofmly. 1189 */ 1190 if (strcmp(mik.mik_proto, "ibtf") == 0) { 1191 printf(" Flags: vers=%u,proto=rdma", 1192 mik.mik_vers); 1193 transport_flag = 1; 1194 } else { 1195 printf(" Flags: vers=%u,proto=%s", 1196 mik.mik_vers, mik.mik_proto); 1197 transport_flag = 0; 1198 } 1199 1200 /* 1201 * get the secmode name from /etc/nfssec.conf. 1202 */ 1203 if (!nfs_getseconfig_bynumber(mik.mik_secmod, &nfs_sec)) { 1204 flavor = nfs_sec.sc_name; 1205 } else 1206 flavor = NULL; 1207 1208 if (flavor != NULL) 1209 printf(",sec=%s", flavor); 1210 else 1211 printf(",sec#=%d", mik.mik_secmod); 1212 1213 printf(",%s", (mik.mik_flags & MI_HARD) ? "hard" : "soft"); 1214 if (mik.mik_flags & MI_PRINTED) 1215 printf(",printed"); 1216 printf(",%s", (mik.mik_flags & MI_INT) ? "intr" : "nointr"); 1217 if (mik.mik_flags & MI_DOWN) 1218 printf(",down"); 1219 if (mik.mik_flags & MI_NOAC) 1220 printf(",noac"); 1221 if (mik.mik_flags & MI_NOCTO) 1222 printf(",nocto"); 1223 if (mik.mik_flags & MI_DYNAMIC) 1224 printf(",dynamic"); 1225 if (mik.mik_flags & MI_LLOCK) 1226 printf(",llock"); 1227 if (mik.mik_flags & MI_GRPID) 1228 printf(",grpid"); 1229 if (mik.mik_flags & MI_RPCTIMESYNC) 1230 printf(",rpctimesync"); 1231 if (mik.mik_flags & MI_LINK) 1232 printf(",link"); 1233 if (mik.mik_flags & MI_SYMLINK) 1234 printf(",symlink"); 1235 if (mik.mik_vers < NFS_V4 && mik.mik_flags & MI_READDIRONLY) 1236 printf(",readdironly"); 1237 if (mik.mik_flags & MI_ACL) 1238 printf(",acl"); 1239 if (mik.mik_flags & MI_DIRECTIO) 1240 printf(",forcedirectio"); 1241 1242 if (mik.mik_vers >= NFS_V4) { 1243 if (mik.mik_flags & MI4_MIRRORMOUNT) 1244 printf(",mirrormount"); 1245 if (mik.mik_flags & MI4_REFERRAL) 1246 printf(",referral"); 1247 } 1248 1249 printf(",rsize=%d,wsize=%d,retrans=%d,timeo=%d", 1250 mik.mik_curread, mik.mik_curwrite, mik.mik_retrans, 1251 mik.mik_timeo); 1252 printf("\n"); 1253 printf(" Attr cache: acregmin=%d,acregmax=%d" 1254 ",acdirmin=%d,acdirmax=%d\n", mik.mik_acregmin, 1255 mik.mik_acregmax, mik.mik_acdirmin, mik.mik_acdirmax); 1256 1257 if (transport_flag) { 1258 printf(" Transport: proto=rdma, plugin=%s\n", 1259 mik.mik_proto); 1260 } 1261 1262 #define srtt_to_ms(x) x, (x * 2 + x / 2) 1263 #define dev_to_ms(x) x, (x * 5) 1264 1265 for (i = 0; i < NFS_CALLTYPES + 1; i++) { 1266 int j; 1267 1268 j = (i == NFS_CALLTYPES ? i - 1 : i); 1269 if (mik.mik_timers[j].srtt || 1270 mik.mik_timers[j].rtxcur) { 1271 printf(" %s: srtt=%d (%dms), " 1272 "dev=%d (%dms), cur=%u (%ums)\n", 1273 timer_name[i], 1274 srtt_to_ms(mik.mik_timers[i].srtt), 1275 dev_to_ms(mik.mik_timers[i].deviate), 1276 mik.mik_timers[i].rtxcur, 1277 mik.mik_timers[i].rtxcur * 20); 1278 } 1279 } 1280 1281 if (strchr(mrp->my_path, ',')) 1282 printf( 1283 " Failover: noresponse=%d,failover=%d," 1284 "remap=%d,currserver=%s\n", 1285 mik.mik_noresponse, mik.mik_failover, 1286 mik.mik_remap, mik.mik_curserver); 1287 printf("\n"); 1288 } 1289 } 1290 1291 static char *mntopts[] = { MNTOPT_IGNORE, MNTOPT_DEV, NULL }; 1292 #define IGNORE 0 1293 #define DEV 1 1294 1295 /* 1296 * Return 1 if "ignore" appears in the options string 1297 */ 1298 static int 1299 ignore(char *opts) 1300 { 1301 char *value; 1302 char *s; 1303 1304 if (opts == NULL) 1305 return (0); 1306 s = strdup(opts); 1307 if (s == NULL) 1308 return (0); 1309 opts = s; 1310 1311 while (*opts != '\0') { 1312 if (getsubopt(&opts, mntopts, &value) == IGNORE) { 1313 free(s); 1314 return (1); 1315 } 1316 } 1317 1318 free(s); 1319 return (0); 1320 } 1321 1322 void 1323 usage(void) 1324 { 1325 fprintf(stderr, "Usage: nfsstat [-cnrsza [-v version] " 1326 "[-T d|u] [interval [count]]\n"); 1327 fprintf(stderr, "Usage: nfsstat -m [pathname..]\n"); 1328 exit(1); 1329 } 1330 1331 void 1332 fail(int do_perror, char *message, ...) 1333 { 1334 va_list args; 1335 1336 va_start(args, message); 1337 fprintf(stderr, "nfsstat: "); 1338 vfprintf(stderr, message, args); 1339 va_end(args); 1340 if (do_perror) 1341 fprintf(stderr, ": %s", strerror(errno)); 1342 fprintf(stderr, "\n"); 1343 exit(1); 1344 } 1345 1346 kid_t 1347 safe_kstat_read(kstat_ctl_t *kc, kstat_t *ksp, void *data) 1348 { 1349 kid_t kstat_chain_id = kstat_read(kc, ksp, data); 1350 1351 if (kstat_chain_id == -1) 1352 fail(1, "kstat_read(%x, '%s') failed", kc, ksp->ks_name); 1353 return (kstat_chain_id); 1354 } 1355 1356 kid_t 1357 safe_kstat_write(kstat_ctl_t *kc, kstat_t *ksp, void *data) 1358 { 1359 kid_t kstat_chain_id = 0; 1360 1361 if (ksp->ks_data != NULL) { 1362 kstat_chain_id = kstat_write(kc, ksp, data); 1363 1364 if (kstat_chain_id == -1) 1365 fail(1, "kstat_write(%x, '%s') failed", kc, 1366 ksp->ks_name); 1367 } 1368 return (kstat_chain_id); 1369 } 1370 1371 void 1372 stats_timer(int interval) 1373 { 1374 timer_t t_id; 1375 itimerspec_t time_struct; 1376 struct sigevent sig_struct; 1377 struct sigaction act; 1378 1379 bzero(&sig_struct, sizeof (struct sigevent)); 1380 bzero(&act, sizeof (struct sigaction)); 1381 1382 /* Create timer */ 1383 sig_struct.sigev_notify = SIGEV_SIGNAL; 1384 sig_struct.sigev_signo = SIGUSR1; 1385 sig_struct.sigev_value.sival_int = 0; 1386 1387 if (timer_create(CLOCK_REALTIME, &sig_struct, &t_id) != 0) { 1388 fail(1, "Timer creation failed"); 1389 } 1390 1391 act.sa_handler = handle_sig; 1392 1393 if (sigaction(SIGUSR1, &act, NULL) != 0) { 1394 fail(1, "Could not set up signal handler"); 1395 } 1396 1397 time_struct.it_value.tv_sec = interval; 1398 time_struct.it_value.tv_nsec = 0; 1399 time_struct.it_interval.tv_sec = interval; 1400 time_struct.it_interval.tv_nsec = 0; 1401 1402 /* Arm timer */ 1403 if ((timer_settime(t_id, 0, &time_struct, NULL)) != 0) { 1404 fail(1, "Setting timer failed"); 1405 } 1406 } 1407 1408 void 1409 handle_sig(int x) 1410 { 1411 } 1412 1413 static void 1414 nfsstat_kstat_copy(kstat_t *src, kstat_t *dst, int fr) 1415 { 1416 1417 if (fr) 1418 free(dst->ks_data); 1419 1420 *dst = *src; 1421 1422 if (src->ks_data != NULL) { 1423 safe_zalloc(&dst->ks_data, src->ks_data_size, 0); 1424 (void) memcpy(dst->ks_data, src->ks_data, src->ks_data_size); 1425 } else { 1426 dst->ks_data = NULL; 1427 dst->ks_data_size = 0; 1428 } 1429 } 1430 1431 /* 1432 * "Safe" allocators - if we return we're guaranteed to have the desired space 1433 * allocated and zero-filled. We exit via fail if we can't get the space. 1434 */ 1435 void 1436 safe_zalloc(void **ptr, uint_t size, int free_first) 1437 { 1438 if (ptr == NULL) 1439 fail(1, "invalid pointer"); 1440 if (free_first && *ptr != NULL) 1441 free(*ptr); 1442 if ((*ptr = (void *)malloc(size)) == NULL) 1443 fail(1, "malloc failed"); 1444 (void) memset(*ptr, 0, size); 1445 } 1446 1447 static int 1448 safe_strtoi(char const *val, char *errmsg) 1449 { 1450 char *end; 1451 long tmp; 1452 errno = 0; 1453 tmp = strtol(val, &end, 10); 1454 if (*end != '\0' || errno) 1455 fail(0, "%s %s", errmsg, val); 1456 return ((int)tmp); 1457 } 1458