talloc: Fix exports and increment talloc version
[Samba/ekacnet.git] / source4 / torture / basic / misc.c
blobf4f91c8ba37f8866b5a51ce31a28d43573c0eaca
1 /*
2 Unix SMB/CIFS implementation.
3 SMB torture tester
4 Copyright (C) Andrew Tridgell 1997-2003
5 Copyright (C) Jelmer Vernooij 2006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "libcli/raw/libcliraw.h"
23 #include "libcli/raw/raw_proto.h"
24 #include "system/time.h"
25 #include "system/wait.h"
26 #include "system/filesys.h"
27 #include "libcli/raw/ioctl.h"
28 #include "libcli/libcli.h"
29 #include "lib/events/events.h"
30 #include "libcli/resolve/resolve.h"
31 #include "auth/credentials/credentials.h"
32 #include "librpc/gen_ndr/ndr_nbt.h"
33 #include "torture/smbtorture.h"
34 #include "torture/util.h"
35 #include "libcli/smb_composite/smb_composite.h"
36 #include "libcli/composite/composite.h"
37 #include "param/param.h"
39 extern struct cli_credentials *cmdline_credentials;
41 static bool wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
43 while (NT_STATUS_IS_ERR(smbcli_lock(c->tree, fnum, offset, len, -1, WRITE_LOCK))) {
44 if (!check_error(__location__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
46 return true;
50 static bool rw_torture(struct torture_context *tctx, struct smbcli_state *c)
52 const char *lockfname = "\\torture.lck";
53 char *fname;
54 int fnum;
55 int fnum2;
56 pid_t pid2, pid = getpid();
57 int i, j;
58 uint8_t buf[1024];
59 bool correct = true;
61 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR | O_CREAT | O_EXCL,
62 DENY_NONE);
63 if (fnum2 == -1)
64 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR, DENY_NONE);
65 if (fnum2 == -1) {
66 torture_comment(tctx, "open of %s failed (%s)\n", lockfname, smbcli_errstr(c->tree));
67 return false;
70 generate_random_buffer(buf, sizeof(buf));
72 for (i=0;i<torture_numops;i++) {
73 uint_t n = (uint_t)random()%10;
74 if (i % 10 == 0) {
75 if (torture_setting_bool(tctx, "progress", true)) {
76 torture_comment(tctx, "%d\r", i);
77 fflush(stdout);
80 asprintf(&fname, "\\torture.%u", n);
82 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
83 return false;
86 fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
87 if (fnum == -1) {
88 torture_comment(tctx, "open failed (%s)\n", smbcli_errstr(c->tree));
89 correct = false;
90 break;
93 if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) {
94 torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
95 correct = false;
98 for (j=0;j<50;j++) {
99 if (smbcli_write(c->tree, fnum, 0, buf,
100 sizeof(pid)+(j*sizeof(buf)),
101 sizeof(buf)) != sizeof(buf)) {
102 torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
103 correct = false;
107 pid2 = 0;
109 if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) {
110 torture_comment(tctx, "read failed (%s)\n", smbcli_errstr(c->tree));
111 correct = false;
114 if (pid2 != pid) {
115 torture_comment(tctx, "data corruption!\n");
116 correct = false;
119 if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) {
120 torture_comment(tctx, "close failed (%s)\n", smbcli_errstr(c->tree));
121 correct = false;
124 if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) {
125 torture_comment(tctx, "unlink failed (%s)\n", smbcli_errstr(c->tree));
126 correct = false;
129 if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) {
130 torture_comment(tctx, "unlock failed (%s)\n", smbcli_errstr(c->tree));
131 correct = false;
133 free(fname);
136 smbcli_close(c->tree, fnum2);
137 smbcli_unlink(c->tree, lockfname);
139 torture_comment(tctx, "%d\n", i);
141 return correct;
144 bool run_torture(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
146 return rw_torture(tctx, cli);
151 see how many RPC pipes we can open at once
153 bool run_pipe_number(struct torture_context *tctx,
154 struct smbcli_state *cli1)
156 const char *pipe_name = "\\WKSSVC";
157 int fnum;
158 int num_pipes = 0;
160 while(1) {
161 fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
162 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0);
164 if (fnum == -1) {
165 torture_comment(tctx, "Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree));
166 break;
168 num_pipes++;
169 if (torture_setting_bool(tctx, "progress", true)) {
170 torture_comment(tctx, "%d\r", num_pipes);
171 fflush(stdout);
175 torture_comment(tctx, "pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
176 return true;
183 open N connections to the server and just hold them open
184 used for testing performance when there are N idle users
185 already connected
187 bool torture_holdcon(struct torture_context *tctx)
189 int i;
190 struct smbcli_state **cli;
191 int num_dead = 0;
193 torture_comment(tctx, "Opening %d connections\n", torture_numops);
195 cli = malloc_array_p(struct smbcli_state *, torture_numops);
197 for (i=0;i<torture_numops;i++) {
198 if (!torture_open_connection(&cli[i], tctx, i)) {
199 return false;
201 if (torture_setting_bool(tctx, "progress", true)) {
202 torture_comment(tctx, "opened %d connections\r", i);
203 fflush(stdout);
207 torture_comment(tctx, "\nStarting pings\n");
209 while (1) {
210 for (i=0;i<torture_numops;i++) {
211 NTSTATUS status;
212 if (cli[i]) {
213 status = smbcli_chkpath(cli[i]->tree, "\\");
214 if (!NT_STATUS_IS_OK(status)) {
215 torture_comment(tctx, "Connection %d is dead\n", i);
216 cli[i] = NULL;
217 num_dead++;
219 usleep(100);
223 if (num_dead == torture_numops) {
224 torture_comment(tctx, "All connections dead - finishing\n");
225 break;
228 torture_comment(tctx, ".");
229 fflush(stdout);
232 return true;
236 test how many open files this server supports on the one socket
238 bool run_maxfidtest(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
240 #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
241 char *fname;
242 int fnums[0x11000], i;
243 int retries=4, maxfid;
244 bool correct = true;
246 if (retries <= 0) {
247 torture_comment(tctx, "failed to connect\n");
248 return false;
251 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
252 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
253 smbcli_errstr(cli->tree));
254 return false;
256 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
257 torture_comment(tctx, "Failed to mkdir \\maxfid, error=%s\n",
258 smbcli_errstr(cli->tree));
259 return false;
262 torture_comment(tctx, "Testing maximum number of open files\n");
264 for (i=0; i<0x11000; i++) {
265 if (i % 1000 == 0) {
266 asprintf(&fname, "\\maxfid\\fid%d", i/1000);
267 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
268 torture_comment(tctx, "Failed to mkdir %s, error=%s\n",
269 fname, smbcli_errstr(cli->tree));
270 return false;
272 free(fname);
274 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
275 if ((fnums[i] = smbcli_open(cli->tree, fname,
276 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
277 -1) {
278 torture_comment(tctx, "open of %s failed (%s)\n",
279 fname, smbcli_errstr(cli->tree));
280 torture_comment(tctx, "maximum fnum is %d\n", i);
281 break;
283 free(fname);
284 if (torture_setting_bool(tctx, "progress", true)) {
285 torture_comment(tctx, "%6d\r", i);
286 fflush(stdout);
289 torture_comment(tctx, "%6d\n", i);
290 i--;
292 maxfid = i;
294 torture_comment(tctx, "cleaning up\n");
295 for (i=0;i<maxfid/2;i++) {
296 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
297 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
298 torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
300 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
301 torture_comment(tctx, "unlink of %s failed (%s)\n",
302 fname, smbcli_errstr(cli->tree));
303 correct = false;
305 free(fname);
307 asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid());
308 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) {
309 torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree));
311 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
312 torture_comment(tctx, "unlink of %s failed (%s)\n",
313 fname, smbcli_errstr(cli->tree));
314 correct = false;
316 free(fname);
318 if (torture_setting_bool(tctx, "progress", true)) {
319 torture_comment(tctx, "%6d %6d\r", i, maxfid-i);
320 fflush(stdout);
323 torture_comment(tctx, "%6d\n", 0);
325 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
326 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
327 smbcli_errstr(cli->tree));
328 return false;
331 torture_comment(tctx, "maxfid test finished\n");
332 if (!torture_close_connection(cli)) {
333 correct = false;
335 return correct;
336 #undef MAXFID_TEMPLATE
342 sees what IOCTLs are supported
344 bool torture_ioctl_test(struct torture_context *tctx,
345 struct smbcli_state *cli)
347 uint16_t device, function;
348 int fnum;
349 const char *fname = "\\ioctl.dat";
350 NTSTATUS status;
351 union smb_ioctl parms;
352 TALLOC_CTX *mem_ctx;
354 mem_ctx = talloc_named_const(tctx, 0, "ioctl_test");
356 smbcli_unlink(cli->tree, fname);
358 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
359 if (fnum == -1) {
360 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
361 return false;
364 parms.ioctl.level = RAW_IOCTL_IOCTL;
365 parms.ioctl.in.file.fnum = fnum;
366 parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
367 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
368 torture_comment(tctx, "ioctl job info: %s\n", smbcli_errstr(cli->tree));
370 for (device=0;device<0x100;device++) {
371 torture_comment(tctx, "testing device=0x%x\n", device);
372 for (function=0;function<0x100;function++) {
373 parms.ioctl.in.request = (device << 16) | function;
374 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
376 if (NT_STATUS_IS_OK(status)) {
377 torture_comment(tctx, "ioctl device=0x%x function=0x%x OK : %d bytes\n",
378 device, function, (int)parms.ioctl.out.blob.length);
383 return true;
386 static void benchrw_callback(struct smbcli_request *req);
387 enum benchrw_stage {
388 START,
389 OPEN_CONNECTION,
390 CLEANUP_TESTDIR,
391 MK_TESTDIR,
392 OPEN_FILE,
393 INITIAL_WRITE,
394 READ_WRITE_DATA,
395 MAX_OPS_REACHED,
396 ERROR,
397 CLOSE_FILE,
398 CLEANUP,
399 FINISHED
402 struct benchrw_state {
403 struct torture_context *tctx;
404 char *dname;
405 char *fname;
406 uint16_t fnum;
407 int nr;
408 struct smbcli_tree *cli;
409 uint8_t *buffer;
410 int writecnt;
411 int readcnt;
412 int completed;
413 int num_parallel_requests;
414 void *req_params;
415 enum benchrw_stage mode;
416 struct params{
417 struct unclist{
418 const char *host;
419 const char *share;
420 } **unc;
421 const char *workgroup;
422 int retry;
423 unsigned int writeblocks;
424 unsigned int blocksize;
425 unsigned int writeratio;
426 int num_parallel_requests;
427 } *lp_params;
431 init params using lp_parm_xxx
432 return number of unclist entries
434 static int init_benchrw_params(struct torture_context *tctx,
435 struct params *lpar)
437 char **unc_list = NULL;
438 int num_unc_names = 0, conn_index=0, empty_lines=0;
439 const char *p;
440 lpar->retry = torture_setting_int(tctx, "retry",3);
441 lpar->blocksize = torture_setting_int(tctx, "blocksize",65535);
442 lpar->writeblocks = torture_setting_int(tctx, "writeblocks",15);
443 lpar->writeratio = torture_setting_int(tctx, "writeratio",5);
444 lpar->num_parallel_requests = torture_setting_int(
445 tctx, "parallel_requests", 5);
446 lpar->workgroup = lp_workgroup(tctx->lp_ctx);
448 p = torture_setting_string(tctx, "unclist", NULL);
449 if (p) {
450 char *h, *s;
451 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
452 if (!unc_list || num_unc_names <= 0) {
453 torture_comment(tctx, "Failed to load unc names list "
454 "from '%s'\n", p);
455 exit(1);
458 lpar->unc = talloc_array(tctx, struct unclist *,
459 (num_unc_names-empty_lines));
460 for(conn_index = 0; conn_index < num_unc_names; conn_index++) {
461 /* ignore empty lines */
462 if(strlen(unc_list[conn_index % num_unc_names])==0){
463 empty_lines++;
464 continue;
466 if (!smbcli_parse_unc(
467 unc_list[conn_index % num_unc_names],
468 NULL, &h, &s)) {
469 torture_comment(
470 tctx, "Failed to parse UNC "
471 "name %s\n",
472 unc_list[conn_index % num_unc_names]);
473 exit(1);
475 lpar->unc[conn_index-empty_lines] =
476 talloc(tctx, struct unclist);
477 lpar->unc[conn_index-empty_lines]->host = h;
478 lpar->unc[conn_index-empty_lines]->share = s;
480 return num_unc_names-empty_lines;
481 }else{
482 lpar->unc = talloc_array(tctx, struct unclist *, 1);
483 lpar->unc[0] = talloc(tctx,struct unclist);
484 lpar->unc[0]->host = torture_setting_string(tctx, "host",
485 NULL);
486 lpar->unc[0]->share = torture_setting_string(tctx, "share",
487 NULL);
488 return 1;
493 Called when the reads & writes are finished. closes the file.
495 static NTSTATUS benchrw_close(struct torture_context *tctx,
496 struct smbcli_request *req,
497 struct benchrw_state *state)
499 union smb_close close_parms;
501 NT_STATUS_NOT_OK_RETURN(req->status);
503 torture_comment(tctx, "Close file %d (%d)\n",state->nr,state->fnum);
504 close_parms.close.level = RAW_CLOSE_CLOSE;
505 close_parms.close.in.file.fnum = state->fnum ;
506 close_parms.close.in.write_time = 0;
507 state->mode=CLOSE_FILE;
509 req = smb_raw_close_send(state->cli, &close_parms);
510 NT_STATUS_HAVE_NO_MEMORY(req);
511 /*register the callback function!*/
512 req->async.fn = benchrw_callback;
513 req->async.private_data = state;
515 return NT_STATUS_OK;
518 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
519 struct benchrw_state *state);
520 static void benchrw_callback(struct smbcli_request *req);
522 static void benchrw_rw_callback(struct smbcli_request *req)
524 struct benchrw_state *state = req->async.private_data;
525 struct torture_context *tctx = state->tctx;
527 if (!NT_STATUS_IS_OK(req->status)) {
528 state->mode = ERROR;
529 return;
532 state->completed++;
533 state->num_parallel_requests--;
535 if ((state->completed >= torture_numops)
536 && (state->num_parallel_requests == 0)) {
537 benchrw_callback(req);
538 talloc_free(req);
539 return;
542 talloc_free(req);
544 if (state->completed + state->num_parallel_requests
545 < torture_numops) {
546 benchrw_readwrite(tctx, state);
551 Called when the initial write is completed is done. write or read a file.
553 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
554 struct benchrw_state *state)
556 struct smbcli_request *req;
557 union smb_read rd;
558 union smb_write wr;
560 /* randomize between writes and reads*/
561 if (random() % state->lp_params->writeratio == 0) {
562 torture_comment(tctx, "Callback WRITE file:%d (%d/%d)\n",
563 state->nr,state->completed,torture_numops);
564 wr.generic.level = RAW_WRITE_WRITEX ;
565 wr.writex.in.file.fnum = state->fnum ;
566 wr.writex.in.offset = 0;
567 wr.writex.in.wmode = 0 ;
568 wr.writex.in.remaining = 0;
569 wr.writex.in.count = state->lp_params->blocksize;
570 wr.writex.in.data = state->buffer;
571 state->readcnt=0;
572 req = smb_raw_write_send(state->cli,&wr);
574 else {
575 torture_comment(tctx,
576 "Callback READ file:%d (%d/%d) Offset:%d\n",
577 state->nr,state->completed,torture_numops,
578 (state->readcnt*state->lp_params->blocksize));
579 rd.generic.level = RAW_READ_READX;
580 rd.readx.in.file.fnum = state->fnum ;
581 rd.readx.in.offset = state->readcnt*state->lp_params->blocksize;
582 rd.readx.in.mincnt = state->lp_params->blocksize;
583 rd.readx.in.maxcnt = rd.readx.in.mincnt;
584 rd.readx.in.remaining = 0 ;
585 rd.readx.out.data = state->buffer;
586 rd.readx.in.read_for_execute = false;
587 if(state->readcnt < state->lp_params->writeblocks){
588 state->readcnt++;
589 }else{
590 /*start reading from beginn of file*/
591 state->readcnt=0;
593 req = smb_raw_read_send(state->cli,&rd);
595 state->num_parallel_requests += 1;
596 NT_STATUS_HAVE_NO_MEMORY(req);
597 /*register the callback function!*/
598 req->async.fn = benchrw_rw_callback;
599 req->async.private_data = state;
601 return NT_STATUS_OK;
605 Called when the open is done. writes to the file.
607 static NTSTATUS benchrw_open(struct torture_context *tctx,
608 struct smbcli_request *req,
609 struct benchrw_state *state)
611 union smb_write wr;
612 if(state->mode == OPEN_FILE){
613 NTSTATUS status;
614 status = smb_raw_open_recv(req,tctx,(
615 union smb_open*)state->req_params);
616 NT_STATUS_NOT_OK_RETURN(status);
618 state->fnum = ((union smb_open*)state->req_params)
619 ->openx.out.file.fnum;
620 torture_comment(tctx, "File opened (%d)\n",state->fnum);
621 state->mode=INITIAL_WRITE;
624 torture_comment(tctx, "Write initial test file:%d (%d/%d)\n",state->nr,
625 (state->writecnt+1)*state->lp_params->blocksize,
626 (state->lp_params->writeblocks*state->lp_params->blocksize));
627 wr.generic.level = RAW_WRITE_WRITEX ;
628 wr.writex.in.file.fnum = state->fnum ;
629 wr.writex.in.offset = state->writecnt *
630 state->lp_params->blocksize;
631 wr.writex.in.wmode = 0 ;
632 wr.writex.in.remaining = (state->lp_params->writeblocks *
633 state->lp_params->blocksize)-
634 ((state->writecnt+1)*state->
635 lp_params->blocksize);
636 wr.writex.in.count = state->lp_params->blocksize;
637 wr.writex.in.data = state->buffer;
638 state->writecnt++;
639 if(state->writecnt == state->lp_params->writeblocks){
640 state->mode=READ_WRITE_DATA;
642 req = smb_raw_write_send(state->cli,&wr);
643 NT_STATUS_HAVE_NO_MEMORY(req);
645 /*register the callback function!*/
646 req->async.fn = benchrw_callback;
647 req->async.private_data = state;
648 return NT_STATUS_OK;
652 Called when the mkdir is done. Opens a file.
654 static NTSTATUS benchrw_mkdir(struct torture_context *tctx,
655 struct smbcli_request *req,
656 struct benchrw_state *state)
658 union smb_open *open_parms;
659 uint8_t *writedata;
661 NT_STATUS_NOT_OK_RETURN(req->status);
663 /* open/create the files */
664 torture_comment(tctx, "Open File %d/%d\n",state->nr+1,
665 torture_setting_int(tctx, "nprocs", 4));
666 open_parms=talloc_zero(tctx, union smb_open);
667 NT_STATUS_HAVE_NO_MEMORY(open_parms);
668 open_parms->openx.level = RAW_OPEN_OPENX;
669 open_parms->openx.in.flags = 0;
670 open_parms->openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
671 open_parms->openx.in.search_attrs =
672 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
673 open_parms->openx.in.file_attrs = 0;
674 open_parms->openx.in.write_time = 0;
675 open_parms->openx.in.open_func = OPENX_OPEN_FUNC_CREATE;
676 open_parms->openx.in.size = 0;
677 open_parms->openx.in.timeout = 0;
678 open_parms->openx.in.fname = state->fname;
680 writedata = talloc_size(tctx,state->lp_params->blocksize);
681 NT_STATUS_HAVE_NO_MEMORY(writedata);
682 generate_random_buffer(writedata,state->lp_params->blocksize);
683 state->buffer=writedata;
684 state->writecnt=1;
685 state->readcnt=0;
686 state->req_params=open_parms;
687 state->mode=OPEN_FILE;
689 req = smb_raw_open_send(state->cli,open_parms);
690 NT_STATUS_HAVE_NO_MEMORY(req);
692 /*register the callback function!*/
693 req->async.fn = benchrw_callback;
694 req->async.private_data = state;
696 return NT_STATUS_OK;
700 handler for completion of a sub-request of the bench-rw test
702 static void benchrw_callback(struct smbcli_request *req)
704 struct benchrw_state *state = req->async.private_data;
705 struct torture_context *tctx = state->tctx;
707 /*dont send new requests when torture_numops is reached*/
708 if ((state->mode == READ_WRITE_DATA)
709 && (state->completed >= torture_numops)) {
710 state->mode=MAX_OPS_REACHED;
713 switch (state->mode) {
715 case MK_TESTDIR:
716 if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx, req,state))) {
717 torture_comment(tctx, "Failed to create the test "
718 "directory - %s\n",
719 nt_errstr(req->status));
720 state->mode=ERROR;
721 return;
723 break;
724 case OPEN_FILE:
725 case INITIAL_WRITE:
726 if (!NT_STATUS_IS_OK(benchrw_open(tctx, req,state))){
727 torture_comment(tctx, "Failed to open/write the "
728 "file - %s\n",
729 nt_errstr(req->status));
730 state->mode=ERROR;
731 state->readcnt=0;
732 return;
734 break;
735 case READ_WRITE_DATA:
736 while (state->num_parallel_requests
737 < state->lp_params->num_parallel_requests) {
738 NTSTATUS status;
739 status = benchrw_readwrite(tctx,state);
740 if (!NT_STATUS_IS_OK(status)){
741 torture_comment(tctx, "Failed to read/write "
742 "the file - %s\n",
743 nt_errstr(req->status));
744 state->mode=ERROR;
745 return;
748 break;
749 case MAX_OPS_REACHED:
750 if (!NT_STATUS_IS_OK(benchrw_close(tctx,req,state))){
751 torture_comment(tctx, "Failed to read/write/close "
752 "the file - %s\n",
753 nt_errstr(req->status));
754 state->mode=ERROR;
755 return;
757 break;
758 case CLOSE_FILE:
759 torture_comment(tctx, "File %d closed\n",state->nr);
760 if (!NT_STATUS_IS_OK(req->status)) {
761 torture_comment(tctx, "Failed to close the "
762 "file - %s\n",
763 nt_errstr(req->status));
764 state->mode=ERROR;
765 return;
767 state->mode=CLEANUP;
768 return;
769 default:
770 break;
775 /* open connection async callback function*/
776 static void async_open_callback(struct composite_context *con)
778 struct benchrw_state *state = con->async.private_data;
779 struct torture_context *tctx = state->tctx;
780 int retry = state->lp_params->retry;
782 if (NT_STATUS_IS_OK(con->status)) {
783 state->cli=((struct smb_composite_connect*)
784 state->req_params)->out.tree;
785 state->mode=CLEANUP_TESTDIR;
786 }else{
787 if(state->writecnt < retry){
788 torture_comment(tctx, "Failed to open connection: "
789 "%d, Retry (%d/%d)\n",
790 state->nr,state->writecnt,retry);
791 state->writecnt++;
792 state->mode=START;
793 usleep(1000);
794 }else{
795 torture_comment(tctx, "Failed to open connection "
796 "(%d) - %s\n",
797 state->nr, nt_errstr(con->status));
798 state->mode=ERROR;
800 return;
805 establishs a smbcli_tree from scratch (async)
807 static struct composite_context *torture_connect_async(
808 struct torture_context *tctx,
809 struct smb_composite_connect *smb,
810 TALLOC_CTX *mem_ctx,
811 struct tevent_context *ev,
812 const char *host,
813 const char *share,
814 const char *workgroup)
816 torture_comment(tctx, "Open Connection to %s/%s\n",host,share);
817 smb->in.dest_host=talloc_strdup(mem_ctx,host);
818 smb->in.service=talloc_strdup(mem_ctx,share);
819 smb->in.dest_ports=lp_smb_ports(tctx->lp_ctx);
820 smb->in.socket_options = lp_socket_options(tctx->lp_ctx);
821 smb->in.called_name = strupper_talloc(mem_ctx, host);
822 smb->in.service_type=NULL;
823 smb->in.credentials=cmdline_credentials;
824 smb->in.fallback_to_anonymous=false;
825 smb->in.iconv_convenience = lp_iconv_convenience(tctx->lp_ctx);
826 smb->in.gensec_settings = lp_gensec_settings(mem_ctx, tctx->lp_ctx);
827 smb->in.workgroup=workgroup;
828 lp_smbcli_options(tctx->lp_ctx, &smb->in.options);
829 lp_smbcli_session_options(tctx->lp_ctx, &smb->in.session_options);
831 return smb_composite_connect_send(smb,mem_ctx,
832 lp_resolve_context(tctx->lp_ctx),ev);
835 bool run_benchrw(struct torture_context *tctx)
837 struct smb_composite_connect *smb_con;
838 const char *fname = "\\rwtest.dat";
839 struct smbcli_request *req;
840 struct benchrw_state **state;
841 int i , num_unc_names;
842 struct tevent_context *ev ;
843 struct composite_context *req1;
844 struct params lpparams;
845 union smb_mkdir parms;
846 int finished = 0;
847 bool success=true;
848 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
850 torture_comment(tctx, "Start BENCH-READWRITE num_ops=%d "
851 "num_nprocs=%d\n",
852 torture_numops, torture_nprocs);
854 /*init talloc context*/
855 ev = tctx->ev;
856 state = talloc_array(tctx, struct benchrw_state *, torture_nprocs);
858 /* init params using lp_parm_xxx */
859 num_unc_names = init_benchrw_params(tctx,&lpparams);
861 /* init private data structs*/
862 for(i = 0; i<torture_nprocs;i++){
863 state[i]=talloc(tctx,struct benchrw_state);
864 state[i]->tctx = tctx;
865 state[i]->completed=0;
866 state[i]->num_parallel_requests=0;
867 state[i]->lp_params=&lpparams;
868 state[i]->nr=i;
869 state[i]->dname=talloc_asprintf(tctx,"benchrw%d",i);
870 state[i]->fname=talloc_asprintf(tctx,"%s%s",
871 state[i]->dname,fname);
872 state[i]->mode=START;
873 state[i]->writecnt=0;
876 torture_comment(tctx, "Starting async requests\n");
877 while(finished != torture_nprocs){
878 finished=0;
879 for(i = 0; i<torture_nprocs;i++){
880 switch (state[i]->mode){
881 /*open multiple connections with the same userid */
882 case START:
883 smb_con = talloc(
884 tctx,struct smb_composite_connect) ;
885 state[i]->req_params=smb_con;
886 state[i]->mode=OPEN_CONNECTION;
887 req1 = torture_connect_async(
888 tctx, smb_con, tctx,ev,
889 lpparams.unc[i % num_unc_names]->host,
890 lpparams.unc[i % num_unc_names]->share,
891 lpparams.workgroup);
892 /* register callback fn + private data */
893 req1->async.fn = async_open_callback;
894 req1->async.private_data=state[i];
895 break;
896 /*setup test dirs (sync)*/
897 case CLEANUP_TESTDIR:
898 torture_comment(tctx, "Setup test dir %d\n",i);
899 smb_raw_exit(state[i]->cli->session);
900 if (smbcli_deltree(state[i]->cli,
901 state[i]->dname) == -1) {
902 torture_comment(
903 tctx,
904 "Unable to delete %s - %s\n",
905 state[i]->dname,
906 smbcli_errstr(state[i]->cli));
907 state[i]->mode=ERROR;
908 break;
910 state[i]->mode=MK_TESTDIR;
911 parms.mkdir.level = RAW_MKDIR_MKDIR;
912 parms.mkdir.in.path = state[i]->dname;
913 req = smb_raw_mkdir_send(state[i]->cli,&parms);
914 /* register callback fn + private data */
915 req->async.fn = benchrw_callback;
916 req->async.private_data=state[i];
917 break;
918 /* error occured , finish */
919 case ERROR:
920 finished++;
921 success=false;
922 break;
923 /* cleanup , close connection */
924 case CLEANUP:
925 torture_comment(tctx, "Deleting test dir %s "
926 "%d/%d\n",state[i]->dname,
927 i+1,torture_nprocs);
928 smbcli_deltree(state[i]->cli,state[i]->dname);
929 if (NT_STATUS_IS_ERR(smb_tree_disconnect(
930 state[i]->cli))) {
931 torture_comment(tctx, "ERROR: Tree "
932 "disconnect failed");
933 state[i]->mode=ERROR;
934 break;
936 state[i]->mode=FINISHED;
937 case FINISHED:
938 finished++;
939 break;
940 default:
941 event_loop_once(ev);
946 return success;