s4-selftest: fix output of opened connections in torture_holdcon
[Samba/bjacke.git] / source4 / torture / basic / misc.c
blob213d9239509fca9249083e1615870c3fea8aa401
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/smb/smb_constants.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"
36 #include "torture/basic/proto.h"
38 extern struct cli_credentials *cmdline_credentials;
40 static bool wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
42 while (NT_STATUS_IS_ERR(smbcli_lock(c->tree, fnum, offset, len, -1, WRITE_LOCK))) {
43 if (!check_error(__location__, c, ERRDOS, ERRlock, NT_STATUS_LOCK_NOT_GRANTED)) return false;
45 return true;
49 static bool rw_torture(struct torture_context *tctx, struct smbcli_state *c)
51 const char *lockfname = "\\torture.lck";
52 char *fname;
53 int fnum;
54 int fnum2;
55 pid_t pid2, pid = getpid();
56 int i, j;
57 uint8_t buf[1024];
58 bool correct = true;
60 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR | O_CREAT | O_EXCL,
61 DENY_NONE);
62 if (fnum2 == -1)
63 fnum2 = smbcli_open(c->tree, lockfname, O_RDWR, DENY_NONE);
64 if (fnum2 == -1) {
65 torture_comment(tctx, "open of %s failed (%s)\n", lockfname, smbcli_errstr(c->tree));
66 return false;
69 generate_random_buffer(buf, sizeof(buf));
71 for (i=0;i<torture_numops;i++) {
72 unsigned int n = (unsigned int)random()%10;
73 if (i % 10 == 0) {
74 if (torture_setting_bool(tctx, "progress", true)) {
75 torture_comment(tctx, "%d\r", i);
76 fflush(stdout);
79 asprintf(&fname, "\\torture.%u", n);
81 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
82 return false;
85 fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
86 if (fnum == -1) {
87 torture_comment(tctx, "open failed (%s)\n", smbcli_errstr(c->tree));
88 correct = false;
89 break;
92 if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) {
93 torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
94 correct = false;
97 for (j=0;j<50;j++) {
98 if (smbcli_write(c->tree, fnum, 0, buf,
99 sizeof(pid)+(j*sizeof(buf)),
100 sizeof(buf)) != sizeof(buf)) {
101 torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
102 correct = false;
106 pid2 = 0;
108 if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) {
109 torture_comment(tctx, "read failed (%s)\n", smbcli_errstr(c->tree));
110 correct = false;
113 if (pid2 != pid) {
114 torture_comment(tctx, "data corruption!\n");
115 correct = false;
118 if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) {
119 torture_comment(tctx, "close failed (%s)\n", smbcli_errstr(c->tree));
120 correct = false;
123 if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) {
124 torture_comment(tctx, "unlink failed (%s)\n", smbcli_errstr(c->tree));
125 correct = false;
128 if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) {
129 torture_comment(tctx, "unlock failed (%s)\n", smbcli_errstr(c->tree));
130 correct = false;
132 free(fname);
135 smbcli_close(c->tree, fnum2);
136 smbcli_unlink(c->tree, lockfname);
138 torture_comment(tctx, "%d\n", i);
140 return correct;
143 bool run_torture(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
145 return rw_torture(tctx, cli);
150 see how many RPC pipes we can open at once
152 bool run_pipe_number(struct torture_context *tctx,
153 struct smbcli_state *cli1)
155 const char *pipe_name = "\\WKSSVC";
156 int fnum;
157 int num_pipes = 0;
159 while(1) {
160 fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
161 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0);
163 if (fnum == -1) {
164 torture_comment(tctx, "Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree));
165 break;
167 num_pipes++;
168 if (torture_setting_bool(tctx, "progress", true)) {
169 torture_comment(tctx, "%d\r", num_pipes);
170 fflush(stdout);
174 torture_comment(tctx, "pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
175 return true;
182 open N connections to the server and just hold them open
183 used for testing performance when there are N idle users
184 already connected
186 bool torture_holdcon(struct torture_context *tctx)
188 int i;
189 struct smbcli_state **cli;
190 int num_dead = 0;
192 torture_comment(tctx, "Opening %d connections\n", torture_numops);
194 cli = malloc_array_p(struct smbcli_state *, torture_numops);
196 for (i=0;i<torture_numops;i++) {
197 if (!torture_open_connection(&cli[i], tctx, i)) {
198 return false;
200 if (torture_setting_bool(tctx, "progress", true)) {
201 torture_comment(tctx, "opened %d connections\r", i+1);
202 fflush(stdout);
206 torture_comment(tctx, "\nStarting pings\n");
208 while (1) {
209 for (i=0;i<torture_numops;i++) {
210 NTSTATUS status;
211 if (cli[i]) {
212 status = smbcli_chkpath(cli[i]->tree, "\\");
213 if (!NT_STATUS_IS_OK(status)) {
214 torture_comment(tctx, "Connection %d is dead\n", i);
215 cli[i] = NULL;
216 num_dead++;
218 usleep(100);
222 if (num_dead == torture_numops) {
223 torture_comment(tctx, "All connections dead - finishing\n");
224 break;
227 torture_comment(tctx, ".");
228 fflush(stdout);
231 return true;
235 open a file N times on the server and just hold them open
236 used for testing performance when there are N file handles
237 alopenn
239 bool torture_holdopen(struct torture_context *tctx,
240 struct smbcli_state *cli)
242 int i, fnum;
243 const char *fname = "\\holdopen.dat";
244 NTSTATUS status;
246 smbcli_unlink(cli->tree, fname);
248 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
249 if (fnum == -1) {
250 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
251 return false;
254 smbcli_close(cli->tree, fnum);
256 for (i=0;i<torture_numops;i++) {
257 union smb_open op;
259 op.generic.level = RAW_OPEN_NTCREATEX;
260 op.ntcreatex.in.root_fid.fnum = 0;
261 op.ntcreatex.in.flags = 0;
262 op.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
263 op.ntcreatex.in.create_options = 0;
264 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
265 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
266 op.ntcreatex.in.alloc_size = 0;
267 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
268 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
269 op.ntcreatex.in.security_flags = 0;
270 op.ntcreatex.in.fname = fname;
271 status = smb_raw_open(cli->tree, tctx, &op);
272 if (!NT_STATUS_IS_OK(status)) {
273 torture_warning(tctx, "open %d failed\n", i);
274 continue;
277 if (torture_setting_bool(tctx, "progress", true)) {
278 torture_comment(tctx, "opened %d file\r", i);
279 fflush(stdout);
283 torture_comment(tctx, "\nStarting pings\n");
285 while (1) {
286 struct smb_echo ec;
288 status = smb_raw_echo(cli->transport, &ec);
289 torture_comment(tctx, ".");
290 fflush(stdout);
291 sleep(15);
296 test how many open files this server supports on the one socket
298 bool run_maxfidtest(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
300 #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
301 char *fname;
302 int fnums[0x11000], i;
303 int retries=4, maxfid;
304 bool correct = true;
306 if (retries <= 0) {
307 torture_comment(tctx, "failed to connect\n");
308 return false;
311 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
312 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
313 smbcli_errstr(cli->tree));
314 return false;
316 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
317 torture_comment(tctx, "Failed to mkdir \\maxfid, error=%s\n",
318 smbcli_errstr(cli->tree));
319 return false;
322 torture_comment(tctx, "Testing maximum number of open files\n");
324 for (i=0; i<0x11000; i++) {
325 if (i % 1000 == 0) {
326 asprintf(&fname, "\\maxfid\\fid%d", i/1000);
327 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
328 torture_comment(tctx, "Failed to mkdir %s, error=%s\n",
329 fname, smbcli_errstr(cli->tree));
330 return false;
332 free(fname);
334 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
335 if ((fnums[i] = smbcli_open(cli->tree, fname,
336 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
337 -1) {
338 torture_comment(tctx, "open of %s failed (%s)\n",
339 fname, smbcli_errstr(cli->tree));
340 torture_comment(tctx, "maximum fnum is %d\n", i);
341 break;
343 free(fname);
344 if (torture_setting_bool(tctx, "progress", true)) {
345 torture_comment(tctx, "%6d\r", i);
346 fflush(stdout);
349 torture_comment(tctx, "%6d\n", i);
350 i--;
352 maxfid = i;
354 torture_comment(tctx, "cleaning up\n");
355 for (i=0;i<maxfid/2;i++) {
356 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
357 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
358 torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
360 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
361 torture_comment(tctx, "unlink of %s failed (%s)\n",
362 fname, smbcli_errstr(cli->tree));
363 correct = false;
365 free(fname);
367 asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid());
368 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) {
369 torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree));
371 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
372 torture_comment(tctx, "unlink of %s failed (%s)\n",
373 fname, smbcli_errstr(cli->tree));
374 correct = false;
376 free(fname);
378 if (torture_setting_bool(tctx, "progress", true)) {
379 torture_comment(tctx, "%6d %6d\r", i, maxfid-i);
380 fflush(stdout);
383 torture_comment(tctx, "%6d\n", 0);
385 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
386 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
387 smbcli_errstr(cli->tree));
388 return false;
391 torture_comment(tctx, "maxfid test finished\n");
392 if (!torture_close_connection(cli)) {
393 correct = false;
395 return correct;
396 #undef MAXFID_TEMPLATE
402 sees what IOCTLs are supported
404 bool torture_ioctl_test(struct torture_context *tctx,
405 struct smbcli_state *cli)
407 uint16_t device, function;
408 int fnum;
409 const char *fname = "\\ioctl.dat";
410 NTSTATUS status;
411 union smb_ioctl parms;
412 TALLOC_CTX *mem_ctx;
414 mem_ctx = talloc_named_const(tctx, 0, "ioctl_test");
416 smbcli_unlink(cli->tree, fname);
418 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
419 if (fnum == -1) {
420 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
421 return false;
424 parms.ioctl.level = RAW_IOCTL_IOCTL;
425 parms.ioctl.in.file.fnum = fnum;
426 parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
427 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
428 torture_comment(tctx, "ioctl job info: %s\n", smbcli_errstr(cli->tree));
430 for (device=0;device<0x100;device++) {
431 torture_comment(tctx, "Testing device=0x%x\n", device);
432 for (function=0;function<0x100;function++) {
433 parms.ioctl.in.request = (device << 16) | function;
434 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
436 if (NT_STATUS_IS_OK(status)) {
437 torture_comment(tctx, "ioctl device=0x%x function=0x%x OK : %d bytes\n",
438 device, function, (int)parms.ioctl.out.blob.length);
443 return true;
446 static void benchrw_callback(struct smbcli_request *req);
447 enum benchrw_stage {
448 START,
449 OPEN_CONNECTION,
450 CLEANUP_TESTDIR,
451 MK_TESTDIR,
452 OPEN_FILE,
453 INITIAL_WRITE,
454 READ_WRITE_DATA,
455 MAX_OPS_REACHED,
456 ERROR,
457 CLOSE_FILE,
458 CLEANUP,
459 FINISHED
462 struct benchrw_state {
463 struct torture_context *tctx;
464 char *dname;
465 char *fname;
466 uint16_t fnum;
467 int nr;
468 struct smbcli_tree *cli;
469 uint8_t *buffer;
470 int writecnt;
471 int readcnt;
472 int completed;
473 int num_parallel_requests;
474 void *req_params;
475 enum benchrw_stage mode;
476 struct params{
477 struct unclist{
478 const char *host;
479 const char *share;
480 } **unc;
481 const char *workgroup;
482 int retry;
483 unsigned int writeblocks;
484 unsigned int blocksize;
485 unsigned int writeratio;
486 int num_parallel_requests;
487 } *lpcfg_params;
491 init params using lpcfg_parm_xxx
492 return number of unclist entries
494 static int init_benchrw_params(struct torture_context *tctx,
495 struct params *lpar)
497 char **unc_list = NULL;
498 int num_unc_names = 0, conn_index=0, empty_lines=0;
499 const char *p;
500 lpar->retry = torture_setting_int(tctx, "retry",3);
501 lpar->blocksize = torture_setting_int(tctx, "blocksize",65535);
502 lpar->writeblocks = torture_setting_int(tctx, "writeblocks",15);
503 lpar->writeratio = torture_setting_int(tctx, "writeratio",5);
504 lpar->num_parallel_requests = torture_setting_int(
505 tctx, "parallel_requests", 5);
506 lpar->workgroup = lpcfg_workgroup(tctx->lp_ctx);
508 p = torture_setting_string(tctx, "unclist", NULL);
509 if (p) {
510 char *h, *s;
511 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
512 if (!unc_list || num_unc_names <= 0) {
513 torture_comment(tctx, "Failed to load unc names list "
514 "from '%s'\n", p);
515 exit(1);
518 lpar->unc = talloc_array(tctx, struct unclist *,
519 (num_unc_names-empty_lines));
520 for(conn_index = 0; conn_index < num_unc_names; conn_index++) {
521 /* ignore empty lines */
522 if(strlen(unc_list[conn_index % num_unc_names])==0){
523 empty_lines++;
524 continue;
526 if (!smbcli_parse_unc(
527 unc_list[conn_index % num_unc_names],
528 NULL, &h, &s)) {
529 torture_comment(
530 tctx, "Failed to parse UNC "
531 "name %s\n",
532 unc_list[conn_index % num_unc_names]);
533 exit(1);
535 lpar->unc[conn_index-empty_lines] =
536 talloc(tctx, struct unclist);
537 lpar->unc[conn_index-empty_lines]->host = h;
538 lpar->unc[conn_index-empty_lines]->share = s;
540 return num_unc_names-empty_lines;
541 }else{
542 lpar->unc = talloc_array(tctx, struct unclist *, 1);
543 lpar->unc[0] = talloc(tctx,struct unclist);
544 lpar->unc[0]->host = torture_setting_string(tctx, "host",
545 NULL);
546 lpar->unc[0]->share = torture_setting_string(tctx, "share",
547 NULL);
548 return 1;
553 Called when the reads & writes are finished. closes the file.
555 static NTSTATUS benchrw_close(struct torture_context *tctx,
556 struct smbcli_request *req,
557 struct benchrw_state *state)
559 union smb_close close_parms;
561 NT_STATUS_NOT_OK_RETURN(req->status);
563 torture_comment(tctx, "Close file %d (%d)\n",state->nr,state->fnum);
564 close_parms.close.level = RAW_CLOSE_CLOSE;
565 close_parms.close.in.file.fnum = state->fnum ;
566 close_parms.close.in.write_time = 0;
567 state->mode=CLOSE_FILE;
569 req = smb_raw_close_send(state->cli, &close_parms);
570 NT_STATUS_HAVE_NO_MEMORY(req);
571 /*register the callback function!*/
572 req->async.fn = benchrw_callback;
573 req->async.private_data = state;
575 return NT_STATUS_OK;
578 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
579 struct benchrw_state *state);
580 static void benchrw_callback(struct smbcli_request *req);
582 static void benchrw_rw_callback(struct smbcli_request *req)
584 struct benchrw_state *state = req->async.private_data;
585 struct torture_context *tctx = state->tctx;
587 if (!NT_STATUS_IS_OK(req->status)) {
588 state->mode = ERROR;
589 return;
592 state->completed++;
593 state->num_parallel_requests--;
595 if ((state->completed >= torture_numops)
596 && (state->num_parallel_requests == 0)) {
597 benchrw_callback(req);
598 talloc_free(req);
599 return;
602 talloc_free(req);
604 if (state->completed + state->num_parallel_requests
605 < torture_numops) {
606 benchrw_readwrite(tctx, state);
611 Called when the initial write is completed is done. write or read a file.
613 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
614 struct benchrw_state *state)
616 struct smbcli_request *req;
617 union smb_read rd;
618 union smb_write wr;
620 /* randomize between writes and reads*/
621 if (random() % state->lpcfg_params->writeratio == 0) {
622 torture_comment(tctx, "Callback WRITE file:%d (%d/%d)\n",
623 state->nr,state->completed,torture_numops);
624 wr.generic.level = RAW_WRITE_WRITEX ;
625 wr.writex.in.file.fnum = state->fnum ;
626 wr.writex.in.offset = 0;
627 wr.writex.in.wmode = 0 ;
628 wr.writex.in.remaining = 0;
629 wr.writex.in.count = state->lpcfg_params->blocksize;
630 wr.writex.in.data = state->buffer;
631 state->readcnt=0;
632 req = smb_raw_write_send(state->cli,&wr);
634 else {
635 torture_comment(tctx,
636 "Callback READ file:%d (%d/%d) Offset:%d\n",
637 state->nr,state->completed,torture_numops,
638 (state->readcnt*state->lpcfg_params->blocksize));
639 rd.generic.level = RAW_READ_READX;
640 rd.readx.in.file.fnum = state->fnum ;
641 rd.readx.in.offset = state->readcnt*state->lpcfg_params->blocksize;
642 rd.readx.in.mincnt = state->lpcfg_params->blocksize;
643 rd.readx.in.maxcnt = rd.readx.in.mincnt;
644 rd.readx.in.remaining = 0 ;
645 rd.readx.out.data = state->buffer;
646 rd.readx.in.read_for_execute = false;
647 if(state->readcnt < state->lpcfg_params->writeblocks){
648 state->readcnt++;
649 }else{
650 /*start reading from beginn of file*/
651 state->readcnt=0;
653 req = smb_raw_read_send(state->cli,&rd);
655 state->num_parallel_requests += 1;
656 NT_STATUS_HAVE_NO_MEMORY(req);
657 /*register the callback function!*/
658 req->async.fn = benchrw_rw_callback;
659 req->async.private_data = state;
661 return NT_STATUS_OK;
665 Called when the open is done. writes to the file.
667 static NTSTATUS benchrw_open(struct torture_context *tctx,
668 struct smbcli_request *req,
669 struct benchrw_state *state)
671 union smb_write wr;
672 if(state->mode == OPEN_FILE){
673 NTSTATUS status;
674 status = smb_raw_open_recv(req,tctx,(
675 union smb_open*)state->req_params);
676 NT_STATUS_NOT_OK_RETURN(status);
678 state->fnum = ((union smb_open*)state->req_params)
679 ->openx.out.file.fnum;
680 torture_comment(tctx, "File opened (%d)\n",state->fnum);
681 state->mode=INITIAL_WRITE;
684 torture_comment(tctx, "Write initial test file:%d (%d/%d)\n",state->nr,
685 (state->writecnt+1)*state->lpcfg_params->blocksize,
686 (state->lpcfg_params->writeblocks*state->lpcfg_params->blocksize));
687 wr.generic.level = RAW_WRITE_WRITEX ;
688 wr.writex.in.file.fnum = state->fnum ;
689 wr.writex.in.offset = state->writecnt *
690 state->lpcfg_params->blocksize;
691 wr.writex.in.wmode = 0 ;
692 wr.writex.in.remaining = (state->lpcfg_params->writeblocks *
693 state->lpcfg_params->blocksize)-
694 ((state->writecnt+1)*state->
695 lpcfg_params->blocksize);
696 wr.writex.in.count = state->lpcfg_params->blocksize;
697 wr.writex.in.data = state->buffer;
698 state->writecnt++;
699 if(state->writecnt == state->lpcfg_params->writeblocks){
700 state->mode=READ_WRITE_DATA;
702 req = smb_raw_write_send(state->cli,&wr);
703 NT_STATUS_HAVE_NO_MEMORY(req);
705 /*register the callback function!*/
706 req->async.fn = benchrw_callback;
707 req->async.private_data = state;
708 return NT_STATUS_OK;
712 Called when the mkdir is done. Opens a file.
714 static NTSTATUS benchrw_mkdir(struct torture_context *tctx,
715 struct smbcli_request *req,
716 struct benchrw_state *state)
718 union smb_open *open_parms;
719 uint8_t *writedata;
721 NT_STATUS_NOT_OK_RETURN(req->status);
723 /* open/create the files */
724 torture_comment(tctx, "Open File %d/%d\n",state->nr+1,
725 torture_setting_int(tctx, "nprocs", 4));
726 open_parms=talloc_zero(tctx, union smb_open);
727 NT_STATUS_HAVE_NO_MEMORY(open_parms);
728 open_parms->openx.level = RAW_OPEN_OPENX;
729 open_parms->openx.in.flags = 0;
730 open_parms->openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
731 open_parms->openx.in.search_attrs =
732 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
733 open_parms->openx.in.file_attrs = 0;
734 open_parms->openx.in.write_time = 0;
735 open_parms->openx.in.open_func = OPENX_OPEN_FUNC_CREATE;
736 open_parms->openx.in.size = 0;
737 open_parms->openx.in.timeout = 0;
738 open_parms->openx.in.fname = state->fname;
740 writedata = talloc_size(tctx,state->lpcfg_params->blocksize);
741 NT_STATUS_HAVE_NO_MEMORY(writedata);
742 generate_random_buffer(writedata,state->lpcfg_params->blocksize);
743 state->buffer=writedata;
744 state->writecnt=1;
745 state->readcnt=0;
746 state->req_params=open_parms;
747 state->mode=OPEN_FILE;
749 req = smb_raw_open_send(state->cli,open_parms);
750 NT_STATUS_HAVE_NO_MEMORY(req);
752 /*register the callback function!*/
753 req->async.fn = benchrw_callback;
754 req->async.private_data = state;
756 return NT_STATUS_OK;
760 handler for completion of a sub-request of the bench-rw test
762 static void benchrw_callback(struct smbcli_request *req)
764 struct benchrw_state *state = req->async.private_data;
765 struct torture_context *tctx = state->tctx;
767 /*dont send new requests when torture_numops is reached*/
768 if ((state->mode == READ_WRITE_DATA)
769 && (state->completed >= torture_numops)) {
770 state->mode=MAX_OPS_REACHED;
773 switch (state->mode) {
775 case MK_TESTDIR:
776 if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx, req,state))) {
777 torture_comment(tctx, "Failed to create the test "
778 "directory - %s\n",
779 nt_errstr(req->status));
780 state->mode=ERROR;
781 return;
783 break;
784 case OPEN_FILE:
785 case INITIAL_WRITE:
786 if (!NT_STATUS_IS_OK(benchrw_open(tctx, req,state))){
787 torture_comment(tctx, "Failed to open/write the "
788 "file - %s\n",
789 nt_errstr(req->status));
790 state->mode=ERROR;
791 state->readcnt=0;
792 return;
794 break;
795 case READ_WRITE_DATA:
796 while (state->num_parallel_requests
797 < state->lpcfg_params->num_parallel_requests) {
798 NTSTATUS status;
799 status = benchrw_readwrite(tctx,state);
800 if (!NT_STATUS_IS_OK(status)){
801 torture_comment(tctx, "Failed to read/write "
802 "the file - %s\n",
803 nt_errstr(req->status));
804 state->mode=ERROR;
805 return;
808 break;
809 case MAX_OPS_REACHED:
810 if (!NT_STATUS_IS_OK(benchrw_close(tctx,req,state))){
811 torture_comment(tctx, "Failed to read/write/close "
812 "the file - %s\n",
813 nt_errstr(req->status));
814 state->mode=ERROR;
815 return;
817 break;
818 case CLOSE_FILE:
819 torture_comment(tctx, "File %d closed\n",state->nr);
820 if (!NT_STATUS_IS_OK(req->status)) {
821 torture_comment(tctx, "Failed to close the "
822 "file - %s\n",
823 nt_errstr(req->status));
824 state->mode=ERROR;
825 return;
827 state->mode=CLEANUP;
828 return;
829 default:
830 break;
835 /* open connection async callback function*/
836 static void async_open_callback(struct composite_context *con)
838 struct benchrw_state *state = con->async.private_data;
839 struct torture_context *tctx = state->tctx;
840 int retry = state->lpcfg_params->retry;
842 if (NT_STATUS_IS_OK(con->status)) {
843 state->cli=((struct smb_composite_connect*)
844 state->req_params)->out.tree;
845 state->mode=CLEANUP_TESTDIR;
846 }else{
847 if(state->writecnt < retry){
848 torture_comment(tctx, "Failed to open connection: "
849 "%d, Retry (%d/%d)\n",
850 state->nr,state->writecnt,retry);
851 state->writecnt++;
852 state->mode=START;
853 usleep(1000);
854 }else{
855 torture_comment(tctx, "Failed to open connection "
856 "(%d) - %s\n",
857 state->nr, nt_errstr(con->status));
858 state->mode=ERROR;
860 return;
865 establishs a smbcli_tree from scratch (async)
867 static struct composite_context *torture_connect_async(
868 struct torture_context *tctx,
869 struct smb_composite_connect *smb,
870 TALLOC_CTX *mem_ctx,
871 struct tevent_context *ev,
872 const char *host,
873 const char *share,
874 const char *workgroup)
876 torture_comment(tctx, "Open Connection to %s/%s\n",host,share);
877 smb->in.dest_host=talloc_strdup(mem_ctx,host);
878 smb->in.service=talloc_strdup(mem_ctx,share);
879 smb->in.dest_ports=lpcfg_smb_ports(tctx->lp_ctx);
880 smb->in.socket_options = lpcfg_socket_options(tctx->lp_ctx);
881 smb->in.called_name = strupper_talloc(mem_ctx, host);
882 smb->in.service_type=NULL;
883 smb->in.credentials=cmdline_credentials;
884 smb->in.fallback_to_anonymous=false;
885 smb->in.gensec_settings = lpcfg_gensec_settings(mem_ctx, tctx->lp_ctx);
886 smb->in.workgroup=workgroup;
887 lpcfg_smbcli_options(tctx->lp_ctx, &smb->in.options);
888 lpcfg_smbcli_session_options(tctx->lp_ctx, &smb->in.session_options);
890 return smb_composite_connect_send(smb,mem_ctx,
891 lpcfg_resolve_context(tctx->lp_ctx),ev);
894 bool run_benchrw(struct torture_context *tctx)
896 struct smb_composite_connect *smb_con;
897 const char *fname = "\\rwtest.dat";
898 struct smbcli_request *req;
899 struct benchrw_state **state;
900 int i , num_unc_names;
901 struct tevent_context *ev ;
902 struct composite_context *req1;
903 struct params lpparams;
904 union smb_mkdir parms;
905 int finished = 0;
906 bool success=true;
907 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
909 torture_comment(tctx, "Start BENCH-READWRITE num_ops=%d "
910 "num_nprocs=%d\n",
911 torture_numops, torture_nprocs);
913 /*init talloc context*/
914 ev = tctx->ev;
915 state = talloc_array(tctx, struct benchrw_state *, torture_nprocs);
917 /* init params using lpcfg_parm_xxx */
918 num_unc_names = init_benchrw_params(tctx,&lpparams);
920 /* init private data structs*/
921 for(i = 0; i<torture_nprocs;i++){
922 state[i]=talloc(tctx,struct benchrw_state);
923 state[i]->tctx = tctx;
924 state[i]->completed=0;
925 state[i]->num_parallel_requests=0;
926 state[i]->lpcfg_params=&lpparams;
927 state[i]->nr=i;
928 state[i]->dname=talloc_asprintf(tctx,"benchrw%d",i);
929 state[i]->fname=talloc_asprintf(tctx,"%s%s",
930 state[i]->dname,fname);
931 state[i]->mode=START;
932 state[i]->writecnt=0;
935 torture_comment(tctx, "Starting async requests\n");
936 while(finished != torture_nprocs){
937 finished=0;
938 for(i = 0; i<torture_nprocs;i++){
939 switch (state[i]->mode){
940 /*open multiple connections with the same userid */
941 case START:
942 smb_con = talloc(
943 tctx,struct smb_composite_connect) ;
944 state[i]->req_params=smb_con;
945 state[i]->mode=OPEN_CONNECTION;
946 req1 = torture_connect_async(
947 tctx, smb_con, tctx,ev,
948 lpparams.unc[i % num_unc_names]->host,
949 lpparams.unc[i % num_unc_names]->share,
950 lpparams.workgroup);
951 /* register callback fn + private data */
952 req1->async.fn = async_open_callback;
953 req1->async.private_data=state[i];
954 break;
955 /*setup test dirs (sync)*/
956 case CLEANUP_TESTDIR:
957 torture_comment(tctx, "Setup test dir %d\n",i);
958 smb_raw_exit(state[i]->cli->session);
959 if (smbcli_deltree(state[i]->cli,
960 state[i]->dname) == -1) {
961 torture_comment(
962 tctx,
963 "Unable to delete %s - %s\n",
964 state[i]->dname,
965 smbcli_errstr(state[i]->cli));
966 state[i]->mode=ERROR;
967 break;
969 state[i]->mode=MK_TESTDIR;
970 parms.mkdir.level = RAW_MKDIR_MKDIR;
971 parms.mkdir.in.path = state[i]->dname;
972 req = smb_raw_mkdir_send(state[i]->cli,&parms);
973 /* register callback fn + private data */
974 req->async.fn = benchrw_callback;
975 req->async.private_data=state[i];
976 break;
977 /* error occured , finish */
978 case ERROR:
979 finished++;
980 success=false;
981 break;
982 /* cleanup , close connection */
983 case CLEANUP:
984 torture_comment(tctx, "Deleting test dir %s "
985 "%d/%d\n",state[i]->dname,
986 i+1,torture_nprocs);
987 smbcli_deltree(state[i]->cli,state[i]->dname);
988 if (NT_STATUS_IS_ERR(smb_tree_disconnect(
989 state[i]->cli))) {
990 torture_comment(tctx, "ERROR: Tree "
991 "disconnect failed");
992 state[i]->mode=ERROR;
993 break;
995 state[i]->mode=FINISHED;
996 case FINISHED:
997 finished++;
998 break;
999 default:
1000 tevent_loop_once(ev);
1005 return success;