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).

*** 19,29 **** * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2015 Nexenta Systems, Inc. All rights reserved. */ /* * smbstat: Server Message Block File System statistics * --- 19,29 ---- * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. ! * Copyright 2016 Nexenta Systems, Inc. All rights reserved. */ /* * smbstat: Server Message Block File System statistics *
*** 101,110 **** --- 101,112 ---- #include <stropts.h> #include <math.h> #include <umem.h> #include <locale.h> #include <smbsrv/smb_kstat.h> + #include <smbsrv/smb.h> + #include <smbsrv/smb2.h> #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SYS_TEST" #endif /* TEXT_DOMAIN */
*** 142,151 **** --- 144,159 ---- "\n%30s code %% rbytes/s tbytes/s req/s rt-mean" \ " rt-stddev\n" #define SMBSRV_REQUESTS_FORMAT \ "%30s %02X %3.0f %1.3e %1.3e %1.3e %1.3e %1.3e\n" + #define SMBSRV_CLNT_SHARE_BANNER \ + "%30s rbytes/s tbytes/s req/s rt-mean rt-stddev\n" + #define SMBSRV_CLNT_SHARE_FORMAT \ + "%30s %1.3e %1.3e %1.3e %1.3e %1.3e\n" + + typedef enum { CPU_TICKS_IDLE = 0, CPU_TICKS_USER, CPU_TICKS_KERNEL, CPU_TICKS_SENTINEL
*** 165,174 **** --- 173,188 ---- typedef struct smbstat_wrk_snapshot { uint64_t ws_maxthreads; uint64_t ws_bnalloc; } smbstat_wrk_snapshot_t; + /* Per-Client or Per-Share statistics. */ + typedef struct smbstat_clsh_snapshot { + hrtime_t cs_snaptime; + smbsrv_clsh_kstats_t cs_data; + } smbstat_clsh_snapshot_t; + typedef struct smbstat_req_info { char ri_name[KSTAT_STRLEN]; int ri_opcode; double ri_pct; double ri_tbs;
*** 212,223 **** boolean_t si_sat; double si_ticks[CPU_TICKS_SENTINEL]; /* * Latency & Throughput per request */ ! smbstat_req_info_t si_reqs1[SMB_COM_NUM]; ! smbstat_req_info_t si_reqs2[SMB2__NCMDS]; } smbstat_srv_info_t; static void smbstat_init(void); static void smbstat_fini(void); static void smbstat_kstat_snapshot(void); --- 226,241 ---- boolean_t si_sat; double si_ticks[CPU_TICKS_SENTINEL]; /* * Latency & Throughput per request */ ! smbstat_req_info_t si_reqs1[SMBSRV_KS_NREQS1]; ! smbstat_req_info_t si_reqs2[SMBSRV_KS_NREQS2]; ! /* ! * Latency & Throughput on specified client or share ! */ ! smbstat_req_info_t si_clsh[SMBSRV_CLSH__NREQ]; } smbstat_srv_info_t; static void smbstat_init(void); static void smbstat_fini(void); static void smbstat_kstat_snapshot(void);
*** 226,235 **** --- 244,254 ---- static void smbstat_print_counters(void); static void smbstat_print_throughput(void); static void smbstat_print_utilization(void); static void smbstat_print_requests(void); + static void smbstat_print_client_or_share(void); static void smbstat_cpu_init(void); static void smbstat_cpu_fini(void); static smbstat_cpu_snapshot_t *smbstat_cpu_current_snapshot(void); static smbstat_cpu_snapshot_t *smbstat_cpu_previous_snapshot(void);
*** 240,249 **** --- 259,275 ---- static void smbstat_wrk_fini(void); static void smbstat_wrk_snapshot(void); static void smbstat_wrk_process(void); static smbstat_wrk_snapshot_t *smbstat_wrk_current_snapshot(void); + static void smbstat_clsh_init(void); + static void smbstat_clsh_fini(void); + static void smbstat_clsh_snapshot(void); + static void smbstat_clsh_process(void); + static smbstat_clsh_snapshot_t *smbstat_clsh_current_snapshot(void); + static smbstat_clsh_snapshot_t *smbstat_clsh_previous_snapshot(void); + static void smbstat_srv_init(void); static void smbstat_srv_fini(void); static void smbstat_srv_snapshot(void); static void smbstat_srv_process(void); static void smbstat_srv_process_counters(smbstat_srv_snapshot_t *);
*** 284,306 **** --- 310,337 ---- static boolean_t smbstat_opt_n = B_FALSE; /* by name */ static boolean_t smbstat_opt_u = B_FALSE; /* utilization */ static boolean_t smbstat_opt_t = B_FALSE; /* throughput */ static boolean_t smbstat_opt_r = B_FALSE; /* requests */ static boolean_t smbstat_opt_z = B_FALSE; /* non-zero requests */ + static boolean_t smbstat_opt_C = B_FALSE; /* per-client stats */ + static boolean_t smbstat_opt_S = B_FALSE; /* per-share stats */ + static char *smbstat_opt_clsh = NULL; /* -C or -S arg. */ static uint_t smbstat_interval = 0; static long smbstat_nrcpus = 0; static kstat_ctl_t *smbstat_ksc = NULL; static kstat_t *smbstat_srv_ksp = NULL; static kstat_t *smbstat_wrk_ksp = NULL; + static kstat_t *smbstat_clsh_ksp = NULL; static struct winsize smbstat_ws; static uint16_t smbstat_rows = 0; static int smbstat_snapshot_idx = 0; static smbstat_cpu_snapshot_t *smbstat_cpu_snapshots[SMBSTAT_SNAPSHOT_COUNT]; static smbstat_srv_snapshot_t smbstat_srv_snapshots[SMBSTAT_SNAPSHOT_COUNT]; static smbstat_wrk_snapshot_t smbstat_wrk_snapshots[SMBSTAT_SNAPSHOT_COUNT]; + static smbstat_clsh_snapshot_t smbstat_clsh_snapshots[SMBSTAT_SNAPSHOT_COUNT]; static smbstat_srv_info_t smbstat_srv_info; /* * main */
*** 317,327 **** gettext("%s: Trusted Extensions not supported.\n"), argv[0]); return (1); } ! while ((c = getopt(argc, argv, "achnrtuz")) != EOF) { switch (c) { case 'a': smbstat_opt_a = B_TRUE; break; case 'n': --- 348,358 ---- gettext("%s: Trusted Extensions not supported.\n"), argv[0]); return (1); } ! while ((c = getopt(argc, argv, "achnrtuzC:S:")) != EOF) { switch (c) { case 'a': smbstat_opt_a = B_TRUE; break; case 'n':
*** 340,349 **** --- 371,390 ---- smbstat_opt_t = B_TRUE; break; case 'z': smbstat_opt_z = B_TRUE; break; + case 'C': /* per-client stats. */ + smbstat_opt_S = B_FALSE; + smbstat_opt_C = B_TRUE; + smbstat_opt_clsh = optarg; + break; + case 'S': /* per-share stats. */ + smbstat_opt_C = B_FALSE; + smbstat_opt_S = B_TRUE; + smbstat_opt_clsh = optarg; + break; case 'h': smbstat_usage(stdout, 0); default: smbstat_usage(stderr, 1); }
*** 350,360 **** } if (!smbstat_opt_u && !smbstat_opt_c && !smbstat_opt_r && ! !smbstat_opt_t) { /* Default options when none is specified. */ smbstat_opt_u = B_TRUE; smbstat_opt_t = B_TRUE; } --- 391,403 ---- } if (!smbstat_opt_u && !smbstat_opt_c && !smbstat_opt_r && ! !smbstat_opt_t && ! !smbstat_opt_C && ! !smbstat_opt_S) { /* Default options when none is specified. */ smbstat_opt_u = B_TRUE; smbstat_opt_t = B_TRUE; }
*** 367,376 **** --- 410,420 ---- if ((argc - optind) > 1) smbstat_usage(stderr, 1); (void) atexit(smbstat_fini); smbstat_init(); + smbstat_req_order(); for (;;) { smbstat_kstat_snapshot(); smbstat_kstat_process(); smbstat_kstat_print(); if (smbstat_interval == 0)
*** 393,403 **** smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat")); smbstat_cpu_init(); smbstat_srv_init(); smbstat_wrk_init(); ! smbstat_req_order(); } /* * smbstat_fini * --- 437,447 ---- smbstat_fail(1, gettext("kstat_open(): can't open /dev/kstat")); smbstat_cpu_init(); smbstat_srv_init(); smbstat_wrk_init(); ! smbstat_clsh_init(); } /* * smbstat_fini *
*** 404,413 **** --- 448,458 ---- * Releases the resources smbstat_init() allocated. */ static void smbstat_fini(void) { + smbstat_clsh_fini(); smbstat_wrk_fini(); smbstat_srv_fini(); smbstat_cpu_fini(); (void) kstat_close(smbstat_ksc); }
*** 421,430 **** --- 466,476 ---- smbstat_kstat_snapshot(void) { smbstat_cpu_snapshot(); smbstat_srv_snapshot(); smbstat_wrk_snapshot(); + smbstat_clsh_snapshot(); } /* * smbstat_kstat_process */
*** 432,441 **** --- 478,488 ---- smbstat_kstat_process(void) { smbstat_cpu_process(); smbstat_srv_process(); smbstat_wrk_process(); + smbstat_clsh_process(); } /* * smbstat_kstat_print *
*** 447,456 **** --- 494,504 ---- smbstat_termio_init(); smbstat_print_counters(); smbstat_print_throughput(); smbstat_print_utilization(); smbstat_print_requests(); + smbstat_print_client_or_share(); (void) fflush(stdout); } /* * smbstat_print_counters
*** 489,499 **** { if (!smbstat_opt_t) return; if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_c || ! (smbstat_rows == 0) || (smbstat_rows >= smbstat_ws.ws_row)) { (void) printf(SMBSRV_THROUGHPUT_BANNER); smbstat_rows = 1; } (void) printf(SMBSRV_THROUGHPUT_FORMAT, smbstat_zero(smbstat_srv_info.si_rbs), --- 537,548 ---- { if (!smbstat_opt_t) return; if (smbstat_opt_u || smbstat_opt_r || smbstat_opt_c || ! smbstat_opt_C || smbstat_opt_S || (smbstat_rows == 0) || ! (smbstat_rows >= smbstat_ws.ws_row)) { (void) printf(SMBSRV_THROUGHPUT_BANNER); smbstat_rows = 1; } (void) printf(SMBSRV_THROUGHPUT_FORMAT, smbstat_zero(smbstat_srv_info.si_rbs),
*** 555,565 **** return; (void) printf(SMBSRV_REQUESTS_BANNER, " "); prq = smbstat_srv_info.si_reqs1; ! for (i = 0; i < SMB_COM_NUM; i++) { if (!smbstat_opt_a && strncmp(prq[i].ri_name, "Invalid", sizeof ("Invalid")) == 0) continue; if (!smbstat_opt_z || (prq[i].ri_pct != 0)) { --- 604,614 ---- return; (void) printf(SMBSRV_REQUESTS_BANNER, " "); prq = smbstat_srv_info.si_reqs1; ! for (i = 0; i < SMBSRV_KS_NREQS1; i++) { if (!smbstat_opt_a && strncmp(prq[i].ri_name, "Invalid", sizeof ("Invalid")) == 0) continue; if (!smbstat_opt_z || (prq[i].ri_pct != 0)) {
*** 574,584 **** prq[i].ri_stddev); } } prq = smbstat_srv_info.si_reqs2; ! for (i = 0; i < SMB2__NCMDS; i++) { if (!smbstat_opt_a && i == SMB2_INVALID_CMD) continue; if (!smbstat_opt_z || (prq[i].ri_pct != 0)) { (void) printf(SMBSRV_REQUESTS_FORMAT, --- 623,633 ---- prq[i].ri_stddev); } } prq = smbstat_srv_info.si_reqs2; ! for (i = 0; i < SMBSRV_KS_NREQS2; i++) { if (!smbstat_opt_a && i == SMB2_INVALID_CMD) continue; if (!smbstat_opt_z || (prq[i].ri_pct != 0)) { (void) printf(SMBSRV_REQUESTS_FORMAT,
*** 592,601 **** --- 641,675 ---- prq[i].ri_stddev); } } } + static void + smbstat_print_client_or_share(void) + { + smbstat_req_info_t *prq; + int idx; + + if (smbstat_opt_clsh == NULL) + return; + + (void) printf(SMBSRV_CLNT_SHARE_BANNER, " "); + + prq = &smbstat_srv_info.si_clsh[0]; + + for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++, prq++) { + (void) printf(SMBSRV_CLNT_SHARE_FORMAT, + prq->ri_name, + smbstat_zero(prq->ri_rbs), + smbstat_zero(prq->ri_tbs), + smbstat_zero(prq->ri_rqs), + prq->ri_mean, + prq->ri_stddev); + } + } + + /* * smbstat_cpu_init */ static void smbstat_cpu_init(void)
*** 790,806 **** { return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]); } /* * smbstat_srv_init */ static void smbstat_srv_init(void) { smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE, ! getzoneid(), SMBSRV_KSTAT_STATISTICS); if (smbstat_srv_ksp == NULL) smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n")); } /* --- 864,1003 ---- { return (&smbstat_wrk_snapshots[smbstat_snapshot_idx]); } /* + * smbstat_clsh_init + * + * Lookup the kstat for the client or share specified. + * The names for these look like: + * session (a.k.a. client) + * cl/$IPADDR and instance ss->s_kid + * share + * sh/sharename (always instance 0) + * + * These will look like: smbsrv:0:sh/myshare + * or smbsrv:N:cl/10.10.0.2 + */ + static void + smbstat_clsh_init(void) + { + static const char *kr_names[] = SMBSRV_CLSH__NAMES; + char ks_name[KSTAT_STRLEN]; + char *prefix = ""; + smbstat_req_info_t *info; + int instance = -1; + int i; + + if (smbstat_opt_clsh == NULL) + return; + + /* + * Currently we don't take an instance so this will return data + * from the first or the only client from the IP address specified. + */ + if (smbstat_opt_C) + prefix = "cl"; + if (smbstat_opt_S) + prefix = "sh"; + (void) snprintf(ks_name, sizeof (ks_name), + "%s/%s", prefix, smbstat_opt_clsh); + + smbstat_clsh_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE, + instance, ks_name); + if (smbstat_clsh_ksp == NULL) { + smbstat_fail(1, gettext("cannot retrieve smbsrv %s kstat\n"), + ks_name); + } + + info = smbstat_srv_info.si_clsh; + for (i = 0; i < SMBSRV_CLSH__NREQ; i++) { + (void) strlcpy(info[i].ri_name, kr_names[i], + sizeof (info[i].ri_name)); + } + } + + static void + smbstat_clsh_fini(void) + { + smbstat_clsh_ksp = NULL; + } + + /* + * smbstat_clsh_snapshot + */ + static void + smbstat_clsh_snapshot(void) + { + smbstat_clsh_snapshot_t *curr; + + if (smbstat_clsh_ksp == NULL) + return; + + curr = smbstat_clsh_current_snapshot(); + + if ((kstat_read(smbstat_ksc, smbstat_clsh_ksp, NULL) == -1) || + (smbstat_clsh_ksp->ks_data_size != sizeof (curr->cs_data))) + smbstat_fail(1, gettext("kstat_read('%s') failed"), + smbstat_clsh_ksp->ks_name); + + curr->cs_snaptime = smbstat_clsh_ksp->ks_snaptime; + + bcopy(smbstat_clsh_ksp->ks_data, &curr->cs_data, + sizeof (curr->cs_data)); + } + + /* + * smbstat_clsh_process + */ + static void + smbstat_clsh_process(void) + { + smbstat_clsh_snapshot_t *curr, *prev; + boolean_t firstcall; + int idx; + + curr = smbstat_clsh_current_snapshot(); + prev = smbstat_clsh_previous_snapshot(); + firstcall = (prev->cs_snaptime == 0); + + + for (idx = 0; idx < SMBSRV_CLSH__NREQ; idx++) { + smbstat_srv_process_one_req( + &smbstat_srv_info.si_clsh[idx], + &curr->cs_data.ks_clsh[idx], + &prev->cs_data.ks_clsh[idx], + firstcall); + } + } + + /* + * smbstat_clsh_current_snapshot + */ + static smbstat_clsh_snapshot_t * + smbstat_clsh_current_snapshot(void) + { + return (&smbstat_clsh_snapshots[smbstat_snapshot_idx]); + } + + static smbstat_clsh_snapshot_t * + smbstat_clsh_previous_snapshot(void) + { + int idx; + + idx = (smbstat_snapshot_idx - 1) & SMBSTAT_SNAPSHOT_MASK; + return (&smbstat_clsh_snapshots[idx]); + } + + /* * smbstat_srv_init */ static void smbstat_srv_init(void) { smbstat_srv_ksp = kstat_lookup(smbstat_ksc, SMBSRV_KSTAT_MODULE, ! -1, SMBSRV_KSTAT_STATISTICS); if (smbstat_srv_ksp == NULL) smbstat_fail(1, gettext("cannot retrieve smbsrv kstat\n")); } /*
*** 1030,1049 **** smb_kstat_req_t *curr_req; smb_kstat_req_t *prev_req; int i, idx; boolean_t firstcall = (prev->ss_snaptime == 0); ! for (i = 0; i < SMB_COM_NUM; i++) { info = &smbstat_srv_info.si_reqs1[i]; idx = info[i].ri_opcode & 0xFF; curr_req = &curr->ss_data.ks_reqs1[idx]; prev_req = &prev->ss_data.ks_reqs1[idx]; smbstat_srv_process_one_req( info, curr_req, prev_req, firstcall); } ! for (i = 0; i < SMB2__NCMDS; i++) { info = &smbstat_srv_info.si_reqs2[i]; curr_req = &curr->ss_data.ks_reqs2[i]; prev_req = &prev->ss_data.ks_reqs2[i]; smbstat_srv_process_one_req( info, curr_req, prev_req, firstcall); --- 1227,1246 ---- smb_kstat_req_t *curr_req; smb_kstat_req_t *prev_req; int i, idx; boolean_t firstcall = (prev->ss_snaptime == 0); ! for (i = 0; i < SMBSRV_KS_NREQS1; i++) { info = &smbstat_srv_info.si_reqs1[i]; idx = info[i].ri_opcode & 0xFF; curr_req = &curr->ss_data.ks_reqs1[idx]; prev_req = &prev->ss_data.ks_reqs1[idx]; smbstat_srv_process_one_req( info, curr_req, prev_req, firstcall); } ! for (i = 0; i < SMBSRV_KS_NREQS2; i++) { info = &smbstat_srv_info.si_reqs2[i]; curr_req = &curr->ss_data.ks_reqs2[i]; prev_req = &prev->ss_data.ks_reqs2[i]; smbstat_srv_process_one_req( info, curr_req, prev_req, firstcall);
*** 1097,1107 **** } info->ri_stddev /= NANOSEC; info->ri_mean /= NANOSEC; } - /* * smbstat_srv_current_snapshot * * Returns the current snapshot. */ --- 1294,1303 ----
*** 1276,1303 **** smbstat_srv_snapshot(); ss = smbstat_srv_current_snapshot(); reqs = ss->ss_data.ks_reqs1; info = smbstat_srv_info.si_reqs1; ! for (i = 0; i < SMB_COM_NUM; i++) { (void) strlcpy(info[i].ri_name, reqs[i].kr_name, sizeof (reqs[i].kr_name)); info[i].ri_opcode = i; } if (smbstat_opt_n) ! qsort(info, SMB_COM_NUM, sizeof (smbstat_req_info_t), smbstat_req_cmp_name); reqs = ss->ss_data.ks_reqs2; info = smbstat_srv_info.si_reqs2; ! for (i = 0; i < SMB2__NCMDS; i++) { (void) strlcpy(info[i].ri_name, reqs[i].kr_name, sizeof (reqs[i].kr_name)); info[i].ri_opcode = i; } if (smbstat_opt_n) ! qsort(info, SMB2__NCMDS, sizeof (smbstat_req_info_t), smbstat_req_cmp_name); } /* * Return the number of ticks delta between two hrtime_t --- 1472,1499 ---- smbstat_srv_snapshot(); ss = smbstat_srv_current_snapshot(); reqs = ss->ss_data.ks_reqs1; info = smbstat_srv_info.si_reqs1; ! for (i = 0; i < SMBSRV_KS_NREQS1; i++) { (void) strlcpy(info[i].ri_name, reqs[i].kr_name, sizeof (reqs[i].kr_name)); info[i].ri_opcode = i; } if (smbstat_opt_n) ! qsort(info, SMBSRV_KS_NREQS1, sizeof (smbstat_req_info_t), smbstat_req_cmp_name); reqs = ss->ss_data.ks_reqs2; info = smbstat_srv_info.si_reqs2; ! for (i = 0; i < SMBSRV_KS_NREQS2; i++) { (void) strlcpy(info[i].ri_name, reqs[i].kr_name, sizeof (reqs[i].kr_name)); info[i].ri_opcode = i; } if (smbstat_opt_n) ! qsort(info, SMBSRV_KS_NREQS2, sizeof (smbstat_req_info_t), smbstat_req_cmp_name); } /* * Return the number of ticks delta between two hrtime_t