Print this page
NEX-5175 want SMB statistics separately for reads, writes, other
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-5197 smbstat copying out wrong stats for per-share or per-client
Reviewed by: Gordon Ross <gwr@nexenta.com>
NEX-4811 SMB needs to export a header for kstats
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Jeffry Molanus <jeffry.molanus@nexenta.com>
NEX-4313 want iops, bandwidth, and latency kstats for smb
Portions contributed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
Reviewed by: Gordon Ross <gordon.ross@nexenta.com>
5606 support build with binutils 2.25
Reviewed by: Josef 'Jeff' Sipek <josef.sipek@nexenta.com>
Reviewed by: Marcel Telka <marcel.telka@nexenta.com>
Reviewed by: Piotr Jasiukajtis <estibi@me.com>
Reviewed by: Richard Lowe <richlowe@richlowe.net>
NEX-3273 smbstat delays its output when redirected to a file
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
NEX-2705 smbstat output may lie about sat and show only zero for writes/s
SMB-78 smbstat should show SMB2 activity
SMB-11 SMB2 message parse & dispatch
SMB-12 SMB2 Negotiate Protocol
SMB-13 SMB2 Session Setup
SMB-14 SMB2 Logoff
SMB-15 SMB2 Tree Connect
SMB-16 SMB2 Tree Disconnect
SMB-17 SMB2 Create
SMB-18 SMB2 Close
SMB-19 SMB2 Flush
SMB-20 SMB2 Read
SMB-21 SMB2 Write
SMB-22 SMB2 Lock/Unlock
SMB-23 SMB2 Ioctl
SMB-24 SMB2 Cancel
SMB-25 SMB2 Echo
SMB-26 SMB2 Query Dir
SMB-27 SMB2 Change Notify
SMB-28 SMB2 Query Info
SMB-29 SMB2 Set Info
SMB-30 SMB2 Oplocks
SMB-53 SMB2 Create Context options
(SMB2 code review cleanup 1, 2, 3)
SMB-65 SMB server in non-global zones (data structure changes)
Many things move to the smb_server_t object, and
many functions gain an sv arg (which server).


   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                 /*