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 31308 : static void test_smb2_bench_path_contention_loop_open(
561 : struct test_smb2_bench_path_contention_shared_loop *loop)
562 : {
563 31308 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
564 :
565 31308 : loop->opens.num_started += 1;
566 31308 : loop->opens.starttime = timeval_current();
567 31308 : loop->opens.req = smb2_create_send(loop->conn->tree, &loop->opens.io);
568 31308 : torture_assert_goto(state->tctx, loop->opens.req != NULL,
569 : state->ok, asserted, "smb2_create_send");
570 :
571 31308 : loop->opens.req->async.fn = test_smb2_bench_path_contention_loop_opened;
572 31308 : loop->opens.req->async.private_data = loop;
573 31308 : 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 31298 : static void test_smb2_bench_path_contention_loop_opened(struct smb2_request *req)
582 : {
583 31298 : struct test_smb2_bench_path_contention_shared_loop *loop =
584 : (struct test_smb2_bench_path_contention_shared_loop *)
585 : req->async.private_data;
586 31298 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
587 31298 : double latency = timeval_elapsed(&loop->opens.starttime);
588 31298 : TALLOC_CTX *frame = talloc_stackframe();
589 :
590 31298 : torture_assert_goto(state->tctx, loop->opens.req == req,
591 : state->ok, asserted, __location__);
592 31298 : loop->error = smb2_create_recv(req, frame, &loop->opens.io);
593 31298 : torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
594 : state->ok, asserted, __location__);
595 31298 : ZERO_STRUCT(loop->opens.io.out.blobs);
596 31298 : SMB_ASSERT(latency >= 0.000001);
597 :
598 31298 : 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 31298 : loop->opens.num_finished += 1;
605 31298 : loop->opens.total_latency += latency;
606 :
607 31298 : if (latency < loop->opens.min_latency) {
608 193 : loop->opens.min_latency = latency;
609 : }
610 :
611 31298 : if (latency > loop->opens.max_latency) {
612 75 : loop->opens.max_latency = latency;
613 : }
614 :
615 31298 : TALLOC_FREE(frame);
616 31298 : test_smb2_bench_path_contention_loop_close(loop);
617 31298 : 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 31298 : static void test_smb2_bench_path_contention_loop_close(
626 : struct test_smb2_bench_path_contention_shared_loop *loop)
627 : {
628 31298 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
629 :
630 31298 : loop->closes.num_started += 1;
631 31298 : loop->closes.starttime = timeval_current();
632 31298 : loop->closes.io.in.file = loop->opens.io.out.file;
633 31298 : loop->closes.req = smb2_close_send(loop->conn->tree, &loop->closes.io);
634 31298 : torture_assert_goto(state->tctx, loop->closes.req != NULL,
635 : state->ok, asserted, "smb2_close_send");
636 :
637 31298 : loop->closes.req->async.fn = test_smb2_bench_path_contention_loop_closed;
638 31298 : loop->closes.req->async.private_data = loop;
639 31298 : return;
640 0 : asserted:
641 0 : state->stop = true;
642 : }
643 :
644 31284 : static void test_smb2_bench_path_contention_loop_closed(struct smb2_request *req)
645 : {
646 31284 : struct test_smb2_bench_path_contention_shared_loop *loop =
647 : (struct test_smb2_bench_path_contention_shared_loop *)
648 : req->async.private_data;
649 31284 : struct test_smb2_bench_path_contention_shared_state *state = loop->state;
650 31284 : double latency = timeval_elapsed(&loop->closes.starttime);
651 :
652 31284 : torture_assert_goto(state->tctx, loop->closes.req == req,
653 : state->ok, asserted, __location__);
654 31284 : loop->error = smb2_close_recv(req, &loop->closes.io);
655 31284 : torture_assert_ntstatus_ok_goto(state->tctx, loop->error,
656 : state->ok, asserted, __location__);
657 31284 : SMB_ASSERT(latency >= 0.000001);
658 31284 : 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 31284 : loop->closes.num_finished += 1;
664 :
665 31284 : loop->closes.total_latency += latency;
666 :
667 31284 : if (latency < loop->closes.min_latency) {
668 145 : loop->closes.min_latency = latency;
669 : }
670 :
671 31284 : if (latency > loop->closes.max_latency) {
672 116 : loop->closes.max_latency = latency;
673 : }
674 :
675 31284 : test_smb2_bench_path_contention_loop_open(loop);
676 31284 : 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 1 : 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 5 : 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 2 : 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 4 : 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 221201 : while (!state->stop) {
941 221195 : int rc = tevent_loop_once(tctx->ev);
942 221195 : 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 2354 : struct torture_suite *torture_smb2_bench_init(TALLOC_CTX *ctx)
1365 : {
1366 2354 : struct torture_suite *suite = torture_suite_create(ctx, "bench");
1367 :
1368 2354 : torture_suite_add_1smb2_test(suite, "oplock1", test_smb2_bench_oplock);
1369 2354 : torture_suite_add_1smb2_test(suite, "echo", test_smb2_bench_echo);
1370 2354 : torture_suite_add_1smb2_test(suite, "path-contention-shared", test_smb2_bench_path_contention_shared);
1371 2354 : torture_suite_add_1smb2_test(suite, "read", test_smb2_bench_read);
1372 :
1373 2354 : suite->description = talloc_strdup(suite, "SMB2-BENCH tests");
1374 :
1375 2354 : return suite;
1376 : }
|