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