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