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