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