LCOV - code coverage report
Current view: top level - source4/torture/smb2 - bench.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 206 602 34.2 %
Date: 2023-11-21 12:31:41 Functions: 8 18 44.4 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    SMB2 bench test suite
       5             : 
       6             :    Copyright (C) Stefan Metzmacher 2022
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "libcli/smb2/smb2.h"
      24             : #include "libcli/smb2/smb2_calls.h"
      25             : #include "libcli/smb/smbXcli_base.h"
      26             : #include "torture/torture.h"
      27             : #include "torture/util.h"
      28             : #include "torture/smb2/proto.h"
      29             : #include "librpc/gen_ndr/ndr_security.h"
      30             : #include "libcli/security/security.h"
      31             : 
      32             : #include "system/filesys.h"
      33             : #include "auth/credentials/credentials.h"
      34             : #include "lib/cmdline/cmdline.h"
      35             : #include "librpc/gen_ndr/security.h"
      36             : #include "lib/events/events.h"
      37             : 
      38             : #define FNAME "test_create.dat"
      39             : #define DNAME "smb2_open"
      40             : 
      41             : #define CHECK_STATUS(status, correct) do { \
      42             :         if (!NT_STATUS_EQUAL(status, correct)) { \
      43             :                 torture_result(tctx, TORTURE_FAIL, \
      44             :                         "(%s) Incorrect status %s - should be %s\n", \
      45             :                          __location__, nt_errstr(status), nt_errstr(correct)); \
      46             :                 return false; \
      47             :         }} while (0)
      48             : 
      49             : #define CHECK_EQUAL(v, correct) do { \
      50             :         if (v != correct) { \
      51             :                 torture_result(tctx, TORTURE_FAIL, \
      52             :                         "(%s) Incorrect value for %s 0x%08llx - " \
      53             :                         "should be 0x%08llx\n", \
      54             :                          __location__, #v, \
      55             :                         (unsigned long long)v, \
      56             :                         (unsigned long long)correct); \
      57             :                 return false;                                   \
      58             :         }} while (0)
      59             : 
      60             : #define CHECK_TIME(t, field) do { \
      61             :         time_t t1, t2; \
      62             :         finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
      63             :         finfo.all_info.in.file.handle = h1; \
      64             :         status = smb2_getinfo_file(tree, tctx, &finfo); \
      65             :         CHECK_STATUS(status, NT_STATUS_OK); \
      66             :         t1 = t & ~1; \
      67             :         t2 = nt_time_to_unix(finfo.all_info.out.field) & ~1; \
      68             :         if (abs(t1-t2) > 2) { \
      69             :                 torture_result(tctx, TORTURE_FAIL, \
      70             :                         "(%s) wrong time for field %s  %s - %s\n", \
      71             :                         __location__, #field, \
      72             :                         timestring(tctx, t1), \
      73             :                         timestring(tctx, t2)); \
      74             :                 dump_all_info(tctx, &finfo); \
      75             :                 ret = false; \
      76             :         }} while (0)
      77             : 
      78             : #define CHECK_NTTIME(t, field) do { \
      79             :         NTTIME t2; \
      80             :         finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
      81             :         finfo.all_info.in.file.handle = h1; \
      82             :         status = smb2_getinfo_file(tree, tctx, &finfo); \
      83             :         CHECK_STATUS(status, NT_STATUS_OK); \
      84             :         t2 = finfo.all_info.out.field; \
      85             :         if (llabs((int64_t)(t-t2)) > 20000) { \
      86             :                 torture_result(tctx, TORTURE_FAIL, \
      87             :                         "(%s) wrong time for field %s  %s - %s\n", \
      88             :                        __location__, #field, \
      89             :                        nt_time_string(tctx, t), \
      90             :                        nt_time_string(tctx, t2)); \
      91             :                 dump_all_info(tctx, &finfo); \
      92             :                 ret = false; \
      93             :         }} while (0)
      94             : 
      95             : #define CHECK_ALL_INFO(v, field) do { \
      96             :         finfo.all_info.level = RAW_FILEINFO_ALL_INFORMATION; \
      97             :         finfo.all_info.in.file.handle = h1; \
      98             :         status = smb2_getinfo_file(tree, tctx, &finfo); \
      99             :         CHECK_STATUS(status, NT_STATUS_OK); \
     100             :         if ((v) != (finfo.all_info.out.field)) { \
     101             :                torture_result(tctx, TORTURE_FAIL, \
     102             :                         "(%s) wrong value for field %s  0x%x - 0x%x\n", \
     103             :                         __location__, #field, (int)v,\
     104             :                         (int)(finfo.all_info.out.field)); \
     105             :                 dump_all_info(tctx, &finfo); \
     106             :                 ret = false; \
     107             :         }} while (0)
     108             : 
     109             : #define CHECK_VAL(v, correct) do { \
     110             :         if ((v) != (correct)) { \
     111             :                 torture_result(tctx, TORTURE_FAIL, \
     112             :                         "(%s) wrong value for %s  0x%x - should be 0x%x\n", \
     113             :                        __location__, #v, (int)(v), (int)correct); \
     114             :                 ret = false; \
     115             :         }} while (0)
     116             : 
     117             : #define SET_ATTRIB(sattrib) do { \
     118             :         union smb_setfileinfo sfinfo; \
     119             :         ZERO_STRUCT(sfinfo.basic_info.in); \
     120             :         sfinfo.basic_info.level = RAW_SFILEINFO_BASIC_INFORMATION; \
     121             :         sfinfo.basic_info.in.file.handle = h1; \
     122             :         sfinfo.basic_info.in.attrib = sattrib; \
     123             :         status = smb2_setinfo_file(tree, &sfinfo); \
     124             :         if (!NT_STATUS_IS_OK(status)) { \
     125             :                 torture_comment(tctx, \
     126             :                     "(%s) Failed to set attrib 0x%x on %s\n", \
     127             :                        __location__, (unsigned int)(sattrib), fname); \
     128             :         }} while (0)
     129             : 
     130             : /*
     131             :    stress testing keepalive iops
     132             :  */
     133             : 
     134             : struct test_smb2_bench_echo_conn;
     135             : struct test_smb2_bench_echo_loop;
     136             : 
     137             : struct test_smb2_bench_echo_state {
     138             :         struct torture_context *tctx;
     139             :         size_t num_conns;
     140             :         struct test_smb2_bench_echo_conn *conns;
     141             :         size_t num_loops;
     142             :         struct test_smb2_bench_echo_loop *loops;
     143             :         size_t pending_loops;
     144             :         struct timeval starttime;
     145             :         int timecount;
     146             :         int timelimit;
     147             :         uint64_t num_finished;
     148             :         double total_latency;
     149             :         double min_latency;
     150             :         double max_latency;
     151             :         bool ok;
     152             :         bool stop;
     153             : };
     154             : 
     155             : struct test_smb2_bench_echo_conn {
     156             :         struct test_smb2_bench_echo_state *state;
     157             :         int idx;
     158             :         struct smb2_tree *tree;
     159             : };
     160             : 
     161             : struct test_smb2_bench_echo_loop {
     162             :         struct test_smb2_bench_echo_state *state;
     163             :         struct test_smb2_bench_echo_conn *conn;
     164             :         int idx;
     165             :         struct tevent_immediate *im;
     166             :         struct tevent_req *req;
     167             :         struct timeval starttime;
     168             :         uint64_t num_started;
     169             :         uint64_t num_finished;
     170             :         uint64_t total_finished;
     171             :         uint64_t max_finished;
     172             :         double total_latency;
     173             :         double min_latency;
     174             :         double max_latency;
     175             :         NTSTATUS error;
     176             : };
     177             : 
     178             : static void test_smb2_bench_echo_loop_do(
     179             :         struct test_smb2_bench_echo_loop *loop);
     180             : 
     181           0 : static void test_smb2_bench_echo_loop_start(struct tevent_context *ctx,
     182             :                                                        struct tevent_immediate *im,
     183             :                                                        void *private_data)
     184             : {
     185           0 :         struct test_smb2_bench_echo_loop *loop =
     186             :                 (struct test_smb2_bench_echo_loop *)
     187             :                 private_data;
     188             : 
     189           0 :         test_smb2_bench_echo_loop_do(loop);
     190           0 : }
     191             : 
     192             : static void test_smb2_bench_echo_loop_done(struct tevent_req *req);
     193             : 
     194           0 : static void test_smb2_bench_echo_loop_do(
     195             :         struct test_smb2_bench_echo_loop *loop)
     196             : {
     197           0 :         struct test_smb2_bench_echo_state *state = loop->state;
     198             : 
     199           0 :         loop->num_started += 1;
     200           0 :         loop->starttime = timeval_current();
     201           0 :         loop->req = smb2cli_echo_send(state->loops,
     202           0 :                                       state->tctx->ev,
     203           0 :                                       loop->conn->tree->session->transport->conn,
     204             :                                       1000);
     205           0 :         torture_assert_goto(state->tctx, loop->req != NULL,
     206             :                             state->ok, asserted, "smb2cli_echo_send");
     207             : 
     208           0 :         tevent_req_set_callback(loop->req,
     209             :                                 test_smb2_bench_echo_loop_done,
     210             :                                 loop);
     211           0 :         return;
     212           0 : asserted:
     213           0 :         state->stop = true;
     214             : }
     215             : 
     216           0 : static void test_smb2_bench_echo_loop_done(struct tevent_req *req)
     217             : {
     218           0 :         struct test_smb2_bench_echo_loop *loop =
     219             :                 (struct test_smb2_bench_echo_loop *)
     220           0 :                 _tevent_req_callback_data(req);
     221           0 :         struct test_smb2_bench_echo_state *state = loop->state;
     222           0 :         double latency = timeval_elapsed(&loop->starttime);
     223           0 :         TALLOC_CTX *frame = talloc_stackframe();
     224             : 
     225           0 :         torture_assert_goto(state->tctx, loop->req == req,
     226             :                             state->ok, asserted, __location__);
     227           0 :         loop->error = smb2cli_echo_recv(req);
     228           0 :         torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
     229             :                                         state->ok, asserted, __location__);
     230           0 :         SMB_ASSERT(latency >= 0.000001);
     231             : 
     232           0 :         if (loop->num_finished == 0) {
     233             :                 /* first round */
     234           0 :                 loop->min_latency = latency;
     235           0 :                 loop->max_latency = latency;
     236             :         }
     237             : 
     238           0 :         loop->num_finished += 1;
     239           0 :         loop->total_finished += 1;
     240           0 :         loop->total_latency += latency;
     241             : 
     242           0 :         if (latency < loop->min_latency) {
     243           0 :                 loop->min_latency = latency;
     244             :         }
     245             : 
     246           0 :         if (latency > loop->max_latency) {
     247           0 :                 loop->max_latency = latency;
     248             :         }
     249             : 
     250           0 :         if (loop->total_finished >= loop->max_finished) {
     251           0 :                 if (state->pending_loops > 0) {
     252           0 :                         state->pending_loops -= 1;
     253             :                 }
     254           0 :                 if (state->pending_loops == 0) {
     255           0 :                         goto asserted;
     256             :                 }
     257             :         }
     258             : 
     259           0 :         TALLOC_FREE(frame);
     260           0 :         test_smb2_bench_echo_loop_do(loop);
     261           0 :         return;
     262           0 : asserted:
     263           0 :         state->stop = true;
     264           0 :         TALLOC_FREE(frame);
     265             : }
     266             : 
     267           0 : static void test_smb2_bench_echo_progress(struct tevent_context *ev,
     268             :                                           struct tevent_timer *te,
     269             :                                           struct timeval current_time,
     270             :                                           void *private_data)
     271             : {
     272           0 :         struct test_smb2_bench_echo_state *state =
     273             :                 (struct test_smb2_bench_echo_state *)private_data;
     274           0 :         uint64_t num_echos = 0;
     275           0 :         double total_echo_latency = 0;
     276           0 :         double min_echo_latency = 0;
     277           0 :         double max_echo_latency = 0;
     278           0 :         double avs_echo_latency = 0;
     279           0 :         size_t i;
     280             : 
     281           0 :         state->timecount += 1;
     282             : 
     283           0 :         for (i=0;i<state->num_loops;i++) {
     284           0 :                 struct test_smb2_bench_echo_loop *loop =
     285           0 :                         &state->loops[i];
     286             : 
     287           0 :                 num_echos += loop->num_finished;
     288           0 :                 total_echo_latency += loop->total_latency;
     289           0 :                 if (min_echo_latency == 0.0 && loop->min_latency != 0.0) {
     290           0 :                         min_echo_latency = loop->min_latency;
     291             :                 }
     292           0 :                 if (loop->min_latency < min_echo_latency) {
     293           0 :                         min_echo_latency = loop->min_latency;
     294             :                 }
     295           0 :                 if (max_echo_latency == 0.0) {
     296           0 :                         max_echo_latency = loop->max_latency;
     297             :                 }
     298           0 :                 if (loop->max_latency > max_echo_latency) {
     299           0 :                         max_echo_latency = loop->max_latency;
     300             :                 }
     301           0 :                 loop->num_finished = 0;
     302           0 :                 loop->total_latency = 0.0;
     303             :         }
     304             : 
     305           0 :         state->num_finished += num_echos;
     306           0 :         state->total_latency += total_echo_latency;
     307           0 :         if (state->min_latency == 0.0 && min_echo_latency != 0.0) {
     308           0 :                 state->min_latency = min_echo_latency;
     309             :         }
     310           0 :         if (min_echo_latency < state->min_latency) {
     311           0 :                 state->min_latency = min_echo_latency;
     312             :         }
     313           0 :         if (state->max_latency == 0.0) {
     314           0 :                 state->max_latency = max_echo_latency;
     315             :         }
     316           0 :         if (max_echo_latency > state->max_latency) {
     317           0 :                 state->max_latency = max_echo_latency;
     318             :         }
     319             : 
     320           0 :         if (state->timecount < state->timelimit) {
     321           0 :                 te = tevent_add_timer(state->tctx->ev,
     322             :                                       state,
     323             :                                       timeval_current_ofs(1, 0),
     324             :                                       test_smb2_bench_echo_progress,
     325             :                                       state);
     326           0 :                 torture_assert_goto(state->tctx, te != NULL,
     327             :                                     state->ok, asserted, "tevent_add_timer");
     328             : 
     329           0 :                 if (!torture_setting_bool(state->tctx, "progress", true)) {
     330           0 :                         return;
     331             :                 }
     332             : 
     333           0 :                 avs_echo_latency = total_echo_latency / num_echos;
     334             : 
     335           0 :                 torture_comment(state->tctx,
     336             :                                 "%.2f second: "
     337             :                                 "echo[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]      \r",
     338           0 :                                 timeval_elapsed(&state->starttime),
     339             :                                 (unsigned long long)num_echos,
     340             :                                 avs_echo_latency,
     341             :                                 min_echo_latency,
     342             :                                 max_echo_latency);
     343           0 :                 return;
     344             :         }
     345             : 
     346           0 :         avs_echo_latency = state->total_latency / state->num_finished;
     347           0 :         num_echos = state->num_finished / state->timelimit;
     348             : 
     349           0 :         torture_comment(state->tctx,
     350             :                         "%.2f second: "
     351             :                         "echo[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
     352           0 :                         timeval_elapsed(&state->starttime),
     353             :                         (unsigned long long)num_echos,
     354             :                         avs_echo_latency,
     355             :                         state->min_latency,
     356             :                         state->max_latency);
     357             : 
     358           0 : asserted:
     359           0 :         state->stop = true;
     360             : }
     361             : 
     362           0 : static bool test_smb2_bench_echo(struct torture_context *tctx,
     363             :                                  struct smb2_tree *tree)
     364             : {
     365           0 :         struct test_smb2_bench_echo_state *state = NULL;
     366           0 :         bool ret = true;
     367           0 :         int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
     368           0 :         int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
     369           0 :         size_t i;
     370           0 :         size_t li = 0;
     371           0 :         int looplimit = torture_setting_int(tctx, "looplimit", -1);
     372           0 :         int timelimit = torture_setting_int(tctx, "timelimit", 10);
     373           0 :         struct tevent_timer *te = NULL;
     374           0 :         uint32_t timeout_msec;
     375             : 
     376           0 :         state = talloc_zero(tctx, struct test_smb2_bench_echo_state);
     377           0 :         torture_assert(tctx, state != NULL, __location__);
     378           0 :         state->tctx = tctx;
     379           0 :         state->num_conns = torture_nprocs;
     380           0 :         state->conns = talloc_zero_array(state,
     381             :                         struct test_smb2_bench_echo_conn,
     382             :                         state->num_conns);
     383           0 :         torture_assert(tctx, state->conns != NULL, __location__);
     384           0 :         state->num_loops = torture_nprocs * torture_qdepth;
     385           0 :         state->loops = talloc_zero_array(state,
     386             :                         struct test_smb2_bench_echo_loop,
     387             :                         state->num_loops);
     388           0 :         torture_assert(tctx, state->loops != NULL, __location__);
     389           0 :         state->ok = true;
     390           0 :         state->timelimit = MAX(timelimit, 1);
     391             : 
     392           0 :         timeout_msec = tree->session->transport->options.request_timeout * 1000;
     393             : 
     394           0 :         torture_comment(tctx, "Opening %zu connections\n", state->num_conns);
     395             : 
     396           0 :         for (i=0;i<state->num_conns;i++) {
     397           0 :                 struct smb2_tree *ct = NULL;
     398           0 :                 DATA_BLOB out_input_buffer = data_blob_null;
     399           0 :                 DATA_BLOB out_output_buffer = data_blob_null;
     400           0 :                 size_t pcli;
     401             : 
     402           0 :                 state->conns[i].state = state;
     403           0 :                 state->conns[i].idx = i;
     404             : 
     405           0 :                 if (!torture_smb2_connection(tctx, &ct)) {
     406           0 :                         torture_comment(tctx, "Failed opening %zu/%zu connections\n", i, state->num_conns);
     407           0 :                         return false;
     408             :                 }
     409           0 :                 state->conns[i].tree = talloc_steal(state->conns, ct);
     410             : 
     411           0 :                 smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
     412           0 :                 smb2cli_ioctl(ct->session->transport->conn,
     413             :                               timeout_msec,
     414           0 :                               ct->session->smbXcli,
     415           0 :                               ct->smbXcli,
     416             :                               UINT64_MAX, /* in_fid_persistent */
     417             :                               UINT64_MAX, /* in_fid_volatile */
     418             :                               UINT32_MAX,
     419             :                               0, /* in_max_input_length */
     420             :                               NULL, /* in_input_buffer */
     421             :                               1, /* in_max_output_length */
     422             :                               NULL, /* in_output_buffer */
     423             :                               SMB2_IOCTL_FLAG_IS_FSCTL,
     424             :                               ct,
     425             :                               &out_input_buffer,
     426             :                               &out_output_buffer);
     427           0 :                 torture_assert(tctx,
     428             :                        smbXcli_conn_is_connected(ct->session->transport->conn),
     429             :                        "smbXcli_conn_is_connected");
     430             : 
     431           0 :                 for (pcli = 0; pcli < torture_qdepth; pcli++) {
     432           0 :                         struct test_smb2_bench_echo_loop *loop = &state->loops[li];
     433             : 
     434           0 :                         loop->idx = li++;
     435           0 :                         if (looplimit != -1) {
     436           0 :                                 loop->max_finished = looplimit;
     437             :                         } else {
     438           0 :                                 loop->max_finished = UINT64_MAX;
     439             :                         }
     440           0 :                         loop->state = state;
     441           0 :                         loop->conn = &state->conns[i];
     442           0 :                         loop->im = tevent_create_immediate(state->loops);
     443           0 :                         torture_assert(tctx, loop->im != NULL, __location__);
     444             : 
     445           0 :                         tevent_schedule_immediate(loop->im,
     446             :                                                   tctx->ev,
     447             :                                                   test_smb2_bench_echo_loop_start,
     448           0 :                                                   loop);
     449             :                 }
     450             :         }
     451             : 
     452           0 :         torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
     453             :                         state->num_conns, torture_qdepth, state->num_loops);
     454             : 
     455           0 :         torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
     456             : 
     457           0 :         state->starttime = timeval_current();
     458           0 :         state->pending_loops = state->num_loops;
     459             : 
     460           0 :         te = tevent_add_timer(tctx->ev,
     461             :                               state,
     462             :                               timeval_current_ofs(1, 0),
     463             :                               test_smb2_bench_echo_progress,
     464             :                               state);
     465           0 :         torture_assert(tctx, te != NULL, __location__);
     466             : 
     467           0 :         while (!state->stop) {
     468           0 :                 int rc = tevent_loop_once(tctx->ev);
     469           0 :                 torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
     470             :         }
     471             : 
     472           0 :         torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
     473           0 :         TALLOC_FREE(state);
     474           0 :         return ret;
     475             : }
     476             : 
     477             : /*
     478             :    stress testing path base operations
     479             :    e.g. contention on lockting.tdb records
     480             :  */
     481             : 
     482             : struct test_smb2_bench_path_contention_shared_conn;
     483             : struct test_smb2_bench_path_contention_shared_loop;
     484             : 
     485             : struct test_smb2_bench_path_contention_shared_state {
     486             :         struct torture_context *tctx;
     487             :         size_t num_conns;
     488             :         struct test_smb2_bench_path_contention_shared_conn *conns;
     489             :         size_t num_loops;
     490             :         struct test_smb2_bench_path_contention_shared_loop *loops;
     491             :         struct timeval starttime;
     492             :         int timecount;
     493             :         int timelimit;
     494             :         struct {
     495             :                 uint64_t num_finished;
     496             :                 double total_latency;
     497             :                 double min_latency;
     498             :                 double max_latency;
     499             :         } opens;
     500             :         struct {
     501             :                 uint64_t num_finished;
     502             :                 double total_latency;
     503             :                 double min_latency;
     504             :                 double max_latency;
     505             :         } closes;
     506             :         bool ok;
     507             :         bool stop;
     508             : };
     509             : 
     510             : struct test_smb2_bench_path_contention_shared_conn {
     511             :         struct test_smb2_bench_path_contention_shared_state *state;
     512             :         int idx;
     513             :         struct smb2_tree *tree;
     514             : };
     515             : 
     516             : struct test_smb2_bench_path_contention_shared_loop {
     517             :         struct test_smb2_bench_path_contention_shared_state *state;
     518             :         struct test_smb2_bench_path_contention_shared_conn *conn;
     519             :         int idx;
     520             :         struct tevent_immediate *im;
     521             :         struct {
     522             :                 struct smb2_create io;
     523             :                 struct smb2_request *req;
     524             :                 struct timeval starttime;
     525             :                 uint64_t num_started;
     526             :                 uint64_t num_finished;
     527             :                 double total_latency;
     528             :                 double min_latency;
     529             :                 double max_latency;
     530             :         } opens;
     531             :         struct {
     532             :                 struct smb2_close io;
     533             :                 struct smb2_request *req;
     534             :                 struct timeval starttime;
     535             :                 uint64_t num_started;
     536             :                 uint64_t num_finished;
     537             :                 double total_latency;
     538             :                 double min_latency;
     539             :                 double max_latency;
     540             :         } closes;
     541             :         NTSTATUS error;
     542             : };
     543             : 
     544             : static void test_smb2_bench_path_contention_loop_open(
     545             :         struct test_smb2_bench_path_contention_shared_loop *loop);
     546             : 
     547          24 : static void test_smb2_bench_path_contention_loop_start(struct tevent_context *ctx,
     548             :                                                        struct tevent_immediate *im,
     549             :                                                        void *private_data)
     550             : {
     551          24 :         struct test_smb2_bench_path_contention_shared_loop *loop =
     552             :                 (struct test_smb2_bench_path_contention_shared_loop *)
     553             :                 private_data;
     554             : 
     555          24 :         test_smb2_bench_path_contention_loop_open(loop);
     556          24 : }
     557             : 
     558             : static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req);
     559             : 
     560       28924 : static void test_smb2_bench_path_contention_loop_open(
     561             :         struct test_smb2_bench_path_contention_shared_loop *loop)
     562             : {
     563       28924 :         struct test_smb2_bench_path_contention_shared_state *state = loop->state;
     564             : 
     565       28924 :         loop->opens.num_started += 1;
     566       28924 :         loop->opens.starttime = timeval_current();
     567       28924 :         loop->opens.req = smb2_create_send(loop->conn->tree, &loop->opens.io);
     568       28924 :         torture_assert_goto(state->tctx, loop->opens.req != NULL,
     569             :                             state->ok, asserted, "smb2_create_send");
     570             : 
     571       28924 :         loop->opens.req->async.fn = test_smb2_bench_path_contention_loop_opened;
     572       28924 :         loop->opens.req->async.private_data = loop;
     573       28924 :         return;
     574           0 : asserted:
     575           0 :         state->stop = true;
     576             : }
     577             : 
     578             : static void test_smb2_bench_path_contention_loop_close(
     579             :         struct test_smb2_bench_path_contention_shared_loop *loop);
     580             : 
     581       28907 : static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req)
     582             : {
     583       28907 :         struct test_smb2_bench_path_contention_shared_loop *loop =
     584             :                 (struct test_smb2_bench_path_contention_shared_loop *)
     585             :                 req->async.private_data;
     586       28907 :         struct test_smb2_bench_path_contention_shared_state *state = loop->state;
     587       28907 :         double latency = timeval_elapsed(&loop->opens.starttime);
     588       28907 :         TALLOC_CTX *frame = talloc_stackframe();
     589             : 
     590       28907 :         torture_assert_goto(state->tctx, loop->opens.req == req,
     591             :                             state->ok, asserted, __location__);
     592       28907 :         loop->error = smb2_create_recv(req, frame, &loop->opens.io);
     593       28907 :         torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
     594             :                                         state->ok, asserted, __location__);
     595       28907 :         ZERO_STRUCT(loop->opens.io.out.blobs);
     596       28907 :         SMB_ASSERT(latency >= 0.000001);
     597             : 
     598       28907 :         if (loop->opens.num_finished == 0) {
     599             :                 /* first round */
     600          24 :                 loop->opens.min_latency = latency;
     601          24 :                 loop->opens.max_latency = latency;
     602             :         }
     603             : 
     604       28907 :         loop->opens.num_finished += 1;
     605       28907 :         loop->opens.total_latency += latency;
     606             : 
     607       28907 :         if (latency < loop->opens.min_latency) {
     608         174 :                 loop->opens.min_latency = latency;
     609             :         }
     610             : 
     611       28907 :         if (latency > loop->opens.max_latency) {
     612          54 :                 loop->opens.max_latency = latency;
     613             :         }
     614             : 
     615       28907 :         TALLOC_FREE(frame);
     616       28907 :         test_smb2_bench_path_contention_loop_close(loop);
     617       28907 :         return;
     618           0 : asserted:
     619           0 :         state->stop = true;
     620           0 :         TALLOC_FREE(frame);
     621             : }
     622             : 
     623             : static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req);
     624             : 
     625       28907 : static void test_smb2_bench_path_contention_loop_close(
     626             :         struct test_smb2_bench_path_contention_shared_loop *loop)
     627             : {
     628       28907 :         struct test_smb2_bench_path_contention_shared_state *state = loop->state;
     629             : 
     630       28907 :         loop->closes.num_started += 1;
     631       28907 :         loop->closes.starttime = timeval_current();
     632       28907 :         loop->closes.io.in.file = loop->opens.io.out.file;
     633       28907 :         loop->closes.req = smb2_close_send(loop->conn->tree, &loop->closes.io);
     634       28907 :         torture_assert_goto(state->tctx, loop->closes.req != NULL,
     635             :                             state->ok, asserted, "smb2_close_send");
     636             : 
     637       28907 :         loop->closes.req->async.fn = test_smb2_bench_path_contention_loop_closed;
     638       28907 :         loop->closes.req->async.private_data = loop;
     639       28907 :         return;
     640           0 : asserted:
     641           0 :         state->stop = true;
     642             : }
     643             : 
     644       28900 : static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req)
     645             : {
     646       28900 :         struct test_smb2_bench_path_contention_shared_loop *loop =
     647             :                 (struct test_smb2_bench_path_contention_shared_loop *)
     648             :                 req->async.private_data;
     649       28900 :         struct test_smb2_bench_path_contention_shared_state *state = loop->state;
     650       28900 :         double latency = timeval_elapsed(&loop->closes.starttime);
     651             : 
     652       28900 :         torture_assert_goto(state->tctx, loop->closes.req == req,
     653             :                             state->ok, asserted, __location__);
     654       28900 :         loop->error = smb2_close_recv(req, &loop->closes.io);
     655       28900 :         torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
     656             :                                         state->ok, asserted, __location__);
     657       28900 :         SMB_ASSERT(latency >= 0.000001);
     658       28900 :         if (loop->closes.num_finished == 0) {
     659             :                 /* first round */
     660          24 :                 loop->closes.min_latency = latency;
     661          24 :                 loop->closes.max_latency = latency;
     662             :         }
     663       28900 :         loop->closes.num_finished += 1;
     664             : 
     665       28900 :         loop->closes.total_latency += latency;
     666             : 
     667       28900 :         if (latency < loop->closes.min_latency) {
     668         166 :                 loop->closes.min_latency = latency;
     669             :         }
     670             : 
     671       28900 :         if (latency > loop->closes.max_latency) {
     672         122 :                 loop->closes.max_latency = latency;
     673             :         }
     674             : 
     675       28900 :         test_smb2_bench_path_contention_loop_open(loop);
     676       28900 :         return;
     677           0 : asserted:
     678           0 :         state->stop = true;
     679             : }
     680             : 
     681           6 : static void test_smb2_bench_path_contention_progress(struct tevent_context *ev,
     682             :                                                      struct tevent_timer *te,
     683             :                                                      struct timeval current_time,
     684             :                                                      void *private_data)
     685             : {
     686           6 :         struct test_smb2_bench_path_contention_shared_state *state =
     687             :                 (struct test_smb2_bench_path_contention_shared_state *)private_data;
     688           6 :         uint64_t num_opens = 0;
     689           6 :         double total_open_latency = 0;
     690           6 :         double min_open_latency = 0;
     691           6 :         double max_open_latency = 0;
     692           6 :         double avs_open_latency = 0;
     693           6 :         uint64_t num_closes = 0;
     694           6 :         double total_close_latency = 0;
     695           6 :         double min_close_latency = 0;
     696           6 :         double max_close_latency = 0;
     697           6 :         double avs_close_latency = 0;
     698           0 :         size_t i;
     699             : 
     700           6 :         state->timecount += 1;
     701             : 
     702          30 :         for (i=0;i<state->num_loops;i++) {
     703          24 :                 struct test_smb2_bench_path_contention_shared_loop *loop =
     704          24 :                         &state->loops[i];
     705             : 
     706          24 :                 num_opens += loop->opens.num_finished;
     707          24 :                 total_open_latency += loop->opens.total_latency;
     708          24 :                 if (min_open_latency == 0.0 && loop->opens.min_latency != 0.0) {
     709           6 :                         min_open_latency = loop->opens.min_latency;
     710             :                 }
     711          24 :                 if (loop->opens.min_latency < min_open_latency) {
     712           2 :                         min_open_latency = loop->opens.min_latency;
     713             :                 }
     714          24 :                 if (max_open_latency == 0.0) {
     715           6 :                         max_open_latency = loop->opens.max_latency;
     716             :                 }
     717          24 :                 if (loop->opens.max_latency > max_open_latency) {
     718           2 :                         max_open_latency = loop->opens.max_latency;
     719             :                 }
     720          24 :                 loop->opens.num_finished = 0;
     721          24 :                 loop->opens.total_latency = 0.0;
     722             : 
     723          24 :                 num_closes += loop->closes.num_finished;
     724          24 :                 total_close_latency += loop->closes.total_latency;
     725          24 :                 if (min_close_latency == 0.0 && loop->closes.min_latency != 0.0) {
     726           6 :                         min_close_latency = loop->closes.min_latency;
     727             :                 }
     728          24 :                 if (loop->closes.min_latency < min_close_latency) {
     729           4 :                         min_close_latency = loop->closes.min_latency;
     730             :                 }
     731          24 :                 if (max_close_latency == 0.0) {
     732           6 :                         max_close_latency = loop->closes.max_latency;
     733             :                 }
     734          24 :                 if (loop->closes.max_latency > max_close_latency) {
     735           6 :                         max_close_latency = loop->closes.max_latency;
     736             :                 }
     737          24 :                 loop->closes.num_finished = 0;
     738          24 :                 loop->closes.total_latency = 0.0;
     739             :         }
     740             : 
     741           6 :         state->opens.num_finished += num_opens;
     742           6 :         state->opens.total_latency += total_open_latency;
     743           6 :         if (state->opens.min_latency == 0.0 && min_open_latency != 0.0) {
     744           6 :                 state->opens.min_latency = min_open_latency;
     745             :         }
     746           6 :         if (min_open_latency < state->opens.min_latency) {
     747           0 :                 state->opens.min_latency = min_open_latency;
     748             :         }
     749           6 :         if (state->opens.max_latency == 0.0) {
     750           6 :                 state->opens.max_latency = max_open_latency;
     751             :         }
     752           6 :         if (max_open_latency > state->opens.max_latency) {
     753           0 :                 state->opens.max_latency = max_open_latency;
     754             :         }
     755             : 
     756           6 :         state->closes.num_finished += num_closes;
     757           6 :         state->closes.total_latency += total_close_latency;
     758           6 :         if (state->closes.min_latency == 0.0 && min_close_latency != 0.0) {
     759           6 :                 state->closes.min_latency = min_close_latency;
     760             :         }
     761           6 :         if (min_close_latency < state->closes.min_latency) {
     762           0 :                 state->closes.min_latency = min_close_latency;
     763             :         }
     764           6 :         if (state->closes.max_latency == 0.0) {
     765           6 :                 state->closes.max_latency = max_close_latency;
     766             :         }
     767           6 :         if (max_close_latency > state->closes.max_latency) {
     768           0 :                 state->closes.max_latency = max_close_latency;
     769             :         }
     770             : 
     771           6 :         if (state->timecount < state->timelimit) {
     772           0 :                 te = tevent_add_timer(state->tctx->ev,
     773             :                                       state,
     774             :                                       timeval_current_ofs(1, 0),
     775             :                                       test_smb2_bench_path_contention_progress,
     776             :                                       state);
     777           0 :                 torture_assert_goto(state->tctx, te != NULL,
     778             :                                     state->ok, asserted, "tevent_add_timer");
     779             : 
     780           0 :                 if (!torture_setting_bool(state->tctx, "progress", true)) {
     781           0 :                         return;
     782             :                 }
     783             : 
     784           0 :                 avs_open_latency = total_open_latency / num_opens;
     785           0 :                 avs_close_latency = total_close_latency / num_closes;
     786             : 
     787           0 :                 torture_comment(state->tctx,
     788             :                                 "%.2f second: "
     789             :                                 "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
     790             :                                 "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]     \r",
     791           0 :                                 timeval_elapsed(&state->starttime),
     792             :                                 (unsigned long long)num_opens,
     793             :                                 avs_open_latency,
     794             :                                 min_open_latency,
     795             :                                 max_open_latency,
     796             :                                 (unsigned long long)num_closes,
     797             :                                 avs_close_latency,
     798             :                                 min_close_latency,
     799             :                                 max_close_latency);
     800           0 :                 return;
     801             :         }
     802             : 
     803           6 :         avs_open_latency = state->opens.total_latency / state->opens.num_finished;
     804           6 :         avs_close_latency = state->closes.total_latency / state->closes.num_finished;
     805           6 :         num_opens = state->opens.num_finished / state->timelimit;
     806           6 :         num_closes = state->closes.num_finished / state->timelimit;
     807             : 
     808           6 :         torture_comment(state->tctx,
     809             :                         "%.2f second: "
     810             :                         "open[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f] "
     811             :                         "close[num/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
     812           6 :                         timeval_elapsed(&state->starttime),
     813             :                         (unsigned long long)num_opens,
     814             :                         avs_open_latency,
     815             :                         state->opens.min_latency,
     816             :                         state->opens.max_latency,
     817             :                         (unsigned long long)num_closes,
     818             :                         avs_close_latency,
     819             :                         state->closes.min_latency,
     820             :                         state->closes.max_latency);
     821             : 
     822           6 : asserted:
     823           6 :         state->stop = true;
     824             : }
     825             : 
     826           6 : bool test_smb2_bench_path_contention_shared(struct torture_context *tctx,
     827             :                                             struct smb2_tree *tree)
     828             : {
     829           6 :         struct test_smb2_bench_path_contention_shared_state *state = NULL;
     830           6 :         bool ret = true;
     831           6 :         int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
     832           6 :         int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
     833           0 :         size_t i;
     834           6 :         size_t li = 0;
     835           6 :         int timelimit = torture_setting_int(tctx, "timelimit", 10);
     836           6 :         const char *path = torture_setting_string(tctx, "bench_path", "");
     837           6 :         struct smb2_create open_io = { .level = RAW_OPEN_SMB2, };
     838           6 :         struct smb2_close close_io = { .level = RAW_CLOSE_SMB2, };
     839           6 :         struct tevent_timer *te = NULL;
     840           0 :         uint32_t timeout_msec;
     841             : 
     842           6 :         state = talloc_zero(tctx, struct test_smb2_bench_path_contention_shared_state);
     843           6 :         torture_assert(tctx, state != NULL, __location__);
     844           6 :         state->tctx = tctx;
     845           6 :         state->num_conns = torture_nprocs;
     846           6 :         state->conns = talloc_zero_array(state,
     847             :                         struct test_smb2_bench_path_contention_shared_conn,
     848             :                         state->num_conns);
     849           6 :         torture_assert(tctx, state->conns != NULL, __location__);
     850           6 :         state->num_loops = torture_nprocs * torture_qdepth;
     851           6 :         state->loops = talloc_zero_array(state,
     852             :                         struct test_smb2_bench_path_contention_shared_loop,
     853             :                         state->num_loops);
     854           6 :         torture_assert(tctx, state->loops != NULL, __location__);
     855           6 :         state->ok = true;
     856           6 :         state->timelimit = MAX(timelimit, 1);
     857             : 
     858           6 :         open_io.in.desired_access = SEC_DIR_READ_ATTRIBUTE;
     859           6 :         open_io.in.alloc_size = 0;
     860           6 :         open_io.in.file_attributes = 0;
     861           6 :         open_io.in.share_access = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
     862           6 :         open_io.in.create_disposition = FILE_OPEN;
     863           6 :         open_io.in.create_options = FILE_OPEN_REPARSE_POINT;
     864           6 :         open_io.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
     865           6 :         open_io.in.security_flags = 0;
     866           6 :         open_io.in.fname = path;
     867           6 :         open_io.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
     868           6 :         open_io.in.oplock_level = SMB2_OPLOCK_LEVEL_NONE;
     869             : 
     870           6 :         timeout_msec = tree->session->transport->options.request_timeout * 1000;
     871             : 
     872           6 :         torture_comment(tctx, "Opening %zd connections\n", state->num_conns);
     873             : 
     874          30 :         for (i=0;i<state->num_conns;i++) {
     875          24 :                 struct smb2_tree *ct = NULL;
     876          24 :                 DATA_BLOB out_input_buffer = data_blob_null;
     877          24 :                 DATA_BLOB out_output_buffer = data_blob_null;
     878           0 :                 size_t pcli;
     879             : 
     880          24 :                 state->conns[i].state = state;
     881          24 :                 state->conns[i].idx = i;
     882             : 
     883          24 :                 if (!torture_smb2_connection(tctx, &ct)) {
     884           0 :                         torture_comment(tctx, "Failed opening %zd/%zd connections\n", i, state->num_conns);
     885           0 :                         return false;
     886             :                 }
     887          24 :                 state->conns[i].tree = talloc_steal(state->conns, ct);
     888             : 
     889          24 :                 smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
     890          24 :                 smb2cli_ioctl(ct->session->transport->conn,
     891             :                               timeout_msec,
     892          24 :                               ct->session->smbXcli,
     893          24 :                               ct->smbXcli,
     894             :                               UINT64_MAX, /* in_fid_persistent */
     895             :                               UINT64_MAX, /* in_fid_volatile */
     896             :                               UINT32_MAX,
     897             :                               0, /* in_max_input_length */
     898             :                               NULL, /* in_input_buffer */
     899             :                               1, /* in_max_output_length */
     900             :                               NULL, /* in_output_buffer */
     901             :                               SMB2_IOCTL_FLAG_IS_FSCTL,
     902             :                               ct,
     903             :                               &out_input_buffer,
     904             :                               &out_output_buffer);
     905          24 :                 torture_assert(tctx,
     906             :                        smbXcli_conn_is_connected(ct->session->transport->conn),
     907             :                        "smbXcli_conn_is_connected");
     908          48 :                 for (pcli = 0; pcli < torture_qdepth; pcli++) {
     909          24 :                         struct test_smb2_bench_path_contention_shared_loop *loop = &state->loops[li];
     910             : 
     911          24 :                         loop->idx = li++;
     912          24 :                         loop->state = state;
     913          24 :                         loop->conn = &state->conns[i];
     914          24 :                         loop->im = tevent_create_immediate(state->loops);
     915          24 :                         torture_assert(tctx, loop->im != NULL, __location__);
     916          24 :                         loop->opens.io = open_io;
     917          24 :                         loop->closes.io = close_io;
     918             : 
     919          24 :                         tevent_schedule_immediate(loop->im,
     920             :                                                   tctx->ev,
     921             :                                                   test_smb2_bench_path_contention_loop_start,
     922           0 :                                                   loop);
     923             :                 }
     924             :         }
     925             : 
     926           6 :         torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
     927             :                         state->num_conns, torture_qdepth, state->num_loops);
     928             : 
     929           6 :         torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
     930             : 
     931           6 :         state->starttime = timeval_current();
     932             : 
     933           6 :         te = tevent_add_timer(tctx->ev,
     934             :                               state,
     935             :                               timeval_current_ofs(1, 0),
     936             :                               test_smb2_bench_path_contention_progress,
     937             :                               state);
     938           6 :         torture_assert(tctx, te != NULL, __location__);
     939             : 
     940      204892 :         while (!state->stop) {
     941      204886 :                 int rc = tevent_loop_once(tctx->ev);
     942      204886 :                 torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
     943             :         }
     944             : 
     945           6 :         torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
     946           6 :         TALLOC_FREE(state);
     947           6 :         return ret;
     948             : }
     949             : 
     950             : /*
     951             :    stress testing read iops
     952             :  */
     953             : 
     954             : struct test_smb2_bench_read_conn;
     955             : struct test_smb2_bench_read_loop;
     956             : 
     957             : struct test_smb2_bench_read_state {
     958             :         struct torture_context *tctx;
     959             :         size_t num_conns;
     960             :         struct test_smb2_bench_read_conn *conns;
     961             :         size_t num_loops;
     962             :         struct test_smb2_bench_read_loop *loops;
     963             :         size_t pending_loops;
     964             :         uint32_t io_size;
     965             :         struct timeval starttime;
     966             :         int timecount;
     967             :         int timelimit;
     968             :         uint64_t num_finished;
     969             :         double total_latency;
     970             :         double min_latency;
     971             :         double max_latency;
     972             :         bool ok;
     973             :         bool stop;
     974             : };
     975             : 
     976             : struct test_smb2_bench_read_conn {
     977             :         struct test_smb2_bench_read_state *state;
     978             :         int idx;
     979             :         struct smb2_tree *tree;
     980             : };
     981             : 
     982             : struct test_smb2_bench_read_loop {
     983             :         struct test_smb2_bench_read_state *state;
     984             :         struct test_smb2_bench_read_conn *conn;
     985             :         int idx;
     986             :         struct tevent_immediate *im;
     987             :         char *fname;
     988             :         struct smb2_handle handle;
     989             :         struct tevent_req *req;
     990             :         struct timeval starttime;
     991             :         uint64_t num_started;
     992             :         uint64_t num_finished;
     993             :         uint64_t total_finished;
     994             :         uint64_t max_finished;
     995             :         double total_latency;
     996             :         double min_latency;
     997             :         double max_latency;
     998             :         NTSTATUS error;
     999             : };
    1000             : 
    1001             : static void test_smb2_bench_read_loop_do(
    1002             :         struct test_smb2_bench_read_loop *loop);
    1003             : 
    1004           0 : static void test_smb2_bench_read_loop_start(struct tevent_context *ctx,
    1005             :                                                        struct tevent_immediate *im,
    1006             :                                                        void *private_data)
    1007             : {
    1008           0 :         struct test_smb2_bench_read_loop *loop =
    1009             :                 (struct test_smb2_bench_read_loop *)
    1010             :                 private_data;
    1011             : 
    1012           0 :         test_smb2_bench_read_loop_do(loop);
    1013           0 : }
    1014             : 
    1015             : static void test_smb2_bench_read_loop_done(struct tevent_req *req);
    1016             : 
    1017           0 : static void test_smb2_bench_read_loop_do(
    1018             :         struct test_smb2_bench_read_loop *loop)
    1019             : {
    1020           0 :         struct test_smb2_bench_read_state *state = loop->state;
    1021           0 :         uint32_t timeout_msec;
    1022             : 
    1023           0 :         timeout_msec = loop->conn->tree->session->transport->options.request_timeout * 1000;
    1024             : 
    1025           0 :         loop->num_started += 1;
    1026           0 :         loop->starttime = timeval_current();
    1027           0 :         loop->req = smb2cli_read_send(state->loops,
    1028           0 :                                       state->tctx->ev,
    1029           0 :                                       loop->conn->tree->session->transport->conn,
    1030             :                                       timeout_msec,
    1031           0 :                                       loop->conn->tree->session->smbXcli,
    1032           0 :                                       loop->conn->tree->smbXcli,
    1033             :                                       state->io_size, /* length */
    1034             :                                       0,              /* offset */
    1035             :                                       loop->handle.data[0],/* fid_persistent */
    1036             :                                       loop->handle.data[1],/* fid_volatile */
    1037           0 :                                       state->io_size, /* minimum_count */
    1038             :                                       0);              /* remaining_bytes */
    1039           0 :         torture_assert_goto(state->tctx, loop->req != NULL,
    1040             :                             state->ok, asserted, "smb2cli_read_send");
    1041             : 
    1042           0 :         tevent_req_set_callback(loop->req,
    1043             :                                 test_smb2_bench_read_loop_done,
    1044             :                                 loop);
    1045           0 :         return;
    1046           0 : asserted:
    1047           0 :         state->stop = true;
    1048             : }
    1049             : 
    1050           0 : static void test_smb2_bench_read_loop_done(struct tevent_req *req)
    1051             : {
    1052           0 :         struct test_smb2_bench_read_loop *loop =
    1053             :                 (struct test_smb2_bench_read_loop *)
    1054           0 :                 _tevent_req_callback_data(req);
    1055           0 :         struct test_smb2_bench_read_state *state = loop->state;
    1056           0 :         double latency = timeval_elapsed(&loop->starttime);
    1057           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1058           0 :         uint8_t *data = NULL;
    1059           0 :         uint32_t data_length = 0;
    1060             : 
    1061           0 :         torture_assert_goto(state->tctx, loop->req == req,
    1062             :                             state->ok, asserted, __location__);
    1063           0 :         loop->error = smb2cli_read_recv(req, frame, &data, &data_length);
    1064           0 :         torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
    1065             :                                         state->ok, asserted, __location__);
    1066           0 :         torture_assert_u32_equal_goto(state->tctx, data_length, state->io_size,
    1067             :                                         state->ok, asserted, __location__);
    1068           0 :         SMB_ASSERT(latency >= 0.000001);
    1069             : 
    1070           0 :         if (loop->num_finished == 0) {
    1071             :                 /* first round */
    1072           0 :                 loop->min_latency = latency;
    1073           0 :                 loop->max_latency = latency;
    1074             :         }
    1075             : 
    1076           0 :         loop->num_finished += 1;
    1077           0 :         loop->total_finished += 1;
    1078           0 :         loop->total_latency += latency;
    1079             : 
    1080           0 :         if (latency < loop->min_latency) {
    1081           0 :                 loop->min_latency = latency;
    1082             :         }
    1083             : 
    1084           0 :         if (latency > loop->max_latency) {
    1085           0 :                 loop->max_latency = latency;
    1086             :         }
    1087             : 
    1088           0 :         if (loop->total_finished >= loop->max_finished) {
    1089           0 :                 if (state->pending_loops > 0) {
    1090           0 :                         state->pending_loops -= 1;
    1091             :                 }
    1092           0 :                 if (state->pending_loops == 0) {
    1093           0 :                         goto asserted;
    1094             :                 }
    1095             :         }
    1096             : 
    1097           0 :         TALLOC_FREE(frame);
    1098           0 :         test_smb2_bench_read_loop_do(loop);
    1099           0 :         return;
    1100           0 : asserted:
    1101           0 :         state->stop = true;
    1102           0 :         TALLOC_FREE(frame);
    1103             : }
    1104             : 
    1105           0 : static void test_smb2_bench_read_progress(struct tevent_context *ev,
    1106             :                                           struct tevent_timer *te,
    1107             :                                           struct timeval current_time,
    1108             :                                           void *private_data)
    1109             : {
    1110           0 :         struct test_smb2_bench_read_state *state =
    1111             :                 (struct test_smb2_bench_read_state *)private_data;
    1112           0 :         uint64_t num_reads = 0;
    1113           0 :         double total_read_latency = 0;
    1114           0 :         double min_read_latency = 0;
    1115           0 :         double max_read_latency = 0;
    1116           0 :         double avs_read_latency = 0;
    1117           0 :         size_t i;
    1118             : 
    1119           0 :         state->timecount += 1;
    1120             : 
    1121           0 :         for (i=0;i<state->num_loops;i++) {
    1122           0 :                 struct test_smb2_bench_read_loop *loop =
    1123           0 :                         &state->loops[i];
    1124             : 
    1125           0 :                 num_reads += loop->num_finished;
    1126           0 :                 total_read_latency += loop->total_latency;
    1127           0 :                 if (min_read_latency == 0.0 && loop->min_latency != 0.0) {
    1128           0 :                         min_read_latency = loop->min_latency;
    1129             :                 }
    1130           0 :                 if (loop->min_latency < min_read_latency) {
    1131           0 :                         min_read_latency = loop->min_latency;
    1132             :                 }
    1133           0 :                 if (max_read_latency == 0.0) {
    1134           0 :                         max_read_latency = loop->max_latency;
    1135             :                 }
    1136           0 :                 if (loop->max_latency > max_read_latency) {
    1137           0 :                         max_read_latency = loop->max_latency;
    1138             :                 }
    1139           0 :                 loop->num_finished = 0;
    1140           0 :                 loop->total_latency = 0.0;
    1141             :         }
    1142             : 
    1143           0 :         state->num_finished += num_reads;
    1144           0 :         state->total_latency += total_read_latency;
    1145           0 :         if (state->min_latency == 0.0 && min_read_latency != 0.0) {
    1146           0 :                 state->min_latency = min_read_latency;
    1147             :         }
    1148           0 :         if (min_read_latency < state->min_latency) {
    1149           0 :                 state->min_latency = min_read_latency;
    1150             :         }
    1151           0 :         if (state->max_latency == 0.0) {
    1152           0 :                 state->max_latency = max_read_latency;
    1153             :         }
    1154           0 :         if (max_read_latency > state->max_latency) {
    1155           0 :                 state->max_latency = max_read_latency;
    1156             :         }
    1157             : 
    1158           0 :         if (state->timecount < state->timelimit) {
    1159           0 :                 te = tevent_add_timer(state->tctx->ev,
    1160             :                                       state,
    1161             :                                       timeval_current_ofs(1, 0),
    1162             :                                       test_smb2_bench_read_progress,
    1163             :                                       state);
    1164           0 :                 torture_assert_goto(state->tctx, te != NULL,
    1165             :                                     state->ok, asserted, "tevent_add_timer");
    1166             : 
    1167           0 :                 if (!torture_setting_bool(state->tctx, "progress", true)) {
    1168           0 :                         return;
    1169             :                 }
    1170             : 
    1171           0 :                 avs_read_latency = total_read_latency / num_reads;
    1172             : 
    1173           0 :                 torture_comment(state->tctx,
    1174             :                                 "%.2f second: "
    1175             :                                 "read[num/s=%llu,bytes/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]      \r",
    1176           0 :                                 timeval_elapsed(&state->starttime),
    1177             :                                 (unsigned long long)num_reads,
    1178           0 :                                 (unsigned long long)num_reads*state->io_size,
    1179             :                                 avs_read_latency,
    1180             :                                 min_read_latency,
    1181             :                                 max_read_latency);
    1182           0 :                 return;
    1183             :         }
    1184             : 
    1185           0 :         avs_read_latency = state->total_latency / state->num_finished;
    1186           0 :         num_reads = state->num_finished / state->timelimit;
    1187             : 
    1188           0 :         torture_comment(state->tctx,
    1189             :                         "%.2f second: "
    1190             :                         "read[num/s=%llu,bytes/s=%llu,avslat=%.6f,minlat=%.6f,maxlat=%.6f]\n",
    1191           0 :                         timeval_elapsed(&state->starttime),
    1192             :                         (unsigned long long)num_reads,
    1193           0 :                         (unsigned long long)num_reads*state->io_size,
    1194             :                         avs_read_latency,
    1195             :                         state->min_latency,
    1196             :                         state->max_latency);
    1197             : 
    1198           0 : asserted:
    1199           0 :         state->stop = true;
    1200             : }
    1201             : 
    1202           0 : static bool test_smb2_bench_read(struct torture_context *tctx,
    1203             :                                  struct smb2_tree *tree)
    1204             : {
    1205           0 :         struct test_smb2_bench_read_state *state = NULL;
    1206           0 :         bool ret = true;
    1207           0 :         int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
    1208           0 :         int torture_qdepth = torture_setting_int(tctx, "qdepth", 1);
    1209           0 :         int torture_io_size = torture_setting_int(tctx, "io_size", 4096);
    1210           0 :         size_t i;
    1211           0 :         size_t li = 0;
    1212           0 :         int looplimit = torture_setting_int(tctx, "looplimit", -1);
    1213           0 :         int timelimit = torture_setting_int(tctx, "timelimit", 10);
    1214           0 :         struct tevent_timer *te = NULL;
    1215           0 :         uint32_t timeout_msec;
    1216           0 :         const char *dname = "bench_read_dir";
    1217           0 :         const char *unique = generate_random_str(tctx, 8);
    1218           0 :         struct smb2_handle dh;
    1219           0 :         NTSTATUS status;
    1220             : 
    1221           0 :         smb2_deltree(tree, dname);
    1222             : 
    1223           0 :         status = torture_smb2_testdir(tree, dname, &dh);
    1224           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1225           0 :         status = smb2_util_close(tree, dh);
    1226           0 :         CHECK_STATUS(status, NT_STATUS_OK);
    1227             : 
    1228           0 :         state = talloc_zero(tctx, struct test_smb2_bench_read_state);
    1229           0 :         torture_assert(tctx, state != NULL, __location__);
    1230           0 :         state->tctx = tctx;
    1231           0 :         state->num_conns = torture_nprocs;
    1232           0 :         state->conns = talloc_zero_array(state,
    1233             :                         struct test_smb2_bench_read_conn,
    1234             :                         state->num_conns);
    1235           0 :         torture_assert(tctx, state->conns != NULL, __location__);
    1236           0 :         state->num_loops = torture_nprocs * torture_qdepth;
    1237           0 :         state->loops = talloc_zero_array(state,
    1238             :                         struct test_smb2_bench_read_loop,
    1239             :                         state->num_loops);
    1240           0 :         torture_assert(tctx, state->loops != NULL, __location__);
    1241           0 :         state->ok = true;
    1242           0 :         state->timelimit = MAX(timelimit, 1);
    1243           0 :         state->io_size = MAX(torture_io_size, 1);
    1244           0 :         state->io_size = MIN(state->io_size, 16*1024*1024);
    1245             : 
    1246           0 :         timeout_msec = tree->session->transport->options.request_timeout * 1000;
    1247             : 
    1248           0 :         torture_comment(tctx, "Opening %zu connections\n", state->num_conns);
    1249             : 
    1250           0 :         for (i=0;i<state->num_conns;i++) {
    1251           0 :                 struct smb2_tree *ct = NULL;
    1252           0 :                 DATA_BLOB out_input_buffer = data_blob_null;
    1253           0 :                 DATA_BLOB out_output_buffer = data_blob_null;
    1254           0 :                 size_t pcli;
    1255             : 
    1256           0 :                 state->conns[i].state = state;
    1257           0 :                 state->conns[i].idx = i;
    1258             : 
    1259           0 :                 if (!torture_smb2_connection(tctx, &ct)) {
    1260           0 :                         torture_comment(tctx, "Failed opening %zu/%zu connections\n", i, state->num_conns);
    1261           0 :                         return false;
    1262             :                 }
    1263           0 :                 state->conns[i].tree = talloc_steal(state->conns, ct);
    1264             : 
    1265           0 :                 smb2cli_conn_set_max_credits(ct->session->transport->conn, 8192);
    1266           0 :                 smb2cli_ioctl(ct->session->transport->conn,
    1267             :                               timeout_msec,
    1268           0 :                               ct->session->smbXcli,
    1269           0 :                               ct->smbXcli,
    1270             :                               UINT64_MAX, /* in_fid_persistent */
    1271             :                               UINT64_MAX, /* in_fid_volatile */
    1272             :                               UINT32_MAX,
    1273             :                               0, /* in_max_input_length */
    1274             :                               NULL, /* in_input_buffer */
    1275             :                               1, /* in_max_output_length */
    1276             :                               NULL, /* in_output_buffer */
    1277             :                               SMB2_IOCTL_FLAG_IS_FSCTL,
    1278             :                               ct,
    1279             :                               &out_input_buffer,
    1280             :                               &out_output_buffer);
    1281           0 :                 torture_assert(tctx,
    1282             :                        smbXcli_conn_is_connected(ct->session->transport->conn),
    1283             :                        "smbXcli_conn_is_connected");
    1284             : 
    1285           0 :                 for (pcli = 0; pcli < torture_qdepth; pcli++) {
    1286           0 :                         struct test_smb2_bench_read_loop *loop = &state->loops[li];
    1287           0 :                         struct smb2_create cr;
    1288           0 :                         union smb_setfileinfo sfinfo;
    1289             : 
    1290           0 :                         loop->idx = li++;
    1291           0 :                         if (looplimit != -1) {
    1292           0 :                                 loop->max_finished = looplimit;
    1293             :                         } else {
    1294           0 :                                 loop->max_finished = UINT64_MAX;
    1295             :                         }
    1296           0 :                         loop->state = state;
    1297           0 :                         loop->conn = &state->conns[i];
    1298           0 :                         loop->im = tevent_create_immediate(state->loops);
    1299           0 :                         torture_assert(tctx, loop->im != NULL, __location__);
    1300             : 
    1301           0 :                         loop->fname = talloc_asprintf(state->loops,
    1302             :                                                 "%s\\%s_loop_%zu_conn_%zu_loop_%zu.dat",
    1303             :                                                 dname, unique, li, i, pcli);
    1304           0 :                         torture_assert(tctx, loop->fname != NULL, __location__);
    1305             : 
    1306             :                         /* reasonable default parameters */
    1307           0 :                         ZERO_STRUCT(cr);
    1308           0 :                         cr.in.create_flags = NTCREATEX_FLAGS_EXTENDED;
    1309           0 :                         cr.in.alloc_size = state->io_size;
    1310           0 :                         cr.in.desired_access = SEC_RIGHTS_FILE_ALL;
    1311           0 :                         cr.in.file_attributes = FILE_ATTRIBUTE_NORMAL;
    1312           0 :                         cr.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
    1313           0 :                         cr.in.create_disposition = NTCREATEX_DISP_CREATE;
    1314           0 :                         cr.in.create_options =
    1315             :                                 NTCREATEX_OPTIONS_DELETE_ON_CLOSE |
    1316             :                                 NTCREATEX_OPTIONS_NON_DIRECTORY_FILE;
    1317           0 :                         cr.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS;
    1318           0 :                         cr.in.security_flags = 0;
    1319           0 :                         cr.in.fname = loop->fname;
    1320           0 :                         status = smb2_create(state->conns[i].tree, tctx, &cr);
    1321           0 :                         CHECK_STATUS(status, NT_STATUS_OK);
    1322           0 :                         loop->handle = cr.out.file.handle;
    1323             : 
    1324           0 :                         ZERO_STRUCT(sfinfo);
    1325           0 :                         sfinfo.end_of_file_info.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
    1326           0 :                         sfinfo.end_of_file_info.in.file.handle = loop->handle;
    1327           0 :                         sfinfo.end_of_file_info.in.size = state->io_size;
    1328           0 :                         status = smb2_setinfo_file(state->conns[i].tree, &sfinfo);
    1329           0 :                         CHECK_STATUS(status, NT_STATUS_OK);
    1330             : 
    1331           0 :                         tevent_schedule_immediate(loop->im,
    1332             :                                                   tctx->ev,
    1333             :                                                   test_smb2_bench_read_loop_start,
    1334           0 :                                                   loop);
    1335             :                 }
    1336             :         }
    1337             : 
    1338           0 :         torture_comment(tctx, "Opened %zu connections with qdepth=%d => %zu loops\n",
    1339             :                         state->num_conns, torture_qdepth, state->num_loops);
    1340             : 
    1341           0 :         torture_comment(tctx, "Running for %d seconds\n", state->timelimit);
    1342             : 
    1343           0 :         state->starttime = timeval_current();
    1344           0 :         state->pending_loops = state->num_loops;
    1345             : 
    1346           0 :         te = tevent_add_timer(tctx->ev,
    1347             :                               state,
    1348             :                               timeval_current_ofs(1, 0),
    1349             :                               test_smb2_bench_read_progress,
    1350             :                               state);
    1351           0 :         torture_assert(tctx, te != NULL, __location__);
    1352             : 
    1353           0 :         while (!state->stop) {
    1354           0 :                 int rc = tevent_loop_once(tctx->ev);
    1355           0 :                 torture_assert_int_equal(tctx, rc, 0, "tevent_loop_once");
    1356             :         }
    1357             : 
    1358           0 :         torture_comment(tctx, "%.2f seconds\n", timeval_elapsed(&state->starttime));
    1359           0 :         TALLOC_FREE(state);
    1360           0 :         smb2_deltree(tree, dname);
    1361           0 :         return ret;
    1362             : }
    1363             : 
    1364        2358 : struct torture_suite *torture_smb2_bench_init(TALLOC_CTX *ctx)
    1365             : {
    1366        2358 :         struct torture_suite *suite = torture_suite_create(ctx, "bench");
    1367             : 
    1368        2358 :         torture_suite_add_1smb2_test(suite, "oplock1", test_smb2_bench_oplock);
    1369        2358 :         torture_suite_add_1smb2_test(suite, "echo", test_smb2_bench_echo);
    1370        2358 :         torture_suite_add_1smb2_test(suite, "path-contention-shared", test_smb2_bench_path_contention_shared);
    1371        2358 :         torture_suite_add_1smb2_test(suite, "read", test_smb2_bench_read);
    1372             : 
    1373        2358 :         suite->description = talloc_strdup(suite, "SMB2-BENCH tests");
    1374             : 
    1375        2358 :         return suite;
    1376             : }

Generated by: LCOV version 1.14