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);
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
main(int argc,char * argv[])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
smbstat_init(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
smbstat_fini(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
smbstat_kstat_snapshot(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
smbstat_kstat_process(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
smbstat_kstat_print(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
smbstat_print_counters(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
smbstat_print_throughput(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
smbstat_print_utilization(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
smbstat_print_requests(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
smbstat_cpu_init(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
smbstat_cpu_fini(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 *
smbstat_cpu_current_snapshot(void)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 *
smbstat_cpu_previous_snapshot(void)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
smbstat_cpu_snapshot(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
smbstat_cpu_process(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
smbstat_wrk_init(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
smbstat_wrk_fini(void)736 smbstat_wrk_fini(void)
737 {
738 smbstat_wrk_ksp = NULL;
739 }
740
741 /*
742 * smbstat_wrk_snapshot
743 */
744 static void
smbstat_wrk_snapshot(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
smbstat_wrk_process(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 *
smbstat_wrk_current_snapshot(void)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
smbstat_srv_init(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
smbstat_srv_fini(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
smbstat_srv_snapshot(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
smbstat_srv_process(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
smbstat_srv_process_counters(smbstat_srv_snapshot_t * curr)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
smbstat_srv_process_throughput(smbstat_srv_snapshot_t * curr,smbstat_srv_snapshot_t * prev)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
smbstat_srv_process_utilization(smbstat_srv_snapshot_t * curr,smbstat_srv_snapshot_t * prev)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
smbstat_srv_process_requests(smbstat_srv_snapshot_t * curr,smbstat_srv_snapshot_t * prev)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
smbstat_srv_process_one_req(smbstat_req_info_t * info,smb_kstat_req_t * curr_req,smb_kstat_req_t * prev_req,boolean_t firstcall)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 *
smbstat_srv_current_snapshot(void)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 *
smbstat_srv_previous_snapshot(void)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
smbstat_usage(FILE * fd,int exit_code)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
smbstat_fail(int do_perror,char * message,...)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
smbstat_sub_64(uint64_t a,uint64_t b)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
smbstat_zero(double value)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
smbstat_strtoi(char const * val,char * errmsg)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
smbstat_termio_init(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
smbstat_snapshot_inc_idx(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
smbstat_req_cmp_name(const void * obj1,const void * obj2)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
smbstat_req_order(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
smbstat_hrtime_delta(hrtime_t old,hrtime_t new)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 *
smbstat_zalloc(size_t size)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
smbstat_free(void * ptr,size_t size)1363 smbstat_free(void *ptr, size_t size)
1364 {
1365 umem_free(ptr, size);
1366 }
1367