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 /* 23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved. 25 */ 26 27 /* 28 * smbstat: Server Message Block File System statistics 29 * 30 * The statistics this CLI displays come from two sources: 31 * 32 * 1) The kernel module 'smbsrv'. 33 * 2) The SMB workers task queue statistics the task queue manager of Solaris 34 * maintains. 35 * 36 * The flow of the code is the following: 37 * 38 * 39 * +----------------+ 40 * | Initialization | 41 * +----------------+ 42 * | 43 * | 44 * v 45 * +--------------------------* 46 * | Take a snapshot the data | <--------+ 47 * +--------------------------+ | 48 * | | 49 * | | 50 * v | 51 * +----------------------+ | 52 * | Process the snapshot | | 53 * +----------------------+ | 54 * | | 55 * | | 56 * v | 57 * +------------------------------------+ | 58 * | Print the result of the processing | | 59 * +------------------------------------+ | 60 * | | 61 * | | 62 * v | 63 * Yes --------------- | 64 * +------------ < interval == 0 ? > | 65 * | --------------- | 66 * | | | 67 * | | No | 68 * | v | 69 * | +------------------------+ | 70 * | | Sleep for the duration | ----------+ 71 * | | of the interval. | 72 * | +------------------------+ 73 * | 74 * +---------------------+ 75 * | 76 * v 77 * 78 * Exit 79 * 80 * There are two sets of snapshots. One set for the smbsrv module and the other 81 * for the task queue (SMB workers). Each set contains 2 snapshots. One is 82 * labeled 'current' the other one 'previous'. Their role changes after each 83 * snapshot. The 'current' becomes 'previous' and vice versa. 84 * The first snapshot taken is compared against the data gathered since the 85 * smbsrv module was loaded. Subsequent snapshots will be compared against the 86 * previous snapshot. 87 */ 88 89 #include <stdio.h> 90 #include <stdlib.h> 91 #include <unistd.h> 92 #include <kstat.h> 93 #include <stdarg.h> 94 #include <errno.h> 95 #include <inttypes.h> 96 #include <strings.h> 97 #include <utility.h> 98 #include <libintl.h> 99 #include <zone.h> 100 #include <termios.h> 101 #include <stropts.h> 102 #include <math.h> 103 #include <umem.h> 104 #include <locale.h> 105 #include <smbsrv/smb_kstat.h> 106 107 #if !defined(TEXT_DOMAIN) 108 #define TEXT_DOMAIN "SYS_TEST" 109 #endif /* TEXT_DOMAIN */ 110 111 #define SMBSTAT_ID_NO_CPU -1 112 #define SMBSTAT_SNAPSHOT_COUNT 2 /* Must be a power of 2 */ 113 #define SMBSTAT_SNAPSHOT_MASK (SMBSTAT_SNAPSHOT_COUNT - 1) 114 115 #define SMBSTAT_HELP \ 116 "Usage: smbstat [-acnrtuz] [interval]\n" \ 117 " -c: display counters\n" \ 118 " -t: display throughput\n" \ 119 " -u: display utilization\n" \ 120 " -r: display requests\n" \ 121 " -a: all the requests (supported and unsupported)\n" \ 122 " -z: skip the requests not received\n" \ 123 " -n: display in alphabetic order\n" \ 124 " interval: refresh cycle in seconds\n" 125 126 #define SMBSRV_COUNTERS_BANNER "\n nbt tcp users trees files pipes\n" 127 #define SMBSRV_COUNTERS_FORMAT "%5d %5d %5d %5d %5d %5d\n" 128 129 #define SMBSRV_THROUGHPUT_BANNER \ 130 "\nrbytes/s tbytes/s reqs/s reads/s writes/s\n" 131 #define SMBSRV_THROUGHPUT_FORMAT \ 132 "%1.3e %1.3e %1.3e %1.3e %1.3e\n" 133 134 #define SMBSRV_UTILIZATION_BANNER \ 135 "\n wcnt rcnt wtime rtime" \ 136 " w%% r%% u%% sat usr%% sys%% idle%%\n" 137 #define SMBSRV_UTILIZATION_FORMAT \ 138 "%1.3e %1.3e %1.3e %1.3e %3.0f %3.0f %3.0f %s " \ 139 "%3.0f %3.0f %3.0f\n" 140 141 #define SMBSRV_REQUESTS_BANNER \ 142 "\n%30s code %% rbytes/s tbytes/s req/s rt-mean" \ 143 " rt-stddev\n" 144 #define SMBSRV_REQUESTS_FORMAT \ 145 "%30s %02X %3.0f %1.3e %1.3e %1.3e %1.3e %1.3e\n" 146 147 typedef enum { 148 CPU_TICKS_IDLE = 0, 149 CPU_TICKS_USER, 150 CPU_TICKS_KERNEL, 151 CPU_TICKS_SENTINEL 152 } cpu_state_idx_t; 153 154 typedef struct smbstat_cpu_snapshot { 155 processorid_t cs_id; 156 int cs_state; 157 uint64_t cs_ticks[CPU_TICKS_SENTINEL]; 158 } smbstat_cpu_snapshot_t; 159 160 typedef struct smbstat_srv_snapshot { 161 hrtime_t ss_snaptime; 162 smbsrv_kstats_t ss_data; 163 } smbstat_srv_snapshot_t; 164 165 typedef struct smbstat_wrk_snapshot { 166 uint64_t ws_maxthreads; 167 uint64_t ws_bnalloc; 168 } smbstat_wrk_snapshot_t; 169 170 typedef struct smbstat_req_info { 171 char ri_name[KSTAT_STRLEN]; 172 int ri_opcode; 173 double ri_pct; 174 double ri_tbs; 175 double ri_rbs; 176 double ri_rqs; 177 double ri_stddev; 178 double ri_mean; 179 } smbstat_req_info_t; 180 181 typedef struct smbstat_srv_info { 182 double si_hretime; 183 double si_etime; 184 double si_total_nreqs; 185 /* 186 * Counters 187 */ 188 uint32_t si_nbt_sess; /* NBT sessions */ 189 uint32_t si_tcp_sess; /* TCP sessions */ 190 uint32_t si_users; /* Users logged in */ 191 uint32_t si_trees; /* Trees connected */ 192 uint32_t si_files; /* Open files */ 193 uint32_t si_pipes; /* Open pipes */ 194 /* 195 * Throughput of the server 196 */ 197 double si_tbs; /* Bytes transmitted / second */ 198 double si_rbs; /* Bytes received / second */ 199 double si_rqs; /* Requests treated / second */ 200 double si_rds; /* Reads treated / second */ 201 double si_wrs; /* Writes treated / second */ 202 /* 203 * Utilization of the server 204 */ 205 double si_wpct; /* */ 206 double si_rpct; /* */ 207 double si_upct; /* Utilization in % */ 208 double si_avw; /* Average number of requests waiting */ 209 double si_avr; /* Average number of requests running */ 210 double si_wserv; /* Average waiting time */ 211 double si_rserv; /* Average running time */ 212 boolean_t si_sat; 213 double si_ticks[CPU_TICKS_SENTINEL]; 214 /* 215 * Latency & Throughput per request 216 */ 217 smbstat_req_info_t si_reqs1[SMB_COM_NUM]; 218 smbstat_req_info_t si_reqs2[SMB2__NCMDS]; 219 } smbstat_srv_info_t; 220 221 static void smbstat_init(void); 222 static void smbstat_fini(void); 223 static void smbstat_kstat_snapshot(void); 224 static void smbstat_kstat_process(void); 225 static void smbstat_kstat_print(void); 226 227 static void smbstat_print_counters(void); 228 static void smbstat_print_throughput(void); 229 static void smbstat_print_utilization(void); 230 static void smbstat_print_requests(void); 231 232 static void smbstat_cpu_init(void); 233 static void smbstat_cpu_fini(void); 234 static smbstat_cpu_snapshot_t *smbstat_cpu_current_snapshot(void); 235 static smbstat_cpu_snapshot_t *smbstat_cpu_previous_snapshot(void); 236 static void smbstat_cpu_snapshot(void); 237 static void smbstat_cpu_process(void); 238 239 static void smbstat_wrk_init(void); 240 static void smbstat_wrk_fini(void); 241 static void smbstat_wrk_snapshot(void); 242 static void smbstat_wrk_process(void); 243 static smbstat_wrk_snapshot_t *smbstat_wrk_current_snapshot(void); 244 245 static void smbstat_srv_init(void); 246 static void smbstat_srv_fini(void); 247 static void smbstat_srv_snapshot(void); 248 static void smbstat_srv_process(void); 249 static void smbstat_srv_process_counters(smbstat_srv_snapshot_t *); 250 static void smbstat_srv_process_throughput(smbstat_srv_snapshot_t *, 251 smbstat_srv_snapshot_t *); 252 static void smbstat_srv_process_utilization(smbstat_srv_snapshot_t *, 253 smbstat_srv_snapshot_t *); 254 static void smbstat_srv_process_requests(smbstat_srv_snapshot_t *, 255 smbstat_srv_snapshot_t *); 256 static void smbstat_srv_process_one_req(smbstat_req_info_t *, 257 smb_kstat_req_t *, smb_kstat_req_t *, boolean_t); 258 259 static smbstat_srv_snapshot_t *smbstat_srv_current_snapshot(void); 260 static smbstat_srv_snapshot_t *smbstat_srv_previous_snapshot(void); 261 262 static void *smbstat_zalloc(size_t); 263 static void smbstat_free(void *, size_t); 264 static void smbstat_fail(int, char *, ...); 265 static void smbstat_snapshot_inc_idx(void); 266 static void smbstat_usage(FILE *, int) __NORETURN; 267 static uint_t smbstat_strtoi(char const *, char *); 268 static double smbstat_hrtime_delta(hrtime_t, hrtime_t); 269 static double smbstat_sub_64(uint64_t, uint64_t); 270 static void smbstat_req_order(void); 271 static double smbstat_zero(double); 272 static void smbstat_termio_init(void); 273 274 #pragma does_not_return(smbstat_fail, smbstat_usage) 275 276 static char *smbstat_cpu_states[CPU_TICKS_SENTINEL] = { 277 "cpu_ticks_idle", 278 "cpu_ticks_user", 279 "cpu_ticks_kernel" 280 }; 281 282 static boolean_t smbstat_opt_a = B_FALSE; /* all */ 283 static boolean_t smbstat_opt_c = B_FALSE; /* counters */ 284 static boolean_t smbstat_opt_n = B_FALSE; /* by name */ 285 static boolean_t smbstat_opt_u = B_FALSE; /* utilization */ 286 static boolean_t smbstat_opt_t = B_FALSE; /* throughput */ 287 static boolean_t smbstat_opt_r = B_FALSE; /* requests */ 288 static boolean_t smbstat_opt_z = B_FALSE; /* non-zero requests */ 289 290 static uint_t smbstat_interval = 0; 291 static long smbstat_nrcpus = 0; 292 static kstat_ctl_t *smbstat_ksc = NULL; 293 static kstat_t *smbstat_srv_ksp = NULL; 294 static kstat_t *smbstat_wrk_ksp = NULL; 295 static struct winsize smbstat_ws; 296 static uint16_t smbstat_rows = 0; 297 298 static int smbstat_snapshot_idx = 0; 299 static smbstat_cpu_snapshot_t *smbstat_cpu_snapshots[SMBSTAT_SNAPSHOT_COUNT]; 300 static smbstat_srv_snapshot_t smbstat_srv_snapshots[SMBSTAT_SNAPSHOT_COUNT]; 301 static smbstat_wrk_snapshot_t smbstat_wrk_snapshots[SMBSTAT_SNAPSHOT_COUNT]; 302 static smbstat_srv_info_t smbstat_srv_info; 303 304 /* 305 * main 306 */ 307 int 308 main(int argc, char *argv[]) 309 { 310 int c; 311 312 (void) setlocale(LC_ALL, ""); 313 (void) textdomain(TEXT_DOMAIN); 314 315 if (is_system_labeled()) { 316 (void) fprintf(stderr, 317 gettext("%s: Trusted Extensions not supported.\n"), 318 argv[0]); 319 return (1); 320 } 321 322 while ((c = getopt(argc, argv, "achnrtuz")) != EOF) { 323 switch (c) { 324 case 'a': 325 smbstat_opt_a = B_TRUE; 326 break; 327 case 'n': 328 smbstat_opt_n = B_TRUE; 329 break; 330 case 'u': 331 smbstat_opt_u = B_TRUE; 332 break; 333 case 'c': 334 smbstat_opt_c = B_TRUE; 335 break; 336 case 'r': 337 smbstat_opt_r = B_TRUE; 338 break; 339 case 't': 340 smbstat_opt_t = B_TRUE; 341 break; 342 case 'z': 343 smbstat_opt_z = B_TRUE; 344 break; 345 case 'h': 346 smbstat_usage(stdout, 0); 347 default: 348 smbstat_usage(stderr, 1); 349 } 350 } 351 352 if (!smbstat_opt_u && 353 !smbstat_opt_c && 354 !smbstat_opt_r && 355 !smbstat_opt_t) { 356 /* Default options when none is specified. */ 357 smbstat_opt_u = B_TRUE; 358 smbstat_opt_t = B_TRUE; 359 } 360 361 if (optind < argc) { 362 smbstat_interval = 363 smbstat_strtoi(argv[optind], "invalid count"); 364 optind++; 365 } 366 367 if ((argc - optind) > 1) 368 smbstat_usage(stderr, 1); 369 370 (void) atexit(smbstat_fini); 371 smbstat_init(); 372 for (;;) { 373 smbstat_kstat_snapshot(); 374 smbstat_kstat_process(); 375 smbstat_kstat_print(); 376 if (smbstat_interval == 0) 377 break; 378 (void) sleep(smbstat_interval); 379 smbstat_snapshot_inc_idx(); 380 } 381 return (0); 382 } 383 384 /* 385 * smbstat_init 386 * 387 * Global initialization. 388 */ 389 static void 390 smbstat_init(void) 391 { 392 if ((smbstat_ksc = kstat_open()) == NULL) 393 smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat")); 394 395 smbstat_cpu_init(); 396 smbstat_srv_init(); 397 smbstat_wrk_init(); 398 smbstat_req_order(); 399 } 400 401 /* 402 * smbstat_fini 403 * 404 * Releases the resources smbstat_init() allocated. 405 */ 406 static void 407 smbstat_fini(void) 408 { 409 smbstat_wrk_fini(); 410 smbstat_srv_fini(); 411 smbstat_cpu_fini(); 412 (void) kstat_close(smbstat_ksc); 413 } 414 415 /* 416 * smbstat_kstat_snapshot 417 * 418 * Takes a snapshot of the data. 419 */ 420 static void 421 smbstat_kstat_snapshot(void) 422 { 423 smbstat_cpu_snapshot(); 424 smbstat_srv_snapshot(); 425 smbstat_wrk_snapshot(); 426 } 427 428 /* 429 * smbstat_kstat_process 430 */ 431 static void 432 smbstat_kstat_process(void) 433 { 434 smbstat_cpu_process(); 435 smbstat_srv_process(); 436 smbstat_wrk_process(); 437 } 438 439 /* 440 * smbstat_kstat_print 441 * 442 * Print the data processed. 443 */ 444 static void 445 smbstat_kstat_print(void) 446 { 447 smbstat_termio_init(); 448 smbstat_print_counters(); 449 smbstat_print_throughput(); 450 smbstat_print_utilization(); 451 smbstat_print_requests(); 452 (void) fflush(stdout); 453 } 454 455 /* 456 * smbstat_print_counters 457 * 458 * Displays the SMB server counters (session, users...). 459 */ 460 static void 461 smbstat_print_counters(void) 462 { 463 if (!smbstat_opt_c) 464 return; 465 466 if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_t || 467 (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) { 468 (void) printf(SMBSRV_COUNTERS_BANNER); 469 smbstat_rows = 1; 470 } 471 472 (void) printf(SMBSRV_COUNTERS_FORMAT, 473 smbstat_srv_info.si_nbt_sess, 474 smbstat_srv_info.si_tcp_sess, 475 smbstat_srv_info.si_users, 476 smbstat_srv_info.si_trees, 477 smbstat_srv_info.si_files, 478 smbstat_srv_info.si_pipes); 479 480 ++smbstat_rows; 481 } 482 /* 483 * smbstat_print_throughput 484 * 485 * Formats the SMB server throughput output. 486 */ 487 static void 488 smbstat_print_throughput(void) 489 { 490 if (!smbstat_opt_t) 491 return; 492 493 if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_c || 494 (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) { 495 (void) printf(SMBSRV_THROUGHPUT_BANNER); 496 smbstat_rows = 1; 497 } 498 (void) printf(SMBSRV_THROUGHPUT_FORMAT, 499 smbstat_zero(smbstat_srv_info.si_rbs), 500 smbstat_zero(smbstat_srv_info.si_tbs), 501 smbstat_zero(smbstat_srv_info.si_rqs), 502 smbstat_zero(smbstat_srv_info.si_rds), 503 smbstat_zero(smbstat_srv_info.si_wrs)); 504 505 ++smbstat_rows; 506 } 507 508 /* 509 * smbstat_print_utilization 510 */ 511 static void 512 smbstat_print_utilization(void) 513 { 514 char *sat; 515 if (!smbstat_opt_u) 516 return; 517 518 if (smbstat_opt_t || smbstat_opt_r || smbstat_opt_c || 519 (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) { 520 (void) printf(SMBSRV_UTILIZATION_BANNER); 521 smbstat_rows = 1; 522 } 523 524 if (smbstat_srv_info.si_sat) 525 sat = "yes"; 526 else 527 sat = "no "; 528 529 (void) printf(SMBSRV_UTILIZATION_FORMAT, 530 smbstat_srv_info.si_avw, 531 smbstat_srv_info.si_avr, 532 smbstat_srv_info.si_wserv, 533 smbstat_srv_info.si_rserv, 534 smbstat_zero(smbstat_srv_info.si_wpct), 535 smbstat_zero(smbstat_srv_info.si_rpct), 536 smbstat_zero(smbstat_srv_info.si_upct), 537 sat, 538 smbstat_srv_info.si_ticks[CPU_TICKS_USER], 539 smbstat_srv_info.si_ticks[CPU_TICKS_KERNEL], 540 smbstat_srv_info.si_ticks[CPU_TICKS_IDLE]); 541 542 ++smbstat_rows; 543 } 544 545 /* 546 * smbstat_print_requests 547 */ 548 static void 549 smbstat_print_requests(void) 550 { 551 smbstat_req_info_t *prq; 552 int i; 553 554 if (!smbstat_opt_r) 555 return; 556 557 (void) printf(SMBSRV_REQUESTS_BANNER, " "); 558 559 prq = smbstat_srv_info.si_reqs1; 560 for (i = 0; i < SMB_COM_NUM; i++) { 561 if (!smbstat_opt_a && 562 strncmp(prq[i].ri_name, "Invalid", sizeof ("Invalid")) == 0) 563 continue; 564 565 if (!smbstat_opt_z || (prq[i].ri_pct != 0)) { 566 (void) printf(SMBSRV_REQUESTS_FORMAT, 567 prq[i].ri_name, 568 prq[i].ri_opcode, 569 smbstat_zero(prq[i].ri_pct), 570 smbstat_zero(prq[i].ri_rbs), 571 smbstat_zero(prq[i].ri_tbs), 572 smbstat_zero(prq[i].ri_rqs), 573 prq[i].ri_mean, 574 prq[i].ri_stddev); 575 } 576 } 577 578 prq = smbstat_srv_info.si_reqs2; 579 for (i = 0; i < SMB2__NCMDS; i++) { 580 if (!smbstat_opt_a && i == SMB2_INVALID_CMD) 581 continue; 582 583 if (!smbstat_opt_z || (prq[i].ri_pct != 0)) { 584 (void) printf(SMBSRV_REQUESTS_FORMAT, 585 prq[i].ri_name, 586 prq[i].ri_opcode, 587 smbstat_zero(prq[i].ri_pct), 588 smbstat_zero(prq[i].ri_rbs), 589 smbstat_zero(prq[i].ri_tbs), 590 smbstat_zero(prq[i].ri_rqs), 591 prq[i].ri_mean, 592 prq[i].ri_stddev); 593 } 594 } 595 } 596 597 /* 598 * smbstat_cpu_init 599 */ 600 static void 601 smbstat_cpu_init(void) 602 { 603 size_t size; 604 int i; 605 606 smbstat_nrcpus = sysconf(_SC_CPUID_MAX) + 1; 607 size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t); 608 609 for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++) 610 smbstat_cpu_snapshots[i] = smbstat_zalloc(size); 611 } 612 613 /* 614 * smbstat_cpu_fini 615 */ 616 static void 617 smbstat_cpu_fini(void) 618 { 619 size_t size; 620 int i; 621 622 size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t); 623 624 for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++) 625 smbstat_free(smbstat_cpu_snapshots[i], size); 626 } 627 628 /* 629 * smbstat_cpu_current_snapshot 630 */ 631 static smbstat_cpu_snapshot_t * 632 smbstat_cpu_current_snapshot(void) 633 { 634 return (smbstat_cpu_snapshots[smbstat_snapshot_idx]); 635 } 636 637 /* 638 * smbstat_cpu_previous_snapshot 639 */ 640 static smbstat_cpu_snapshot_t * 641 smbstat_cpu_previous_snapshot(void) 642 { 643 int idx; 644 645 idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK; 646 return (smbstat_cpu_snapshots[idx]); 647 } 648 649 /* 650 * smbstat_cpu_snapshot 651 */ 652 static void 653 smbstat_cpu_snapshot(void) 654 { 655 kstat_t *ksp; 656 kstat_named_t *ksn; 657 smbstat_cpu_snapshot_t *curr; 658 long i; 659 int j; 660 661 curr = smbstat_cpu_current_snapshot(); 662 663 for (i = 0; i < smbstat_nrcpus; i++, curr++) { 664 curr->cs_id = SMBSTAT_ID_NO_CPU; 665 curr->cs_state = p_online(i, P_STATUS); 666 /* If no valid CPU is present, move on to the next one */ 667 if (curr->cs_state == -1) 668 continue; 669 670 curr->cs_id = i; 671 672 ksp = kstat_lookup(smbstat_ksc, "cpu", i, "sys"); 673 if (ksp == NULL) 674 smbstat_fail(1, 675 gettext("kstat_lookup('cpu sys %d') failed"), i); 676 677 if (kstat_read(smbstat_ksc, ksp, NULL) == -1) 678 smbstat_fail(1, 679 gettext("kstat_read('cpu sys %d') failed"), i); 680 681 for (j = 0; j < CPU_TICKS_SENTINEL; j++) { 682 ksn = kstat_data_lookup(ksp, smbstat_cpu_states[j]); 683 if (ksn == NULL) 684 smbstat_fail(1, 685 gettext("kstat_data_lookup('%s') failed"), 686 smbstat_cpu_states[j]); 687 curr->cs_ticks[j] = ksn->value.ui64; 688 } 689 } 690 } 691 692 /* 693 * smbstat_cpu_process 694 */ 695 static void 696 smbstat_cpu_process(void) 697 { 698 smbstat_cpu_snapshot_t *curr, *prev; 699 double total_ticks; 700 double agg_ticks[CPU_TICKS_SENTINEL]; 701 int i, j; 702 703 curr = smbstat_cpu_current_snapshot(); 704 prev = smbstat_cpu_previous_snapshot(); 705 bzero(agg_ticks, sizeof (agg_ticks)); 706 total_ticks = 0; 707 708 for (i = 0; i < smbstat_nrcpus; i++, curr++, prev++) { 709 for (j = 0; j < CPU_TICKS_SENTINEL; j++) { 710 agg_ticks[j] += smbstat_sub_64(curr->cs_ticks[j], 711 prev->cs_ticks[j]); 712 total_ticks += smbstat_sub_64(curr->cs_ticks[j], 713 prev->cs_ticks[j]); 714 } 715 } 716 717 for (j = 0; j < CPU_TICKS_SENTINEL; j++) 718 smbstat_srv_info.si_ticks[j] = 719 (agg_ticks[j] * 100.0) / total_ticks; 720 } 721 722 /* 723 * smbstat_wrk_init 724 */ 725 static void 726 smbstat_wrk_init(void) 727 { 728 smbstat_wrk_ksp = 729 kstat_lookup(smbstat_ksc, "unix", -1, SMBSRV_KSTAT_WORKERS); 730 if (smbstat_wrk_ksp == NULL) 731 smbstat_fail(1, 732 gettext("cannot retrieve smbsrv workers kstat\n")); 733 } 734 735 static void 736 smbstat_wrk_fini(void) 737 { 738 smbstat_wrk_ksp = NULL; 739 } 740 741 /* 742 * smbstat_wrk_snapshot 743 */ 744 static void 745 smbstat_wrk_snapshot(void) 746 { 747 smbstat_wrk_snapshot_t *curr; 748 kstat_named_t *kn; 749 750 curr = smbstat_wrk_current_snapshot(); 751 752 if (kstat_read(smbstat_ksc, smbstat_wrk_ksp, NULL) == -1) 753 smbstat_fail(1, gettext("kstat_read('%s') failed"), 754 smbstat_wrk_ksp->ks_name); 755 756 kn = kstat_data_lookup(smbstat_wrk_ksp, "maxthreads"); 757 if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64)) 758 smbstat_fail(1, gettext("kstat_read('%s') failed"), 759 "maxthreads"); 760 curr->ws_maxthreads = kn->value.ui64; 761 762 kn = kstat_data_lookup(smbstat_wrk_ksp, "bnalloc"); 763 if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64)) 764 smbstat_fail(1, gettext("kstat_read('%s') failed"), 765 "bnalloc"); 766 curr->ws_bnalloc = kn->value.ui64; 767 } 768 769 /* 770 * smbstat_wrk_process 771 */ 772 static void 773 smbstat_wrk_process(void) 774 { 775 smbstat_wrk_snapshot_t *curr; 776 777 curr = smbstat_wrk_current_snapshot(); 778 779 if (curr->ws_bnalloc >= curr->ws_maxthreads) 780 smbstat_srv_info.si_sat = B_TRUE; 781 else 782 smbstat_srv_info.si_sat = B_FALSE; 783 } 784 785 /* 786 * smbstat_wrk_current_snapshot 787 */ 788 static smbstat_wrk_snapshot_t * 789 smbstat_wrk_current_snapshot(void) 790 { 791 return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]); 792 } 793 794 /* 795 * smbstat_srv_init 796 */ 797 static void 798 smbstat_srv_init(void) 799 { 800 smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE, 801 getzoneid(), SMBSRV_KSTAT_STATISTICS); 802 if (smbstat_srv_ksp == NULL) 803 smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n")); 804 } 805 806 /* 807 * smbstat_srv_fini 808 */ 809 static void 810 smbstat_srv_fini(void) 811 { 812 smbstat_srv_ksp = NULL; 813 } 814 815 /* 816 * smbstat_srv_snapshot 817 * 818 * Take a snapshot of the smbsrv module statistics. 819 */ 820 static void 821 smbstat_srv_snapshot(void) 822 { 823 smbstat_srv_snapshot_t *curr; 824 825 curr = smbstat_srv_current_snapshot(); 826 827 if ((kstat_read(smbstat_ksc, smbstat_srv_ksp, NULL) == -1) || 828 (smbstat_srv_ksp->ks_data_size != sizeof (curr->ss_data))) 829 smbstat_fail(1, gettext("kstat_read('%s') failed"), 830 smbstat_srv_ksp->ks_name); 831 832 curr->ss_snaptime = smbstat_srv_ksp->ks_snaptime; 833 bcopy(smbstat_srv_ksp->ks_data, &curr->ss_data, sizeof (curr->ss_data)); 834 } 835 836 /* 837 * smbstat_srv_process 838 * 839 * Processes the snapshot data. 840 */ 841 static void 842 smbstat_srv_process(void) 843 { 844 smbstat_srv_snapshot_t *curr, *prev; 845 846 curr = smbstat_srv_current_snapshot(); 847 prev = smbstat_srv_previous_snapshot(); 848 849 if (prev->ss_snaptime == 0) 850 smbstat_srv_info.si_hretime = 851 smbstat_hrtime_delta(curr->ss_data.ks_start_time, 852 curr->ss_snaptime); 853 else 854 smbstat_srv_info.si_hretime = 855 smbstat_hrtime_delta(prev->ss_snaptime, curr->ss_snaptime); 856 857 smbstat_srv_info.si_etime = smbstat_srv_info.si_hretime / NANOSEC; 858 smbstat_srv_info.si_total_nreqs = 859 smbstat_sub_64(curr->ss_data.ks_nreq, prev->ss_data.ks_nreq); 860 861 if (smbstat_opt_c) 862 smbstat_srv_process_counters(curr); 863 if (smbstat_opt_t) 864 smbstat_srv_process_throughput(curr, prev); 865 if (smbstat_opt_u) 866 smbstat_srv_process_utilization(curr, prev); 867 if (smbstat_opt_r) 868 smbstat_srv_process_requests(curr, prev); 869 } 870 871 /* 872 * smbstat_srv_process_counters 873 */ 874 static void 875 smbstat_srv_process_counters(smbstat_srv_snapshot_t *curr) 876 { 877 smbstat_srv_info.si_nbt_sess = curr->ss_data.ks_nbt_sess; 878 smbstat_srv_info.si_tcp_sess = curr->ss_data.ks_tcp_sess; 879 smbstat_srv_info.si_users = curr->ss_data.ks_users; 880 smbstat_srv_info.si_trees = curr->ss_data.ks_trees; 881 smbstat_srv_info.si_files = curr->ss_data.ks_files; 882 smbstat_srv_info.si_pipes = curr->ss_data.ks_pipes; 883 } 884 885 /* 886 * smbstat_srv_process_throughput 887 * 888 * Processes the data relative to the throughput of the smbsrv module and 889 * stores the results in the structure smbstat_srv_info. 890 */ 891 static void 892 smbstat_srv_process_throughput( 893 smbstat_srv_snapshot_t *curr, 894 smbstat_srv_snapshot_t *prev) 895 { 896 smbstat_srv_info.si_tbs = 897 smbstat_sub_64(curr->ss_data.ks_txb, prev->ss_data.ks_txb); 898 smbstat_srv_info.si_tbs /= smbstat_srv_info.si_etime; 899 smbstat_srv_info.si_rbs = 900 smbstat_sub_64(curr->ss_data.ks_rxb, prev->ss_data.ks_rxb); 901 smbstat_srv_info.si_rbs /= smbstat_srv_info.si_etime; 902 smbstat_srv_info.si_rqs = smbstat_srv_info.si_total_nreqs; 903 smbstat_srv_info.si_rqs /= smbstat_srv_info.si_etime; 904 905 smbstat_srv_info.si_rds = smbstat_sub_64( 906 curr->ss_data.ks_reqs1[SMB_COM_READ].kr_nreq, 907 prev->ss_data.ks_reqs1[SMB_COM_READ].kr_nreq); 908 smbstat_srv_info.si_rds += smbstat_sub_64( 909 curr->ss_data.ks_reqs1[SMB_COM_LOCK_AND_READ].kr_nreq, 910 prev->ss_data.ks_reqs1[SMB_COM_LOCK_AND_READ].kr_nreq); 911 smbstat_srv_info.si_rds += smbstat_sub_64( 912 curr->ss_data.ks_reqs1[SMB_COM_READ_RAW].kr_nreq, 913 prev->ss_data.ks_reqs1[SMB_COM_READ_RAW].kr_nreq); 914 smbstat_srv_info.si_rds += smbstat_sub_64( 915 curr->ss_data.ks_reqs1[SMB_COM_READ_ANDX].kr_nreq, 916 prev->ss_data.ks_reqs1[SMB_COM_READ_ANDX].kr_nreq); 917 smbstat_srv_info.si_rds += smbstat_sub_64( 918 curr->ss_data.ks_reqs2[SMB2_READ].kr_nreq, 919 prev->ss_data.ks_reqs2[SMB2_READ].kr_nreq); 920 smbstat_srv_info.si_rds /= smbstat_srv_info.si_etime; 921 922 smbstat_srv_info.si_wrs = smbstat_sub_64( 923 curr->ss_data.ks_reqs1[SMB_COM_WRITE].kr_nreq, 924 prev->ss_data.ks_reqs1[SMB_COM_WRITE].kr_nreq); 925 smbstat_srv_info.si_wrs += smbstat_sub_64( 926 curr->ss_data.ks_reqs1[SMB_COM_WRITE_AND_UNLOCK].kr_nreq, 927 prev->ss_data.ks_reqs1[SMB_COM_WRITE_AND_UNLOCK].kr_nreq); 928 smbstat_srv_info.si_wrs += smbstat_sub_64( 929 curr->ss_data.ks_reqs1[SMB_COM_WRITE_RAW].kr_nreq, 930 prev->ss_data.ks_reqs1[SMB_COM_WRITE_RAW].kr_nreq); 931 smbstat_srv_info.si_wrs += smbstat_sub_64( 932 curr->ss_data.ks_reqs1[SMB_COM_WRITE_AND_CLOSE].kr_nreq, 933 prev->ss_data.ks_reqs1[SMB_COM_WRITE_AND_CLOSE].kr_nreq); 934 smbstat_srv_info.si_wrs += smbstat_sub_64( 935 curr->ss_data.ks_reqs1[SMB_COM_WRITE_ANDX].kr_nreq, 936 prev->ss_data.ks_reqs1[SMB_COM_WRITE_ANDX].kr_nreq); 937 smbstat_srv_info.si_wrs += smbstat_sub_64( 938 curr->ss_data.ks_reqs2[SMB2_WRITE].kr_nreq, 939 prev->ss_data.ks_reqs2[SMB2_WRITE].kr_nreq); 940 smbstat_srv_info.si_wrs /= smbstat_srv_info.si_etime; 941 } 942 943 /* 944 * smbstat_srv_process_utilization 945 * 946 * Processes the data relative to the utilization of the smbsrv module and 947 * stores the results in the structure smbstat_srv_info. 948 */ 949 static void 950 smbstat_srv_process_utilization( 951 smbstat_srv_snapshot_t *curr, 952 smbstat_srv_snapshot_t *prev) 953 { 954 double tw_delta, tr_delta; 955 double w_delta, r_delta; 956 double tps, rqs; 957 958 w_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wlentime, 959 curr->ss_data.ks_utilization.ku_wlentime); 960 r_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rlentime, 961 curr->ss_data.ks_utilization.ku_rlentime); 962 tw_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wtime, 963 curr->ss_data.ks_utilization.ku_wtime); 964 tr_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rtime, 965 curr->ss_data.ks_utilization.ku_rtime); 966 rqs = smbstat_srv_info.si_total_nreqs / smbstat_srv_info.si_etime; 967 968 /* Average number of requests waiting */ 969 if (w_delta != 0) 970 smbstat_srv_info.si_avw = w_delta / smbstat_srv_info.si_hretime; 971 else 972 smbstat_srv_info.si_avw = 0.0; 973 974 /* Average number of request running */ 975 if (r_delta != 0) 976 smbstat_srv_info.si_avr = r_delta / smbstat_srv_info.si_hretime; 977 else 978 smbstat_srv_info.si_avr = 0.0; 979 980 /* Utilization */ 981 smbstat_srv_info.si_upct = 982 (smbstat_srv_info.si_avr / curr->ss_data.ks_maxreqs) * 100; 983 984 /* Average wait service time in milliseconds */ 985 smbstat_srv_info.si_rserv = 0.0; 986 smbstat_srv_info.si_wserv = 0.0; 987 if (rqs > 0.0 && 988 (smbstat_srv_info.si_avw != 0.0 || 989 smbstat_srv_info.si_avr != 0.0)) { 990 tps = 1 / rqs; 991 if (smbstat_srv_info.si_avw != 0.0) 992 smbstat_srv_info.si_wserv = 993 smbstat_srv_info.si_avw * tps; 994 if (smbstat_srv_info.si_avr != 0.0) 995 smbstat_srv_info.si_rserv = 996 smbstat_srv_info.si_avr * tps; 997 } 998 999 /* % of time there is a transaction waiting for service */ 1000 if (tw_delta != 0) { 1001 smbstat_srv_info.si_wpct = tw_delta; 1002 smbstat_srv_info.si_wpct /= smbstat_srv_info.si_hretime; 1003 smbstat_srv_info.si_wpct *= 100.0; 1004 } else { 1005 smbstat_srv_info.si_wpct = 0.0; 1006 } 1007 1008 /* % of time there is a transaction running */ 1009 if (tr_delta != 0) { 1010 smbstat_srv_info.si_rpct = tr_delta; 1011 smbstat_srv_info.si_rpct /= smbstat_srv_info.si_hretime; 1012 smbstat_srv_info.si_rpct *= 100.0; 1013 } else { 1014 smbstat_srv_info.si_rpct = 0.0; 1015 } 1016 } 1017 1018 /* 1019 * smbstat_srv_process_requests 1020 * 1021 * Processes the data relative to the SMB requests and stores the results in 1022 * the structure smbstat_srv_info. 1023 */ 1024 static void 1025 smbstat_srv_process_requests( 1026 smbstat_srv_snapshot_t *curr, 1027 smbstat_srv_snapshot_t *prev) 1028 { 1029 smbstat_req_info_t *info; 1030 smb_kstat_req_t *curr_req; 1031 smb_kstat_req_t *prev_req; 1032 int i, idx; 1033 boolean_t firstcall = (prev->ss_snaptime == 0); 1034 1035 for (i = 0; i < SMB_COM_NUM; i++) { 1036 info = &smbstat_srv_info.si_reqs1[i]; 1037 idx = info[i].ri_opcode & 0xFF; 1038 curr_req = &curr->ss_data.ks_reqs1[idx]; 1039 prev_req = &prev->ss_data.ks_reqs1[idx]; 1040 smbstat_srv_process_one_req( 1041 info, curr_req, prev_req, firstcall); 1042 } 1043 1044 for (i = 0; i < SMB2__NCMDS; i++) { 1045 info = &smbstat_srv_info.si_reqs2[i]; 1046 curr_req = &curr->ss_data.ks_reqs2[i]; 1047 prev_req = &prev->ss_data.ks_reqs2[i]; 1048 smbstat_srv_process_one_req( 1049 info, curr_req, prev_req, firstcall); 1050 } 1051 } 1052 1053 static void 1054 smbstat_srv_process_one_req( 1055 smbstat_req_info_t *info, 1056 smb_kstat_req_t *curr_req, 1057 smb_kstat_req_t *prev_req, 1058 boolean_t firstcall) 1059 { 1060 double nrqs; 1061 1062 nrqs = smbstat_sub_64(curr_req->kr_nreq, 1063 prev_req->kr_nreq); 1064 1065 info->ri_rqs = nrqs / smbstat_srv_info.si_etime; 1066 1067 info->ri_rbs = smbstat_sub_64( 1068 curr_req->kr_rxb, 1069 prev_req->kr_rxb) / 1070 smbstat_srv_info.si_etime; 1071 1072 info->ri_tbs = smbstat_sub_64( 1073 curr_req->kr_txb, 1074 prev_req->kr_txb) / 1075 smbstat_srv_info.si_etime; 1076 1077 info->ri_pct = nrqs * 100; 1078 if (smbstat_srv_info.si_total_nreqs > 0) 1079 info->ri_pct /= smbstat_srv_info.si_total_nreqs; 1080 1081 if (firstcall) { 1082 /* First time. Take the aggregate */ 1083 info->ri_stddev = 1084 curr_req->kr_a_stddev; 1085 info->ri_mean = curr_req->kr_a_mean; 1086 } else { 1087 /* Take the differential */ 1088 info->ri_stddev = 1089 curr_req->kr_d_stddev; 1090 info->ri_mean = curr_req->kr_d_mean; 1091 } 1092 if (nrqs > 0) { 1093 info->ri_stddev /= nrqs; 1094 info->ri_stddev = sqrt(info->ri_stddev); 1095 } else { 1096 info->ri_stddev = 0; 1097 } 1098 info->ri_stddev /= NANOSEC; 1099 info->ri_mean /= NANOSEC; 1100 } 1101 1102 1103 /* 1104 * smbstat_srv_current_snapshot 1105 * 1106 * Returns the current snapshot. 1107 */ 1108 static smbstat_srv_snapshot_t * 1109 smbstat_srv_current_snapshot(void) 1110 { 1111 return (&smbstat_srv_snapshots[smbstat_snapshot_idx]); 1112 } 1113 1114 /* 1115 * smbstat_srv_previous_snapshot 1116 * 1117 * Returns the previous snapshot. 1118 */ 1119 static smbstat_srv_snapshot_t * 1120 smbstat_srv_previous_snapshot(void) 1121 { 1122 int idx; 1123 1124 idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK; 1125 return (&smbstat_srv_snapshots[idx]); 1126 } 1127 1128 /* 1129 * smbstat_usage 1130 * 1131 * Prints out a help message. 1132 */ 1133 static void 1134 smbstat_usage(FILE *fd, int exit_code) 1135 { 1136 (void) fprintf(fd, gettext(SMBSTAT_HELP)); 1137 exit(exit_code); 1138 } 1139 1140 /* 1141 * smbstat_fail 1142 * 1143 * Prints out to stderr an error message and exits the process. 1144 */ 1145 static void 1146 smbstat_fail(int do_perror, char *message, ...) 1147 { 1148 va_list args; 1149 1150 va_start(args, message); 1151 (void) fprintf(stderr, gettext("smbstat: ")); 1152 /* LINTED E_SEC_PRINTF_VAR_FMT */ 1153 (void) vfprintf(stderr, message, args); 1154 va_end(args); 1155 if (do_perror) 1156 (void) fprintf(stderr, ": %s", strerror(errno)); 1157 (void) fprintf(stderr, "\n"); 1158 exit(1); 1159 } 1160 1161 /* 1162 * smbstat_sub_64 1163 * 1164 * Substract 2 uint64_t and returns a double. 1165 */ 1166 static double 1167 smbstat_sub_64(uint64_t a, uint64_t b) 1168 { 1169 return ((double)(a - b)); 1170 } 1171 1172 /* 1173 * smbstat_zero 1174 * 1175 * Returns zero if the value passed in is less than 1. 1176 */ 1177 static double 1178 smbstat_zero(double value) 1179 { 1180 if (value < 1) 1181 value = 0; 1182 return (value); 1183 } 1184 1185 /* 1186 * smbstat_strtoi 1187 * 1188 * Converts a string representing an integer value into its binary value. 1189 * If the conversion fails this routine exits the process. 1190 */ 1191 static uint_t 1192 smbstat_strtoi(char const *val, char *errmsg) 1193 { 1194 char *end; 1195 long tmp; 1196 1197 errno = 0; 1198 tmp = strtol(val, &end, 10); 1199 if (*end != '\0' || errno) 1200 smbstat_fail(1, "%s %s", errmsg, val); 1201 return ((uint_t)tmp); 1202 } 1203 1204 /* 1205 * smbstat_termio_init 1206 * 1207 * Determines the size of the terminal associated with the process. 1208 */ 1209 static void 1210 smbstat_termio_init(void) 1211 { 1212 char *envp; 1213 1214 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &smbstat_ws) != -1) { 1215 if (smbstat_ws.ws_row == 0) { 1216 envp = getenv("LINES"); 1217 if (envp != NULL) 1218 smbstat_ws.ws_row = atoi(envp); 1219 } 1220 1221 if (smbstat_ws.ws_col == 0) { 1222 envp = getenv("COLUMNS"); 1223 if (envp != NULL) 1224 smbstat_ws.ws_row = atoi(envp); 1225 } 1226 } 1227 if (smbstat_ws.ws_col == 0) 1228 smbstat_ws.ws_col = 80; 1229 if (smbstat_ws.ws_row == 0) 1230 smbstat_ws.ws_row = 25; 1231 } 1232 1233 /* 1234 * smbstat_snapshot_idx_inc 1235 * 1236 * Increments the snapshot index. 1237 */ 1238 static void 1239 smbstat_snapshot_inc_idx(void) 1240 { 1241 smbstat_snapshot_idx++; 1242 smbstat_snapshot_idx &= SMBSTAT_SNAPSHOT_MASK; 1243 } 1244 1245 /* 1246 * smbstat_req_cmp_name 1247 * 1248 * Call back function passed to qsort() when the list of requests must be sorted 1249 * by name. 1250 */ 1251 static int 1252 smbstat_req_cmp_name(const void *obj1, const void *obj2) 1253 { 1254 return (strncasecmp( 1255 ((smbstat_req_info_t *)obj1)->ri_name, 1256 ((smbstat_req_info_t *)obj2)->ri_name, 1257 sizeof (((smbstat_req_info_t *)obj2)->ri_name))); 1258 } 1259 1260 /* 1261 * smbstat_req_order 1262 * 1263 * Snapshots the smbsrv module statistics once to get the name of the requests. 1264 * The request list is smbstat_srv_info is then sorted by name or by code 1265 * depending on the boolean smbstat_opt_a. 1266 * The function should be called once during initialization. 1267 */ 1268 static void 1269 smbstat_req_order(void) 1270 { 1271 smbstat_srv_snapshot_t *ss; 1272 smbstat_req_info_t *info; 1273 smb_kstat_req_t *reqs; 1274 int i; 1275 1276 smbstat_srv_snapshot(); 1277 ss = smbstat_srv_current_snapshot(); 1278 1279 reqs = ss->ss_data.ks_reqs1; 1280 info = smbstat_srv_info.si_reqs1; 1281 for (i = 0; i < SMB_COM_NUM; i++) { 1282 (void) strlcpy(info[i].ri_name, reqs[i].kr_name, 1283 sizeof (reqs[i].kr_name)); 1284 info[i].ri_opcode = i; 1285 } 1286 if (smbstat_opt_n) 1287 qsort(info, SMB_COM_NUM, sizeof (smbstat_req_info_t), 1288 smbstat_req_cmp_name); 1289 1290 reqs = ss->ss_data.ks_reqs2; 1291 info = smbstat_srv_info.si_reqs2; 1292 for (i = 0; i < SMB2__NCMDS; i++) { 1293 (void) strlcpy(info[i].ri_name, reqs[i].kr_name, 1294 sizeof (reqs[i].kr_name)); 1295 info[i].ri_opcode = i; 1296 } 1297 if (smbstat_opt_n) 1298 qsort(info, SMB2__NCMDS, sizeof (smbstat_req_info_t), 1299 smbstat_req_cmp_name); 1300 } 1301 1302 /* 1303 * Return the number of ticks delta between two hrtime_t 1304 * values. Attempt to cater for various kinds of overflow 1305 * in hrtime_t - no matter how improbable. 1306 */ 1307 static double 1308 smbstat_hrtime_delta(hrtime_t old, hrtime_t new) 1309 { 1310 uint64_t del; 1311 1312 if ((new >= old) && (old >= 0L)) 1313 return ((double)(new - old)); 1314 /* 1315 * We've overflowed the positive portion of an hrtime_t. 1316 */ 1317 if (new < 0L) { 1318 /* 1319 * The new value is negative. Handle the case where the old 1320 * value is positive or negative. 1321 */ 1322 uint64_t n1; 1323 uint64_t o1; 1324 1325 n1 = -new; 1326 if (old > 0L) 1327 return ((double)(n1 - old)); 1328 1329 o1 = -old; 1330 del = n1 - o1; 1331 return ((double)del); 1332 } 1333 1334 /* 1335 * Either we've just gone from being negative to positive *or* the last 1336 * entry was positive and the new entry is also positive but *less* than 1337 * the old entry. This implies we waited quite a few days on a very fast 1338 * system between displays. 1339 */ 1340 if (old < 0L) { 1341 uint64_t o2; 1342 o2 = -old; 1343 del = UINT64_MAX - o2; 1344 } else { 1345 del = UINT64_MAX - old; 1346 } 1347 del += new; 1348 return ((double)del); 1349 } 1350 1351 static void * 1352 smbstat_zalloc(size_t size) 1353 { 1354 void *ptr; 1355 1356 ptr = umem_zalloc(size, UMEM_DEFAULT); 1357 if (ptr == NULL) 1358 smbstat_fail(1, gettext("out of memory")); 1359 return (ptr); 1360 } 1361 1362 static void 1363 smbstat_free(void *ptr, size_t size) 1364 { 1365 umem_free(ptr, size); 1366 } 1367