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