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