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