1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw 
22da6c28aaSamw /*
23148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24*5015ecc3SGordon Ross  * Copyright 2020 Nexenta by DDN, Inc.  All rights reserved.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw /*
28da6c28aaSamw  * smbstat: Server Message Block File System statistics
29148c5f43SAlan Wright  *
30148c5f43SAlan Wright  * The statistics this CLI displays come from two sources:
31148c5f43SAlan Wright  *
32148c5f43SAlan Wright  * 1) The kernel module 'smbsrv'.
33148c5f43SAlan Wright  * 2) The SMB workers task queue statistics the task queue manager of Solaris
34148c5f43SAlan Wright  *    maintains.
35148c5f43SAlan Wright  *
36148c5f43SAlan Wright  * The flow of the code is the following:
37148c5f43SAlan Wright  *
38148c5f43SAlan Wright  *
39*5015ecc3SGordon Ross  *			+----------------+
40*5015ecc3SGordon Ross  *			| Initialization |
41*5015ecc3SGordon Ross  *			+----------------+
42148c5f43SAlan Wright  *				|
43148c5f43SAlan Wright  *				|
44148c5f43SAlan Wright  *				v
45148c5f43SAlan Wright  *		  +--------------------------*
46148c5f43SAlan Wright  *		  | Take a snapshot the data | <--------+
47148c5f43SAlan Wright  *		  +--------------------------+		|
48148c5f43SAlan Wright  *				|			|
49*5015ecc3SGordon Ross  *				|			|
50148c5f43SAlan Wright  *				v			|
51148c5f43SAlan Wright  *		    +----------------------+		|
52148c5f43SAlan Wright  *		    | Process the snapshot |		|
53148c5f43SAlan Wright  *		    +----------------------+		|
54148c5f43SAlan Wright  *				|			|
55148c5f43SAlan Wright  *				|			|
56148c5f43SAlan Wright  *				v			|
57148c5f43SAlan Wright  *	     +------------------------------------+	|
58148c5f43SAlan Wright  *	     | Print the result of the processing |	|
59148c5f43SAlan Wright  *	     +------------------------------------+	|
60148c5f43SAlan Wright  *				|			|
61148c5f43SAlan Wright  *				|			|
62148c5f43SAlan Wright  *				v			|
63148c5f43SAlan Wright  *		Yes	---------------			|
64148c5f43SAlan Wright  *	+------------ < interval == 0 ? >		|
65*5015ecc3SGordon Ross  *	|		---------------			|
66148c5f43SAlan Wright  *	|		       |			|
67*5015ecc3SGordon Ross  *	|		       | No			|
68*5015ecc3SGordon Ross  *	|		       v			|
69148c5f43SAlan Wright  *	|	   +------------------------+		|
70*5015ecc3SGordon Ross  *	|	   | Sleep for the duration | ----------+
71*5015ecc3SGordon Ross  *	|	   |   of the interval.     |
72*5015ecc3SGordon Ross  *	|	   +------------------------+
73*5015ecc3SGordon Ross  *	|
74*5015ecc3SGordon Ross  *	+---------------------+
75148c5f43SAlan Wright  *			      |
76148c5f43SAlan Wright  *			      v
77148c5f43SAlan Wright  *
78148c5f43SAlan Wright  *			    Exit
79148c5f43SAlan Wright  *
80148c5f43SAlan Wright  * There are two sets of snapshots. One set for the smbsrv module and the other
81148c5f43SAlan Wright  * for the task queue (SMB workers). Each set contains 2 snapshots. One is
82148c5f43SAlan Wright  * labeled 'current' the other one 'previous'. Their role changes after each
83148c5f43SAlan Wright  * snapshot. The 'current' becomes 'previous' and vice versa.
84148c5f43SAlan Wright  * The first snapshot taken is compared against the data gathered since the
85148c5f43SAlan Wright  * smbsrv module was loaded. Subsequent snapshots will be compared against the
86148c5f43SAlan Wright  * previous snapshot.
87da6c28aaSamw  */
88148c5f43SAlan Wright 
89da6c28aaSamw #include <stdio.h>
90da6c28aaSamw #include <stdlib.h>
91148c5f43SAlan Wright #include <unistd.h>
92da6c28aaSamw #include <kstat.h>
93da6c28aaSamw #include <stdarg.h>
94da6c28aaSamw #include <errno.h>
95da6c28aaSamw #include <inttypes.h>
96da6c28aaSamw #include <strings.h>
97da6c28aaSamw #include <utility.h>
98da6c28aaSamw #include <libintl.h>
99da6c28aaSamw #include <zone.h>
100148c5f43SAlan Wright #include <termios.h>
101148c5f43SAlan Wright #include <stropts.h>
102148c5f43SAlan Wright #include <math.h>
103148c5f43SAlan Wright #include <umem.h>
104148c5f43SAlan Wright #include <locale.h>
105b3b35633SGordon Ross #include <sys/processor.h>
1066537f381Sas #include <smbsrv/smb_kstat.h>
107da6c28aaSamw 
108148c5f43SAlan Wright #if !defined(TEXT_DOMAIN)
109148c5f43SAlan Wright #define	TEXT_DOMAIN "SYS_TEST"
110148c5f43SAlan Wright #endif /* TEXT_DOMAIN */
111148c5f43SAlan Wright 
112148c5f43SAlan Wright #define	SMBSTAT_ID_NO_CPU	-1
113148c5f43SAlan Wright #define	SMBSTAT_SNAPSHOT_COUNT	2		/* Must be a power of 2 */
114148c5f43SAlan Wright #define	SMBSTAT_SNAPSHOT_MASK	(SMBSTAT_SNAPSHOT_COUNT - 1)
115148c5f43SAlan Wright 
116148c5f43SAlan Wright #define	SMBSTAT_HELP	\
117148c5f43SAlan Wright 	"Usage: smbstat [-acnrtuz] [interval]\n" \
118148c5f43SAlan Wright 	"    -c: display counters\n" \
119148c5f43SAlan Wright 	"    -t: display throughput\n" \
120148c5f43SAlan Wright 	"    -u: display utilization\n" \
121148c5f43SAlan Wright 	"    -r: display requests\n" \
122148c5f43SAlan Wright 	"        -a: all the requests (supported and unsupported)\n" \
123148c5f43SAlan Wright 	"        -z: skip the requests not received\n" \
124148c5f43SAlan Wright 	"        -n: display in alphabetic order\n" \
125148c5f43SAlan Wright 	"    interval: refresh cycle in seconds\n"
126148c5f43SAlan Wright 
127148c5f43SAlan Wright #define	SMBSRV_COUNTERS_BANNER	"\n  nbt   tcp users trees files pipes\n"
128148c5f43SAlan Wright #define	SMBSRV_COUNTERS_FORMAT	"%5d %5d %5d %5d %5d %5d\n"
129148c5f43SAlan Wright 
130148c5f43SAlan Wright #define	SMBSRV_THROUGHPUT_BANNER	\
131148c5f43SAlan Wright 	"\nrbytes/s   tbytes/s    reqs/s     reads/s   writes/s\n"
132148c5f43SAlan Wright #define	SMBSRV_THROUGHPUT_FORMAT	\
133148c5f43SAlan Wright 	"%1.3e  %1.3e  %1.3e  %1.3e  %1.3e\n"
134148c5f43SAlan Wright 
135148c5f43SAlan Wright #define	SMBSRV_UTILIZATION_BANNER	\
136148c5f43SAlan Wright 	"\n  wcnt       rcnt       wtime      rtime" \
137148c5f43SAlan Wright 	"     w%%   r%%   u%%  sat usr%% sys%%  idle%%\n"
138148c5f43SAlan Wright #define	SMBSRV_UTILIZATION_FORMAT	\
139148c5f43SAlan Wright 	"%1.3e  %1.3e  %1.3e  %1.3e  %3.0f  %3.0f  %3.0f  %s " \
140148c5f43SAlan Wright 	"%3.0f  %3.0f    %3.0f\n"
141148c5f43SAlan Wright 
142148c5f43SAlan Wright #define	SMBSRV_REQUESTS_BANNER	\
143148c5f43SAlan Wright 	"\n%30s code   %%   rbytes/s   tbytes/s     req/s     rt-mean"	\
144148c5f43SAlan Wright 	"   rt-stddev\n"
145148c5f43SAlan Wright #define	SMBSRV_REQUESTS_FORMAT	\
146148c5f43SAlan Wright 	"%30s  %02X   %3.0f  %1.3e  %1.3e  %1.3e  %1.3e  %1.3e\n"
147148c5f43SAlan Wright 
148148c5f43SAlan Wright typedef enum {
149148c5f43SAlan Wright 	CPU_TICKS_IDLE = 0,
150148c5f43SAlan Wright 	CPU_TICKS_USER,
151148c5f43SAlan Wright 	CPU_TICKS_KERNEL,
152148c5f43SAlan Wright 	CPU_TICKS_SENTINEL
153148c5f43SAlan Wright } cpu_state_idx_t;
154148c5f43SAlan Wright 
155148c5f43SAlan Wright typedef struct smbstat_cpu_snapshot {
156148c5f43SAlan Wright 	processorid_t	cs_id;
157148c5f43SAlan Wright 	int		cs_state;
158148c5f43SAlan Wright 	uint64_t	cs_ticks[CPU_TICKS_SENTINEL];
159148c5f43SAlan Wright } smbstat_cpu_snapshot_t;
160148c5f43SAlan Wright 
161148c5f43SAlan Wright typedef struct smbstat_srv_snapshot {
162148c5f43SAlan Wright 	hrtime_t	ss_snaptime;
163148c5f43SAlan Wright 	smbsrv_kstats_t	ss_data;
164148c5f43SAlan Wright } smbstat_srv_snapshot_t;
165148c5f43SAlan Wright 
166148c5f43SAlan Wright typedef struct smbstat_wrk_snapshot {
167148c5f43SAlan Wright 	uint64_t	ws_maxthreads;
168148c5f43SAlan Wright 	uint64_t	ws_bnalloc;
169148c5f43SAlan Wright } smbstat_wrk_snapshot_t;
170148c5f43SAlan Wright 
171148c5f43SAlan Wright typedef struct smbstat_req_info {
172148c5f43SAlan Wright 	char		ri_name[KSTAT_STRLEN];
173148c5f43SAlan Wright 	int		ri_opcode;
174148c5f43SAlan Wright 	double		ri_pct;
175148c5f43SAlan Wright 	double		ri_tbs;
176148c5f43SAlan Wright 	double		ri_rbs;
177148c5f43SAlan Wright 	double		ri_rqs;
178148c5f43SAlan Wright 	double		ri_stddev;
179148c5f43SAlan Wright 	double		ri_mean;
180148c5f43SAlan Wright } smbstat_req_info_t;
181148c5f43SAlan Wright 
182148c5f43SAlan Wright typedef struct smbstat_srv_info {
183148c5f43SAlan Wright 	double		si_hretime;
184148c5f43SAlan Wright 	double		si_etime;
185148c5f43SAlan Wright 	double		si_total_nreqs;
186148c5f43SAlan Wright 	/*
187148c5f43SAlan Wright 	 * Counters
188148c5f43SAlan Wright 	 */
189148c5f43SAlan Wright 	uint32_t	si_nbt_sess;	/* NBT sessions */
190148c5f43SAlan Wright 	uint32_t	si_tcp_sess;	/* TCP sessions */
191148c5f43SAlan Wright 	uint32_t	si_users;	/* Users logged in */
192148c5f43SAlan Wright 	uint32_t	si_trees;	/* Trees connected */
193148c5f43SAlan Wright 	uint32_t	si_files;	/* Open files */
194148c5f43SAlan Wright 	uint32_t	si_pipes;	/* Open pipes */
195148c5f43SAlan Wright 	/*
196148c5f43SAlan Wright 	 * Throughput of the server
197148c5f43SAlan Wright 	 */
198148c5f43SAlan Wright 	double		si_tbs;		/* Bytes transmitted / second */
199148c5f43SAlan Wright 	double		si_rbs;		/* Bytes received / second */
200148c5f43SAlan Wright 	double		si_rqs;		/* Requests treated / second */
201148c5f43SAlan Wright 	double		si_rds;		/* Reads treated / second */
202148c5f43SAlan Wright 	double		si_wrs;		/* Writes treated / second */
203148c5f43SAlan Wright 	/*
204148c5f43SAlan Wright 	 * Utilization of the server
205148c5f43SAlan Wright 	 */
206148c5f43SAlan Wright 	double		si_wpct;	/* */
207148c5f43SAlan Wright 	double		si_rpct;	/* */
208148c5f43SAlan Wright 	double		si_upct;	/* Utilization in % */
209148c5f43SAlan Wright 	double		si_avw;		/* Average number of requests waiting */
210148c5f43SAlan Wright 	double		si_avr;		/* Average number of requests running */
211148c5f43SAlan Wright 	double		si_wserv;	/* Average waiting time */
212148c5f43SAlan Wright 	double		si_rserv;	/* Average running time */
213148c5f43SAlan Wright 	boolean_t	si_sat;
214148c5f43SAlan Wright 	double		si_ticks[CPU_TICKS_SENTINEL];
215148c5f43SAlan Wright 	/*
216148c5f43SAlan Wright 	 * Latency & Throughput per request
217148c5f43SAlan Wright 	 */
218a90cf9f2SGordon Ross 	smbstat_req_info_t	si_reqs1[SMB_COM_NUM];
219a90cf9f2SGordon Ross 	smbstat_req_info_t	si_reqs2[SMB2__NCMDS];
220148c5f43SAlan Wright } smbstat_srv_info_t;
221da6c28aaSamw 
2226537f381Sas static void smbstat_init(void);
2236537f381Sas static void smbstat_fini(void);
224148c5f43SAlan Wright static void smbstat_kstat_snapshot(void);
225148c5f43SAlan Wright static void smbstat_kstat_process(void);
226148c5f43SAlan Wright static void smbstat_kstat_print(void);
227148c5f43SAlan Wright 
228148c5f43SAlan Wright static void smbstat_print_counters(void);
229148c5f43SAlan Wright static void smbstat_print_throughput(void);
230148c5f43SAlan Wright static void smbstat_print_utilization(void);
231148c5f43SAlan Wright static void smbstat_print_requests(void);
232148c5f43SAlan Wright 
233148c5f43SAlan Wright static void smbstat_cpu_init(void);
234148c5f43SAlan Wright static void smbstat_cpu_fini(void);
235148c5f43SAlan Wright static smbstat_cpu_snapshot_t *smbstat_cpu_current_snapshot(void);
236148c5f43SAlan Wright static smbstat_cpu_snapshot_t *smbstat_cpu_previous_snapshot(void);
237148c5f43SAlan Wright static void smbstat_cpu_snapshot(void);
238148c5f43SAlan Wright static void smbstat_cpu_process(void);
239148c5f43SAlan Wright 
240148c5f43SAlan Wright static void smbstat_wrk_init(void);
241148c5f43SAlan Wright static void smbstat_wrk_fini(void);
242148c5f43SAlan Wright static void smbstat_wrk_snapshot(void);
243148c5f43SAlan Wright static void smbstat_wrk_process(void);
244148c5f43SAlan Wright static smbstat_wrk_snapshot_t *smbstat_wrk_current_snapshot(void);
245148c5f43SAlan Wright 
246148c5f43SAlan Wright static void smbstat_srv_init(void);
247148c5f43SAlan Wright static void smbstat_srv_fini(void);
248148c5f43SAlan Wright static void smbstat_srv_snapshot(void);
249148c5f43SAlan Wright static void smbstat_srv_process(void);
250148c5f43SAlan Wright static void smbstat_srv_process_counters(smbstat_srv_snapshot_t *);
251148c5f43SAlan Wright static void smbstat_srv_process_throughput(smbstat_srv_snapshot_t *,
252148c5f43SAlan Wright     smbstat_srv_snapshot_t *);
253148c5f43SAlan Wright static void smbstat_srv_process_utilization(smbstat_srv_snapshot_t *,
254148c5f43SAlan Wright     smbstat_srv_snapshot_t *);
255148c5f43SAlan Wright static void smbstat_srv_process_requests(smbstat_srv_snapshot_t *,
256148c5f43SAlan Wright     smbstat_srv_snapshot_t *);
257a90cf9f2SGordon Ross static void smbstat_srv_process_one_req(smbstat_req_info_t *,
258a90cf9f2SGordon Ross     smb_kstat_req_t *, smb_kstat_req_t *, boolean_t);
259a90cf9f2SGordon Ross 
260148c5f43SAlan Wright static smbstat_srv_snapshot_t *smbstat_srv_current_snapshot(void);
261148c5f43SAlan Wright static smbstat_srv_snapshot_t *smbstat_srv_previous_snapshot(void);
262148c5f43SAlan Wright 
263148c5f43SAlan Wright static void *smbstat_zalloc(size_t);
264148c5f43SAlan Wright static void smbstat_free(void *, size_t);
265da6c28aaSamw static void smbstat_fail(int, char *, ...);
266148c5f43SAlan Wright static void smbstat_snapshot_inc_idx(void);
267f5aec946SToomas Soome static void smbstat_usage(FILE *, int) __NORETURN;
268148c5f43SAlan Wright static uint_t smbstat_strtoi(char const *, char *);
269148c5f43SAlan Wright static double smbstat_hrtime_delta(hrtime_t, hrtime_t);
270148c5f43SAlan Wright static double smbstat_sub_64(uint64_t, uint64_t);
271148c5f43SAlan Wright static void smbstat_req_order(void);
272148c5f43SAlan Wright static double smbstat_zero(double);
273148c5f43SAlan Wright static void smbstat_termio_init(void);
274148c5f43SAlan Wright 
275148c5f43SAlan Wright #pragma does_not_return(smbstat_fail, smbstat_usage)
276148c5f43SAlan Wright 
277148c5f43SAlan Wright static char *smbstat_cpu_states[CPU_TICKS_SENTINEL] = {
278148c5f43SAlan Wright 	"cpu_ticks_idle",
279148c5f43SAlan Wright 	"cpu_ticks_user",
280148c5f43SAlan Wright 	"cpu_ticks_kernel"
281148c5f43SAlan Wright };
282da6c28aaSamw 
283148c5f43SAlan Wright static boolean_t	smbstat_opt_a = B_FALSE;	/* all */
284148c5f43SAlan Wright static boolean_t	smbstat_opt_c = B_FALSE;	/* counters */
285148c5f43SAlan Wright static boolean_t	smbstat_opt_n = B_FALSE;	/* by name */
286148c5f43SAlan Wright static boolean_t	smbstat_opt_u = B_FALSE;	/* utilization */
287148c5f43SAlan Wright static boolean_t	smbstat_opt_t = B_FALSE;	/* throughput */
288148c5f43SAlan Wright static boolean_t	smbstat_opt_r = B_FALSE;	/* requests */
289148c5f43SAlan Wright static boolean_t	smbstat_opt_z = B_FALSE;	/* non-zero requests */
290da6c28aaSamw 
291148c5f43SAlan Wright static uint_t		smbstat_interval = 0;
292148c5f43SAlan Wright static long		smbstat_nrcpus = 0;
293148c5f43SAlan Wright static kstat_ctl_t	*smbstat_ksc = NULL;
294148c5f43SAlan Wright static kstat_t		*smbstat_srv_ksp = NULL;
295148c5f43SAlan Wright static kstat_t		*smbstat_wrk_ksp = NULL;
296148c5f43SAlan Wright static struct winsize	smbstat_ws;
297148c5f43SAlan Wright static uint16_t		smbstat_rows = 0;
298148c5f43SAlan Wright 
299148c5f43SAlan Wright static int smbstat_snapshot_idx = 0;
300148c5f43SAlan Wright static smbstat_cpu_snapshot_t *smbstat_cpu_snapshots[SMBSTAT_SNAPSHOT_COUNT];
301148c5f43SAlan Wright static smbstat_srv_snapshot_t smbstat_srv_snapshots[SMBSTAT_SNAPSHOT_COUNT];
302148c5f43SAlan Wright static smbstat_wrk_snapshot_t smbstat_wrk_snapshots[SMBSTAT_SNAPSHOT_COUNT];
303148c5f43SAlan Wright static smbstat_srv_info_t smbstat_srv_info;
304148c5f43SAlan Wright 
305148c5f43SAlan Wright /*
306148c5f43SAlan Wright  * main
307148c5f43SAlan Wright  */
308da6c28aaSamw int
309da6c28aaSamw main(int argc, char *argv[])
310da6c28aaSamw {
311148c5f43SAlan Wright 	int	c;
312148c5f43SAlan Wright 
313148c5f43SAlan Wright 	(void) setlocale(LC_ALL, "");
314148c5f43SAlan Wright 	(void) textdomain(TEXT_DOMAIN);
315da6c28aaSamw 
316da6c28aaSamw 	if (is_system_labeled()) {
317da6c28aaSamw 		(void) fprintf(stderr,
318da6c28aaSamw 		    gettext("%s: Trusted Extensions not supported.\n"),
319da6c28aaSamw 		    argv[0]);
3208622ec45SGordon Ross 		return (1);
321da6c28aaSamw 	}
322da6c28aaSamw 
323148c5f43SAlan Wright 	while ((c = getopt(argc, argv, "achnrtuz")) != EOF) {
324da6c28aaSamw 		switch (c) {
325148c5f43SAlan Wright 		case 'a':
326148c5f43SAlan Wright 			smbstat_opt_a = B_TRUE;
327da6c28aaSamw 			break;
328148c5f43SAlan Wright 		case 'n':
329148c5f43SAlan Wright 			smbstat_opt_n = B_TRUE;
330da6c28aaSamw 			break;
331148c5f43SAlan Wright 		case 'u':
332148c5f43SAlan Wright 			smbstat_opt_u = B_TRUE;
333148c5f43SAlan Wright 			break;
334148c5f43SAlan Wright 		case 'c':
335148c5f43SAlan Wright 			smbstat_opt_c = B_TRUE;
336148c5f43SAlan Wright 			break;
337148c5f43SAlan Wright 		case 'r':
338148c5f43SAlan Wright 			smbstat_opt_r = B_TRUE;
339148c5f43SAlan Wright 			break;
340148c5f43SAlan Wright 		case 't':
341148c5f43SAlan Wright 			smbstat_opt_t = B_TRUE;
342148c5f43SAlan Wright 			break;
343148c5f43SAlan Wright 		case 'z':
344148c5f43SAlan Wright 			smbstat_opt_z = B_TRUE;
345148c5f43SAlan Wright 			break;
346148c5f43SAlan Wright 		case 'h':
347148c5f43SAlan Wright 			smbstat_usage(stdout, 0);
348da6c28aaSamw 		default:
349148c5f43SAlan Wright 			smbstat_usage(stderr, 1);
350da6c28aaSamw 		}
351da6c28aaSamw 	}
352da6c28aaSamw 
353148c5f43SAlan Wright 	if (!smbstat_opt_u &&
354148c5f43SAlan Wright 	    !smbstat_opt_c &&
355148c5f43SAlan Wright 	    !smbstat_opt_r &&
356148c5f43SAlan Wright 	    !smbstat_opt_t) {
357148c5f43SAlan Wright 		/* Default options when none is specified. */
358148c5f43SAlan Wright 		smbstat_opt_u = B_TRUE;
359148c5f43SAlan Wright 		smbstat_opt_t = B_TRUE;
360da6c28aaSamw 	}
361da6c28aaSamw 
362148c5f43SAlan Wright 	if (optind < argc) {
363148c5f43SAlan Wright 		smbstat_interval =
364148c5f43SAlan Wright 		    smbstat_strtoi(argv[optind], "invalid count");
365148c5f43SAlan Wright 		optind++;
366da6c28aaSamw 	}
367da6c28aaSamw 
368148c5f43SAlan Wright 	if ((argc - optind) > 1)
369148c5f43SAlan Wright 		smbstat_usage(stderr, 1);
370148c5f43SAlan Wright 
371148c5f43SAlan Wright 	(void) atexit(smbstat_fini);
372148c5f43SAlan Wright 	smbstat_init();
373148c5f43SAlan Wright 	for (;;) {
374148c5f43SAlan Wright 		smbstat_kstat_snapshot();
375148c5f43SAlan Wright 		smbstat_kstat_process();
376148c5f43SAlan Wright 		smbstat_kstat_print();
377148c5f43SAlan Wright 		if (smbstat_interval == 0)
378148c5f43SAlan Wright 			break;
379148c5f43SAlan Wright 		(void) sleep(smbstat_interval);
380148c5f43SAlan Wright 		smbstat_snapshot_inc_idx();
381148c5f43SAlan Wright 	}
382da6c28aaSamw 	return (0);
383da6c28aaSamw }
384da6c28aaSamw 
385148c5f43SAlan Wright /*
386148c5f43SAlan Wright  * smbstat_init
387148c5f43SAlan Wright  *
388148c5f43SAlan Wright  * Global initialization.
389148c5f43SAlan Wright  */
390148c5f43SAlan Wright static void
391148c5f43SAlan Wright smbstat_init(void)
392148c5f43SAlan Wright {
393148c5f43SAlan Wright 	if ((smbstat_ksc = kstat_open()) == NULL)
394148c5f43SAlan Wright 		smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat"));
395da6c28aaSamw 
396148c5f43SAlan Wright 	smbstat_cpu_init();
397148c5f43SAlan Wright 	smbstat_srv_init();
398148c5f43SAlan Wright 	smbstat_wrk_init();
399148c5f43SAlan Wright 	smbstat_req_order();
400148c5f43SAlan Wright }
401148c5f43SAlan Wright 
402148c5f43SAlan Wright /*
403148c5f43SAlan Wright  * smbstat_fini
404148c5f43SAlan Wright  *
405148c5f43SAlan Wright  * Releases the resources smbstat_init() allocated.
406148c5f43SAlan Wright  */
407148c5f43SAlan Wright static void
408148c5f43SAlan Wright smbstat_fini(void)
409da6c28aaSamw {
410148c5f43SAlan Wright 	smbstat_wrk_fini();
411148c5f43SAlan Wright 	smbstat_srv_fini();
412148c5f43SAlan Wright 	smbstat_cpu_fini();
413148c5f43SAlan Wright 	(void) kstat_close(smbstat_ksc);
414da6c28aaSamw }
415da6c28aaSamw 
416148c5f43SAlan Wright /*
417148c5f43SAlan Wright  * smbstat_kstat_snapshot
418148c5f43SAlan Wright  *
419148c5f43SAlan Wright  * Takes a snapshot of the data.
420148c5f43SAlan Wright  */
421148c5f43SAlan Wright static void
422148c5f43SAlan Wright smbstat_kstat_snapshot(void)
423148c5f43SAlan Wright {
424148c5f43SAlan Wright 	smbstat_cpu_snapshot();
425148c5f43SAlan Wright 	smbstat_srv_snapshot();
426148c5f43SAlan Wright 	smbstat_wrk_snapshot();
427148c5f43SAlan Wright }
428148c5f43SAlan Wright 
429148c5f43SAlan Wright /*
430148c5f43SAlan Wright  * smbstat_kstat_process
431148c5f43SAlan Wright  */
432148c5f43SAlan Wright static void
433148c5f43SAlan Wright smbstat_kstat_process(void)
434148c5f43SAlan Wright {
435148c5f43SAlan Wright 	smbstat_cpu_process();
436148c5f43SAlan Wright 	smbstat_srv_process();
437148c5f43SAlan Wright 	smbstat_wrk_process();
438148c5f43SAlan Wright }
439148c5f43SAlan Wright 
440148c5f43SAlan Wright /*
441148c5f43SAlan Wright  * smbstat_kstat_print
442148c5f43SAlan Wright  *
443148c5f43SAlan Wright  * Print the data processed.
444148c5f43SAlan Wright  */
445148c5f43SAlan Wright static void
446148c5f43SAlan Wright smbstat_kstat_print(void)
447148c5f43SAlan Wright {
448148c5f43SAlan Wright 	smbstat_termio_init();
449148c5f43SAlan Wright 	smbstat_print_counters();
450148c5f43SAlan Wright 	smbstat_print_throughput();
451148c5f43SAlan Wright 	smbstat_print_utilization();
452148c5f43SAlan Wright 	smbstat_print_requests();
453a90cf9f2SGordon Ross 	(void) fflush(stdout);
454148c5f43SAlan Wright }
455148c5f43SAlan Wright 
456148c5f43SAlan Wright /*
457148c5f43SAlan Wright  * smbstat_print_counters
458148c5f43SAlan Wright  *
459148c5f43SAlan Wright  * Displays the SMB server counters (session, users...).
460148c5f43SAlan Wright  */
461148c5f43SAlan Wright static void
462148c5f43SAlan Wright smbstat_print_counters(void)
463148c5f43SAlan Wright {
464148c5f43SAlan Wright 	if (!smbstat_opt_c)
465148c5f43SAlan Wright 		return;
466148c5f43SAlan Wright 
467148c5f43SAlan Wright 	if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_t ||
468148c5f43SAlan Wright 	    (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
469148c5f43SAlan Wright 		(void) printf(SMBSRV_COUNTERS_BANNER);
470148c5f43SAlan Wright 		smbstat_rows = 1;
471148c5f43SAlan Wright 	}
472148c5f43SAlan Wright 
473148c5f43SAlan Wright 	(void) printf(SMBSRV_COUNTERS_FORMAT,
474148c5f43SAlan Wright 	    smbstat_srv_info.si_nbt_sess,
475148c5f43SAlan Wright 	    smbstat_srv_info.si_tcp_sess,
476148c5f43SAlan Wright 	    smbstat_srv_info.si_users,
477148c5f43SAlan Wright 	    smbstat_srv_info.si_trees,
478148c5f43SAlan Wright 	    smbstat_srv_info.si_files,
479148c5f43SAlan Wright 	    smbstat_srv_info.si_pipes);
480148c5f43SAlan Wright 
481148c5f43SAlan Wright 	++smbstat_rows;
482148c5f43SAlan Wright }
483148c5f43SAlan Wright /*
484148c5f43SAlan Wright  * smbstat_print_throughput
485148c5f43SAlan Wright  *
486148c5f43SAlan Wright  * Formats the SMB server throughput output.
487148c5f43SAlan Wright  */
488148c5f43SAlan Wright static void
489148c5f43SAlan Wright smbstat_print_throughput(void)
490148c5f43SAlan Wright {
491148c5f43SAlan Wright 	if (!smbstat_opt_t)
492148c5f43SAlan Wright 		return;
493148c5f43SAlan Wright 
494148c5f43SAlan Wright 	if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_c ||
495148c5f43SAlan Wright 	    (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
496148c5f43SAlan Wright 		(void) printf(SMBSRV_THROUGHPUT_BANNER);
497148c5f43SAlan Wright 		smbstat_rows = 1;
498148c5f43SAlan Wright 	}
499148c5f43SAlan Wright 	(void) printf(SMBSRV_THROUGHPUT_FORMAT,
500148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_rbs),
501148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_tbs),
502148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_rqs),
503148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_rds),
504148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_wrs));
505148c5f43SAlan Wright 
506148c5f43SAlan Wright 	++smbstat_rows;
507148c5f43SAlan Wright }
508148c5f43SAlan Wright 
509148c5f43SAlan Wright /*
510148c5f43SAlan Wright  * smbstat_print_utilization
511148c5f43SAlan Wright  */
512148c5f43SAlan Wright static void
513148c5f43SAlan Wright smbstat_print_utilization(void)
514da6c28aaSamw {
515148c5f43SAlan Wright 	char	*sat;
516148c5f43SAlan Wright 	if (!smbstat_opt_u)
517148c5f43SAlan Wright 		return;
518148c5f43SAlan Wright 
519148c5f43SAlan Wright 	if (smbstat_opt_t || smbstat_opt_r || smbstat_opt_c ||
520148c5f43SAlan Wright 	    (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
521148c5f43SAlan Wright 		(void) printf(SMBSRV_UTILIZATION_BANNER);
522148c5f43SAlan Wright 		smbstat_rows = 1;
523148c5f43SAlan Wright 	}
524148c5f43SAlan Wright 
525148c5f43SAlan Wright 	if (smbstat_srv_info.si_sat)
526148c5f43SAlan Wright 		sat = "yes";
527148c5f43SAlan Wright 	else
528148c5f43SAlan Wright 		sat = "no ";
529148c5f43SAlan Wright 
530148c5f43SAlan Wright 	(void) printf(SMBSRV_UTILIZATION_FORMAT,
531148c5f43SAlan Wright 	    smbstat_srv_info.si_avw,
532148c5f43SAlan Wright 	    smbstat_srv_info.si_avr,
533148c5f43SAlan Wright 	    smbstat_srv_info.si_wserv,
534148c5f43SAlan Wright 	    smbstat_srv_info.si_rserv,
535148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_wpct),
536148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_rpct),
537148c5f43SAlan Wright 	    smbstat_zero(smbstat_srv_info.si_upct),
538148c5f43SAlan Wright 	    sat,
539148c5f43SAlan Wright 	    smbstat_srv_info.si_ticks[CPU_TICKS_USER],
540148c5f43SAlan Wright 	    smbstat_srv_info.si_ticks[CPU_TICKS_KERNEL],
541148c5f43SAlan Wright 	    smbstat_srv_info.si_ticks[CPU_TICKS_IDLE]);
542148c5f43SAlan Wright 
543148c5f43SAlan Wright 	++smbstat_rows;
544da6c28aaSamw }
545da6c28aaSamw 
546148c5f43SAlan Wright /*
547148c5f43SAlan Wright  * smbstat_print_requests
548148c5f43SAlan Wright  */
549da6c28aaSamw static void
550148c5f43SAlan Wright smbstat_print_requests(void)
551da6c28aaSamw {
552148c5f43SAlan Wright 	smbstat_req_info_t	*prq;
553148c5f43SAlan Wright 	int			i;
554da6c28aaSamw 
555148c5f43SAlan Wright 	if (!smbstat_opt_r)
556da6c28aaSamw 		return;
557da6c28aaSamw 
558148c5f43SAlan Wright 	(void) printf(SMBSRV_REQUESTS_BANNER, "       ");
5596537f381Sas 
560a90cf9f2SGordon Ross 	prq = smbstat_srv_info.si_reqs1;
561148c5f43SAlan Wright 	for (i = 0; i < SMB_COM_NUM; i++) {
562148c5f43SAlan Wright 		if (!smbstat_opt_a &&
563148c5f43SAlan Wright 		    strncmp(prq[i].ri_name, "Invalid", sizeof ("Invalid")) == 0)
564148c5f43SAlan Wright 			continue;
5656537f381Sas 
566148c5f43SAlan Wright 		if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
567148c5f43SAlan Wright 			(void) printf(SMBSRV_REQUESTS_FORMAT,
568148c5f43SAlan Wright 			    prq[i].ri_name,
569148c5f43SAlan Wright 			    prq[i].ri_opcode,
570148c5f43SAlan Wright 			    smbstat_zero(prq[i].ri_pct),
571148c5f43SAlan Wright 			    smbstat_zero(prq[i].ri_rbs),
572148c5f43SAlan Wright 			    smbstat_zero(prq[i].ri_tbs),
573148c5f43SAlan Wright 			    smbstat_zero(prq[i].ri_rqs),
574148c5f43SAlan Wright 			    prq[i].ri_mean,
575148c5f43SAlan Wright 			    prq[i].ri_stddev);
5766537f381Sas 		}
577148c5f43SAlan Wright 	}
578a90cf9f2SGordon Ross 
579a90cf9f2SGordon Ross 	prq = smbstat_srv_info.si_reqs2;
580a90cf9f2SGordon Ross 	for (i = 0; i < SMB2__NCMDS; i++) {
581a90cf9f2SGordon Ross 		if (!smbstat_opt_a && i == SMB2_INVALID_CMD)
582a90cf9f2SGordon Ross 			continue;
583a90cf9f2SGordon Ross 
584a90cf9f2SGordon Ross 		if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
585a90cf9f2SGordon Ross 			(void) printf(SMBSRV_REQUESTS_FORMAT,
586a90cf9f2SGordon Ross 			    prq[i].ri_name,
587a90cf9f2SGordon Ross 			    prq[i].ri_opcode,
588a90cf9f2SGordon Ross 			    smbstat_zero(prq[i].ri_pct),
589a90cf9f2SGordon Ross 			    smbstat_zero(prq[i].ri_rbs),
590a90cf9f2SGordon Ross 			    smbstat_zero(prq[i].ri_tbs),
591a90cf9f2SGordon Ross 			    smbstat_zero(prq[i].ri_rqs),
592a90cf9f2SGordon Ross 			    prq[i].ri_mean,
593a90cf9f2SGordon Ross 			    prq[i].ri_stddev);
594a90cf9f2SGordon Ross 		}
595a90cf9f2SGordon Ross 	}
596148c5f43SAlan Wright }
597148c5f43SAlan Wright 
598148c5f43SAlan Wright /*
599148c5f43SAlan Wright  * smbstat_cpu_init
600148c5f43SAlan Wright  */
601148c5f43SAlan Wright static void
602148c5f43SAlan Wright smbstat_cpu_init(void)
603148c5f43SAlan Wright {
604148c5f43SAlan Wright 	size_t	size;
605148c5f43SAlan Wright 	int	i;
606148c5f43SAlan Wright 
607148c5f43SAlan Wright 	smbstat_nrcpus = sysconf(_SC_CPUID_MAX) + 1;
608148c5f43SAlan Wright 	size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t);
609148c5f43SAlan Wright 
610148c5f43SAlan Wright 	for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
611148c5f43SAlan Wright 		smbstat_cpu_snapshots[i] = smbstat_zalloc(size);
612148c5f43SAlan Wright }
613148c5f43SAlan Wright 
614148c5f43SAlan Wright /*
615148c5f43SAlan Wright  * smbstat_cpu_fini
616148c5f43SAlan Wright  */
617148c5f43SAlan Wright static void
618148c5f43SAlan Wright smbstat_cpu_fini(void)
619148c5f43SAlan Wright {
620148c5f43SAlan Wright 	size_t	size;
621148c5f43SAlan Wright 	int	i;
622148c5f43SAlan Wright 
623148c5f43SAlan Wright 	size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t);
624148c5f43SAlan Wright 
625148c5f43SAlan Wright 	for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
626148c5f43SAlan Wright 		smbstat_free(smbstat_cpu_snapshots[i], size);
627148c5f43SAlan Wright }
628148c5f43SAlan Wright 
629148c5f43SAlan Wright /*
630148c5f43SAlan Wright  * smbstat_cpu_current_snapshot
631148c5f43SAlan Wright  */
632148c5f43SAlan Wright static smbstat_cpu_snapshot_t *
633148c5f43SAlan Wright smbstat_cpu_current_snapshot(void)
634148c5f43SAlan Wright {
635148c5f43SAlan Wright 	return (smbstat_cpu_snapshots[smbstat_snapshot_idx]);
636148c5f43SAlan Wright }
637148c5f43SAlan Wright 
638148c5f43SAlan Wright /*
639148c5f43SAlan Wright  * smbstat_cpu_previous_snapshot
640148c5f43SAlan Wright  */
641148c5f43SAlan Wright static smbstat_cpu_snapshot_t *
642148c5f43SAlan Wright smbstat_cpu_previous_snapshot(void)
643148c5f43SAlan Wright {
644148c5f43SAlan Wright 	int	idx;
645148c5f43SAlan Wright 
646148c5f43SAlan Wright 	idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK;
647148c5f43SAlan Wright 	return (smbstat_cpu_snapshots[idx]);
648148c5f43SAlan Wright }
649148c5f43SAlan Wright 
650148c5f43SAlan Wright /*
651148c5f43SAlan Wright  * smbstat_cpu_snapshot
652148c5f43SAlan Wright  */
653148c5f43SAlan Wright static void
654148c5f43SAlan Wright smbstat_cpu_snapshot(void)
655148c5f43SAlan Wright {
656148c5f43SAlan Wright 	kstat_t			*ksp;
657148c5f43SAlan Wright 	kstat_named_t		*ksn;
658148c5f43SAlan Wright 	smbstat_cpu_snapshot_t	*curr;
659148c5f43SAlan Wright 	long			i;
660148c5f43SAlan Wright 	int			j;
661148c5f43SAlan Wright 
662148c5f43SAlan Wright 	curr =  smbstat_cpu_current_snapshot();
663148c5f43SAlan Wright 
664148c5f43SAlan Wright 	for (i = 0; i < smbstat_nrcpus;	i++, curr++) {
665148c5f43SAlan Wright 		curr->cs_id = SMBSTAT_ID_NO_CPU;
666148c5f43SAlan Wright 		curr->cs_state = p_online(i, P_STATUS);
667148c5f43SAlan Wright 		/* If no valid CPU is present, move on to the next one */
668148c5f43SAlan Wright 		if (curr->cs_state == -1)
669148c5f43SAlan Wright 			continue;
670148c5f43SAlan Wright 
671148c5f43SAlan Wright 		curr->cs_id = i;
672148c5f43SAlan Wright 
673148c5f43SAlan Wright 		ksp = kstat_lookup(smbstat_ksc, "cpu", i, "sys");
674148c5f43SAlan Wright 		if (ksp == NULL)
675148c5f43SAlan Wright 			smbstat_fail(1,
676148c5f43SAlan Wright 			    gettext("kstat_lookup('cpu sys %d') failed"), i);
677148c5f43SAlan Wright 
678148c5f43SAlan Wright 		if (kstat_read(smbstat_ksc, ksp, NULL) == -1)
679148c5f43SAlan Wright 			smbstat_fail(1,
680148c5f43SAlan Wright 			    gettext("kstat_read('cpu sys %d') failed"), i);
681148c5f43SAlan Wright 
682148c5f43SAlan Wright 		for (j = 0; j < CPU_TICKS_SENTINEL; j++) {
683148c5f43SAlan Wright 			ksn = kstat_data_lookup(ksp, smbstat_cpu_states[j]);
684148c5f43SAlan Wright 			if (ksn == NULL)
685148c5f43SAlan Wright 				smbstat_fail(1,
686148c5f43SAlan Wright 				    gettext("kstat_data_lookup('%s') failed"),
687148c5f43SAlan Wright 				    smbstat_cpu_states[j]);
688148c5f43SAlan Wright 			curr->cs_ticks[j] = ksn->value.ui64;
6896537f381Sas 		}
6906537f381Sas 	}
691da6c28aaSamw }
692da6c28aaSamw 
693148c5f43SAlan Wright /*
694148c5f43SAlan Wright  * smbstat_cpu_process
695148c5f43SAlan Wright  */
696da6c28aaSamw static void
697148c5f43SAlan Wright smbstat_cpu_process(void)
698da6c28aaSamw {
699148c5f43SAlan Wright 	smbstat_cpu_snapshot_t	*curr, *prev;
700148c5f43SAlan Wright 	double			total_ticks;
701148c5f43SAlan Wright 	double			agg_ticks[CPU_TICKS_SENTINEL];
702148c5f43SAlan Wright 	int			i, j;
703da6c28aaSamw 
704148c5f43SAlan Wright 	curr =  smbstat_cpu_current_snapshot();
705148c5f43SAlan Wright 	prev =  smbstat_cpu_previous_snapshot();
706148c5f43SAlan Wright 	bzero(agg_ticks, sizeof (agg_ticks));
707148c5f43SAlan Wright 	total_ticks = 0;
708da6c28aaSamw 
709148c5f43SAlan Wright 	for (i = 0; i < smbstat_nrcpus; i++, curr++, prev++) {
710148c5f43SAlan Wright 		for (j = 0; j < CPU_TICKS_SENTINEL; j++) {
711148c5f43SAlan Wright 			agg_ticks[j] +=	smbstat_sub_64(curr->cs_ticks[j],
712148c5f43SAlan Wright 			    prev->cs_ticks[j]);
713148c5f43SAlan Wright 			total_ticks += smbstat_sub_64(curr->cs_ticks[j],
714148c5f43SAlan Wright 			    prev->cs_ticks[j]);
715148c5f43SAlan Wright 		}
716148c5f43SAlan Wright 	}
717148c5f43SAlan Wright 
718148c5f43SAlan Wright 	for (j = 0; j < CPU_TICKS_SENTINEL; j++)
719148c5f43SAlan Wright 		smbstat_srv_info.si_ticks[j] =
720148c5f43SAlan Wright 		    (agg_ticks[j] * 100.0) / total_ticks;
721da6c28aaSamw }
722da6c28aaSamw 
723148c5f43SAlan Wright /*
724148c5f43SAlan Wright  * smbstat_wrk_init
725148c5f43SAlan Wright  */
726da6c28aaSamw static void
727148c5f43SAlan Wright smbstat_wrk_init(void)
728da6c28aaSamw {
729148c5f43SAlan Wright 	smbstat_wrk_ksp =
730148c5f43SAlan Wright 	    kstat_lookup(smbstat_ksc, "unix", -1, SMBSRV_KSTAT_WORKERS);
731148c5f43SAlan Wright 	if (smbstat_wrk_ksp == NULL)
732148c5f43SAlan Wright 		smbstat_fail(1,
733148c5f43SAlan Wright 		    gettext("cannot retrieve smbsrv workers kstat\n"));
734148c5f43SAlan Wright }
7356537f381Sas 
736148c5f43SAlan Wright static void
737148c5f43SAlan Wright smbstat_wrk_fini(void)
738148c5f43SAlan Wright {
739148c5f43SAlan Wright 	smbstat_wrk_ksp = NULL;
740148c5f43SAlan Wright }
7416537f381Sas 
742148c5f43SAlan Wright /*
743148c5f43SAlan Wright  * smbstat_wrk_snapshot
744148c5f43SAlan Wright  */
745148c5f43SAlan Wright static void
746148c5f43SAlan Wright smbstat_wrk_snapshot(void)
747148c5f43SAlan Wright {
748148c5f43SAlan Wright 	smbstat_wrk_snapshot_t	*curr;
749148c5f43SAlan Wright 	kstat_named_t		*kn;
750da6c28aaSamw 
751148c5f43SAlan Wright 	curr = smbstat_wrk_current_snapshot();
752da6c28aaSamw 
753148c5f43SAlan Wright 	if (kstat_read(smbstat_ksc, smbstat_wrk_ksp, NULL) == -1)
754148c5f43SAlan Wright 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
755148c5f43SAlan Wright 		    smbstat_wrk_ksp->ks_name);
756148c5f43SAlan Wright 
757148c5f43SAlan Wright 	kn = kstat_data_lookup(smbstat_wrk_ksp, "maxthreads");
758148c5f43SAlan Wright 	if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64))
759148c5f43SAlan Wright 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
760148c5f43SAlan Wright 		    "maxthreads");
761148c5f43SAlan Wright 	curr->ws_maxthreads = kn->value.ui64;
762148c5f43SAlan Wright 
763148c5f43SAlan Wright 	kn = kstat_data_lookup(smbstat_wrk_ksp, "bnalloc");
764148c5f43SAlan Wright 	if ((kn == NULL) || (kn->data_type != KSTAT_DATA_UINT64))
765148c5f43SAlan Wright 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
766148c5f43SAlan Wright 		    "bnalloc");
767148c5f43SAlan Wright 	curr->ws_bnalloc = kn->value.ui64;
768da6c28aaSamw }
769da6c28aaSamw 
770148c5f43SAlan Wright /*
771148c5f43SAlan Wright  * smbstat_wrk_process
772148c5f43SAlan Wright  */
7736537f381Sas static void
774148c5f43SAlan Wright smbstat_wrk_process(void)
7756537f381Sas {
776148c5f43SAlan Wright 	smbstat_wrk_snapshot_t	*curr;
777148c5f43SAlan Wright 
778148c5f43SAlan Wright 	curr = smbstat_wrk_current_snapshot();
779148c5f43SAlan Wright 
780a90cf9f2SGordon Ross 	if (curr->ws_bnalloc >= curr->ws_maxthreads)
781148c5f43SAlan Wright 		smbstat_srv_info.si_sat = B_TRUE;
782148c5f43SAlan Wright 	else
783148c5f43SAlan Wright 		smbstat_srv_info.si_sat = B_FALSE;
7846537f381Sas }
7856537f381Sas 
786148c5f43SAlan Wright /*
787148c5f43SAlan Wright  * smbstat_wrk_current_snapshot
788148c5f43SAlan Wright  */
789148c5f43SAlan Wright static smbstat_wrk_snapshot_t *
790148c5f43SAlan Wright smbstat_wrk_current_snapshot(void)
791148c5f43SAlan Wright {
792148c5f43SAlan Wright 	return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]);
793148c5f43SAlan Wright }
794148c5f43SAlan Wright 
795148c5f43SAlan Wright /*
796148c5f43SAlan Wright  * smbstat_srv_init
797148c5f43SAlan Wright  */
798148c5f43SAlan Wright static void
799148c5f43SAlan Wright smbstat_srv_init(void)
800148c5f43SAlan Wright {
801148c5f43SAlan Wright 	smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE,
802148c5f43SAlan Wright 	    getzoneid(), SMBSRV_KSTAT_STATISTICS);
803148c5f43SAlan Wright 	if (smbstat_srv_ksp == NULL)
804148c5f43SAlan Wright 		smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n"));
805148c5f43SAlan Wright }
806148c5f43SAlan Wright 
807148c5f43SAlan Wright /*
808148c5f43SAlan Wright  * smbstat_srv_fini
809148c5f43SAlan Wright  */
810148c5f43SAlan Wright static void
811148c5f43SAlan Wright smbstat_srv_fini(void)
812148c5f43SAlan Wright {
813148c5f43SAlan Wright 	smbstat_srv_ksp = NULL;
814148c5f43SAlan Wright }
815148c5f43SAlan Wright 
816148c5f43SAlan Wright /*
817148c5f43SAlan Wright  * smbstat_srv_snapshot
818148c5f43SAlan Wright  *
819148c5f43SAlan Wright  * Take a snapshot of the smbsrv module statistics.
820148c5f43SAlan Wright  */
821148c5f43SAlan Wright static void
822148c5f43SAlan Wright smbstat_srv_snapshot(void)
823148c5f43SAlan Wright {
824148c5f43SAlan Wright 	smbstat_srv_snapshot_t	*curr;
825148c5f43SAlan Wright 
826148c5f43SAlan Wright 	curr = smbstat_srv_current_snapshot();
827148c5f43SAlan Wright 
828148c5f43SAlan Wright 	if ((kstat_read(smbstat_ksc, smbstat_srv_ksp, NULL) == -1) ||
829148c5f43SAlan Wright 	    (smbstat_srv_ksp->ks_data_size != sizeof (curr->ss_data)))
830148c5f43SAlan Wright 		smbstat_fail(1, gettext("kstat_read('%s') failed"),
831148c5f43SAlan Wright 		    smbstat_srv_ksp->ks_name);
832148c5f43SAlan Wright 
833148c5f43SAlan Wright 	curr->ss_snaptime = smbstat_srv_ksp->ks_snaptime;
834148c5f43SAlan Wright 	bcopy(smbstat_srv_ksp->ks_data, &curr->ss_data, sizeof (curr->ss_data));
835148c5f43SAlan Wright }
836148c5f43SAlan Wright 
837148c5f43SAlan Wright /*
838148c5f43SAlan Wright  * smbstat_srv_process
839148c5f43SAlan Wright  *
840148c5f43SAlan Wright  * Processes the snapshot data.
841148c5f43SAlan Wright  */
842148c5f43SAlan Wright static void
843148c5f43SAlan Wright smbstat_srv_process(void)
844148c5f43SAlan Wright {
845148c5f43SAlan Wright 	smbstat_srv_snapshot_t	*curr, *prev;
846148c5f43SAlan Wright 
847148c5f43SAlan Wright 	curr = smbstat_srv_current_snapshot();
848148c5f43SAlan Wright 	prev = smbstat_srv_previous_snapshot();
849148c5f43SAlan Wright 
850148c5f43SAlan Wright 	if (prev->ss_snaptime == 0)
851148c5f43SAlan Wright 		smbstat_srv_info.si_hretime =
852148c5f43SAlan Wright 		    smbstat_hrtime_delta(curr->ss_data.ks_start_time,
853148c5f43SAlan Wright 		    curr->ss_snaptime);
854148c5f43SAlan Wright 	else
855148c5f43SAlan Wright 		smbstat_srv_info.si_hretime =
856148c5f43SAlan Wright 		    smbstat_hrtime_delta(prev->ss_snaptime, curr->ss_snaptime);
857148c5f43SAlan Wright 
858148c5f43SAlan Wright 	smbstat_srv_info.si_etime = smbstat_srv_info.si_hretime / NANOSEC;
859148c5f43SAlan Wright 	smbstat_srv_info.si_total_nreqs =
860148c5f43SAlan Wright 	    smbstat_sub_64(curr->ss_data.ks_nreq, prev->ss_data.ks_nreq);
861148c5f43SAlan Wright 
862148c5f43SAlan Wright 	if (smbstat_opt_c)
863148c5f43SAlan Wright 		smbstat_srv_process_counters(curr);
864148c5f43SAlan Wright 	if (smbstat_opt_t)
865148c5f43SAlan Wright 		smbstat_srv_process_throughput(curr, prev);
866148c5f43SAlan Wright 	if (smbstat_opt_u)
867148c5f43SAlan Wright 		smbstat_srv_process_utilization(curr, prev);
868148c5f43SAlan Wright 	if (smbstat_opt_r)
869148c5f43SAlan Wright 		smbstat_srv_process_requests(curr, prev);
870148c5f43SAlan Wright }
871148c5f43SAlan Wright 
872148c5f43SAlan Wright /*
873148c5f43SAlan Wright  * smbstat_srv_process_counters
874148c5f43SAlan Wright  */
875148c5f43SAlan Wright static void
876148c5f43SAlan Wright smbstat_srv_process_counters(smbstat_srv_snapshot_t *curr)
877148c5f43SAlan Wright {
878148c5f43SAlan Wright 	smbstat_srv_info.si_nbt_sess = curr->ss_data.ks_nbt_sess;
879148c5f43SAlan Wright 	smbstat_srv_info.si_tcp_sess = curr->ss_data.ks_tcp_sess;
880148c5f43SAlan Wright 	smbstat_srv_info.si_users = curr->ss_data.ks_users;
881148c5f43SAlan Wright 	smbstat_srv_info.si_trees = curr->ss_data.ks_trees;
882148c5f43SAlan Wright 	smbstat_srv_info.si_files = curr->ss_data.ks_files;
883148c5f43SAlan Wright 	smbstat_srv_info.si_pipes = curr->ss_data.ks_pipes;
884148c5f43SAlan Wright }
885148c5f43SAlan Wright 
886148c5f43SAlan Wright /*
887148c5f43SAlan Wright  * smbstat_srv_process_throughput
888148c5f43SAlan Wright  *
889148c5f43SAlan Wright  * Processes the data relative to the throughput of the smbsrv module and
890148c5f43SAlan Wright  * stores the results in the structure smbstat_srv_info.
891148c5f43SAlan Wright  */
892148c5f43SAlan Wright static void
893148c5f43SAlan Wright smbstat_srv_process_throughput(
894148c5f43SAlan Wright     smbstat_srv_snapshot_t	*curr,
895148c5f43SAlan Wright     smbstat_srv_snapshot_t	*prev)
896148c5f43SAlan Wright {
897148c5f43SAlan Wright 	smbstat_srv_info.si_tbs =
898148c5f43SAlan Wright 	    smbstat_sub_64(curr->ss_data.ks_txb, prev->ss_data.ks_txb);
899148c5f43SAlan Wright 	smbstat_srv_info.si_tbs /= smbstat_srv_info.si_etime;
900148c5f43SAlan Wright 	smbstat_srv_info.si_rbs =
901148c5f43SAlan Wright 	    smbstat_sub_64(curr->ss_data.ks_rxb, prev->ss_data.ks_rxb);
902148c5f43SAlan Wright 	smbstat_srv_info.si_rbs /= smbstat_srv_info.si_etime;
903148c5f43SAlan Wright 	smbstat_srv_info.si_rqs = smbstat_srv_info.si_total_nreqs;
904148c5f43SAlan Wright 	smbstat_srv_info.si_rqs /= smbstat_srv_info.si_etime;
905148c5f43SAlan Wright 
906148c5f43SAlan Wright 	smbstat_srv_info.si_rds = smbstat_sub_64(
907a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs1[SMB_COM_READ].kr_nreq,
908a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs1[SMB_COM_READ].kr_nreq);
909a90cf9f2SGordon Ross 	smbstat_srv_info.si_rds += smbstat_sub_64(
910a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs1[SMB_COM_LOCK_AND_READ].kr_nreq,
911a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs1[SMB_COM_LOCK_AND_READ].kr_nreq);
912148c5f43SAlan Wright 	smbstat_srv_info.si_rds += smbstat_sub_64(
913a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs1[SMB_COM_READ_RAW].kr_nreq,
914a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs1[SMB_COM_READ_RAW].kr_nreq);
915148c5f43SAlan Wright 	smbstat_srv_info.si_rds += smbstat_sub_64(
916a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs1[SMB_COM_READ_ANDX].kr_nreq,
917a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs1[SMB_COM_READ_ANDX].kr_nreq);
918148c5f43SAlan Wright 	smbstat_srv_info.si_rds += smbstat_sub_64(
919a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs2[SMB2_READ].kr_nreq,
920a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs2[SMB2_READ].kr_nreq);
921148c5f43SAlan Wright 	smbstat_srv_info.si_rds /= smbstat_srv_info.si_etime;
922148c5f43SAlan Wright 
923148c5f43SAlan Wright 	smbstat_srv_info.si_wrs = smbstat_sub_64(
924a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE].kr_nreq,
925a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE].kr_nreq);
926148c5f43SAlan Wright 	smbstat_srv_info.si_wrs += smbstat_sub_64(
927a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE_AND_UNLOCK].kr_nreq,
928a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE_AND_UNLOCK].kr_nreq);
929148c5f43SAlan Wright 	smbstat_srv_info.si_wrs += smbstat_sub_64(
930a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE_RAW].kr_nreq,
931a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE_RAW].kr_nreq);
932148c5f43SAlan Wright 	smbstat_srv_info.si_wrs += smbstat_sub_64(
933a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE_AND_CLOSE].kr_nreq,
934a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE_AND_CLOSE].kr_nreq);
935148c5f43SAlan Wright 	smbstat_srv_info.si_wrs += smbstat_sub_64(
936a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs1[SMB_COM_WRITE_ANDX].kr_nreq,
937a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs1[SMB_COM_WRITE_ANDX].kr_nreq);
938a90cf9f2SGordon Ross 	smbstat_srv_info.si_wrs += smbstat_sub_64(
939a90cf9f2SGordon Ross 	    curr->ss_data.ks_reqs2[SMB2_WRITE].kr_nreq,
940a90cf9f2SGordon Ross 	    prev->ss_data.ks_reqs2[SMB2_WRITE].kr_nreq);
941148c5f43SAlan Wright 	smbstat_srv_info.si_wrs /= smbstat_srv_info.si_etime;
942148c5f43SAlan Wright }
943148c5f43SAlan Wright 
944148c5f43SAlan Wright /*
945148c5f43SAlan Wright  * smbstat_srv_process_utilization
946148c5f43SAlan Wright  *
947148c5f43SAlan Wright  * Processes the data relative to the utilization of the smbsrv module and
948148c5f43SAlan Wright  * stores the results in the structure smbstat_srv_info.
949148c5f43SAlan Wright  */
950148c5f43SAlan Wright static void
951148c5f43SAlan Wright smbstat_srv_process_utilization(
952148c5f43SAlan Wright     smbstat_srv_snapshot_t	*curr,
953148c5f43SAlan Wright     smbstat_srv_snapshot_t	*prev)
954148c5f43SAlan Wright {
955148c5f43SAlan Wright 	double	tw_delta, tr_delta;
956148c5f43SAlan Wright 	double	w_delta, r_delta;
957148c5f43SAlan Wright 	double	tps, rqs;
958148c5f43SAlan Wright 
959148c5f43SAlan Wright 	w_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wlentime,
960148c5f43SAlan Wright 	    curr->ss_data.ks_utilization.ku_wlentime);
961148c5f43SAlan Wright 	r_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rlentime,
962148c5f43SAlan Wright 	    curr->ss_data.ks_utilization.ku_rlentime);
963148c5f43SAlan Wright 	tw_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_wtime,
964148c5f43SAlan Wright 	    curr->ss_data.ks_utilization.ku_wtime);
965148c5f43SAlan Wright 	tr_delta = smbstat_hrtime_delta(prev->ss_data.ks_utilization.ku_rtime,
966148c5f43SAlan Wright 	    curr->ss_data.ks_utilization.ku_rtime);
967148c5f43SAlan Wright 	rqs = smbstat_srv_info.si_total_nreqs / smbstat_srv_info.si_etime;
968148c5f43SAlan Wright 
969148c5f43SAlan Wright 	/* Average number of requests waiting */
970148c5f43SAlan Wright 	if (w_delta != 0)
971148c5f43SAlan Wright 		smbstat_srv_info.si_avw = w_delta / smbstat_srv_info.si_hretime;
972148c5f43SAlan Wright 	else
973148c5f43SAlan Wright 		smbstat_srv_info.si_avw = 0.0;
974148c5f43SAlan Wright 
975148c5f43SAlan Wright 	/* Average number of request running */
976148c5f43SAlan Wright 	if (r_delta != 0)
977148c5f43SAlan Wright 		smbstat_srv_info.si_avr = r_delta / smbstat_srv_info.si_hretime;
978148c5f43SAlan Wright 	else
979148c5f43SAlan Wright 		smbstat_srv_info.si_avr = 0.0;
980148c5f43SAlan Wright 
981148c5f43SAlan Wright 	/* Utilization */
982148c5f43SAlan Wright 	smbstat_srv_info.si_upct =
983148c5f43SAlan Wright 	    (smbstat_srv_info.si_avr / curr->ss_data.ks_maxreqs) * 100;
984148c5f43SAlan Wright 
985148c5f43SAlan Wright 	/* Average wait service time in milliseconds */
986148c5f43SAlan Wright 	smbstat_srv_info.si_rserv = 0.0;
987148c5f43SAlan Wright 	smbstat_srv_info.si_wserv = 0.0;
988148c5f43SAlan Wright 	if (rqs > 0.0 &&
989148c5f43SAlan Wright 	    (smbstat_srv_info.si_avw != 0.0 ||
990148c5f43SAlan Wright 	    smbstat_srv_info.si_avr != 0.0)) {
991148c5f43SAlan Wright 		tps = 1 / rqs;
992148c5f43SAlan Wright 		if (smbstat_srv_info.si_avw != 0.0)
993148c5f43SAlan Wright 			smbstat_srv_info.si_wserv =
994148c5f43SAlan Wright 			    smbstat_srv_info.si_avw * tps;
995148c5f43SAlan Wright 		if (smbstat_srv_info.si_avr != 0.0)
996148c5f43SAlan Wright 			smbstat_srv_info.si_rserv =
997148c5f43SAlan Wright 			    smbstat_srv_info.si_avr * tps;
998148c5f43SAlan Wright 	}
999148c5f43SAlan Wright 
1000148c5f43SAlan Wright 	/* % of time there is a transaction waiting for service */
1001148c5f43SAlan Wright 	if (tw_delta != 0) {
1002148c5f43SAlan Wright 		smbstat_srv_info.si_wpct = tw_delta;
1003148c5f43SAlan Wright 		smbstat_srv_info.si_wpct /= smbstat_srv_info.si_hretime;
1004148c5f43SAlan Wright 		smbstat_srv_info.si_wpct *= 100.0;
1005148c5f43SAlan Wright 	} else {
1006148c5f43SAlan Wright 		smbstat_srv_info.si_wpct = 0.0;
1007148c5f43SAlan Wright 	}
1008148c5f43SAlan Wright 
1009148c5f43SAlan Wright 	/* % of time there is a transaction running */
1010148c5f43SAlan Wright 	if (tr_delta != 0) {
1011148c5f43SAlan Wright 		smbstat_srv_info.si_rpct = tr_delta;
1012148c5f43SAlan Wright 		smbstat_srv_info.si_rpct /= smbstat_srv_info.si_hretime;
1013148c5f43SAlan Wright 		smbstat_srv_info.si_rpct *= 100.0;
1014148c5f43SAlan Wright 	} else {
1015148c5f43SAlan Wright 		smbstat_srv_info.si_rpct = 0.0;
1016da6c28aaSamw 	}
1017da6c28aaSamw }
1018da6c28aaSamw 
1019148c5f43SAlan Wright /*
1020148c5f43SAlan Wright  * smbstat_srv_process_requests
1021148c5f43SAlan Wright  *
1022148c5f43SAlan Wright  * Processes the data relative to the SMB requests and stores the results in
1023148c5f43SAlan Wright  * the structure smbstat_srv_info.
1024148c5f43SAlan Wright  */
1025da6c28aaSamw static void
1026148c5f43SAlan Wright smbstat_srv_process_requests(
1027148c5f43SAlan Wright     smbstat_srv_snapshot_t	*curr,
1028148c5f43SAlan Wright     smbstat_srv_snapshot_t	*prev)
1029da6c28aaSamw {
1030148c5f43SAlan Wright 	smbstat_req_info_t	*info;
1031a90cf9f2SGordon Ross 	smb_kstat_req_t		*curr_req;
1032a90cf9f2SGordon Ross 	smb_kstat_req_t		*prev_req;
1033148c5f43SAlan Wright 	int			i, idx;
1034a90cf9f2SGordon Ross 	boolean_t	firstcall = (prev->ss_snaptime == 0);
1035da6c28aaSamw 
1036148c5f43SAlan Wright 	for (i = 0; i < SMB_COM_NUM; i++) {
1037a90cf9f2SGordon Ross 		info = &smbstat_srv_info.si_reqs1[i];
1038*5015ecc3SGordon Ross 		idx = info->ri_opcode;
1039*5015ecc3SGordon Ross 		if (idx >= SMB_COM_NUM)
1040*5015ecc3SGordon Ross 			continue;
1041a90cf9f2SGordon Ross 		curr_req = &curr->ss_data.ks_reqs1[idx];
1042a90cf9f2SGordon Ross 		prev_req = &prev->ss_data.ks_reqs1[idx];
1043a90cf9f2SGordon Ross 		smbstat_srv_process_one_req(
1044a90cf9f2SGordon Ross 		    info, curr_req, prev_req, firstcall);
1045a90cf9f2SGordon Ross 	}
1046a90cf9f2SGordon Ross 
1047a90cf9f2SGordon Ross 	for (i = 0; i < SMB2__NCMDS; i++) {
1048a90cf9f2SGordon Ross 		info = &smbstat_srv_info.si_reqs2[i];
1049*5015ecc3SGordon Ross 		idx = info->ri_opcode;
1050*5015ecc3SGordon Ross 		if (idx >= SMB2__NCMDS)
1051*5015ecc3SGordon Ross 			continue;
1052*5015ecc3SGordon Ross 		curr_req = &curr->ss_data.ks_reqs2[idx];
1053*5015ecc3SGordon Ross 		prev_req = &prev->ss_data.ks_reqs2[idx];
1054a90cf9f2SGordon Ross 		smbstat_srv_process_one_req(
1055a90cf9f2SGordon Ross 		    info, curr_req, prev_req, firstcall);
1056a90cf9f2SGordon Ross 	}
1057a90cf9f2SGordon Ross }
1058a90cf9f2SGordon Ross 
1059a90cf9f2SGordon Ross static void
1060a90cf9f2SGordon Ross smbstat_srv_process_one_req(
1061a90cf9f2SGordon Ross 	smbstat_req_info_t	*info,
1062a90cf9f2SGordon Ross 	smb_kstat_req_t		*curr_req,
1063a90cf9f2SGordon Ross 	smb_kstat_req_t		*prev_req,
1064a90cf9f2SGordon Ross 	boolean_t		firstcall)
1065a90cf9f2SGordon Ross {
1066a90cf9f2SGordon Ross 	double			nrqs;
1067a90cf9f2SGordon Ross 
1068a90cf9f2SGordon Ross 	nrqs = smbstat_sub_64(curr_req->kr_nreq,
1069a90cf9f2SGordon Ross 	    prev_req->kr_nreq);
1070a90cf9f2SGordon Ross 
1071a90cf9f2SGordon Ross 	info->ri_rqs = nrqs / smbstat_srv_info.si_etime;
1072a90cf9f2SGordon Ross 
1073a90cf9f2SGordon Ross 	info->ri_rbs = smbstat_sub_64(
1074a90cf9f2SGordon Ross 	    curr_req->kr_rxb,
1075a90cf9f2SGordon Ross 	    prev_req->kr_rxb) /
1076a90cf9f2SGordon Ross 	    smbstat_srv_info.si_etime;
1077a90cf9f2SGordon Ross 
1078a90cf9f2SGordon Ross 	info->ri_tbs = smbstat_sub_64(
1079a90cf9f2SGordon Ross 	    curr_req->kr_txb,
1080a90cf9f2SGordon Ross 	    prev_req->kr_txb) /
1081a90cf9f2SGordon Ross 	    smbstat_srv_info.si_etime;
1082a90cf9f2SGordon Ross 
1083a90cf9f2SGordon Ross 	info->ri_pct = nrqs * 100;
1084a90cf9f2SGordon Ross 	if (smbstat_srv_info.si_total_nreqs > 0)
1085a90cf9f2SGordon Ross 		info->ri_pct /= smbstat_srv_info.si_total_nreqs;
1086a90cf9f2SGordon Ross 
1087a90cf9f2SGordon Ross 	if (firstcall) {
1088a90cf9f2SGordon Ross 		/* First time. Take the aggregate */
1089a90cf9f2SGordon Ross 		info->ri_stddev =
1090a90cf9f2SGordon Ross 		    curr_req->kr_a_stddev;
1091a90cf9f2SGordon Ross 		info->ri_mean = curr_req->kr_a_mean;
1092a90cf9f2SGordon Ross 	} else {
1093a90cf9f2SGordon Ross 		/* Take the differential */
1094a90cf9f2SGordon Ross 		info->ri_stddev =
1095a90cf9f2SGordon Ross 		    curr_req->kr_d_stddev;
1096a90cf9f2SGordon Ross 		info->ri_mean = curr_req->kr_d_mean;
1097a90cf9f2SGordon Ross 	}
1098a90cf9f2SGordon Ross 	if (nrqs > 0) {
1099a90cf9f2SGordon Ross 		info->ri_stddev /= nrqs;
1100a90cf9f2SGordon Ross 		info->ri_stddev = sqrt(info->ri_stddev);
1101a90cf9f2SGordon Ross 	} else {
1102a90cf9f2SGordon Ross 		info->ri_stddev = 0;
1103da6c28aaSamw 	}
1104a90cf9f2SGordon Ross 	info->ri_stddev /= NANOSEC;
1105a90cf9f2SGordon Ross 	info->ri_mean /= NANOSEC;
1106da6c28aaSamw }
1107da6c28aaSamw 
1108a90cf9f2SGordon Ross 
1109148c5f43SAlan Wright /*
1110148c5f43SAlan Wright  * smbstat_srv_current_snapshot
1111148c5f43SAlan Wright  *
1112148c5f43SAlan Wright  * Returns the current snapshot.
1113148c5f43SAlan Wright  */
1114148c5f43SAlan Wright static smbstat_srv_snapshot_t *
1115148c5f43SAlan Wright smbstat_srv_current_snapshot(void)
1116148c5f43SAlan Wright {
1117148c5f43SAlan Wright 	return (&smbstat_srv_snapshots[smbstat_snapshot_idx]);
1118148c5f43SAlan Wright }
1119148c5f43SAlan Wright 
1120148c5f43SAlan Wright /*
1121148c5f43SAlan Wright  * smbstat_srv_previous_snapshot
1122148c5f43SAlan Wright  *
1123148c5f43SAlan Wright  * Returns the previous snapshot.
1124148c5f43SAlan Wright  */
1125148c5f43SAlan Wright static smbstat_srv_snapshot_t *
1126148c5f43SAlan Wright smbstat_srv_previous_snapshot(void)
1127148c5f43SAlan Wright {
1128148c5f43SAlan Wright 	int	idx;
1129148c5f43SAlan Wright 
1130148c5f43SAlan Wright 	idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK;
1131148c5f43SAlan Wright 	return (&smbstat_srv_snapshots[idx]);
1132148c5f43SAlan Wright }
1133148c5f43SAlan Wright 
1134148c5f43SAlan Wright /*
1135148c5f43SAlan Wright  * smbstat_usage
1136148c5f43SAlan Wright  *
1137148c5f43SAlan Wright  * Prints out a help message.
1138148c5f43SAlan Wright  */
1139da6c28aaSamw static void
1140148c5f43SAlan Wright smbstat_usage(FILE *fd, int exit_code)
1141da6c28aaSamw {
1142148c5f43SAlan Wright 	(void) fprintf(fd, gettext(SMBSTAT_HELP));
1143148c5f43SAlan Wright 	exit(exit_code);
1144da6c28aaSamw }
1145da6c28aaSamw 
1146148c5f43SAlan Wright /*
1147148c5f43SAlan Wright  * smbstat_fail
1148148c5f43SAlan Wright  *
1149148c5f43SAlan Wright  * Prints out to stderr an error message and exits the process.
1150148c5f43SAlan Wright  */
1151da6c28aaSamw static void
1152da6c28aaSamw smbstat_fail(int do_perror, char *message, ...)
1153da6c28aaSamw {
1154da6c28aaSamw 	va_list args;
1155da6c28aaSamw 
1156da6c28aaSamw 	va_start(args, message);
1157da6c28aaSamw 	(void) fprintf(stderr, gettext("smbstat: "));
1158da6c28aaSamw 	/* LINTED E_SEC_PRINTF_VAR_FMT */
1159da6c28aaSamw 	(void) vfprintf(stderr, message, args);
1160da6c28aaSamw 	va_end(args);
1161da6c28aaSamw 	if (do_perror)
1162da6c28aaSamw 		(void) fprintf(stderr, ": %s", strerror(errno));
1163da6c28aaSamw 	(void) fprintf(stderr, "\n");
1164da6c28aaSamw 	exit(1);
1165da6c28aaSamw }
1166da6c28aaSamw 
1167148c5f43SAlan Wright /*
1168148c5f43SAlan Wright  * smbstat_sub_64
1169148c5f43SAlan Wright  *
1170148c5f43SAlan Wright  * Substract 2 uint64_t and returns a double.
1171148c5f43SAlan Wright  */
1172148c5f43SAlan Wright static double
1173148c5f43SAlan Wright smbstat_sub_64(uint64_t a, uint64_t b)
1174da6c28aaSamw {
1175148c5f43SAlan Wright 	return ((double)(a - b));
1176148c5f43SAlan Wright }
1177da6c28aaSamw 
1178148c5f43SAlan Wright /*
1179148c5f43SAlan Wright  * smbstat_zero
1180148c5f43SAlan Wright  *
1181148c5f43SAlan Wright  * Returns zero if the value passed in is less than 1.
1182148c5f43SAlan Wright  */
1183148c5f43SAlan Wright static double
1184148c5f43SAlan Wright smbstat_zero(double value)
1185148c5f43SAlan Wright {
1186148c5f43SAlan Wright 	if (value < 1)
1187148c5f43SAlan Wright 		value = 0;
1188148c5f43SAlan Wright 	return (value);
1189148c5f43SAlan Wright }
1190148c5f43SAlan Wright 
1191148c5f43SAlan Wright /*
1192148c5f43SAlan Wright  * smbstat_strtoi
1193148c5f43SAlan Wright  *
1194148c5f43SAlan Wright  * Converts a string representing an integer value into its binary value.
1195148c5f43SAlan Wright  * If the conversion fails this routine exits the process.
1196148c5f43SAlan Wright  */
1197148c5f43SAlan Wright static uint_t
1198148c5f43SAlan Wright smbstat_strtoi(char const *val, char *errmsg)
1199148c5f43SAlan Wright {
1200148c5f43SAlan Wright 	char	*end;
1201148c5f43SAlan Wright 	long	tmp;
1202148c5f43SAlan Wright 
1203148c5f43SAlan Wright 	errno = 0;
1204148c5f43SAlan Wright 	tmp = strtol(val, &end, 10);
1205148c5f43SAlan Wright 	if (*end != '\0' || errno)
1206148c5f43SAlan Wright 		smbstat_fail(1, "%s %s", errmsg, val);
1207148c5f43SAlan Wright 	return ((uint_t)tmp);
1208148c5f43SAlan Wright }
1209148c5f43SAlan Wright 
1210148c5f43SAlan Wright /*
1211148c5f43SAlan Wright  * smbstat_termio_init
1212148c5f43SAlan Wright  *
1213148c5f43SAlan Wright  * Determines the size of the terminal associated with the process.
1214148c5f43SAlan Wright  */
1215148c5f43SAlan Wright static void
1216148c5f43SAlan Wright smbstat_termio_init(void)
1217148c5f43SAlan Wright {
1218148c5f43SAlan Wright 	char	*envp;
1219148c5f43SAlan Wright 
1220148c5f43SAlan Wright 	if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &smbstat_ws) != -1) {
1221148c5f43SAlan Wright 		if (smbstat_ws.ws_row == 0) {
1222148c5f43SAlan Wright 			envp = getenv("LINES");
1223148c5f43SAlan Wright 			if (envp != NULL)
1224148c5f43SAlan Wright 				smbstat_ws.ws_row = atoi(envp);
1225148c5f43SAlan Wright 		}
1226148c5f43SAlan Wright 
1227148c5f43SAlan Wright 		if (smbstat_ws.ws_col == 0) {
1228148c5f43SAlan Wright 			envp = getenv("COLUMNS");
1229148c5f43SAlan Wright 			if (envp != NULL)
1230148c5f43SAlan Wright 				smbstat_ws.ws_row = atoi(envp);
1231148c5f43SAlan Wright 		}
1232148c5f43SAlan Wright 	}
1233148c5f43SAlan Wright 	if (smbstat_ws.ws_col == 0)
1234148c5f43SAlan Wright 		smbstat_ws.ws_col = 80;
1235148c5f43SAlan Wright 	if (smbstat_ws.ws_row == 0)
1236148c5f43SAlan Wright 		smbstat_ws.ws_row = 25;
1237148c5f43SAlan Wright }
1238148c5f43SAlan Wright 
1239148c5f43SAlan Wright /*
1240148c5f43SAlan Wright  * smbstat_snapshot_idx_inc
1241148c5f43SAlan Wright  *
1242148c5f43SAlan Wright  * Increments the snapshot index.
1243148c5f43SAlan Wright  */
1244148c5f43SAlan Wright static void
1245148c5f43SAlan Wright smbstat_snapshot_inc_idx(void)
1246148c5f43SAlan Wright {
1247148c5f43SAlan Wright 	smbstat_snapshot_idx++;
1248148c5f43SAlan Wright 	smbstat_snapshot_idx &= SMBSTAT_SNAPSHOT_MASK;
1249da6c28aaSamw }
1250da6c28aaSamw 
1251da6c28aaSamw /*
1252148c5f43SAlan Wright  * smbstat_req_cmp_name
1253148c5f43SAlan Wright  *
1254148c5f43SAlan Wright  * Call back function passed to qsort() when the list of requests must be sorted
1255148c5f43SAlan Wright  * by name.
1256da6c28aaSamw  */
1257148c5f43SAlan Wright static int
1258148c5f43SAlan Wright smbstat_req_cmp_name(const void *obj1, const void *obj2)
1259da6c28aaSamw {
1260148c5f43SAlan Wright 	return (strncasecmp(
1261148c5f43SAlan Wright 	    ((smbstat_req_info_t *)obj1)->ri_name,
1262148c5f43SAlan Wright 	    ((smbstat_req_info_t *)obj2)->ri_name,
1263148c5f43SAlan Wright 	    sizeof (((smbstat_req_info_t *)obj2)->ri_name)));
1264da6c28aaSamw }
1265da6c28aaSamw 
1266148c5f43SAlan Wright /*
1267148c5f43SAlan Wright  * smbstat_req_order
1268148c5f43SAlan Wright  *
1269148c5f43SAlan Wright  * Snapshots the smbsrv module statistics once to get the name of the requests.
1270148c5f43SAlan Wright  * The request list is smbstat_srv_info is then sorted by name or by code
1271148c5f43SAlan Wright  * depending on the boolean smbstat_opt_a.
1272148c5f43SAlan Wright  * The function should be called once during initialization.
1273148c5f43SAlan Wright  */
1274148c5f43SAlan Wright static void
1275148c5f43SAlan Wright smbstat_req_order(void)
1276148c5f43SAlan Wright {
1277a90cf9f2SGordon Ross 	smbstat_srv_snapshot_t  *ss;
1278148c5f43SAlan Wright 	smbstat_req_info_t	*info;
1279148c5f43SAlan Wright 	smb_kstat_req_t		*reqs;
1280148c5f43SAlan Wright 	int			i;
1281148c5f43SAlan Wright 
1282148c5f43SAlan Wright 	smbstat_srv_snapshot();
1283a90cf9f2SGordon Ross 	ss = smbstat_srv_current_snapshot();
1284148c5f43SAlan Wright 
1285a90cf9f2SGordon Ross 	reqs = ss->ss_data.ks_reqs1;
1286a90cf9f2SGordon Ross 	info = smbstat_srv_info.si_reqs1;
1287148c5f43SAlan Wright 	for (i = 0; i < SMB_COM_NUM; i++) {
1288148c5f43SAlan Wright 		(void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1289148c5f43SAlan Wright 		    sizeof (reqs[i].kr_name));
1290148c5f43SAlan Wright 		info[i].ri_opcode = i;
1291148c5f43SAlan Wright 	}
1292148c5f43SAlan Wright 	if (smbstat_opt_n)
1293148c5f43SAlan Wright 		qsort(info, SMB_COM_NUM, sizeof (smbstat_req_info_t),
1294148c5f43SAlan Wright 		    smbstat_req_cmp_name);
1295a90cf9f2SGordon Ross 
1296a90cf9f2SGordon Ross 	reqs = ss->ss_data.ks_reqs2;
1297a90cf9f2SGordon Ross 	info = smbstat_srv_info.si_reqs2;
1298a90cf9f2SGordon Ross 	for (i = 0; i < SMB2__NCMDS; i++) {
1299a90cf9f2SGordon Ross 		(void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1300a90cf9f2SGordon Ross 		    sizeof (reqs[i].kr_name));
1301a90cf9f2SGordon Ross 		info[i].ri_opcode = i;
1302a90cf9f2SGordon Ross 	}
1303a90cf9f2SGordon Ross 	if (smbstat_opt_n)
1304a90cf9f2SGordon Ross 		qsort(info, SMB2__NCMDS, sizeof (smbstat_req_info_t),
1305a90cf9f2SGordon Ross 		    smbstat_req_cmp_name);
1306148c5f43SAlan Wright }
1307148c5f43SAlan Wright 
1308148c5f43SAlan Wright /*
1309148c5f43SAlan Wright  * Return the number of ticks delta between two hrtime_t
1310148c5f43SAlan Wright  * values. Attempt to cater for various kinds of overflow
1311148c5f43SAlan Wright  * in hrtime_t - no matter how improbable.
1312148c5f43SAlan Wright  */
1313148c5f43SAlan Wright static double
1314148c5f43SAlan Wright smbstat_hrtime_delta(hrtime_t old, hrtime_t new)
1315148c5f43SAlan Wright {
1316148c5f43SAlan Wright 	uint64_t	del;
1317148c5f43SAlan Wright 
1318148c5f43SAlan Wright 	if ((new >= old) && (old >= 0L))
1319148c5f43SAlan Wright 		return ((double)(new - old));
1320148c5f43SAlan Wright 	/*
1321148c5f43SAlan Wright 	 * We've overflowed the positive portion of an hrtime_t.
1322148c5f43SAlan Wright 	 */
1323148c5f43SAlan Wright 	if (new < 0L) {
1324148c5f43SAlan Wright 		/*
1325148c5f43SAlan Wright 		 * The new value is negative. Handle the case where the old
1326148c5f43SAlan Wright 		 * value is positive or negative.
1327148c5f43SAlan Wright 		 */
1328148c5f43SAlan Wright 		uint64_t n1;
1329148c5f43SAlan Wright 		uint64_t o1;
1330148c5f43SAlan Wright 
1331148c5f43SAlan Wright 		n1 = -new;
1332148c5f43SAlan Wright 		if (old > 0L)
1333148c5f43SAlan Wright 			return ((double)(n1 - old));
1334148c5f43SAlan Wright 
1335148c5f43SAlan Wright 		o1 = -old;
1336148c5f43SAlan Wright 		del = n1 - o1;
1337148c5f43SAlan Wright 		return ((double)del);
1338148c5f43SAlan Wright 	}
1339148c5f43SAlan Wright 
1340148c5f43SAlan Wright 	/*
1341148c5f43SAlan Wright 	 * Either we've just gone from being negative to positive *or* the last
1342148c5f43SAlan Wright 	 * entry was positive and the new entry is also positive but *less* than
1343148c5f43SAlan Wright 	 * the old entry. This implies we waited quite a few days on a very fast
1344148c5f43SAlan Wright 	 * system between displays.
1345148c5f43SAlan Wright 	 */
1346148c5f43SAlan Wright 	if (old < 0L) {
1347148c5f43SAlan Wright 		uint64_t o2;
1348148c5f43SAlan Wright 		o2 = -old;
1349148c5f43SAlan Wright 		del = UINT64_MAX - o2;
1350148c5f43SAlan Wright 	} else {
1351148c5f43SAlan Wright 		del = UINT64_MAX - old;
1352148c5f43SAlan Wright 	}
1353148c5f43SAlan Wright 	del += new;
1354148c5f43SAlan Wright 	return ((double)del);
1355148c5f43SAlan Wright }
1356148c5f43SAlan Wright 
1357148c5f43SAlan Wright static void *
1358148c5f43SAlan Wright smbstat_zalloc(size_t size)
1359148c5f43SAlan Wright {
1360148c5f43SAlan Wright 	void	*ptr;
1361148c5f43SAlan Wright 
1362148c5f43SAlan Wright 	ptr = umem_zalloc(size, UMEM_DEFAULT);
1363148c5f43SAlan Wright 	if (ptr == NULL)
1364148c5f43SAlan Wright 		smbstat_fail(1,	gettext("out of memory"));
1365148c5f43SAlan Wright 	return (ptr);
1366148c5f43SAlan Wright }
1367148c5f43SAlan Wright 
1368148c5f43SAlan Wright static void
1369148c5f43SAlan Wright smbstat_free(void *ptr, size_t size)
1370da6c28aaSamw {
1371148c5f43SAlan Wright 	umem_free(ptr, size);
1372da6c28aaSamw }
1373