xref: /illumos-gate/usr/src/cmd/smbsrv/smbstat/smbstat.c (revision f46594905fea795f73f7a6f5d6f03e4b3931e723)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Copyright 2020 Nexenta by DDN, Inc.  All rights reserved.
25  */
26 
27 /*
28  * smbstat: Server Message Block File System statistics
29  *
30  * The statistics this CLI displays come from two sources:
31  *
32  * 1) The kernel module 'smbsrv'.
33  * 2) The SMB workers task queue statistics the task queue manager of Solaris
34  *    maintains.
35  *
36  * The flow of the code is the following:
37  *
38  *
39  *			+----------------+
40  *			| Initialization |
41  *			+----------------+
42  *				|
43  *				|
44  *				v
45  *		  +--------------------------*
46  *		  | Take a snapshot the data | <--------+
47  *		  +--------------------------+		|
48  *				|			|
49  *				|			|
50  *				v			|
51  *		    +----------------------+		|
52  *		    | Process the snapshot |		|
53  *		    +----------------------+		|
54  *				|			|
55  *				|			|
56  *				v			|
57  *	     +------------------------------------+	|
58  *	     | Print the result of the processing |	|
59  *	     +------------------------------------+	|
60  *				|			|
61  *				|			|
62  *				v			|
63  *		Yes	---------------			|
64  *	+------------ < interval == 0 ? >		|
65  *	|		---------------			|
66  *	|		       |			|
67  *	|		       | No			|
68  *	|		       v			|
69  *	|	   +------------------------+		|
70  *	|	   | Sleep for the duration | ----------+
71  *	|	   |   of the interval.     |
72  *	|	   +------------------------+
73  *	|
74  *	+---------------------+
75  *			      |
76  *			      v
77  *
78  *			    Exit
79  *
80  * There are two sets of snapshots. One set for the smbsrv module and the other
81  * for the task queue (SMB workers). Each set contains 2 snapshots. One is
82  * labeled 'current' the other one 'previous'. Their role changes after each
83  * snapshot. The 'current' becomes 'previous' and vice versa.
84  * The first snapshot taken is compared against the data gathered since the
85  * smbsrv module was loaded. Subsequent snapshots will be compared against the
86  * previous snapshot.
87  */
88 
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <unistd.h>
92 #include <kstat.h>
93 #include <stdarg.h>
94 #include <errno.h>
95 #include <inttypes.h>
96 #include <strings.h>
97 #include <utility.h>
98 #include <libintl.h>
99 #include <zone.h>
100 #include <termios.h>
101 #include <stropts.h>
102 #include <math.h>
103 #include <umem.h>
104 #include <locale.h>
105 #include <sys/processor.h>
106 #include <smbsrv/smb_kstat.h>
107 #include <smbsrv/smb.h>
108 #include <smbsrv/smb2.h>
109 
110 #if !defined(TEXT_DOMAIN)
111 #define	TEXT_DOMAIN "SYS_TEST"
112 #endif /* TEXT_DOMAIN */
113 
114 #define	SMBSTAT_ID_NO_CPU	-1
115 #define	SMBSTAT_SNAPSHOT_COUNT	2		/* Must be a power of 2 */
116 #define	SMBSTAT_SNAPSHOT_MASK	(SMBSTAT_SNAPSHOT_COUNT - 1)
117 
118 #define	SMBSTAT_HELP	\
119 	"Usage: smbstat [-acnrtuz] [interval]\n" \
120 	"    -c: display counters\n" \
121 	"    -t: display throughput\n" \
122 	"    -u: display utilization\n" \
123 	"    -r: display requests\n" \
124 	"        -a: all the requests (supported and unsupported)\n" \
125 	"        -z: skip the requests not received\n" \
126 	"        -n: display in alphabetic order\n" \
127 	"    interval: refresh cycle in seconds\n"
128 
129 #define	SMBSRV_COUNTERS_BANNER	"\n  nbt   tcp users trees files pipes\n"
130 #define	SMBSRV_COUNTERS_FORMAT	"%5d %5d %5d %5d %5d %5d\n"
131 
132 #define	SMBSRV_THROUGHPUT_BANNER	\
133 	"\nrbytes/s   tbytes/s    reqs/s     reads/s   writes/s\n"
134 #define	SMBSRV_THROUGHPUT_FORMAT	\
135 	"%1.3e  %1.3e  %1.3e  %1.3e  %1.3e\n"
136 
137 #define	SMBSRV_UTILIZATION_BANNER	\
138 	"\n  wcnt       rcnt       wtime      rtime" \
139 	"     w%%   r%%   u%%  sat usr%% sys%%  idle%%\n"
140 #define	SMBSRV_UTILIZATION_FORMAT	\
141 	"%1.3e  %1.3e  %1.3e  %1.3e  %3.0f  %3.0f  %3.0f  %s " \
142 	"%3.0f  %3.0f    %3.0f\n"
143 
144 #define	SMBSRV_REQUESTS_BANNER	\
145 	"\n%30s code   %%   rbytes/s   tbytes/s     req/s     rt-mean"	\
146 	"   rt-stddev\n"
147 #define	SMBSRV_REQUESTS_FORMAT	\
148 	"%30s  %02X   %3.0f  %1.3e  %1.3e  %1.3e  %1.3e  %1.3e\n"
149 
150 typedef enum {
151 	CPU_TICKS_IDLE = 0,
152 	CPU_TICKS_USER,
153 	CPU_TICKS_KERNEL,
154 	CPU_TICKS_SENTINEL
155 } cpu_state_idx_t;
156 
157 typedef struct smbstat_cpu_snapshot {
158 	processorid_t	cs_id;
159 	int		cs_state;
160 	uint64_t	cs_ticks[CPU_TICKS_SENTINEL];
161 } smbstat_cpu_snapshot_t;
162 
163 typedef struct smbstat_srv_snapshot {
164 	hrtime_t	ss_snaptime;
165 	smbsrv_kstats_t	ss_data;
166 } smbstat_srv_snapshot_t;
167 
168 typedef struct smbstat_wrk_snapshot {
169 	uint64_t	ws_maxthreads;
170 	uint64_t	ws_bnalloc;
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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
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 == -1)
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
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
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
739 smbstat_wrk_fini(void)
740 {
741 	smbstat_wrk_ksp = NULL;
742 }
743 
744 /*
745  * smbstat_wrk_snapshot
746  */
747 static 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, "maxthreads");
760 	if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64))
761 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
762 		    "maxthreads");
763 	curr->ws_maxthreads = kn->value.ui64;
764 
765 	kn = kstat_data_lookup(smbstat_wrk_ksp, "bnalloc");
766 	if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64))
767 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
768 		    "bnalloc");
769 	curr->ws_bnalloc = kn->value.ui64;
770 }
771 
772 /*
773  * smbstat_wrk_process
774  */
775 static void
776 smbstat_wrk_process(void)
777 {
778 	smbstat_wrk_snapshot_t	*curr;
779 
780 	curr = smbstat_wrk_current_snapshot();
781 
782 	if (curr->ws_bnalloc >= curr->ws_maxthreads)
783 		smbstat_srv_info.si_sat = B_TRUE;
784 	else
785 		smbstat_srv_info.si_sat = B_FALSE;
786 }
787 
788 /*
789  * smbstat_wrk_current_snapshot
790  */
791 static smbstat_wrk_snapshot_t *
792 smbstat_wrk_current_snapshot(void)
793 {
794 	return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]);
795 }
796 
797 /*
798  * smbstat_srv_init
799  */
800 static void
801 smbstat_srv_init(void)
802 {
803 	smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE,
804 	    getzoneid(), SMBSRV_KSTAT_STATISTICS);
805 	if (smbstat_srv_ksp == NULL)
806 		smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n"));
807 }
808 
809 /*
810  * smbstat_srv_fini
811  */
812 static void
813 smbstat_srv_fini(void)
814 {
815 	smbstat_srv_ksp = NULL;
816 }
817 
818 /*
819  * smbstat_srv_snapshot
820  *
821  * Take a snapshot of the smbsrv module statistics.
822  */
823 static void
824 smbstat_srv_snapshot(void)
825 {
826 	smbstat_srv_snapshot_t	*curr;
827 
828 	curr = smbstat_srv_current_snapshot();
829 
830 	if ((kstat_read(smbstat_ksc, smbstat_srv_ksp, NULL) == -1) ||
831 	    (smbstat_srv_ksp->ks_data_size != sizeof (curr->ss_data)))
832 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
833 		    smbstat_srv_ksp->ks_name);
834 
835 	curr->ss_snaptime = smbstat_srv_ksp->ks_snaptime;
836 	bcopy(smbstat_srv_ksp->ks_data, &curr->ss_data, sizeof (curr->ss_data));
837 }
838 
839 /*
840  * smbstat_srv_process
841  *
842  * Processes the snapshot data.
843  */
844 static void
845 smbstat_srv_process(void)
846 {
847 	smbstat_srv_snapshot_t	*curr, *prev;
848 
849 	curr = smbstat_srv_current_snapshot();
850 	prev = smbstat_srv_previous_snapshot();
851 
852 	if (prev->ss_snaptime == 0)
853 		smbstat_srv_info.si_hretime =
854 		    smbstat_hrtime_delta(curr->ss_data.ks_start_time,
855 		    curr->ss_snaptime);
856 	else
857 		smbstat_srv_info.si_hretime =
858 		    smbstat_hrtime_delta(prev->ss_snaptime, curr->ss_snaptime);
859 
860 	smbstat_srv_info.si_etime = smbstat_srv_info.si_hretime / NANOSEC;
861 	smbstat_srv_info.si_total_nreqs =
862 	    smbstat_sub_64(curr->ss_data.ks_nreq, prev->ss_data.ks_nreq);
863 
864 	if (smbstat_opt_c)
865 		smbstat_srv_process_counters(curr);
866 	if (smbstat_opt_t)
867 		smbstat_srv_process_throughput(curr, prev);
868 	if (smbstat_opt_u)
869 		smbstat_srv_process_utilization(curr, prev);
870 	if (smbstat_opt_r)
871 		smbstat_srv_process_requests(curr, prev);
872 }
873 
874 /*
875  * smbstat_srv_process_counters
876  */
877 static void
878 smbstat_srv_process_counters(smbstat_srv_snapshot_t *curr)
879 {
880 	smbstat_srv_info.si_nbt_sess = curr->ss_data.ks_nbt_sess;
881 	smbstat_srv_info.si_tcp_sess = curr->ss_data.ks_tcp_sess;
882 	smbstat_srv_info.si_users = curr->ss_data.ks_users;
883 	smbstat_srv_info.si_trees = curr->ss_data.ks_trees;
884 	smbstat_srv_info.si_files = curr->ss_data.ks_files;
885 	smbstat_srv_info.si_pipes = curr->ss_data.ks_pipes;
886 }
887 
888 /*
889  * smbstat_srv_process_throughput
890  *
891  * Processes the data relative to the throughput of the smbsrv module and
892  * stores the results in the structure smbstat_srv_info.
893  */
894 static void
895 smbstat_srv_process_throughput(
896     smbstat_srv_snapshot_t	*curr,
897     smbstat_srv_snapshot_t	*prev)
898 {
899 	smbstat_srv_info.si_tbs =
900 	    smbstat_sub_64(curr->ss_data.ks_txb, prev->ss_data.ks_txb);
901 	smbstat_srv_info.si_tbs /= smbstat_srv_info.si_etime;
902 	smbstat_srv_info.si_rbs =
903 	    smbstat_sub_64(curr->ss_data.ks_rxb, prev->ss_data.ks_rxb);
904 	smbstat_srv_info.si_rbs /= smbstat_srv_info.si_etime;
905 	smbstat_srv_info.si_rqs = smbstat_srv_info.si_total_nreqs;
906 	smbstat_srv_info.si_rqs /= smbstat_srv_info.si_etime;
907 
908 	smbstat_srv_info.si_rds = smbstat_sub_64(
909 	    curr->ss_data.ks_reqs1[SMB_COM_READ].kr_nreq,
910 	    prev->ss_data.ks_reqs1[SMB_COM_READ].kr_nreq);
911 	smbstat_srv_info.si_rds += smbstat_sub_64(
912 	    curr->ss_data.ks_reqs1[SMB_COM_LOCK_AND_READ].kr_nreq,
913 	    prev->ss_data.ks_reqs1[SMB_COM_LOCK_AND_READ].kr_nreq);
914 	smbstat_srv_info.si_rds += smbstat_sub_64(
915 	    curr->ss_data.ks_reqs1[SMB_COM_READ_RAW].kr_nreq,
916 	    prev->ss_data.ks_reqs1[SMB_COM_READ_RAW].kr_nreq);
917 	smbstat_srv_info.si_rds += smbstat_sub_64(
918 	    curr->ss_data.ks_reqs1[SMB_COM_READ_ANDX].kr_nreq,
919 	    prev->ss_data.ks_reqs1[SMB_COM_READ_ANDX].kr_nreq);
920 	smbstat_srv_info.si_rds += smbstat_sub_64(
921 	    curr->ss_data.ks_reqs2[SMB2_READ].kr_nreq,
922 	    prev->ss_data.ks_reqs2[SMB2_READ].kr_nreq);
923 	smbstat_srv_info.si_rds /= smbstat_srv_info.si_etime;
924 
925 	smbstat_srv_info.si_wrs = smbstat_sub_64(
926 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE].kr_nreq,
927 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE].kr_nreq);
928 	smbstat_srv_info.si_wrs += smbstat_sub_64(
929 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE_AND_UNLOCK].kr_nreq,
930 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE_AND_UNLOCK].kr_nreq);
931 	smbstat_srv_info.si_wrs += smbstat_sub_64(
932 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE_RAW].kr_nreq,
933 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE_RAW].kr_nreq);
934 	smbstat_srv_info.si_wrs += smbstat_sub_64(
935 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE_AND_CLOSE].kr_nreq,
936 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE_AND_CLOSE].kr_nreq);
937 	smbstat_srv_info.si_wrs += smbstat_sub_64(
938 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE_ANDX].kr_nreq,
939 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE_ANDX].kr_nreq);
940 	smbstat_srv_info.si_wrs += smbstat_sub_64(
941 	    curr->ss_data.ks_reqs2[SMB2_WRITE].kr_nreq,
942 	    prev->ss_data.ks_reqs2[SMB2_WRITE].kr_nreq);
943 	smbstat_srv_info.si_wrs /= smbstat_srv_info.si_etime;
944 }
945 
946 /*
947  * smbstat_srv_process_utilization
948  *
949  * Processes the data relative to the utilization of the smbsrv module and
950  * stores the results in the structure smbstat_srv_info.
951  */
952 static void
953 smbstat_srv_process_utilization(
954     smbstat_srv_snapshot_t	*curr,
955     smbstat_srv_snapshot_t	*prev)
956 {
957 	double	tw_delta, tr_delta;
958 	double	w_delta, r_delta;
959 	double	tps, rqs;
960 
961 	w_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wlentime,
962 	    curr->ss_data.ks_utilization.ku_wlentime);
963 	r_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rlentime,
964 	    curr->ss_data.ks_utilization.ku_rlentime);
965 	tw_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wtime,
966 	    curr->ss_data.ks_utilization.ku_wtime);
967 	tr_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rtime,
968 	    curr->ss_data.ks_utilization.ku_rtime);
969 	rqs = smbstat_srv_info.si_total_nreqs / smbstat_srv_info.si_etime;
970 
971 	/* Average number of requests waiting */
972 	if (w_delta != 0)
973 		smbstat_srv_info.si_avw = w_delta / smbstat_srv_info.si_hretime;
974 	else
975 		smbstat_srv_info.si_avw = 0.0;
976 
977 	/* Average number of request running */
978 	if (r_delta != 0)
979 		smbstat_srv_info.si_avr = r_delta / smbstat_srv_info.si_hretime;
980 	else
981 		smbstat_srv_info.si_avr = 0.0;
982 
983 	/* Utilization */
984 	smbstat_srv_info.si_upct =
985 	    (smbstat_srv_info.si_avr / curr->ss_data.ks_maxreqs) * 100;
986 
987 	/* Average wait service time in milliseconds */
988 	smbstat_srv_info.si_rserv = 0.0;
989 	smbstat_srv_info.si_wserv = 0.0;
990 	if (rqs > 0.0 &&
991 	    (smbstat_srv_info.si_avw != 0.0 ||
992 	    smbstat_srv_info.si_avr != 0.0)) {
993 		tps = 1 / rqs;
994 		if (smbstat_srv_info.si_avw != 0.0)
995 			smbstat_srv_info.si_wserv =
996 			    smbstat_srv_info.si_avw * tps;
997 		if (smbstat_srv_info.si_avr != 0.0)
998 			smbstat_srv_info.si_rserv =
999 			    smbstat_srv_info.si_avr * tps;
1000 	}
1001 
1002 	/* % of time there is a transaction waiting for service */
1003 	if (tw_delta != 0) {
1004 		smbstat_srv_info.si_wpct = tw_delta;
1005 		smbstat_srv_info.si_wpct /= smbstat_srv_info.si_hretime;
1006 		smbstat_srv_info.si_wpct *= 100.0;
1007 	} else {
1008 		smbstat_srv_info.si_wpct = 0.0;
1009 	}
1010 
1011 	/* % of time there is a transaction running */
1012 	if (tr_delta != 0) {
1013 		smbstat_srv_info.si_rpct = tr_delta;
1014 		smbstat_srv_info.si_rpct /= smbstat_srv_info.si_hretime;
1015 		smbstat_srv_info.si_rpct *= 100.0;
1016 	} else {
1017 		smbstat_srv_info.si_rpct = 0.0;
1018 	}
1019 }
1020 
1021 /*
1022  * smbstat_srv_process_requests
1023  *
1024  * Processes the data relative to the SMB requests and stores the results in
1025  * the structure smbstat_srv_info.
1026  */
1027 static void
1028 smbstat_srv_process_requests(
1029     smbstat_srv_snapshot_t	*curr,
1030     smbstat_srv_snapshot_t	*prev)
1031 {
1032 	smbstat_req_info_t	*info;
1033 	smb_kstat_req_t		*curr_req;
1034 	smb_kstat_req_t		*prev_req;
1035 	int			i, idx;
1036 	boolean_t	firstcall = (prev->ss_snaptime == 0);
1037 
1038 	for (i = 0; i < SMBSRV_KS_NREQS1; i++) {
1039 		info = &smbstat_srv_info.si_reqs1[i];
1040 		idx = info->ri_opcode;
1041 		if (idx >= SMBSRV_KS_NREQS1)
1042 			continue;
1043 		curr_req = &curr->ss_data.ks_reqs1[idx];
1044 		prev_req = &prev->ss_data.ks_reqs1[idx];
1045 		smbstat_srv_process_one_req(
1046 		    info, curr_req, prev_req, firstcall);
1047 	}
1048 
1049 	for (i = 0; i < SMBSRV_KS_NREQS2; i++) {
1050 		info = &smbstat_srv_info.si_reqs2[i];
1051 		idx = info->ri_opcode;
1052 		if (idx >= SMBSRV_KS_NREQS2)
1053 			continue;
1054 		curr_req = &curr->ss_data.ks_reqs2[idx];
1055 		prev_req = &prev->ss_data.ks_reqs2[idx];
1056 		smbstat_srv_process_one_req(
1057 		    info, curr_req, prev_req, firstcall);
1058 	}
1059 }
1060 
1061 static void
1062 smbstat_srv_process_one_req(
1063 	smbstat_req_info_t	*info,
1064 	smb_kstat_req_t		*curr_req,
1065 	smb_kstat_req_t		*prev_req,
1066 	boolean_t		firstcall)
1067 {
1068 	double			nrqs;
1069 
1070 	nrqs = smbstat_sub_64(curr_req->kr_nreq,
1071 	    prev_req->kr_nreq);
1072 
1073 	info->ri_rqs = nrqs / smbstat_srv_info.si_etime;
1074 
1075 	info->ri_rbs = smbstat_sub_64(
1076 	    curr_req->kr_rxb,
1077 	    prev_req->kr_rxb) /
1078 	    smbstat_srv_info.si_etime;
1079 
1080 	info->ri_tbs = smbstat_sub_64(
1081 	    curr_req->kr_txb,
1082 	    prev_req->kr_txb) /
1083 	    smbstat_srv_info.si_etime;
1084 
1085 	info->ri_pct = nrqs * 100;
1086 	if (smbstat_srv_info.si_total_nreqs > 0)
1087 		info->ri_pct /= smbstat_srv_info.si_total_nreqs;
1088 
1089 	if (firstcall) {
1090 		/* First time. Take the aggregate */
1091 		info->ri_stddev =
1092 		    curr_req->kr_a_stddev;
1093 		info->ri_mean = curr_req->kr_a_mean;
1094 	} else {
1095 		/* Take the differential */
1096 		info->ri_stddev =
1097 		    curr_req->kr_d_stddev;
1098 		info->ri_mean = curr_req->kr_d_mean;
1099 	}
1100 	if (nrqs > 0) {
1101 		info->ri_stddev /= nrqs;
1102 		info->ri_stddev = sqrt(info->ri_stddev);
1103 	} else {
1104 		info->ri_stddev = 0;
1105 	}
1106 	info->ri_stddev /= NANOSEC;
1107 	info->ri_mean /= NANOSEC;
1108 }
1109 
1110 
1111 /*
1112  * smbstat_srv_current_snapshot
1113  *
1114  * Returns the current snapshot.
1115  */
1116 static smbstat_srv_snapshot_t *
1117 smbstat_srv_current_snapshot(void)
1118 {
1119 	return (&smbstat_srv_snapshots[smbstat_snapshot_idx]);
1120 }
1121 
1122 /*
1123  * smbstat_srv_previous_snapshot
1124  *
1125  * Returns the previous snapshot.
1126  */
1127 static smbstat_srv_snapshot_t *
1128 smbstat_srv_previous_snapshot(void)
1129 {
1130 	int	idx;
1131 
1132 	idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK;
1133 	return (&smbstat_srv_snapshots[idx]);
1134 }
1135 
1136 /*
1137  * smbstat_usage
1138  *
1139  * Prints out a help message.
1140  */
1141 static void
1142 smbstat_usage(FILE *fd, int exit_code)
1143 {
1144 	(void) fprintf(fd, gettext(SMBSTAT_HELP));
1145 	exit(exit_code);
1146 }
1147 
1148 /*
1149  * smbstat_fail
1150  *
1151  * Prints out to stderr an error message and exits the process.
1152  */
1153 static void
1154 smbstat_fail(int do_perror, char *message, ...)
1155 {
1156 	va_list args;
1157 
1158 	va_start(args, message);
1159 	(void) fprintf(stderr, gettext("smbstat: "));
1160 	/* LINTED E_SEC_PRINTF_VAR_FMT */
1161 	(void) vfprintf(stderr, message, args);
1162 	va_end(args);
1163 	if (do_perror)
1164 		(void) fprintf(stderr, ": %s", strerror(errno));
1165 	(void) fprintf(stderr, "\n");
1166 	exit(1);
1167 }
1168 
1169 /*
1170  * smbstat_sub_64
1171  *
1172  * Substract 2 uint64_t and returns a double.
1173  */
1174 static double
1175 smbstat_sub_64(uint64_t a, uint64_t b)
1176 {
1177 	return ((double)(a - b));
1178 }
1179 
1180 /*
1181  * smbstat_zero
1182  *
1183  * Returns zero if the value passed in is less than 1.
1184  */
1185 static double
1186 smbstat_zero(double value)
1187 {
1188 	if (value < 1)
1189 		value = 0;
1190 	return (value);
1191 }
1192 
1193 /*
1194  * smbstat_strtoi
1195  *
1196  * Converts a string representing an integer value into its binary value.
1197  * If the conversion fails this routine exits the process.
1198  */
1199 static uint_t
1200 smbstat_strtoi(char const *val, char *errmsg)
1201 {
1202 	char	*end;
1203 	long	tmp;
1204 
1205 	errno = 0;
1206 	tmp = strtol(val, &end, 10);
1207 	if (*end != '\0' || errno)
1208 		smbstat_fail(1, "%s %s", errmsg, val);
1209 	return ((uint_t)tmp);
1210 }
1211 
1212 /*
1213  * smbstat_termio_init
1214  *
1215  * Determines the size of the terminal associated with the process.
1216  */
1217 static void
1218 smbstat_termio_init(void)
1219 {
1220 	char	*envp;
1221 
1222 	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &smbstat_ws) != -1) {
1223 		if (smbstat_ws.ws_row == 0) {
1224 			envp = getenv("LINES");
1225 			if (envp != NULL)
1226 				smbstat_ws.ws_row = atoi(envp);
1227 		}
1228 
1229 		if (smbstat_ws.ws_col == 0) {
1230 			envp = getenv("COLUMNS");
1231 			if (envp != NULL)
1232 				smbstat_ws.ws_row = atoi(envp);
1233 		}
1234 	}
1235 	if (smbstat_ws.ws_col == 0)
1236 		smbstat_ws.ws_col = 80;
1237 	if (smbstat_ws.ws_row == 0)
1238 		smbstat_ws.ws_row = 25;
1239 }
1240 
1241 /*
1242  * smbstat_snapshot_idx_inc
1243  *
1244  * Increments the snapshot index.
1245  */
1246 static void
1247 smbstat_snapshot_inc_idx(void)
1248 {
1249 	smbstat_snapshot_idx++;
1250 	smbstat_snapshot_idx &= SMBSTAT_SNAPSHOT_MASK;
1251 }
1252 
1253 /*
1254  * smbstat_req_cmp_name
1255  *
1256  * Call back function passed to qsort() when the list of requests must be sorted
1257  * by name.
1258  */
1259 static int
1260 smbstat_req_cmp_name(const void *obj1, const void *obj2)
1261 {
1262 	return (strncasecmp(
1263 	    ((smbstat_req_info_t *)obj1)->ri_name,
1264 	    ((smbstat_req_info_t *)obj2)->ri_name,
1265 	    sizeof (((smbstat_req_info_t *)obj2)->ri_name)));
1266 }
1267 
1268 /*
1269  * smbstat_req_order
1270  *
1271  * Snapshots the smbsrv module statistics once to get the name of the requests.
1272  * The request list is smbstat_srv_info is then sorted by name or by code
1273  * depending on the boolean smbstat_opt_a.
1274  * The function should be called once during initialization.
1275  */
1276 static void
1277 smbstat_req_order(void)
1278 {
1279 	smbstat_srv_snapshot_t  *ss;
1280 	smbstat_req_info_t	*info;
1281 	smb_kstat_req_t		*reqs;
1282 	int			i;
1283 
1284 	smbstat_srv_snapshot();
1285 	ss = smbstat_srv_current_snapshot();
1286 
1287 	reqs = ss->ss_data.ks_reqs1;
1288 	info = smbstat_srv_info.si_reqs1;
1289 	for (i = 0; i < SMBSRV_KS_NREQS1; i++) {
1290 		(void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1291 		    sizeof (reqs[i].kr_name));
1292 		info[i].ri_opcode = i;
1293 	}
1294 	if (smbstat_opt_n)
1295 		qsort(info, SMBSRV_KS_NREQS1, sizeof (smbstat_req_info_t),
1296 		    smbstat_req_cmp_name);
1297 
1298 	reqs = ss->ss_data.ks_reqs2;
1299 	info = smbstat_srv_info.si_reqs2;
1300 	for (i = 0; i < SMBSRV_KS_NREQS2; i++) {
1301 		(void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1302 		    sizeof (reqs[i].kr_name));
1303 		info[i].ri_opcode = i;
1304 	}
1305 	if (smbstat_opt_n)
1306 		qsort(info, SMBSRV_KS_NREQS2, sizeof (smbstat_req_info_t),
1307 		    smbstat_req_cmp_name);
1308 }
1309 
1310 /*
1311  * Return the number of ticks delta between two hrtime_t
1312  * values. Attempt to cater for various kinds of overflow
1313  * in hrtime_t - no matter how improbable.
1314  */
1315 static double
1316 smbstat_hrtime_delta(hrtime_t old, hrtime_t new)
1317 {
1318 	uint64_t	del;
1319 
1320 	if ((new >= old) && (old >= 0L))
1321 		return ((double)(new - old));
1322 	/*
1323 	 * We've overflowed the positive portion of an hrtime_t.
1324 	 */
1325 	if (new < 0L) {
1326 		/*
1327 		 * The new value is negative. Handle the case where the old
1328 		 * value is positive or negative.
1329 		 */
1330 		uint64_t n1;
1331 		uint64_t o1;
1332 
1333 		n1 = -new;
1334 		if (old > 0L)
1335 			return ((double)(n1 - old));
1336 
1337 		o1 = -old;
1338 		del = n1 - o1;
1339 		return ((double)del);
1340 	}
1341 
1342 	/*
1343 	 * Either we've just gone from being negative to positive *or* the last
1344 	 * entry was positive and the new entry is also positive but *less* than
1345 	 * the old entry. This implies we waited quite a few days on a very fast
1346 	 * system between displays.
1347 	 */
1348 	if (old < 0L) {
1349 		uint64_t o2;
1350 		o2 = -old;
1351 		del = UINT64_MAX - o2;
1352 	} else {
1353 		del = UINT64_MAX - old;
1354 	}
1355 	del += new;
1356 	return ((double)del);
1357 }
1358 
1359 static void *
1360 smbstat_zalloc(size_t size)
1361 {
1362 	void	*ptr;
1363 
1364 	ptr = umem_zalloc(size, UMEM_DEFAULT);
1365 	if (ptr == NULL)
1366 		smbstat_fail(1,	gettext("out of memory"));
1367 	return (ptr);
1368 }
1369 
1370 static void
1371 smbstat_free(void *ptr, size_t size)
1372 {
1373 	umem_free(ptr, size);
1374 }
1375