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