s4:smbtorture: add BASE-BENCH-HOLDOPEN
[Samba/fernandojvsilva.git] / source4 / torture / basic / misc.c
blobab79d798fc52be4bad1d5d0d7b8f26b77594c639
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 "torture/smbtorture.h"
32 #include "torture/util.h"
33 #include "libcli/smb_composite/smb_composite.h"
34 #include "libcli/composite/composite.h"
35 #include "param/param.h"
37 extern struct cli_credentials *cmdline_credentials;
39 static bool wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
41 while (NT_STATUS_IS_ERR(smbcli_lock(c->tree, fnum, offset, len, -1, WRITE_LOCK))) {
42 if (!check_error(__location__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
44 return true;
48 static bool rw_torture(struct torture_context *tctx, struct smbcli_state *c)
50 const char *lockfname = "\\torture.lck";
51 char *fname;
52 int fnum;
53 int fnum2;
54 pid_t pid2, pid = getpid();
55 int i, j;
56 uint8_t buf[1024];
57 bool correct = true;
59 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR | O_CREAT | O_EXCL,
60 DENY_NONE);
61 if (fnum2 == -1)
62 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR, DENY_NONE);
63 if (fnum2 == -1) {
64 torture_comment(tctx, "open of %s failed (%s)\n", lockfname, smbcli_errstr(c->tree));
65 return false;
68 generate_random_buffer(buf, sizeof(buf));
70 for (i=0;i<torture_numops;i++) {
71 uint_t n = (uint_t)random()%10;
72 if (i % 10 == 0) {
73 if (torture_setting_bool(tctx, "progress", true)) {
74 torture_comment(tctx, "%d\r", i);
75 fflush(stdout);
78 asprintf(&fname, "\\torture.%u", n);
80 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
81 return false;
84 fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
85 if (fnum == -1) {
86 torture_comment(tctx, "open failed (%s)\n", smbcli_errstr(c->tree));
87 correct = false;
88 break;
91 if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) {
92 torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
93 correct = false;
96 for (j=0;j<50;j++) {
97 if (smbcli_write(c->tree, fnum, 0, buf,
98 sizeof(pid)+(j*sizeof(buf)),
99 sizeof(buf)) != sizeof(buf)) {
100 torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
101 correct = false;
105 pid2 = 0;
107 if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) {
108 torture_comment(tctx, "read failed (%s)\n", smbcli_errstr(c->tree));
109 correct = false;
112 if (pid2 != pid) {
113 torture_comment(tctx, "data corruption!\n");
114 correct = false;
117 if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) {
118 torture_comment(tctx, "close failed (%s)\n", smbcli_errstr(c->tree));
119 correct = false;
122 if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) {
123 torture_comment(tctx, "unlink failed (%s)\n", smbcli_errstr(c->tree));
124 correct = false;
127 if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) {
128 torture_comment(tctx, "unlock failed (%s)\n", smbcli_errstr(c->tree));
129 correct = false;
131 free(fname);
134 smbcli_close(c->tree, fnum2);
135 smbcli_unlink(c->tree, lockfname);
137 torture_comment(tctx, "%d\n", i);
139 return correct;
142 bool run_torture(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
144 return rw_torture(tctx, cli);
149 see how many RPC pipes we can open at once
151 bool run_pipe_number(struct torture_context *tctx,
152 struct smbcli_state *cli1)
154 const char *pipe_name = "\\WKSSVC";
155 int fnum;
156 int num_pipes = 0;
158 while(1) {
159 fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
160 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0);
162 if (fnum == -1) {
163 torture_comment(tctx, "Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree));
164 break;
166 num_pipes++;
167 if (torture_setting_bool(tctx, "progress", true)) {
168 torture_comment(tctx, "%d\r", num_pipes);
169 fflush(stdout);
173 torture_comment(tctx, "pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
174 return true;
181 open N connections to the server and just hold them open
182 used for testing performance when there are N idle users
183 already connected
185 bool torture_holdcon(struct torture_context *tctx)
187 int i;
188 struct smbcli_state **cli;
189 int num_dead = 0;
191 torture_comment(tctx, "Opening %d connections\n", torture_numops);
193 cli = malloc_array_p(struct smbcli_state *, torture_numops);
195 for (i=0;i<torture_numops;i++) {
196 if (!torture_open_connection(&cli[i], tctx, i)) {
197 return false;
199 if (torture_setting_bool(tctx, "progress", true)) {
200 torture_comment(tctx, "opened %d connections\r", i);
201 fflush(stdout);
205 torture_comment(tctx, "\nStarting pings\n");
207 while (1) {
208 for (i=0;i<torture_numops;i++) {
209 NTSTATUS status;
210 if (cli[i]) {
211 status = smbcli_chkpath(cli[i]->tree, "\\");
212 if (!NT_STATUS_IS_OK(status)) {
213 torture_comment(tctx, "Connection %d is dead\n", i);
214 cli[i] = NULL;
215 num_dead++;
217 usleep(100);
221 if (num_dead == torture_numops) {
222 torture_comment(tctx, "All connections dead - finishing\n");
223 break;
226 torture_comment(tctx, ".");
227 fflush(stdout);
230 return true;
234 open a file N times on the server and just hold them open
235 used for testing performance when there are N file handles
236 alopenn
238 bool torture_holdopen(struct torture_context *tctx,
239 struct smbcli_state *cli)
241 int i, fnum;
242 const char *fname = "\\holdopen.dat";
243 NTSTATUS status;
245 smbcli_unlink(cli->tree, fname);
247 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
248 if (fnum == -1) {
249 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
250 return false;
253 smbcli_close(cli->tree, fnum);
255 for (i=0;i<torture_numops;i++) {
256 union smb_open op;
258 op.generic.level = RAW_OPEN_NTCREATEX;
259 op.ntcreatex.in.root_fid.fnum = 0;
260 op.ntcreatex.in.flags = 0;
261 op.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
262 op.ntcreatex.in.create_options = 0;
263 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
264 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
265 op.ntcreatex.in.alloc_size = 0;
266 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
267 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
268 op.ntcreatex.in.security_flags = 0;
269 op.ntcreatex.in.fname = fname;
270 status = smb_raw_open(cli->tree, tctx, &op);
271 if (!NT_STATUS_IS_OK(status)) {
272 torture_warning(tctx, "open %d failed\n", i);
273 continue;
276 if (torture_setting_bool(tctx, "progress", true)) {
277 torture_comment(tctx, "opened %d file\r", i);
278 fflush(stdout);
282 torture_comment(tctx, "\nStarting pings\n");
284 while (1) {
285 struct smb_echo ec;
287 status = smb_raw_echo(cli->transport, &ec);
288 torture_comment(tctx, ".");
289 fflush(stdout);
290 sleep(15);
293 return true;
297 test how many open files this server supports on the one socket
299 bool run_maxfidtest(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
301 #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
302 char *fname;
303 int fnums[0x11000], i;
304 int retries=4, maxfid;
305 bool correct = true;
307 if (retries <= 0) {
308 torture_comment(tctx, "failed to connect\n");
309 return false;
312 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
313 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
314 smbcli_errstr(cli->tree));
315 return false;
317 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
318 torture_comment(tctx, "Failed to mkdir \\maxfid, error=%s\n",
319 smbcli_errstr(cli->tree));
320 return false;
323 torture_comment(tctx, "Testing maximum number of open files\n");
325 for (i=0; i<0x11000; i++) {
326 if (i % 1000 == 0) {
327 asprintf(&fname, "\\maxfid\\fid%d", i/1000);
328 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
329 torture_comment(tctx, "Failed to mkdir %s, error=%s\n",
330 fname, smbcli_errstr(cli->tree));
331 return false;
333 free(fname);
335 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
336 if ((fnums[i] = smbcli_open(cli->tree, fname,
337 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
338 -1) {
339 torture_comment(tctx, "open of %s failed (%s)\n",
340 fname, smbcli_errstr(cli->tree));
341 torture_comment(tctx, "maximum fnum is %d\n", i);
342 break;
344 free(fname);
345 if (torture_setting_bool(tctx, "progress", true)) {
346 torture_comment(tctx, "%6d\r", i);
347 fflush(stdout);
350 torture_comment(tctx, "%6d\n", i);
351 i--;
353 maxfid = i;
355 torture_comment(tctx, "cleaning up\n");
356 for (i=0;i<maxfid/2;i++) {
357 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
358 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
359 torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
361 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
362 torture_comment(tctx, "unlink of %s failed (%s)\n",
363 fname, smbcli_errstr(cli->tree));
364 correct = false;
366 free(fname);
368 asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid());
369 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) {
370 torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree));
372 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
373 torture_comment(tctx, "unlink of %s failed (%s)\n",
374 fname, smbcli_errstr(cli->tree));
375 correct = false;
377 free(fname);
379 if (torture_setting_bool(tctx, "progress", true)) {
380 torture_comment(tctx, "%6d %6d\r", i, maxfid-i);
381 fflush(stdout);
384 torture_comment(tctx, "%6d\n", 0);
386 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
387 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
388 smbcli_errstr(cli->tree));
389 return false;
392 torture_comment(tctx, "maxfid test finished\n");
393 if (!torture_close_connection(cli)) {
394 correct = false;
396 return correct;
397 #undef MAXFID_TEMPLATE
403 sees what IOCTLs are supported
405 bool torture_ioctl_test(struct torture_context *tctx,
406 struct smbcli_state *cli)
408 uint16_t device, function;
409 int fnum;
410 const char *fname = "\\ioctl.dat";
411 NTSTATUS status;
412 union smb_ioctl parms;
413 TALLOC_CTX *mem_ctx;
415 mem_ctx = talloc_named_const(tctx, 0, "ioctl_test");
417 smbcli_unlink(cli->tree, fname);
419 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
420 if (fnum == -1) {
421 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
422 return false;
425 parms.ioctl.level = RAW_IOCTL_IOCTL;
426 parms.ioctl.in.file.fnum = fnum;
427 parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
428 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
429 torture_comment(tctx, "ioctl job info: %s\n", smbcli_errstr(cli->tree));
431 for (device=0;device<0x100;device++) {
432 torture_comment(tctx, "testing device=0x%x\n", device);
433 for (function=0;function<0x100;function++) {
434 parms.ioctl.in.request = (device << 16) | function;
435 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
437 if (NT_STATUS_IS_OK(status)) {
438 torture_comment(tctx, "ioctl device=0x%x function=0x%x OK : %d bytes\n",
439 device, function, (int)parms.ioctl.out.blob.length);
444 return true;
447 static void benchrw_callback(struct smbcli_request *req);
448 enum benchrw_stage {
449 START,
450 OPEN_CONNECTION,
451 CLEANUP_TESTDIR,
452 MK_TESTDIR,
453 OPEN_FILE,
454 INITIAL_WRITE,
455 READ_WRITE_DATA,
456 MAX_OPS_REACHED,
457 ERROR,
458 CLOSE_FILE,
459 CLEANUP,
460 FINISHED
463 struct benchrw_state {
464 struct torture_context *tctx;
465 char *dname;
466 char *fname;
467 uint16_t fnum;
468 int nr;
469 struct smbcli_tree *cli;
470 uint8_t *buffer;
471 int writecnt;
472 int readcnt;
473 int completed;
474 int num_parallel_requests;
475 void *req_params;
476 enum benchrw_stage mode;
477 struct params{
478 struct unclist{
479 const char *host;
480 const char *share;
481 } **unc;
482 const char *workgroup;
483 int retry;
484 unsigned int writeblocks;
485 unsigned int blocksize;
486 unsigned int writeratio;
487 int num_parallel_requests;
488 } *lp_params;
492 init params using lp_parm_xxx
493 return number of unclist entries
495 static int init_benchrw_params(struct torture_context *tctx,
496 struct params *lpar)
498 char **unc_list = NULL;
499 int num_unc_names = 0, conn_index=0, empty_lines=0;
500 const char *p;
501 lpar->retry = torture_setting_int(tctx, "retry",3);
502 lpar->blocksize = torture_setting_int(tctx, "blocksize",65535);
503 lpar->writeblocks = torture_setting_int(tctx, "writeblocks",15);
504 lpar->writeratio = torture_setting_int(tctx, "writeratio",5);
505 lpar->num_parallel_requests = torture_setting_int(
506 tctx, "parallel_requests", 5);
507 lpar->workgroup = lp_workgroup(tctx->lp_ctx);
509 p = torture_setting_string(tctx, "unclist", NULL);
510 if (p) {
511 char *h, *s;
512 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
513 if (!unc_list || num_unc_names <= 0) {
514 torture_comment(tctx, "Failed to load unc names list "
515 "from '%s'\n", p);
516 exit(1);
519 lpar->unc = talloc_array(tctx, struct unclist *,
520 (num_unc_names-empty_lines));
521 for(conn_index = 0; conn_index < num_unc_names; conn_index++) {
522 /* ignore empty lines */
523 if(strlen(unc_list[conn_index % num_unc_names])==0){
524 empty_lines++;
525 continue;
527 if (!smbcli_parse_unc(
528 unc_list[conn_index % num_unc_names],
529 NULL, &h, &s)) {
530 torture_comment(
531 tctx, "Failed to parse UNC "
532 "name %s\n",
533 unc_list[conn_index % num_unc_names]);
534 exit(1);
536 lpar->unc[conn_index-empty_lines] =
537 talloc(tctx, struct unclist);
538 lpar->unc[conn_index-empty_lines]->host = h;
539 lpar->unc[conn_index-empty_lines]->share = s;
541 return num_unc_names-empty_lines;
542 }else{
543 lpar->unc = talloc_array(tctx, struct unclist *, 1);
544 lpar->unc[0] = talloc(tctx,struct unclist);
545 lpar->unc[0]->host = torture_setting_string(tctx, "host",
546 NULL);
547 lpar->unc[0]->share = torture_setting_string(tctx, "share",
548 NULL);
549 return 1;
554 Called when the reads & writes are finished. closes the file.
556 static NTSTATUS benchrw_close(struct torture_context *tctx,
557 struct smbcli_request *req,
558 struct benchrw_state *state)
560 union smb_close close_parms;
562 NT_STATUS_NOT_OK_RETURN(req->status);
564 torture_comment(tctx, "Close file %d (%d)\n",state->nr,state->fnum);
565 close_parms.close.level = RAW_CLOSE_CLOSE;
566 close_parms.close.in.file.fnum = state->fnum ;
567 close_parms.close.in.write_time = 0;
568 state->mode=CLOSE_FILE;
570 req = smb_raw_close_send(state->cli, &close_parms);
571 NT_STATUS_HAVE_NO_MEMORY(req);
572 /*register the callback function!*/
573 req->async.fn = benchrw_callback;
574 req->async.private_data = state;
576 return NT_STATUS_OK;
579 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
580 struct benchrw_state *state);
581 static void benchrw_callback(struct smbcli_request *req);
583 static void benchrw_rw_callback(struct smbcli_request *req)
585 struct benchrw_state *state = req->async.private_data;
586 struct torture_context *tctx = state->tctx;
588 if (!NT_STATUS_IS_OK(req->status)) {
589 state->mode = ERROR;
590 return;
593 state->completed++;
594 state->num_parallel_requests--;
596 if ((state->completed >= torture_numops)
597 && (state->num_parallel_requests == 0)) {
598 benchrw_callback(req);
599 talloc_free(req);
600 return;
603 talloc_free(req);
605 if (state->completed + state->num_parallel_requests
606 < torture_numops) {
607 benchrw_readwrite(tctx, state);
612 Called when the initial write is completed is done. write or read a file.
614 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
615 struct benchrw_state *state)
617 struct smbcli_request *req;
618 union smb_read rd;
619 union smb_write wr;
621 /* randomize between writes and reads*/
622 if (random() % state->lp_params->writeratio == 0) {
623 torture_comment(tctx, "Callback WRITE file:%d (%d/%d)\n",
624 state->nr,state->completed,torture_numops);
625 wr.generic.level = RAW_WRITE_WRITEX ;
626 wr.writex.in.file.fnum = state->fnum ;
627 wr.writex.in.offset = 0;
628 wr.writex.in.wmode = 0 ;
629 wr.writex.in.remaining = 0;
630 wr.writex.in.count = state->lp_params->blocksize;
631 wr.writex.in.data = state->buffer;
632 state->readcnt=0;
633 req = smb_raw_write_send(state->cli,&wr);
635 else {
636 torture_comment(tctx,
637 "Callback READ file:%d (%d/%d) Offset:%d\n",
638 state->nr,state->completed,torture_numops,
639 (state->readcnt*state->lp_params->blocksize));
640 rd.generic.level = RAW_READ_READX;
641 rd.readx.in.file.fnum = state->fnum ;
642 rd.readx.in.offset = state->readcnt*state->lp_params->blocksize;
643 rd.readx.in.mincnt = state->lp_params->blocksize;
644 rd.readx.in.maxcnt = rd.readx.in.mincnt;
645 rd.readx.in.remaining = 0 ;
646 rd.readx.out.data = state->buffer;
647 rd.readx.in.read_for_execute = false;
648 if(state->readcnt < state->lp_params->writeblocks){
649 state->readcnt++;
650 }else{
651 /*start reading from beginn of file*/
652 state->readcnt=0;
654 req = smb_raw_read_send(state->cli,&rd);
656 state->num_parallel_requests += 1;
657 NT_STATUS_HAVE_NO_MEMORY(req);
658 /*register the callback function!*/
659 req->async.fn = benchrw_rw_callback;
660 req->async.private_data = state;
662 return NT_STATUS_OK;
666 Called when the open is done. writes to the file.
668 static NTSTATUS benchrw_open(struct torture_context *tctx,
669 struct smbcli_request *req,
670 struct benchrw_state *state)
672 union smb_write wr;
673 if(state->mode == OPEN_FILE){
674 NTSTATUS status;
675 status = smb_raw_open_recv(req,tctx,(
676 union smb_open*)state->req_params);
677 NT_STATUS_NOT_OK_RETURN(status);
679 state->fnum = ((union smb_open*)state->req_params)
680 ->openx.out.file.fnum;
681 torture_comment(tctx, "File opened (%d)\n",state->fnum);
682 state->mode=INITIAL_WRITE;
685 torture_comment(tctx, "Write initial test file:%d (%d/%d)\n",state->nr,
686 (state->writecnt+1)*state->lp_params->blocksize,
687 (state->lp_params->writeblocks*state->lp_params->blocksize));
688 wr.generic.level = RAW_WRITE_WRITEX ;
689 wr.writex.in.file.fnum = state->fnum ;
690 wr.writex.in.offset = state->writecnt *
691 state->lp_params->blocksize;
692 wr.writex.in.wmode = 0 ;
693 wr.writex.in.remaining = (state->lp_params->writeblocks *
694 state->lp_params->blocksize)-
695 ((state->writecnt+1)*state->
696 lp_params->blocksize);
697 wr.writex.in.count = state->lp_params->blocksize;
698 wr.writex.in.data = state->buffer;
699 state->writecnt++;
700 if(state->writecnt == state->lp_params->writeblocks){
701 state->mode=READ_WRITE_DATA;
703 req = smb_raw_write_send(state->cli,&wr);
704 NT_STATUS_HAVE_NO_MEMORY(req);
706 /*register the callback function!*/
707 req->async.fn = benchrw_callback;
708 req->async.private_data = state;
709 return NT_STATUS_OK;
713 Called when the mkdir is done. Opens a file.
715 static NTSTATUS benchrw_mkdir(struct torture_context *tctx,
716 struct smbcli_request *req,
717 struct benchrw_state *state)
719 union smb_open *open_parms;
720 uint8_t *writedata;
722 NT_STATUS_NOT_OK_RETURN(req->status);
724 /* open/create the files */
725 torture_comment(tctx, "Open File %d/%d\n",state->nr+1,
726 torture_setting_int(tctx, "nprocs", 4));
727 open_parms=talloc_zero(tctx, union smb_open);
728 NT_STATUS_HAVE_NO_MEMORY(open_parms);
729 open_parms->openx.level = RAW_OPEN_OPENX;
730 open_parms->openx.in.flags = 0;
731 open_parms->openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
732 open_parms->openx.in.search_attrs =
733 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
734 open_parms->openx.in.file_attrs = 0;
735 open_parms->openx.in.write_time = 0;
736 open_parms->openx.in.open_func = OPENX_OPEN_FUNC_CREATE;
737 open_parms->openx.in.size = 0;
738 open_parms->openx.in.timeout = 0;
739 open_parms->openx.in.fname = state->fname;
741 writedata = talloc_size(tctx,state->lp_params->blocksize);
742 NT_STATUS_HAVE_NO_MEMORY(writedata);
743 generate_random_buffer(writedata,state->lp_params->blocksize);
744 state->buffer=writedata;
745 state->writecnt=1;
746 state->readcnt=0;
747 state->req_params=open_parms;
748 state->mode=OPEN_FILE;
750 req = smb_raw_open_send(state->cli,open_parms);
751 NT_STATUS_HAVE_NO_MEMORY(req);
753 /*register the callback function!*/
754 req->async.fn = benchrw_callback;
755 req->async.private_data = state;
757 return NT_STATUS_OK;
761 handler for completion of a sub-request of the bench-rw test
763 static void benchrw_callback(struct smbcli_request *req)
765 struct benchrw_state *state = req->async.private_data;
766 struct torture_context *tctx = state->tctx;
768 /*dont send new requests when torture_numops is reached*/
769 if ((state->mode == READ_WRITE_DATA)
770 && (state->completed >= torture_numops)) {
771 state->mode=MAX_OPS_REACHED;
774 switch (state->mode) {
776 case MK_TESTDIR:
777 if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx, req,state))) {
778 torture_comment(tctx, "Failed to create the test "
779 "directory - %s\n",
780 nt_errstr(req->status));
781 state->mode=ERROR;
782 return;
784 break;
785 case OPEN_FILE:
786 case INITIAL_WRITE:
787 if (!NT_STATUS_IS_OK(benchrw_open(tctx, req,state))){
788 torture_comment(tctx, "Failed to open/write the "
789 "file - %s\n",
790 nt_errstr(req->status));
791 state->mode=ERROR;
792 state->readcnt=0;
793 return;
795 break;
796 case READ_WRITE_DATA:
797 while (state->num_parallel_requests
798 < state->lp_params->num_parallel_requests) {
799 NTSTATUS status;
800 status = benchrw_readwrite(tctx,state);
801 if (!NT_STATUS_IS_OK(status)){
802 torture_comment(tctx, "Failed to read/write "
803 "the file - %s\n",
804 nt_errstr(req->status));
805 state->mode=ERROR;
806 return;
809 break;
810 case MAX_OPS_REACHED:
811 if (!NT_STATUS_IS_OK(benchrw_close(tctx,req,state))){
812 torture_comment(tctx, "Failed to read/write/close "
813 "the file - %s\n",
814 nt_errstr(req->status));
815 state->mode=ERROR;
816 return;
818 break;
819 case CLOSE_FILE:
820 torture_comment(tctx, "File %d closed\n",state->nr);
821 if (!NT_STATUS_IS_OK(req->status)) {
822 torture_comment(tctx, "Failed to close the "
823 "file - %s\n",
824 nt_errstr(req->status));
825 state->mode=ERROR;
826 return;
828 state->mode=CLEANUP;
829 return;
830 default:
831 break;
836 /* open connection async callback function*/
837 static void async_open_callback(struct composite_context *con)
839 struct benchrw_state *state = con->async.private_data;
840 struct torture_context *tctx = state->tctx;
841 int retry = state->lp_params->retry;
843 if (NT_STATUS_IS_OK(con->status)) {
844 state->cli=((struct smb_composite_connect*)
845 state->req_params)->out.tree;
846 state->mode=CLEANUP_TESTDIR;
847 }else{
848 if(state->writecnt < retry){
849 torture_comment(tctx, "Failed to open connection: "
850 "%d, Retry (%d/%d)\n",
851 state->nr,state->writecnt,retry);
852 state->writecnt++;
853 state->mode=START;
854 usleep(1000);
855 }else{
856 torture_comment(tctx, "Failed to open connection "
857 "(%d) - %s\n",
858 state->nr, nt_errstr(con->status));
859 state->mode=ERROR;
861 return;
866 establishs a smbcli_tree from scratch (async)
868 static struct composite_context *torture_connect_async(
869 struct torture_context *tctx,
870 struct smb_composite_connect *smb,
871 TALLOC_CTX *mem_ctx,
872 struct tevent_context *ev,
873 const char *host,
874 const char *share,
875 const char *workgroup)
877 torture_comment(tctx, "Open Connection to %s/%s\n",host,share);
878 smb->in.dest_host=talloc_strdup(mem_ctx,host);
879 smb->in.service=talloc_strdup(mem_ctx,share);
880 smb->in.dest_ports=lp_smb_ports(tctx->lp_ctx);
881 smb->in.socket_options = lp_socket_options(tctx->lp_ctx);
882 smb->in.called_name = strupper_talloc(mem_ctx, host);
883 smb->in.service_type=NULL;
884 smb->in.credentials=cmdline_credentials;
885 smb->in.fallback_to_anonymous=false;
886 smb->in.iconv_convenience = lp_iconv_convenience(tctx->lp_ctx);
887 smb->in.gensec_settings = lp_gensec_settings(mem_ctx, tctx->lp_ctx);
888 smb->in.workgroup=workgroup;
889 lp_smbcli_options(tctx->lp_ctx, &smb->in.options);
890 lp_smbcli_session_options(tctx->lp_ctx, &smb->in.session_options);
892 return smb_composite_connect_send(smb,mem_ctx,
893 lp_resolve_context(tctx->lp_ctx),ev);
896 bool run_benchrw(struct torture_context *tctx)
898 struct smb_composite_connect *smb_con;
899 const char *fname = "\\rwtest.dat";
900 struct smbcli_request *req;
901 struct benchrw_state **state;
902 int i , num_unc_names;
903 struct tevent_context *ev ;
904 struct composite_context *req1;
905 struct params lpparams;
906 union smb_mkdir parms;
907 int finished = 0;
908 bool success=true;
909 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
911 torture_comment(tctx, "Start BENCH-READWRITE num_ops=%d "
912 "num_nprocs=%d\n",
913 torture_numops, torture_nprocs);
915 /*init talloc context*/
916 ev = tctx->ev;
917 state = talloc_array(tctx, struct benchrw_state *, torture_nprocs);
919 /* init params using lp_parm_xxx */
920 num_unc_names = init_benchrw_params(tctx,&lpparams);
922 /* init private data structs*/
923 for(i = 0; i<torture_nprocs;i++){
924 state[i]=talloc(tctx,struct benchrw_state);
925 state[i]->tctx = tctx;
926 state[i]->completed=0;
927 state[i]->num_parallel_requests=0;
928 state[i]->lp_params=&lpparams;
929 state[i]->nr=i;
930 state[i]->dname=talloc_asprintf(tctx,"benchrw%d",i);
931 state[i]->fname=talloc_asprintf(tctx,"%s%s",
932 state[i]->dname,fname);
933 state[i]->mode=START;
934 state[i]->writecnt=0;
937 torture_comment(tctx, "Starting async requests\n");
938 while(finished != torture_nprocs){
939 finished=0;
940 for(i = 0; i<torture_nprocs;i++){
941 switch (state[i]->mode){
942 /*open multiple connections with the same userid */
943 case START:
944 smb_con = talloc(
945 tctx,struct smb_composite_connect) ;
946 state[i]->req_params=smb_con;
947 state[i]->mode=OPEN_CONNECTION;
948 req1 = torture_connect_async(
949 tctx, smb_con, tctx,ev,
950 lpparams.unc[i % num_unc_names]->host,
951 lpparams.unc[i % num_unc_names]->share,
952 lpparams.workgroup);
953 /* register callback fn + private data */
954 req1->async.fn = async_open_callback;
955 req1->async.private_data=state[i];
956 break;
957 /*setup test dirs (sync)*/
958 case CLEANUP_TESTDIR:
959 torture_comment(tctx, "Setup test dir %d\n",i);
960 smb_raw_exit(state[i]->cli->session);
961 if (smbcli_deltree(state[i]->cli,
962 state[i]->dname) == -1) {
963 torture_comment(
964 tctx,
965 "Unable to delete %s - %s\n",
966 state[i]->dname,
967 smbcli_errstr(state[i]->cli));
968 state[i]->mode=ERROR;
969 break;
971 state[i]->mode=MK_TESTDIR;
972 parms.mkdir.level = RAW_MKDIR_MKDIR;
973 parms.mkdir.in.path = state[i]->dname;
974 req = smb_raw_mkdir_send(state[i]->cli,&parms);
975 /* register callback fn + private data */
976 req->async.fn = benchrw_callback;
977 req->async.private_data=state[i];
978 break;
979 /* error occured , finish */
980 case ERROR:
981 finished++;
982 success=false;
983 break;
984 /* cleanup , close connection */
985 case CLEANUP:
986 torture_comment(tctx, "Deleting test dir %s "
987 "%d/%d\n",state[i]->dname,
988 i+1,torture_nprocs);
989 smbcli_deltree(state[i]->cli,state[i]->dname);
990 if (NT_STATUS_IS_ERR(smb_tree_disconnect(
991 state[i]->cli))) {
992 torture_comment(tctx, "ERROR: Tree "
993 "disconnect failed");
994 state[i]->mode=ERROR;
995 break;
997 state[i]->mode=FINISHED;
998 case FINISHED:
999 finished++;
1000 break;
1001 default:
1002 event_loop_once(ev);
1007 return success;