4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * smbstat: Server Message Block File System statistics
29 *
30 * The statistics this CLI displays come from two sources:
31 *
32 * 1) The kernel module 'smbsrv'.
33 * 2) The SMB workers task queue statistics the task queue manager of Solaris
34 * maintains.
35 *
36 * The flow of the code is the following:
37 *
38 *
39 * +----------------+
40 * | Initialization |
41 * +----------------+
42 * |
43 * |
44 * v
86 * previous snapshot.
87 */
88
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <unistd.h>
92 #include <kstat.h>
93 #include <stdarg.h>
94 #include <errno.h>
95 #include <inttypes.h>
96 #include <strings.h>
97 #include <utility.h>
98 #include <libintl.h>
99 #include <zone.h>
100 #include <termios.h>
101 #include <stropts.h>
102 #include <math.h>
103 #include <umem.h>
104 #include <locale.h>
105 #include <smbsrv/smb_kstat.h>
106
107 #if !defined(TEXT_DOMAIN)
108 #define TEXT_DOMAIN "SYS_TEST"
109 #endif /* TEXT_DOMAIN */
110
111 #define SMBSTAT_ID_NO_CPU -1
112 #define SMBSTAT_SNAPSHOT_COUNT 2 /* Must be a power of 2 */
113 #define SMBSTAT_SNAPSHOT_MASK (SMBSTAT_SNAPSHOT_COUNT - 1)
114
115 #define SMBSTAT_HELP \
116 "Usage: smbstat [-acnrtuz] [interval]\n" \
117 " -c: display counters\n" \
118 " -t: display throughput\n" \
119 " -u: display utilization\n" \
120 " -r: display requests\n" \
121 " -a: all the requests (supported and unsupported)\n" \
122 " -z: skip the requests not received\n" \
123 " -n: display in alphabetic order\n" \
124 " interval: refresh cycle in seconds\n"
125
127 #define SMBSRV_COUNTERS_FORMAT "%5d %5d %5d %5d %5d %5d\n"
128
129 #define SMBSRV_THROUGHPUT_BANNER \
130 "\nrbytes/s tbytes/s reqs/s reads/s writes/s\n"
131 #define SMBSRV_THROUGHPUT_FORMAT \
132 "%1.3e %1.3e %1.3e %1.3e %1.3e\n"
133
134 #define SMBSRV_UTILIZATION_BANNER \
135 "\n wcnt rcnt wtime rtime" \
136 " w%% r%% u%% sat usr%% sys%% idle%%\n"
137 #define SMBSRV_UTILIZATION_FORMAT \
138 "%1.3e %1.3e %1.3e %1.3e %3.0f %3.0f %3.0f %s " \
139 "%3.0f %3.0f %3.0f\n"
140
141 #define SMBSRV_REQUESTS_BANNER \
142 "\n%30s code %% rbytes/s tbytes/s req/s rt-mean" \
143 " rt-stddev\n"
144 #define SMBSRV_REQUESTS_FORMAT \
145 "%30s %02X %3.0f %1.3e %1.3e %1.3e %1.3e %1.3e\n"
146
147 typedef enum {
148 CPU_TICKS_IDLE = 0,
149 CPU_TICKS_USER,
150 CPU_TICKS_KERNEL,
151 CPU_TICKS_SENTINEL
152 } cpu_state_idx_t;
153
154 typedef struct smbstat_cpu_snapshot {
155 processorid_t cs_id;
156 int cs_state;
157 uint64_t cs_ticks[CPU_TICKS_SENTINEL];
158 } smbstat_cpu_snapshot_t;
159
160 typedef struct smbstat_srv_snapshot {
161 hrtime_t ss_snaptime;
162 smbsrv_kstats_t ss_data;
163 } smbstat_srv_snapshot_t;
164
165 typedef struct smbstat_wrk_snapshot {
166 uint64_t ws_maxthreads;
167 uint64_t ws_bnalloc;
168 } smbstat_wrk_snapshot_t;
169
170 typedef struct smbstat_req_info {
171 char ri_name[KSTAT_STRLEN];
172 int ri_opcode;
173 double ri_pct;
174 double ri_tbs;
175 double ri_rbs;
176 double ri_rqs;
177 double ri_stddev;
178 double ri_mean;
179 } smbstat_req_info_t;
180
181 typedef struct smbstat_srv_info {
182 double si_hretime;
183 double si_etime;
184 double si_total_nreqs;
185 /*
186 * Counters
187 */
188 uint32_t si_nbt_sess; /* NBT sessions */
189 uint32_t si_tcp_sess; /* TCP sessions */
197 double si_tbs; /* Bytes transmitted / second */
198 double si_rbs; /* Bytes received / second */
199 double si_rqs; /* Requests treated / second */
200 double si_rds; /* Reads treated / second */
201 double si_wrs; /* Writes treated / second */
202 /*
203 * Utilization of the server
204 */
205 double si_wpct; /* */
206 double si_rpct; /* */
207 double si_upct; /* Utilization in % */
208 double si_avw; /* Average number of requests waiting */
209 double si_avr; /* Average number of requests running */
210 double si_wserv; /* Average waiting time */
211 double si_rserv; /* Average running time */
212 boolean_t si_sat;
213 double si_ticks[CPU_TICKS_SENTINEL];
214 /*
215 * Latency & Throughput per request
216 */
217 smbstat_req_info_t si_reqs1[SMB_COM_NUM];
218 smbstat_req_info_t si_reqs2[SMB2__NCMDS];
219 } smbstat_srv_info_t;
220
221 static void smbstat_init(void);
222 static void smbstat_fini(void);
223 static void smbstat_kstat_snapshot(void);
224 static void smbstat_kstat_process(void);
225 static void smbstat_kstat_print(void);
226
227 static void smbstat_print_counters(void);
228 static void smbstat_print_throughput(void);
229 static void smbstat_print_utilization(void);
230 static void smbstat_print_requests(void);
231
232 static void smbstat_cpu_init(void);
233 static void smbstat_cpu_fini(void);
234 static smbstat_cpu_snapshot_t *smbstat_cpu_current_snapshot(void);
235 static smbstat_cpu_snapshot_t *smbstat_cpu_previous_snapshot(void);
236 static void smbstat_cpu_snapshot(void);
237 static void smbstat_cpu_process(void);
238
239 static void smbstat_wrk_init(void);
240 static void smbstat_wrk_fini(void);
241 static void smbstat_wrk_snapshot(void);
242 static void smbstat_wrk_process(void);
243 static smbstat_wrk_snapshot_t *smbstat_wrk_current_snapshot(void);
244
245 static void smbstat_srv_init(void);
246 static void smbstat_srv_fini(void);
247 static void smbstat_srv_snapshot(void);
248 static void smbstat_srv_process(void);
249 static void smbstat_srv_process_counters(smbstat_srv_snapshot_t *);
250 static void smbstat_srv_process_throughput(smbstat_srv_snapshot_t *,
251 smbstat_srv_snapshot_t *);
252 static void smbstat_srv_process_utilization(smbstat_srv_snapshot_t *,
253 smbstat_srv_snapshot_t *);
254 static void smbstat_srv_process_requests(smbstat_srv_snapshot_t *,
255 smbstat_srv_snapshot_t *);
256 static void smbstat_srv_process_one_req(smbstat_req_info_t *,
257 smb_kstat_req_t *, smb_kstat_req_t *, boolean_t);
258
259 static smbstat_srv_snapshot_t *smbstat_srv_current_snapshot(void);
260 static smbstat_srv_snapshot_t *smbstat_srv_previous_snapshot(void);
261
262 static void *smbstat_zalloc(size_t);
263 static void smbstat_free(void *, size_t);
264 static void smbstat_fail(int, char *, ...);
269 static double smbstat_sub_64(uint64_t, uint64_t);
270 static void smbstat_req_order(void);
271 static double smbstat_zero(double);
272 static void smbstat_termio_init(void);
273
274 #pragma does_not_return(smbstat_fail, smbstat_usage)
275
276 static char *smbstat_cpu_states[CPU_TICKS_SENTINEL] = {
277 "cpu_ticks_idle",
278 "cpu_ticks_user",
279 "cpu_ticks_kernel"
280 };
281
282 static boolean_t smbstat_opt_a = B_FALSE; /* all */
283 static boolean_t smbstat_opt_c = B_FALSE; /* counters */
284 static boolean_t smbstat_opt_n = B_FALSE; /* by name */
285 static boolean_t smbstat_opt_u = B_FALSE; /* utilization */
286 static boolean_t smbstat_opt_t = B_FALSE; /* throughput */
287 static boolean_t smbstat_opt_r = B_FALSE; /* requests */
288 static boolean_t smbstat_opt_z = B_FALSE; /* non-zero requests */
289
290 static uint_t smbstat_interval = 0;
291 static long smbstat_nrcpus = 0;
292 static kstat_ctl_t *smbstat_ksc = NULL;
293 static kstat_t *smbstat_srv_ksp = NULL;
294 static kstat_t *smbstat_wrk_ksp = NULL;
295 static struct winsize smbstat_ws;
296 static uint16_t smbstat_rows = 0;
297
298 static int smbstat_snapshot_idx = 0;
299 static smbstat_cpu_snapshot_t *smbstat_cpu_snapshots[SMBSTAT_SNAPSHOT_COUNT];
300 static smbstat_srv_snapshot_t smbstat_srv_snapshots[SMBSTAT_SNAPSHOT_COUNT];
301 static smbstat_wrk_snapshot_t smbstat_wrk_snapshots[SMBSTAT_SNAPSHOT_COUNT];
302 static smbstat_srv_info_t smbstat_srv_info;
303
304 /*
305 * main
306 */
307 int
308 main(int argc, char *argv[])
309 {
310 int c;
311
312 (void) setlocale(LC_ALL, "");
313 (void) textdomain(TEXT_DOMAIN);
314
315 if (is_system_labeled()) {
316 (void) fprintf(stderr,
317 gettext("%s: Trusted Extensions not supported.\n"),
318 argv[0]);
319 return (1);
320 }
321
322 while ((c = getopt(argc, argv, "achnrtuz")) != EOF) {
323 switch (c) {
324 case 'a':
325 smbstat_opt_a = B_TRUE;
326 break;
327 case 'n':
328 smbstat_opt_n = B_TRUE;
329 break;
330 case 'u':
331 smbstat_opt_u = B_TRUE;
332 break;
333 case 'c':
334 smbstat_opt_c = B_TRUE;
335 break;
336 case 'r':
337 smbstat_opt_r = B_TRUE;
338 break;
339 case 't':
340 smbstat_opt_t = B_TRUE;
341 break;
342 case 'z':
343 smbstat_opt_z = B_TRUE;
344 break;
345 case 'h':
346 smbstat_usage(stdout, 0);
347 default:
348 smbstat_usage(stderr, 1);
349 }
350 }
351
352 if (!smbstat_opt_u &&
353 !smbstat_opt_c &&
354 !smbstat_opt_r &&
355 !smbstat_opt_t) {
356 /* Default options when none is specified. */
357 smbstat_opt_u = B_TRUE;
358 smbstat_opt_t = B_TRUE;
359 }
360
361 if (optind < argc) {
362 smbstat_interval =
363 smbstat_strtoi(argv[optind], "invalid count");
364 optind++;
365 }
366
367 if ((argc - optind) > 1)
368 smbstat_usage(stderr, 1);
369
370 (void) atexit(smbstat_fini);
371 smbstat_init();
372 for (;;) {
373 smbstat_kstat_snapshot();
374 smbstat_kstat_process();
375 smbstat_kstat_print();
376 if (smbstat_interval == 0)
377 break;
378 (void) sleep(smbstat_interval);
379 smbstat_snapshot_inc_idx();
380 }
381 return (0);
382 }
383
384 /*
385 * smbstat_init
386 *
387 * Global initialization.
388 */
389 static void
390 smbstat_init(void)
391 {
392 if ((smbstat_ksc = kstat_open()) == NULL)
393 smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat"));
394
395 smbstat_cpu_init();
396 smbstat_srv_init();
397 smbstat_wrk_init();
398 smbstat_req_order();
399 }
400
401 /*
402 * smbstat_fini
403 *
404 * Releases the resources smbstat_init() allocated.
405 */
406 static void
407 smbstat_fini(void)
408 {
409 smbstat_wrk_fini();
410 smbstat_srv_fini();
411 smbstat_cpu_fini();
412 (void) kstat_close(smbstat_ksc);
413 }
414
415 /*
416 * smbstat_kstat_snapshot
417 *
418 * Takes a snapshot of the data.
419 */
420 static void
421 smbstat_kstat_snapshot(void)
422 {
423 smbstat_cpu_snapshot();
424 smbstat_srv_snapshot();
425 smbstat_wrk_snapshot();
426 }
427
428 /*
429 * smbstat_kstat_process
430 */
431 static void
432 smbstat_kstat_process(void)
433 {
434 smbstat_cpu_process();
435 smbstat_srv_process();
436 smbstat_wrk_process();
437 }
438
439 /*
440 * smbstat_kstat_print
441 *
442 * Print the data processed.
443 */
444 static void
445 smbstat_kstat_print(void)
446 {
447 smbstat_termio_init();
448 smbstat_print_counters();
449 smbstat_print_throughput();
450 smbstat_print_utilization();
451 smbstat_print_requests();
452 (void) fflush(stdout);
453 }
454
455 /*
456 * smbstat_print_counters
457 *
458 * Displays the SMB server counters (session, users...).
459 */
460 static void
461 smbstat_print_counters(void)
462 {
463 if (!smbstat_opt_c)
464 return;
465
466 if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_t ||
467 (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
468 (void) printf(SMBSRV_COUNTERS_BANNER);
469 smbstat_rows = 1;
470 }
471
474 smbstat_srv_info.si_tcp_sess,
475 smbstat_srv_info.si_users,
476 smbstat_srv_info.si_trees,
477 smbstat_srv_info.si_files,
478 smbstat_srv_info.si_pipes);
479
480 ++smbstat_rows;
481 }
482 /*
483 * smbstat_print_throughput
484 *
485 * Formats the SMB server throughput output.
486 */
487 static void
488 smbstat_print_throughput(void)
489 {
490 if (!smbstat_opt_t)
491 return;
492
493 if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_c ||
494 (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
495 (void) printf(SMBSRV_THROUGHPUT_BANNER);
496 smbstat_rows = 1;
497 }
498 (void) printf(SMBSRV_THROUGHPUT_FORMAT,
499 smbstat_zero(smbstat_srv_info.si_rbs),
500 smbstat_zero(smbstat_srv_info.si_tbs),
501 smbstat_zero(smbstat_srv_info.si_rqs),
502 smbstat_zero(smbstat_srv_info.si_rds),
503 smbstat_zero(smbstat_srv_info.si_wrs));
504
505 ++smbstat_rows;
506 }
507
508 /*
509 * smbstat_print_utilization
510 */
511 static void
512 smbstat_print_utilization(void)
513 {
514 char *sat;
540 smbstat_srv_info.si_ticks[CPU_TICKS_IDLE]);
541
542 ++smbstat_rows;
543 }
544
545 /*
546 * smbstat_print_requests
547 */
548 static void
549 smbstat_print_requests(void)
550 {
551 smbstat_req_info_t *prq;
552 int i;
553
554 if (!smbstat_opt_r)
555 return;
556
557 (void) printf(SMBSRV_REQUESTS_BANNER, " ");
558
559 prq = smbstat_srv_info.si_reqs1;
560 for (i = 0; i < SMB_COM_NUM; i++) {
561 if (!smbstat_opt_a &&
562 strncmp(prq[i].ri_name, "Invalid", sizeof ("Invalid")) == 0)
563 continue;
564
565 if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
566 (void) printf(SMBSRV_REQUESTS_FORMAT,
567 prq[i].ri_name,
568 prq[i].ri_opcode,
569 smbstat_zero(prq[i].ri_pct),
570 smbstat_zero(prq[i].ri_rbs),
571 smbstat_zero(prq[i].ri_tbs),
572 smbstat_zero(prq[i].ri_rqs),
573 prq[i].ri_mean,
574 prq[i].ri_stddev);
575 }
576 }
577
578 prq = smbstat_srv_info.si_reqs2;
579 for (i = 0; i < SMB2__NCMDS; i++) {
580 if (!smbstat_opt_a && i == SMB2_INVALID_CMD)
581 continue;
582
583 if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
584 (void) printf(SMBSRV_REQUESTS_FORMAT,
585 prq[i].ri_name,
586 prq[i].ri_opcode,
587 smbstat_zero(prq[i].ri_pct),
588 smbstat_zero(prq[i].ri_rbs),
589 smbstat_zero(prq[i].ri_tbs),
590 smbstat_zero(prq[i].ri_rqs),
591 prq[i].ri_mean,
592 prq[i].ri_stddev);
593 }
594 }
595 }
596
597 /*
598 * smbstat_cpu_init
599 */
600 static void
601 smbstat_cpu_init(void)
602 {
603 size_t size;
604 int i;
605
606 smbstat_nrcpus = sysconf(_SC_CPUID_MAX) + 1;
607 size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t);
608
609 for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
610 smbstat_cpu_snapshots[i] = smbstat_zalloc(size);
611 }
612
613 /*
614 * smbstat_cpu_fini
615 */
616 static void
775 smbstat_wrk_snapshot_t *curr;
776
777 curr = smbstat_wrk_current_snapshot();
778
779 if (curr->ws_bnalloc >= curr->ws_maxthreads)
780 smbstat_srv_info.si_sat = B_TRUE;
781 else
782 smbstat_srv_info.si_sat = B_FALSE;
783 }
784
785 /*
786 * smbstat_wrk_current_snapshot
787 */
788 static smbstat_wrk_snapshot_t *
789 smbstat_wrk_current_snapshot(void)
790 {
791 return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]);
792 }
793
794 /*
795 * smbstat_srv_init
796 */
797 static void
798 smbstat_srv_init(void)
799 {
800 smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE,
801 getzoneid(), SMBSRV_KSTAT_STATISTICS);
802 if (smbstat_srv_ksp == NULL)
803 smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n"));
804 }
805
806 /*
807 * smbstat_srv_fini
808 */
809 static void
810 smbstat_srv_fini(void)
811 {
812 smbstat_srv_ksp = NULL;
813 }
814
815 /*
816 * smbstat_srv_snapshot
817 *
818 * Take a snapshot of the smbsrv module statistics.
819 */
820 static void
821 smbstat_srv_snapshot(void)
1015 }
1016 }
1017
1018 /*
1019 * smbstat_srv_process_requests
1020 *
1021 * Processes the data relative to the SMB requests and stores the results in
1022 * the structure smbstat_srv_info.
1023 */
1024 static void
1025 smbstat_srv_process_requests(
1026 smbstat_srv_snapshot_t *curr,
1027 smbstat_srv_snapshot_t *prev)
1028 {
1029 smbstat_req_info_t *info;
1030 smb_kstat_req_t *curr_req;
1031 smb_kstat_req_t *prev_req;
1032 int i, idx;
1033 boolean_t firstcall = (prev->ss_snaptime == 0);
1034
1035 for (i = 0; i < SMB_COM_NUM; i++) {
1036 info = &smbstat_srv_info.si_reqs1[i];
1037 idx = info[i].ri_opcode & 0xFF;
1038 curr_req = &curr->ss_data.ks_reqs1[idx];
1039 prev_req = &prev->ss_data.ks_reqs1[idx];
1040 smbstat_srv_process_one_req(
1041 info, curr_req, prev_req, firstcall);
1042 }
1043
1044 for (i = 0; i < SMB2__NCMDS; i++) {
1045 info = &smbstat_srv_info.si_reqs2[i];
1046 curr_req = &curr->ss_data.ks_reqs2[i];
1047 prev_req = &prev->ss_data.ks_reqs2[i];
1048 smbstat_srv_process_one_req(
1049 info, curr_req, prev_req, firstcall);
1050 }
1051 }
1052
1053 static void
1054 smbstat_srv_process_one_req(
1055 smbstat_req_info_t *info,
1056 smb_kstat_req_t *curr_req,
1057 smb_kstat_req_t *prev_req,
1058 boolean_t firstcall)
1059 {
1060 double nrqs;
1061
1062 nrqs = smbstat_sub_64(curr_req->kr_nreq,
1063 prev_req->kr_nreq);
1064
1082 /* First time. Take the aggregate */
1083 info->ri_stddev =
1084 curr_req->kr_a_stddev;
1085 info->ri_mean = curr_req->kr_a_mean;
1086 } else {
1087 /* Take the differential */
1088 info->ri_stddev =
1089 curr_req->kr_d_stddev;
1090 info->ri_mean = curr_req->kr_d_mean;
1091 }
1092 if (nrqs > 0) {
1093 info->ri_stddev /= nrqs;
1094 info->ri_stddev = sqrt(info->ri_stddev);
1095 } else {
1096 info->ri_stddev = 0;
1097 }
1098 info->ri_stddev /= NANOSEC;
1099 info->ri_mean /= NANOSEC;
1100 }
1101
1102
1103 /*
1104 * smbstat_srv_current_snapshot
1105 *
1106 * Returns the current snapshot.
1107 */
1108 static smbstat_srv_snapshot_t *
1109 smbstat_srv_current_snapshot(void)
1110 {
1111 return (&smbstat_srv_snapshots[smbstat_snapshot_idx]);
1112 }
1113
1114 /*
1115 * smbstat_srv_previous_snapshot
1116 *
1117 * Returns the previous snapshot.
1118 */
1119 static smbstat_srv_snapshot_t *
1120 smbstat_srv_previous_snapshot(void)
1121 {
1122 int idx;
1261 * smbstat_req_order
1262 *
1263 * Snapshots the smbsrv module statistics once to get the name of the requests.
1264 * The request list is smbstat_srv_info is then sorted by name or by code
1265 * depending on the boolean smbstat_opt_a.
1266 * The function should be called once during initialization.
1267 */
1268 static void
1269 smbstat_req_order(void)
1270 {
1271 smbstat_srv_snapshot_t *ss;
1272 smbstat_req_info_t *info;
1273 smb_kstat_req_t *reqs;
1274 int i;
1275
1276 smbstat_srv_snapshot();
1277 ss = smbstat_srv_current_snapshot();
1278
1279 reqs = ss->ss_data.ks_reqs1;
1280 info = smbstat_srv_info.si_reqs1;
1281 for (i = 0; i < SMB_COM_NUM; i++) {
1282 (void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1283 sizeof (reqs[i].kr_name));
1284 info[i].ri_opcode = i;
1285 }
1286 if (smbstat_opt_n)
1287 qsort(info, SMB_COM_NUM, sizeof (smbstat_req_info_t),
1288 smbstat_req_cmp_name);
1289
1290 reqs = ss->ss_data.ks_reqs2;
1291 info = smbstat_srv_info.si_reqs2;
1292 for (i = 0; i < SMB2__NCMDS; i++) {
1293 (void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1294 sizeof (reqs[i].kr_name));
1295 info[i].ri_opcode = i;
1296 }
1297 if (smbstat_opt_n)
1298 qsort(info, SMB2__NCMDS, sizeof (smbstat_req_info_t),
1299 smbstat_req_cmp_name);
1300 }
1301
1302 /*
1303 * Return the number of ticks delta between two hrtime_t
1304 * values. Attempt to cater for various kinds of overflow
1305 * in hrtime_t - no matter how improbable.
1306 */
1307 static double
1308 smbstat_hrtime_delta(hrtime_t old, hrtime_t new)
1309 {
1310 uint64_t del;
1311
1312 if ((new >= old) && (old >= 0L))
1313 return ((double)(new - old));
1314 /*
1315 * We've overflowed the positive portion of an hrtime_t.
1316 */
1317 if (new < 0L) {
1318 /*
|
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * smbstat: Server Message Block File System statistics
29 *
30 * The statistics this CLI displays come from two sources:
31 *
32 * 1) The kernel module 'smbsrv'.
33 * 2) The SMB workers task queue statistics the task queue manager of Solaris
34 * maintains.
35 *
36 * The flow of the code is the following:
37 *
38 *
39 * +----------------+
40 * | Initialization |
41 * +----------------+
42 * |
43 * |
44 * v
86 * previous snapshot.
87 */
88
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <unistd.h>
92 #include <kstat.h>
93 #include <stdarg.h>
94 #include <errno.h>
95 #include <inttypes.h>
96 #include <strings.h>
97 #include <utility.h>
98 #include <libintl.h>
99 #include <zone.h>
100 #include <termios.h>
101 #include <stropts.h>
102 #include <math.h>
103 #include <umem.h>
104 #include <locale.h>
105 #include <smbsrv/smb_kstat.h>
106 #include <smbsrv/smb.h>
107 #include <smbsrv/smb2.h>
108
109 #if !defined(TEXT_DOMAIN)
110 #define TEXT_DOMAIN "SYS_TEST"
111 #endif /* TEXT_DOMAIN */
112
113 #define SMBSTAT_ID_NO_CPU -1
114 #define SMBSTAT_SNAPSHOT_COUNT 2 /* Must be a power of 2 */
115 #define SMBSTAT_SNAPSHOT_MASK (SMBSTAT_SNAPSHOT_COUNT - 1)
116
117 #define SMBSTAT_HELP \
118 "Usage: smbstat [-acnrtuz] [interval]\n" \
119 " -c: display counters\n" \
120 " -t: display throughput\n" \
121 " -u: display utilization\n" \
122 " -r: display requests\n" \
123 " -a: all the requests (supported and unsupported)\n" \
124 " -z: skip the requests not received\n" \
125 " -n: display in alphabetic order\n" \
126 " interval: refresh cycle in seconds\n"
127
129 #define SMBSRV_COUNTERS_FORMAT "%5d %5d %5d %5d %5d %5d\n"
130
131 #define SMBSRV_THROUGHPUT_BANNER \
132 "\nrbytes/s tbytes/s reqs/s reads/s writes/s\n"
133 #define SMBSRV_THROUGHPUT_FORMAT \
134 "%1.3e %1.3e %1.3e %1.3e %1.3e\n"
135
136 #define SMBSRV_UTILIZATION_BANNER \
137 "\n wcnt rcnt wtime rtime" \
138 " w%% r%% u%% sat usr%% sys%% idle%%\n"
139 #define SMBSRV_UTILIZATION_FORMAT \
140 "%1.3e %1.3e %1.3e %1.3e %3.0f %3.0f %3.0f %s " \
141 "%3.0f %3.0f %3.0f\n"
142
143 #define SMBSRV_REQUESTS_BANNER \
144 "\n%30s code %% rbytes/s tbytes/s req/s rt-mean" \
145 " rt-stddev\n"
146 #define SMBSRV_REQUESTS_FORMAT \
147 "%30s %02X %3.0f %1.3e %1.3e %1.3e %1.3e %1.3e\n"
148
149 #define SMBSRV_CLNT_SHARE_BANNER \
150 "%30s rbytes/s tbytes/s req/s rt-mean rt-stddev\n"
151 #define SMBSRV_CLNT_SHARE_FORMAT \
152 "%30s %1.3e %1.3e %1.3e %1.3e %1.3e\n"
153
154
155 typedef enum {
156 CPU_TICKS_IDLE = 0,
157 CPU_TICKS_USER,
158 CPU_TICKS_KERNEL,
159 CPU_TICKS_SENTINEL
160 } cpu_state_idx_t;
161
162 typedef struct smbstat_cpu_snapshot {
163 processorid_t cs_id;
164 int cs_state;
165 uint64_t cs_ticks[CPU_TICKS_SENTINEL];
166 } smbstat_cpu_snapshot_t;
167
168 typedef struct smbstat_srv_snapshot {
169 hrtime_t ss_snaptime;
170 smbsrv_kstats_t ss_data;
171 } smbstat_srv_snapshot_t;
172
173 typedef struct smbstat_wrk_snapshot {
174 uint64_t ws_maxthreads;
175 uint64_t ws_bnalloc;
176 } smbstat_wrk_snapshot_t;
177
178 /* Per-Client or Per-Share statistics. */
179 typedef struct smbstat_clsh_snapshot {
180 hrtime_t cs_snaptime;
181 smbsrv_clsh_kstats_t cs_data;
182 } smbstat_clsh_snapshot_t;
183
184 typedef struct smbstat_req_info {
185 char ri_name[KSTAT_STRLEN];
186 int ri_opcode;
187 double ri_pct;
188 double ri_tbs;
189 double ri_rbs;
190 double ri_rqs;
191 double ri_stddev;
192 double ri_mean;
193 } smbstat_req_info_t;
194
195 typedef struct smbstat_srv_info {
196 double si_hretime;
197 double si_etime;
198 double si_total_nreqs;
199 /*
200 * Counters
201 */
202 uint32_t si_nbt_sess; /* NBT sessions */
203 uint32_t si_tcp_sess; /* TCP sessions */
211 double si_tbs; /* Bytes transmitted / second */
212 double si_rbs; /* Bytes received / second */
213 double si_rqs; /* Requests treated / second */
214 double si_rds; /* Reads treated / second */
215 double si_wrs; /* Writes treated / second */
216 /*
217 * Utilization of the server
218 */
219 double si_wpct; /* */
220 double si_rpct; /* */
221 double si_upct; /* Utilization in % */
222 double si_avw; /* Average number of requests waiting */
223 double si_avr; /* Average number of requests running */
224 double si_wserv; /* Average waiting time */
225 double si_rserv; /* Average running time */
226 boolean_t si_sat;
227 double si_ticks[CPU_TICKS_SENTINEL];
228 /*
229 * Latency & Throughput per request
230 */
231 smbstat_req_info_t si_reqs1[SMBSRV_KS_NREQS1];
232 smbstat_req_info_t si_reqs2[SMBSRV_KS_NREQS2];
233 /*
234 * Latency & Throughput on specified client or share
235 */
236 smbstat_req_info_t si_clsh[SMBSRV_CLSH__NREQ];
237 } smbstat_srv_info_t;
238
239 static void smbstat_init(void);
240 static void smbstat_fini(void);
241 static void smbstat_kstat_snapshot(void);
242 static void smbstat_kstat_process(void);
243 static void smbstat_kstat_print(void);
244
245 static void smbstat_print_counters(void);
246 static void smbstat_print_throughput(void);
247 static void smbstat_print_utilization(void);
248 static void smbstat_print_requests(void);
249 static void smbstat_print_client_or_share(void);
250
251 static void smbstat_cpu_init(void);
252 static void smbstat_cpu_fini(void);
253 static smbstat_cpu_snapshot_t *smbstat_cpu_current_snapshot(void);
254 static smbstat_cpu_snapshot_t *smbstat_cpu_previous_snapshot(void);
255 static void smbstat_cpu_snapshot(void);
256 static void smbstat_cpu_process(void);
257
258 static void smbstat_wrk_init(void);
259 static void smbstat_wrk_fini(void);
260 static void smbstat_wrk_snapshot(void);
261 static void smbstat_wrk_process(void);
262 static smbstat_wrk_snapshot_t *smbstat_wrk_current_snapshot(void);
263
264 static void smbstat_clsh_init(void);
265 static void smbstat_clsh_fini(void);
266 static void smbstat_clsh_snapshot(void);
267 static void smbstat_clsh_process(void);
268 static smbstat_clsh_snapshot_t *smbstat_clsh_current_snapshot(void);
269 static smbstat_clsh_snapshot_t *smbstat_clsh_previous_snapshot(void);
270
271 static void smbstat_srv_init(void);
272 static void smbstat_srv_fini(void);
273 static void smbstat_srv_snapshot(void);
274 static void smbstat_srv_process(void);
275 static void smbstat_srv_process_counters(smbstat_srv_snapshot_t *);
276 static void smbstat_srv_process_throughput(smbstat_srv_snapshot_t *,
277 smbstat_srv_snapshot_t *);
278 static void smbstat_srv_process_utilization(smbstat_srv_snapshot_t *,
279 smbstat_srv_snapshot_t *);
280 static void smbstat_srv_process_requests(smbstat_srv_snapshot_t *,
281 smbstat_srv_snapshot_t *);
282 static void smbstat_srv_process_one_req(smbstat_req_info_t *,
283 smb_kstat_req_t *, smb_kstat_req_t *, boolean_t);
284
285 static smbstat_srv_snapshot_t *smbstat_srv_current_snapshot(void);
286 static smbstat_srv_snapshot_t *smbstat_srv_previous_snapshot(void);
287
288 static void *smbstat_zalloc(size_t);
289 static void smbstat_free(void *, size_t);
290 static void smbstat_fail(int, char *, ...);
295 static double smbstat_sub_64(uint64_t, uint64_t);
296 static void smbstat_req_order(void);
297 static double smbstat_zero(double);
298 static void smbstat_termio_init(void);
299
300 #pragma does_not_return(smbstat_fail, smbstat_usage)
301
302 static char *smbstat_cpu_states[CPU_TICKS_SENTINEL] = {
303 "cpu_ticks_idle",
304 "cpu_ticks_user",
305 "cpu_ticks_kernel"
306 };
307
308 static boolean_t smbstat_opt_a = B_FALSE; /* all */
309 static boolean_t smbstat_opt_c = B_FALSE; /* counters */
310 static boolean_t smbstat_opt_n = B_FALSE; /* by name */
311 static boolean_t smbstat_opt_u = B_FALSE; /* utilization */
312 static boolean_t smbstat_opt_t = B_FALSE; /* throughput */
313 static boolean_t smbstat_opt_r = B_FALSE; /* requests */
314 static boolean_t smbstat_opt_z = B_FALSE; /* non-zero requests */
315 static boolean_t smbstat_opt_C = B_FALSE; /* per-client stats */
316 static boolean_t smbstat_opt_S = B_FALSE; /* per-share stats */
317 static char *smbstat_opt_clsh = NULL; /* -C or -S arg. */
318
319 static uint_t smbstat_interval = 0;
320 static long smbstat_nrcpus = 0;
321 static kstat_ctl_t *smbstat_ksc = NULL;
322 static kstat_t *smbstat_srv_ksp = NULL;
323 static kstat_t *smbstat_wrk_ksp = NULL;
324 static kstat_t *smbstat_clsh_ksp = NULL;
325 static struct winsize smbstat_ws;
326 static uint16_t smbstat_rows = 0;
327
328 static int smbstat_snapshot_idx = 0;
329 static smbstat_cpu_snapshot_t *smbstat_cpu_snapshots[SMBSTAT_SNAPSHOT_COUNT];
330 static smbstat_srv_snapshot_t smbstat_srv_snapshots[SMBSTAT_SNAPSHOT_COUNT];
331 static smbstat_wrk_snapshot_t smbstat_wrk_snapshots[SMBSTAT_SNAPSHOT_COUNT];
332 static smbstat_clsh_snapshot_t smbstat_clsh_snapshots[SMBSTAT_SNAPSHOT_COUNT];
333 static smbstat_srv_info_t smbstat_srv_info;
334
335 /*
336 * main
337 */
338 int
339 main(int argc, char *argv[])
340 {
341 int c;
342
343 (void) setlocale(LC_ALL, "");
344 (void) textdomain(TEXT_DOMAIN);
345
346 if (is_system_labeled()) {
347 (void) fprintf(stderr,
348 gettext("%s: Trusted Extensions not supported.\n"),
349 argv[0]);
350 return (1);
351 }
352
353 while ((c = getopt(argc, argv, "achnrtuzC:S:")) != EOF) {
354 switch (c) {
355 case 'a':
356 smbstat_opt_a = B_TRUE;
357 break;
358 case 'n':
359 smbstat_opt_n = B_TRUE;
360 break;
361 case 'u':
362 smbstat_opt_u = B_TRUE;
363 break;
364 case 'c':
365 smbstat_opt_c = B_TRUE;
366 break;
367 case 'r':
368 smbstat_opt_r = B_TRUE;
369 break;
370 case 't':
371 smbstat_opt_t = B_TRUE;
372 break;
373 case 'z':
374 smbstat_opt_z = B_TRUE;
375 break;
376 case 'C': /* per-client stats. */
377 smbstat_opt_S = B_FALSE;
378 smbstat_opt_C = B_TRUE;
379 smbstat_opt_clsh = optarg;
380 break;
381 case 'S': /* per-share stats. */
382 smbstat_opt_C = B_FALSE;
383 smbstat_opt_S = B_TRUE;
384 smbstat_opt_clsh = optarg;
385 break;
386 case 'h':
387 smbstat_usage(stdout, 0);
388 default:
389 smbstat_usage(stderr, 1);
390 }
391 }
392
393 if (!smbstat_opt_u &&
394 !smbstat_opt_c &&
395 !smbstat_opt_r &&
396 !smbstat_opt_t &&
397 !smbstat_opt_C &&
398 !smbstat_opt_S) {
399 /* Default options when none is specified. */
400 smbstat_opt_u = B_TRUE;
401 smbstat_opt_t = B_TRUE;
402 }
403
404 if (optind < argc) {
405 smbstat_interval =
406 smbstat_strtoi(argv[optind], "invalid count");
407 optind++;
408 }
409
410 if ((argc - optind) > 1)
411 smbstat_usage(stderr, 1);
412
413 (void) atexit(smbstat_fini);
414 smbstat_init();
415 smbstat_req_order();
416 for (;;) {
417 smbstat_kstat_snapshot();
418 smbstat_kstat_process();
419 smbstat_kstat_print();
420 if (smbstat_interval == 0)
421 break;
422 (void) sleep(smbstat_interval);
423 smbstat_snapshot_inc_idx();
424 }
425 return (0);
426 }
427
428 /*
429 * smbstat_init
430 *
431 * Global initialization.
432 */
433 static void
434 smbstat_init(void)
435 {
436 if ((smbstat_ksc = kstat_open()) == NULL)
437 smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat"));
438
439 smbstat_cpu_init();
440 smbstat_srv_init();
441 smbstat_wrk_init();
442 smbstat_clsh_init();
443 }
444
445 /*
446 * smbstat_fini
447 *
448 * Releases the resources smbstat_init() allocated.
449 */
450 static void
451 smbstat_fini(void)
452 {
453 smbstat_clsh_fini();
454 smbstat_wrk_fini();
455 smbstat_srv_fini();
456 smbstat_cpu_fini();
457 (void) kstat_close(smbstat_ksc);
458 }
459
460 /*
461 * smbstat_kstat_snapshot
462 *
463 * Takes a snapshot of the data.
464 */
465 static void
466 smbstat_kstat_snapshot(void)
467 {
468 smbstat_cpu_snapshot();
469 smbstat_srv_snapshot();
470 smbstat_wrk_snapshot();
471 smbstat_clsh_snapshot();
472 }
473
474 /*
475 * smbstat_kstat_process
476 */
477 static void
478 smbstat_kstat_process(void)
479 {
480 smbstat_cpu_process();
481 smbstat_srv_process();
482 smbstat_wrk_process();
483 smbstat_clsh_process();
484 }
485
486 /*
487 * smbstat_kstat_print
488 *
489 * Print the data processed.
490 */
491 static void
492 smbstat_kstat_print(void)
493 {
494 smbstat_termio_init();
495 smbstat_print_counters();
496 smbstat_print_throughput();
497 smbstat_print_utilization();
498 smbstat_print_requests();
499 smbstat_print_client_or_share();
500 (void) fflush(stdout);
501 }
502
503 /*
504 * smbstat_print_counters
505 *
506 * Displays the SMB server counters (session, users...).
507 */
508 static void
509 smbstat_print_counters(void)
510 {
511 if (!smbstat_opt_c)
512 return;
513
514 if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_t ||
515 (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) {
516 (void) printf(SMBSRV_COUNTERS_BANNER);
517 smbstat_rows = 1;
518 }
519
522 smbstat_srv_info.si_tcp_sess,
523 smbstat_srv_info.si_users,
524 smbstat_srv_info.si_trees,
525 smbstat_srv_info.si_files,
526 smbstat_srv_info.si_pipes);
527
528 ++smbstat_rows;
529 }
530 /*
531 * smbstat_print_throughput
532 *
533 * Formats the SMB server throughput output.
534 */
535 static void
536 smbstat_print_throughput(void)
537 {
538 if (!smbstat_opt_t)
539 return;
540
541 if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_c ||
542 smbstat_opt_C || smbstat_opt_S || (smbstat_rows == 0) ||
543 (smbstat_rows >= smbstat_ws.ws_row)) {
544 (void) printf(SMBSRV_THROUGHPUT_BANNER);
545 smbstat_rows = 1;
546 }
547 (void) printf(SMBSRV_THROUGHPUT_FORMAT,
548 smbstat_zero(smbstat_srv_info.si_rbs),
549 smbstat_zero(smbstat_srv_info.si_tbs),
550 smbstat_zero(smbstat_srv_info.si_rqs),
551 smbstat_zero(smbstat_srv_info.si_rds),
552 smbstat_zero(smbstat_srv_info.si_wrs));
553
554 ++smbstat_rows;
555 }
556
557 /*
558 * smbstat_print_utilization
559 */
560 static void
561 smbstat_print_utilization(void)
562 {
563 char *sat;
589 smbstat_srv_info.si_ticks[CPU_TICKS_IDLE]);
590
591 ++smbstat_rows;
592 }
593
594 /*
595 * smbstat_print_requests
596 */
597 static void
598 smbstat_print_requests(void)
599 {
600 smbstat_req_info_t *prq;
601 int i;
602
603 if (!smbstat_opt_r)
604 return;
605
606 (void) printf(SMBSRV_REQUESTS_BANNER, " ");
607
608 prq = smbstat_srv_info.si_reqs1;
609 for (i = 0; i < SMBSRV_KS_NREQS1; i++) {
610 if (!smbstat_opt_a &&
611 strncmp(prq[i].ri_name, "Invalid", sizeof ("Invalid")) == 0)
612 continue;
613
614 if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
615 (void) printf(SMBSRV_REQUESTS_FORMAT,
616 prq[i].ri_name,
617 prq[i].ri_opcode,
618 smbstat_zero(prq[i].ri_pct),
619 smbstat_zero(prq[i].ri_rbs),
620 smbstat_zero(prq[i].ri_tbs),
621 smbstat_zero(prq[i].ri_rqs),
622 prq[i].ri_mean,
623 prq[i].ri_stddev);
624 }
625 }
626
627 prq = smbstat_srv_info.si_reqs2;
628 for (i = 0; i < SMBSRV_KS_NREQS2; i++) {
629 if (!smbstat_opt_a && i == SMB2_INVALID_CMD)
630 continue;
631
632 if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
633 (void) printf(SMBSRV_REQUESTS_FORMAT,
634 prq[i].ri_name,
635 prq[i].ri_opcode,
636 smbstat_zero(prq[i].ri_pct),
637 smbstat_zero(prq[i].ri_rbs),
638 smbstat_zero(prq[i].ri_tbs),
639 smbstat_zero(prq[i].ri_rqs),
640 prq[i].ri_mean,
641 prq[i].ri_stddev);
642 }
643 }
644 }
645
646 static void
647 smbstat_print_client_or_share(void)
648 {
649 smbstat_req_info_t *prq;
650 int idx;
651
652 if (smbstat_opt_clsh == NULL)
653 return;
654
655 (void) printf(SMBSRV_CLNT_SHARE_BANNER, " ");
656
657 prq = &smbstat_srv_info.si_clsh[0];
658
659 for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++, prq++) {
660 (void) printf(SMBSRV_CLNT_SHARE_FORMAT,
661 prq->ri_name,
662 smbstat_zero(prq->ri_rbs),
663 smbstat_zero(prq->ri_tbs),
664 smbstat_zero(prq->ri_rqs),
665 prq->ri_mean,
666 prq->ri_stddev);
667 }
668 }
669
670
671 /*
672 * smbstat_cpu_init
673 */
674 static void
675 smbstat_cpu_init(void)
676 {
677 size_t size;
678 int i;
679
680 smbstat_nrcpus = sysconf(_SC_CPUID_MAX) + 1;
681 size = smbstat_nrcpus * sizeof (smbstat_cpu_snapshot_t);
682
683 for (i = 0; i < SMBSTAT_SNAPSHOT_COUNT; i++)
684 smbstat_cpu_snapshots[i] = smbstat_zalloc(size);
685 }
686
687 /*
688 * smbstat_cpu_fini
689 */
690 static void
849 smbstat_wrk_snapshot_t *curr;
850
851 curr = smbstat_wrk_current_snapshot();
852
853 if (curr->ws_bnalloc >= curr->ws_maxthreads)
854 smbstat_srv_info.si_sat = B_TRUE;
855 else
856 smbstat_srv_info.si_sat = B_FALSE;
857 }
858
859 /*
860 * smbstat_wrk_current_snapshot
861 */
862 static smbstat_wrk_snapshot_t *
863 smbstat_wrk_current_snapshot(void)
864 {
865 return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]);
866 }
867
868 /*
869 * smbstat_clsh_init
870 *
871 * Lookup the kstat for the client or share specified.
872 * The names for these look like:
873 * session (a.k.a. client)
874 * cl/$IPADDR and instance ss->s_kid
875 * share
876 * sh/sharename (always instance 0)
877 *
878 * These will look like: smbsrv:0:sh/myshare
879 * or smbsrv:N:cl/10.10.0.2
880 */
881 static void
882 smbstat_clsh_init(void)
883 {
884 static const char *kr_names[] = SMBSRV_CLSH__NAMES;
885 char ks_name[KSTAT_STRLEN];
886 char *prefix = "";
887 smbstat_req_info_t *info;
888 int instance = -1;
889 int i;
890
891 if (smbstat_opt_clsh == NULL)
892 return;
893
894 /*
895 * Currently we don't take an instance so this will return data
896 * from the first or the only client from the IP address specified.
897 */
898 if (smbstat_opt_C)
899 prefix = "cl";
900 if (smbstat_opt_S)
901 prefix = "sh";
902 (void) snprintf(ks_name, sizeof (ks_name),
903 "%s/%s", prefix, smbstat_opt_clsh);
904
905 smbstat_clsh_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE,
906 instance, ks_name);
907 if (smbstat_clsh_ksp == NULL) {
908 smbstat_fail(1, gettext("cannot retrieve smbsrv %s kstat\n"),
909 ks_name);
910 }
911
912 info = smbstat_srv_info.si_clsh;
913 for (i = 0; i < SMBSRV_CLSH__NREQ; i++) {
914 (void) strlcpy(info[i].ri_name, kr_names[i],
915 sizeof (info[i].ri_name));
916 }
917 }
918
919 static void
920 smbstat_clsh_fini(void)
921 {
922 smbstat_clsh_ksp = NULL;
923 }
924
925 /*
926 * smbstat_clsh_snapshot
927 */
928 static void
929 smbstat_clsh_snapshot(void)
930 {
931 smbstat_clsh_snapshot_t *curr;
932
933 if (smbstat_clsh_ksp == NULL)
934 return;
935
936 curr = smbstat_clsh_current_snapshot();
937
938 if ((kstat_read(smbstat_ksc, smbstat_clsh_ksp, NULL) == -1) ||
939 (smbstat_clsh_ksp->ks_data_size != sizeof (curr->cs_data)))
940 smbstat_fail(1, gettext("kstat_read('%s') failed"),
941 smbstat_clsh_ksp->ks_name);
942
943 curr->cs_snaptime = smbstat_clsh_ksp->ks_snaptime;
944
945 bcopy(smbstat_clsh_ksp->ks_data, &curr->cs_data,
946 sizeof (curr->cs_data));
947 }
948
949 /*
950 * smbstat_clsh_process
951 */
952 static void
953 smbstat_clsh_process(void)
954 {
955 smbstat_clsh_snapshot_t *curr, *prev;
956 boolean_t firstcall;
957 int idx;
958
959 curr = smbstat_clsh_current_snapshot();
960 prev = smbstat_clsh_previous_snapshot();
961 firstcall = (prev->cs_snaptime == 0);
962
963
964 for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++) {
965 smbstat_srv_process_one_req(
966 &smbstat_srv_info.si_clsh[idx],
967 &curr->cs_data.ks_clsh[idx],
968 &prev->cs_data.ks_clsh[idx],
969 firstcall);
970 }
971 }
972
973 /*
974 * smbstat_clsh_current_snapshot
975 */
976 static smbstat_clsh_snapshot_t *
977 smbstat_clsh_current_snapshot(void)
978 {
979 return (&smbstat_clsh_snapshots[smbstat_snapshot_idx]);
980 }
981
982 static smbstat_clsh_snapshot_t *
983 smbstat_clsh_previous_snapshot(void)
984 {
985 int idx;
986
987 idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK;
988 return (&smbstat_clsh_snapshots[idx]);
989 }
990
991 /*
992 * smbstat_srv_init
993 */
994 static void
995 smbstat_srv_init(void)
996 {
997 smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE,
998 -1, SMBSRV_KSTAT_STATISTICS);
999 if (smbstat_srv_ksp == NULL)
1000 smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n"));
1001 }
1002
1003 /*
1004 * smbstat_srv_fini
1005 */
1006 static void
1007 smbstat_srv_fini(void)
1008 {
1009 smbstat_srv_ksp = NULL;
1010 }
1011
1012 /*
1013 * smbstat_srv_snapshot
1014 *
1015 * Take a snapshot of the smbsrv module statistics.
1016 */
1017 static void
1018 smbstat_srv_snapshot(void)
1212 }
1213 }
1214
1215 /*
1216 * smbstat_srv_process_requests
1217 *
1218 * Processes the data relative to the SMB requests and stores the results in
1219 * the structure smbstat_srv_info.
1220 */
1221 static void
1222 smbstat_srv_process_requests(
1223 smbstat_srv_snapshot_t *curr,
1224 smbstat_srv_snapshot_t *prev)
1225 {
1226 smbstat_req_info_t *info;
1227 smb_kstat_req_t *curr_req;
1228 smb_kstat_req_t *prev_req;
1229 int i, idx;
1230 boolean_t firstcall = (prev->ss_snaptime == 0);
1231
1232 for (i = 0; i < SMBSRV_KS_NREQS1; i++) {
1233 info = &smbstat_srv_info.si_reqs1[i];
1234 idx = info[i].ri_opcode & 0xFF;
1235 curr_req = &curr->ss_data.ks_reqs1[idx];
1236 prev_req = &prev->ss_data.ks_reqs1[idx];
1237 smbstat_srv_process_one_req(
1238 info, curr_req, prev_req, firstcall);
1239 }
1240
1241 for (i = 0; i < SMBSRV_KS_NREQS2; i++) {
1242 info = &smbstat_srv_info.si_reqs2[i];
1243 curr_req = &curr->ss_data.ks_reqs2[i];
1244 prev_req = &prev->ss_data.ks_reqs2[i];
1245 smbstat_srv_process_one_req(
1246 info, curr_req, prev_req, firstcall);
1247 }
1248 }
1249
1250 static void
1251 smbstat_srv_process_one_req(
1252 smbstat_req_info_t *info,
1253 smb_kstat_req_t *curr_req,
1254 smb_kstat_req_t *prev_req,
1255 boolean_t firstcall)
1256 {
1257 double nrqs;
1258
1259 nrqs = smbstat_sub_64(curr_req->kr_nreq,
1260 prev_req->kr_nreq);
1261
1279 /* First time. Take the aggregate */
1280 info->ri_stddev =
1281 curr_req->kr_a_stddev;
1282 info->ri_mean = curr_req->kr_a_mean;
1283 } else {
1284 /* Take the differential */
1285 info->ri_stddev =
1286 curr_req->kr_d_stddev;
1287 info->ri_mean = curr_req->kr_d_mean;
1288 }
1289 if (nrqs > 0) {
1290 info->ri_stddev /= nrqs;
1291 info->ri_stddev = sqrt(info->ri_stddev);
1292 } else {
1293 info->ri_stddev = 0;
1294 }
1295 info->ri_stddev /= NANOSEC;
1296 info->ri_mean /= NANOSEC;
1297 }
1298
1299 /*
1300 * smbstat_srv_current_snapshot
1301 *
1302 * Returns the current snapshot.
1303 */
1304 static smbstat_srv_snapshot_t *
1305 smbstat_srv_current_snapshot(void)
1306 {
1307 return (&smbstat_srv_snapshots[smbstat_snapshot_idx]);
1308 }
1309
1310 /*
1311 * smbstat_srv_previous_snapshot
1312 *
1313 * Returns the previous snapshot.
1314 */
1315 static smbstat_srv_snapshot_t *
1316 smbstat_srv_previous_snapshot(void)
1317 {
1318 int idx;
1457 * smbstat_req_order
1458 *
1459 * Snapshots the smbsrv module statistics once to get the name of the requests.
1460 * The request list is smbstat_srv_info is then sorted by name or by code
1461 * depending on the boolean smbstat_opt_a.
1462 * The function should be called once during initialization.
1463 */
1464 static void
1465 smbstat_req_order(void)
1466 {
1467 smbstat_srv_snapshot_t *ss;
1468 smbstat_req_info_t *info;
1469 smb_kstat_req_t *reqs;
1470 int i;
1471
1472 smbstat_srv_snapshot();
1473 ss = smbstat_srv_current_snapshot();
1474
1475 reqs = ss->ss_data.ks_reqs1;
1476 info = smbstat_srv_info.si_reqs1;
1477 for (i = 0; i < SMBSRV_KS_NREQS1; i++) {
1478 (void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1479 sizeof (reqs[i].kr_name));
1480 info[i].ri_opcode = i;
1481 }
1482 if (smbstat_opt_n)
1483 qsort(info, SMBSRV_KS_NREQS1, sizeof (smbstat_req_info_t),
1484 smbstat_req_cmp_name);
1485
1486 reqs = ss->ss_data.ks_reqs2;
1487 info = smbstat_srv_info.si_reqs2;
1488 for (i = 0; i < SMBSRV_KS_NREQS2; i++) {
1489 (void) strlcpy(info[i].ri_name, reqs[i].kr_name,
1490 sizeof (reqs[i].kr_name));
1491 info[i].ri_opcode = i;
1492 }
1493 if (smbstat_opt_n)
1494 qsort(info, SMBSRV_KS_NREQS2, sizeof (smbstat_req_info_t),
1495 smbstat_req_cmp_name);
1496 }
1497
1498 /*
1499 * Return the number of ticks delta between two hrtime_t
1500 * values. Attempt to cater for various kinds of overflow
1501 * in hrtime_t - no matter how improbable.
1502 */
1503 static double
1504 smbstat_hrtime_delta(hrtime_t old, hrtime_t new)
1505 {
1506 uint64_t del;
1507
1508 if ((new >= old) && (old >= 0L))
1509 return ((double)(new - old));
1510 /*
1511 * We've overflowed the positive portion of an hrtime_t.
1512 */
1513 if (new < 0L) {
1514 /*
|