smbd: use check_any_access_fsp() for all access checks
[Samba.git] / source4 / torture / basic / misc.c
blob2d99f2a11e5d2ad55435def68f0f5268823d681c
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"
37 #include "lib/cmdline/cmdline.h"
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 unsigned int n = (unsigned int)random()%10;
72 int ret;
74 if (i % 10 == 0) {
75 if (torture_setting_bool(tctx, "progress", true)) {
76 torture_comment(tctx, "%d\r", i);
77 fflush(stdout);
80 ret = asprintf(&fname, "\\torture.%u", n);
81 torture_assert(tctx, ret != -1, "asprintf failed");
83 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
84 return false;
87 fnum = smbcli_open(c->tree, fname, O_RDWR | O_CREAT | O_TRUNC, DENY_ALL);
88 if (fnum == -1) {
89 torture_comment(tctx, "open failed (%s)\n", smbcli_errstr(c->tree));
90 correct = false;
91 break;
94 if (smbcli_write(c->tree, fnum, 0, &pid, 0, sizeof(pid)) != sizeof(pid)) {
95 torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
96 correct = false;
99 for (j=0;j<50;j++) {
100 if (smbcli_write(c->tree, fnum, 0, buf,
101 sizeof(pid)+(j*sizeof(buf)),
102 sizeof(buf)) != sizeof(buf)) {
103 torture_comment(tctx, "write failed (%s)\n", smbcli_errstr(c->tree));
104 correct = false;
108 pid2 = 0;
110 if (smbcli_read(c->tree, fnum, &pid2, 0, sizeof(pid)) != sizeof(pid)) {
111 torture_comment(tctx, "read failed (%s)\n", smbcli_errstr(c->tree));
112 correct = false;
115 if (pid2 != pid) {
116 torture_comment(tctx, "data corruption!\n");
117 correct = false;
120 if (NT_STATUS_IS_ERR(smbcli_close(c->tree, fnum))) {
121 torture_comment(tctx, "close failed (%s)\n", smbcli_errstr(c->tree));
122 correct = false;
125 if (NT_STATUS_IS_ERR(smbcli_unlink(c->tree, fname))) {
126 torture_comment(tctx, "unlink failed (%s)\n", smbcli_errstr(c->tree));
127 correct = false;
130 if (NT_STATUS_IS_ERR(smbcli_unlock(c->tree, fnum2, n*sizeof(int), sizeof(int)))) {
131 torture_comment(tctx, "unlock failed (%s)\n", smbcli_errstr(c->tree));
132 correct = false;
134 free(fname);
137 smbcli_close(c->tree, fnum2);
138 smbcli_unlink(c->tree, lockfname);
140 torture_comment(tctx, "%d\n", i);
142 return correct;
145 bool run_torture(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
147 return rw_torture(tctx, cli);
152 see how many RPC pipes we can open at once
154 bool run_pipe_number(struct torture_context *tctx,
155 struct smbcli_state *cli1)
157 const char *pipe_name = "\\WKSSVC";
158 int fnum;
159 int num_pipes = 0;
161 while(1) {
162 fnum = smbcli_nt_create_full(cli1->tree, pipe_name, 0, SEC_FILE_READ_DATA, FILE_ATTRIBUTE_NORMAL,
163 NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, NTCREATEX_DISP_OPEN_IF, 0, 0);
165 if (fnum == -1) {
166 torture_comment(tctx, "Open of pipe %s failed with error (%s)\n", pipe_name, smbcli_errstr(cli1->tree));
167 break;
169 num_pipes++;
170 if (torture_setting_bool(tctx, "progress", true)) {
171 torture_comment(tctx, "%d\r", num_pipes);
172 fflush(stdout);
176 torture_comment(tctx, "pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
177 return true;
184 open N connections to the server and just hold them open
185 used for testing performance when there are N idle users
186 already connected
188 bool torture_holdcon(struct torture_context *tctx)
190 int i;
191 struct smbcli_state **cli;
192 int num_dead = 0;
194 torture_comment(tctx, "Opening %d connections\n", torture_numops);
196 cli = malloc_array_p(struct smbcli_state *, torture_numops);
198 for (i=0;i<torture_numops;i++) {
199 if (!torture_open_connection(&cli[i], tctx, i)) {
200 return false;
202 if (torture_setting_bool(tctx, "progress", true)) {
203 torture_comment(tctx, "opened %d connections\r", i+1);
204 fflush(stdout);
208 torture_comment(tctx, "\nStarting pings\n");
210 while (1) {
211 for (i=0;i<torture_numops;i++) {
212 NTSTATUS status;
213 if (cli[i]) {
214 status = smbcli_chkpath(cli[i]->tree, "\\");
215 if (!NT_STATUS_IS_OK(status)) {
216 torture_comment(tctx, "Connection %d is dead\n", i);
217 cli[i] = NULL;
218 num_dead++;
220 usleep(100);
224 if (num_dead == torture_numops) {
225 torture_comment(tctx, "All connections dead - finishing\n");
226 break;
229 torture_comment(tctx, ".");
230 fflush(stdout);
233 return true;
237 open a file N times on the server and just hold them open
238 used for testing performance when there are N file handles
239 open
241 bool torture_holdopen(struct torture_context *tctx,
242 struct smbcli_state *cli)
244 int i, fnum;
245 const char *fname = "\\holdopen.dat";
246 NTSTATUS status;
248 smbcli_unlink(cli->tree, fname);
250 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
251 if (fnum == -1) {
252 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
253 return false;
256 smbcli_close(cli->tree, fnum);
258 for (i=0;i<torture_numops;i++) {
259 union smb_open op;
261 op.generic.level = RAW_OPEN_NTCREATEX;
262 op.ntcreatex.in.root_fid.fnum = 0;
263 op.ntcreatex.in.flags = 0;
264 op.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA;
265 op.ntcreatex.in.create_options = 0;
266 op.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
267 op.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_MASK;
268 op.ntcreatex.in.alloc_size = 0;
269 op.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
270 op.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
271 op.ntcreatex.in.security_flags = 0;
272 op.ntcreatex.in.fname = fname;
273 status = smb_raw_open(cli->tree, tctx, &op);
274 if (!NT_STATUS_IS_OK(status)) {
275 torture_warning(tctx, "open %d failed\n", i);
276 continue;
279 if (torture_setting_bool(tctx, "progress", true)) {
280 torture_comment(tctx, "opened %d file\r", i);
281 fflush(stdout);
285 torture_comment(tctx, "\nStarting pings\n");
287 while (1) {
288 struct smb_echo ec;
289 ZERO_STRUCT(ec);
290 status = smb_raw_echo(cli->transport, &ec);
291 torture_comment(tctx, ".");
292 fflush(stdout);
293 sleep(15);
298 test how many open files this server supports on the one socket
300 bool torture_maxfid_test(struct torture_context *tctx, struct smbcli_state *cli)
302 #define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
303 char *fname;
304 int fnums[0x11000], i;
305 int retries=4, maxfid;
306 bool correct = true;
307 int ret;
309 if (retries <= 0) {
310 torture_comment(tctx, "failed to connect\n");
311 return false;
314 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
315 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
316 smbcli_errstr(cli->tree));
317 return false;
319 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
320 torture_comment(tctx, "Failed to mkdir \\maxfid, error=%s\n",
321 smbcli_errstr(cli->tree));
322 return false;
325 torture_comment(tctx, "Testing maximum number of open files\n");
327 for (i=0; i<0x11000; i++) {
328 if (i % 1000 == 0) {
329 ret = asprintf(&fname, "\\maxfid\\fid%d", i/1000);
330 torture_assert(tctx, ret != -1, "asprintf failed");
331 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
332 torture_comment(tctx, "Failed to mkdir %s, error=%s\n",
333 fname, smbcli_errstr(cli->tree));
334 return false;
336 free(fname);
338 ret = asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
339 torture_assert(tctx, ret != -1, "asprintf failed");
340 if ((fnums[i] = smbcli_open(cli->tree, fname,
341 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
342 -1) {
343 torture_comment(tctx, "open of %s failed (%s)\n",
344 fname, smbcli_errstr(cli->tree));
345 torture_comment(tctx, "maximum fnum is %d\n", i);
346 break;
348 free(fname);
349 if (torture_setting_bool(tctx, "progress", true)) {
350 torture_comment(tctx, "%6d\r", i);
351 fflush(stdout);
354 torture_comment(tctx, "%6d\n", i);
356 maxfid = i;
358 torture_comment(tctx, "cleaning up\n");
359 for (i=0;i<maxfid;i++) {
360 ret = asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
361 torture_assert(tctx, ret != -1, "asprintf failed");
362 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
363 torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
365 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
366 torture_comment(tctx, "unlink of %s failed (%s)\n",
367 fname, smbcli_errstr(cli->tree));
368 correct = false;
370 free(fname);
372 if (torture_setting_bool(tctx, "progress", true)) {
373 torture_comment(tctx, "%6d\r", i);
374 fflush(stdout);
377 torture_comment(tctx, "%6d\n", 0);
379 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
380 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
381 smbcli_errstr(cli->tree));
382 return false;
385 torture_comment(tctx, "maxfid test finished\n");
387 return correct;
388 #undef MAXFID_TEMPLATE
394 sees what IOCTLs are supported
396 bool torture_ioctl_test(struct torture_context *tctx,
397 struct smbcli_state *cli)
399 uint16_t device, function;
400 int fnum;
401 const char *fname = "\\ioctl.dat";
402 NTSTATUS status;
403 union smb_ioctl parms;
404 TALLOC_CTX *mem_ctx;
406 mem_ctx = talloc_named_const(tctx, 0, "ioctl_test");
408 smbcli_unlink(cli->tree, fname);
410 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
411 if (fnum == -1) {
412 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
413 return false;
416 parms.ioctl.level = RAW_IOCTL_IOCTL;
417 parms.ioctl.in.file.fnum = fnum;
418 parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
419 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
420 torture_comment(tctx, "ioctl job info: %s\n", smbcli_errstr(cli->tree));
422 for (device=0;device<0x100;device++) {
423 torture_comment(tctx, "Testing device=0x%x\n", device);
424 for (function=0;function<0x100;function++) {
425 parms.ioctl.in.request = (device << 16) | function;
426 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
428 if (NT_STATUS_IS_OK(status)) {
429 torture_comment(tctx, "ioctl device=0x%x function=0x%x OK : %d bytes\n",
430 device, function, (int)parms.ioctl.out.blob.length);
435 return true;
438 static void benchrw_callback(struct smbcli_request *req);
439 enum benchrw_stage {
440 START,
441 OPEN_CONNECTION,
442 CLEANUP_TESTDIR,
443 MK_TESTDIR,
444 OPEN_FILE,
445 INITIAL_WRITE,
446 READ_WRITE_DATA,
447 MAX_OPS_REACHED,
448 ERROR,
449 CLOSE_FILE,
450 CLEANUP,
451 FINISHED
454 struct bench_params {
455 struct unclist{
456 const char *host;
457 const char *share;
458 } **unc;
459 const char *workgroup;
460 int retry;
461 unsigned int writeblocks;
462 unsigned int blocksize;
463 unsigned int writeratio;
464 int num_parallel_requests;
467 struct benchrw_state {
468 struct torture_context *tctx;
469 char *dname;
470 char *fname;
471 uint16_t fnum;
472 int nr;
473 struct smbcli_tree *cli;
474 uint8_t *buffer;
475 int writecnt;
476 int readcnt;
477 int completed;
478 int num_parallel_requests;
479 void *req_params;
480 enum benchrw_stage mode;
481 struct bench_params *lpcfg_params;
485 init params using lpcfg_parm_xxx
486 return number of unclist entries
488 static int init_benchrw_params(struct torture_context *tctx,
489 struct bench_params *lpar)
491 char **unc_list = NULL;
492 int num_unc_names = 0, conn_index=0, empty_lines=0;
493 const char *p;
494 lpar->retry = torture_setting_int(tctx, "retry",3);
495 lpar->blocksize = torture_setting_int(tctx, "blocksize",65535);
496 lpar->writeblocks = torture_setting_int(tctx, "writeblocks",15);
497 lpar->writeratio = torture_setting_int(tctx, "writeratio",5);
498 lpar->num_parallel_requests = torture_setting_int(
499 tctx, "parallel_requests", 5);
500 lpar->workgroup = lpcfg_workgroup(tctx->lp_ctx);
502 p = torture_setting_string(tctx, "unclist", NULL);
503 if (p) {
504 char *h, *s;
505 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
506 if (!unc_list || num_unc_names <= 0) {
507 torture_comment(tctx, "Failed to load unc names list "
508 "from '%s'\n", p);
509 exit(1);
512 lpar->unc = talloc_array(tctx, struct unclist *,
513 (num_unc_names-empty_lines));
514 for(conn_index = 0; conn_index < num_unc_names; conn_index++) {
515 /* ignore empty lines */
516 if(strlen(unc_list[conn_index % num_unc_names])==0){
517 empty_lines++;
518 continue;
520 if (!smbcli_parse_unc(
521 unc_list[conn_index % num_unc_names],
522 NULL, &h, &s)) {
523 torture_comment(
524 tctx, "Failed to parse UNC "
525 "name %s\n",
526 unc_list[conn_index % num_unc_names]);
527 exit(1);
529 lpar->unc[conn_index-empty_lines] =
530 talloc(tctx, struct unclist);
531 lpar->unc[conn_index-empty_lines]->host = h;
532 lpar->unc[conn_index-empty_lines]->share = s;
534 return num_unc_names-empty_lines;
535 }else{
536 lpar->unc = talloc_array(tctx, struct unclist *, 1);
537 lpar->unc[0] = talloc(tctx,struct unclist);
538 lpar->unc[0]->host = torture_setting_string(tctx, "host",
539 NULL);
540 lpar->unc[0]->share = torture_setting_string(tctx, "share",
541 NULL);
542 return 1;
547 Called when the reads & writes are finished. closes the file.
549 static NTSTATUS benchrw_close(struct torture_context *tctx,
550 struct smbcli_request *req,
551 struct benchrw_state *state)
553 union smb_close close_parms;
555 NT_STATUS_NOT_OK_RETURN(req->status);
557 torture_comment(tctx, "Close file %d (%d)\n",state->nr,state->fnum);
558 close_parms.close.level = RAW_CLOSE_CLOSE;
559 close_parms.close.in.file.fnum = state->fnum ;
560 close_parms.close.in.write_time = 0;
561 state->mode=CLOSE_FILE;
563 req = smb_raw_close_send(state->cli, &close_parms);
564 NT_STATUS_HAVE_NO_MEMORY(req);
565 /*register the callback function!*/
566 req->async.fn = benchrw_callback;
567 req->async.private_data = state;
569 return NT_STATUS_OK;
572 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
573 struct benchrw_state *state);
574 static void benchrw_callback(struct smbcli_request *req);
576 static void benchrw_rw_callback(struct smbcli_request *req)
578 struct benchrw_state *state = req->async.private_data;
579 struct torture_context *tctx = state->tctx;
581 if (!NT_STATUS_IS_OK(req->status)) {
582 state->mode = ERROR;
583 return;
586 state->completed++;
587 state->num_parallel_requests--;
589 if ((state->completed >= torture_numops)
590 && (state->num_parallel_requests == 0)) {
591 benchrw_callback(req);
592 talloc_free(req);
593 return;
596 talloc_free(req);
598 if (state->completed + state->num_parallel_requests
599 < torture_numops) {
600 benchrw_readwrite(tctx, state);
605 Called when the initial write is completed is done. write or read a file.
607 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
608 struct benchrw_state *state)
610 struct smbcli_request *req;
611 union smb_read rd;
612 union smb_write wr;
614 /* randomize between writes and reads*/
615 if (random() % state->lpcfg_params->writeratio == 0) {
616 torture_comment(tctx, "Callback WRITE file:%d (%d/%d)\n",
617 state->nr,state->completed,torture_numops);
618 wr.generic.level = RAW_WRITE_WRITEX ;
619 wr.writex.in.file.fnum = state->fnum ;
620 wr.writex.in.offset = 0;
621 wr.writex.in.wmode = 0 ;
622 wr.writex.in.remaining = 0;
623 wr.writex.in.count = state->lpcfg_params->blocksize;
624 wr.writex.in.data = state->buffer;
625 state->readcnt=0;
626 req = smb_raw_write_send(state->cli,&wr);
628 else {
629 torture_comment(tctx,
630 "Callback READ file:%d (%d/%d) Offset:%d\n",
631 state->nr,state->completed,torture_numops,
632 (state->readcnt*state->lpcfg_params->blocksize));
633 rd.generic.level = RAW_READ_READX;
634 rd.readx.in.file.fnum = state->fnum ;
635 rd.readx.in.offset = state->readcnt*state->lpcfg_params->blocksize;
636 rd.readx.in.mincnt = state->lpcfg_params->blocksize;
637 rd.readx.in.maxcnt = rd.readx.in.mincnt;
638 rd.readx.in.remaining = 0 ;
639 rd.readx.out.data = state->buffer;
640 rd.readx.in.read_for_execute = false;
641 if(state->readcnt < state->lpcfg_params->writeblocks){
642 state->readcnt++;
643 }else{
644 /*start reading from beginn of file*/
645 state->readcnt=0;
647 req = smb_raw_read_send(state->cli,&rd);
649 state->num_parallel_requests += 1;
650 NT_STATUS_HAVE_NO_MEMORY(req);
651 /*register the callback function!*/
652 req->async.fn = benchrw_rw_callback;
653 req->async.private_data = state;
655 return NT_STATUS_OK;
659 Called when the open is done. writes to the file.
661 static NTSTATUS benchrw_open(struct torture_context *tctx,
662 struct smbcli_request *req,
663 struct benchrw_state *state)
665 union smb_write wr;
666 if(state->mode == OPEN_FILE){
667 NTSTATUS status;
668 status = smb_raw_open_recv(req,tctx,(
669 union smb_open*)state->req_params);
670 NT_STATUS_NOT_OK_RETURN(status);
672 state->fnum = ((union smb_open*)state->req_params)
673 ->openx.out.file.fnum;
674 torture_comment(tctx, "File opened (%d)\n",state->fnum);
675 state->mode=INITIAL_WRITE;
678 torture_comment(tctx, "Write initial test file:%d (%d/%d)\n",state->nr,
679 (state->writecnt+1)*state->lpcfg_params->blocksize,
680 (state->lpcfg_params->writeblocks*state->lpcfg_params->blocksize));
681 wr.generic.level = RAW_WRITE_WRITEX ;
682 wr.writex.in.file.fnum = state->fnum ;
683 wr.writex.in.offset = state->writecnt *
684 state->lpcfg_params->blocksize;
685 wr.writex.in.wmode = 0 ;
686 wr.writex.in.remaining = (state->lpcfg_params->writeblocks *
687 state->lpcfg_params->blocksize)-
688 ((state->writecnt+1)*state->
689 lpcfg_params->blocksize);
690 wr.writex.in.count = state->lpcfg_params->blocksize;
691 wr.writex.in.data = state->buffer;
692 state->writecnt++;
693 if(state->writecnt == state->lpcfg_params->writeblocks){
694 state->mode=READ_WRITE_DATA;
696 req = smb_raw_write_send(state->cli,&wr);
697 NT_STATUS_HAVE_NO_MEMORY(req);
699 /*register the callback function!*/
700 req->async.fn = benchrw_callback;
701 req->async.private_data = state;
702 return NT_STATUS_OK;
706 Called when the mkdir is done. Opens a file.
708 static NTSTATUS benchrw_mkdir(struct torture_context *tctx,
709 struct smbcli_request *req,
710 struct benchrw_state *state)
712 union smb_open *open_parms;
713 uint8_t *writedata;
715 NT_STATUS_NOT_OK_RETURN(req->status);
717 /* open/create the files */
718 torture_comment(tctx, "Open File %d/%d\n",state->nr+1,
719 torture_setting_int(tctx, "nprocs", 4));
720 open_parms=talloc_zero(tctx, union smb_open);
721 NT_STATUS_HAVE_NO_MEMORY(open_parms);
722 open_parms->openx.level = RAW_OPEN_OPENX;
723 open_parms->openx.in.flags = 0;
724 open_parms->openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
725 open_parms->openx.in.search_attrs =
726 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
727 open_parms->openx.in.file_attrs = 0;
728 open_parms->openx.in.write_time = 0;
729 open_parms->openx.in.open_func = OPENX_OPEN_FUNC_CREATE;
730 open_parms->openx.in.size = 0;
731 open_parms->openx.in.timeout = 0;
732 open_parms->openx.in.fname = state->fname;
734 writedata = talloc_size(tctx,state->lpcfg_params->blocksize);
735 NT_STATUS_HAVE_NO_MEMORY(writedata);
736 generate_random_buffer(writedata,state->lpcfg_params->blocksize);
737 state->buffer=writedata;
738 state->writecnt=1;
739 state->readcnt=0;
740 state->req_params=open_parms;
741 state->mode=OPEN_FILE;
743 req = smb_raw_open_send(state->cli,open_parms);
744 NT_STATUS_HAVE_NO_MEMORY(req);
746 /*register the callback function!*/
747 req->async.fn = benchrw_callback;
748 req->async.private_data = state;
750 return NT_STATUS_OK;
754 handler for completion of a sub-request of the bench-rw test
756 static void benchrw_callback(struct smbcli_request *req)
758 struct benchrw_state *state = req->async.private_data;
759 struct torture_context *tctx = state->tctx;
761 /*don't send new requests when torture_numops is reached*/
762 if ((state->mode == READ_WRITE_DATA)
763 && (state->completed >= torture_numops)) {
764 state->mode=MAX_OPS_REACHED;
767 switch (state->mode) {
769 case MK_TESTDIR:
770 if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx, req,state))) {
771 torture_comment(tctx, "Failed to create the test "
772 "directory - %s\n",
773 nt_errstr(req->status));
774 state->mode=ERROR;
775 return;
777 break;
778 case OPEN_FILE:
779 case INITIAL_WRITE:
780 if (!NT_STATUS_IS_OK(benchrw_open(tctx, req,state))){
781 torture_comment(tctx, "Failed to open/write the "
782 "file - %s\n",
783 nt_errstr(req->status));
784 state->mode=ERROR;
785 state->readcnt=0;
786 return;
788 break;
789 case READ_WRITE_DATA:
790 while (state->num_parallel_requests
791 < state->lpcfg_params->num_parallel_requests) {
792 NTSTATUS status;
793 status = benchrw_readwrite(tctx,state);
794 if (!NT_STATUS_IS_OK(status)){
795 torture_comment(tctx, "Failed to read/write "
796 "the file - %s\n",
797 nt_errstr(req->status));
798 state->mode=ERROR;
799 return;
802 break;
803 case MAX_OPS_REACHED:
804 if (!NT_STATUS_IS_OK(benchrw_close(tctx,req,state))){
805 torture_comment(tctx, "Failed to read/write/close "
806 "the file - %s\n",
807 nt_errstr(req->status));
808 state->mode=ERROR;
809 return;
811 break;
812 case CLOSE_FILE:
813 torture_comment(tctx, "File %d closed\n",state->nr);
814 if (!NT_STATUS_IS_OK(req->status)) {
815 torture_comment(tctx, "Failed to close the "
816 "file - %s\n",
817 nt_errstr(req->status));
818 state->mode=ERROR;
819 return;
821 state->mode=CLEANUP;
822 return;
823 default:
824 break;
829 /* open connection async callback function*/
830 static void async_open_callback(struct composite_context *con)
832 struct benchrw_state *state = con->async.private_data;
833 struct torture_context *tctx = state->tctx;
834 int retry = state->lpcfg_params->retry;
836 if (NT_STATUS_IS_OK(con->status)) {
837 state->cli=((struct smb_composite_connect*)
838 state->req_params)->out.tree;
839 state->mode=CLEANUP_TESTDIR;
840 }else{
841 if(state->writecnt < retry){
842 torture_comment(tctx, "Failed to open connection: "
843 "%d, Retry (%d/%d)\n",
844 state->nr,state->writecnt,retry);
845 state->writecnt++;
846 state->mode=START;
847 usleep(1000);
848 }else{
849 torture_comment(tctx, "Failed to open connection "
850 "(%d) - %s\n",
851 state->nr, nt_errstr(con->status));
852 state->mode=ERROR;
854 return;
859 establishs a smbcli_tree from scratch (async)
861 static struct composite_context *torture_connect_async(
862 struct torture_context *tctx,
863 struct smb_composite_connect *smb,
864 TALLOC_CTX *mem_ctx,
865 struct tevent_context *ev,
866 const char *host,
867 const char *share,
868 const char *workgroup)
870 torture_comment(tctx, "Open Connection to %s/%s\n",host,share);
871 smb->in.dest_host=talloc_strdup(mem_ctx,host);
872 smb->in.service=talloc_strdup(mem_ctx,share);
873 smb->in.dest_ports=lpcfg_smb_ports(tctx->lp_ctx);
874 smb->in.socket_options = lpcfg_socket_options(tctx->lp_ctx);
875 smb->in.called_name = strupper_talloc(mem_ctx, host);
876 smb->in.service_type=NULL;
877 smb->in.credentials = samba_cmdline_get_creds();
878 smb->in.fallback_to_anonymous=false;
879 smb->in.gensec_settings = lpcfg_gensec_settings(mem_ctx, tctx->lp_ctx);
880 smb->in.workgroup=workgroup;
881 lpcfg_smbcli_options(tctx->lp_ctx, &smb->in.options);
882 lpcfg_smbcli_session_options(tctx->lp_ctx, &smb->in.session_options);
884 return smb_composite_connect_send(smb,mem_ctx,
885 lpcfg_resolve_context(tctx->lp_ctx),ev);
888 bool run_benchrw(struct torture_context *tctx)
890 struct smb_composite_connect *smb_con;
891 const char *fname = "\\rwtest.dat";
892 struct smbcli_request *req;
893 struct benchrw_state **state;
894 int i , num_unc_names;
895 struct tevent_context *ev ;
896 struct composite_context *req1;
897 struct bench_params lpparams;
898 union smb_mkdir parms;
899 int finished = 0;
900 bool success=true;
901 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
903 torture_comment(tctx, "Start BENCH-READWRITE num_ops=%d "
904 "num_nprocs=%d\n",
905 torture_numops, torture_nprocs);
907 /*init talloc context*/
908 ev = tctx->ev;
909 state = talloc_array(tctx, struct benchrw_state *, torture_nprocs);
911 /* init params using lpcfg_parm_xxx */
912 num_unc_names = init_benchrw_params(tctx,&lpparams);
914 /* init private data structs*/
915 for(i = 0; i<torture_nprocs;i++){
916 state[i]=talloc(tctx,struct benchrw_state);
917 state[i]->tctx = tctx;
918 state[i]->completed=0;
919 state[i]->num_parallel_requests=0;
920 state[i]->lpcfg_params=&lpparams;
921 state[i]->nr=i;
922 state[i]->dname=talloc_asprintf(tctx,"benchrw%d",i);
923 state[i]->fname=talloc_asprintf(tctx,"%s%s",
924 state[i]->dname,fname);
925 state[i]->mode=START;
926 state[i]->writecnt=0;
929 torture_comment(tctx, "Starting async requests\n");
930 while(finished != torture_nprocs){
931 finished=0;
932 for(i = 0; i<torture_nprocs;i++){
933 switch (state[i]->mode){
934 /*open multiple connections with the same userid */
935 case START:
936 smb_con = talloc_zero(
937 tctx,struct smb_composite_connect);
938 state[i]->req_params=smb_con;
939 state[i]->mode=OPEN_CONNECTION;
940 req1 = torture_connect_async(
941 tctx, smb_con, tctx,ev,
942 lpparams.unc[i % num_unc_names]->host,
943 lpparams.unc[i % num_unc_names]->share,
944 lpparams.workgroup);
945 /* register callback fn + private data */
946 req1->async.fn = async_open_callback;
947 req1->async.private_data=state[i];
948 break;
949 /*setup test dirs (sync)*/
950 case CLEANUP_TESTDIR:
951 torture_comment(tctx, "Setup test dir %d\n",i);
952 smb_raw_exit(state[i]->cli->session);
953 if (smbcli_deltree(state[i]->cli,
954 state[i]->dname) == -1) {
955 torture_comment(
956 tctx,
957 "Unable to delete %s - %s\n",
958 state[i]->dname,
959 smbcli_errstr(state[i]->cli));
960 state[i]->mode=ERROR;
961 break;
963 state[i]->mode=MK_TESTDIR;
964 parms.mkdir.level = RAW_MKDIR_MKDIR;
965 parms.mkdir.in.path = state[i]->dname;
966 req = smb_raw_mkdir_send(state[i]->cli,&parms);
967 /* register callback fn + private data */
968 req->async.fn = benchrw_callback;
969 req->async.private_data=state[i];
970 break;
971 /* error occurred , finish */
972 case ERROR:
973 finished++;
974 success=false;
975 break;
976 /* cleanup , close connection */
977 case CLEANUP:
978 torture_comment(tctx, "Deleting test dir %s "
979 "%d/%d\n",state[i]->dname,
980 i+1,torture_nprocs);
981 smbcli_deltree(state[i]->cli,state[i]->dname);
982 if (NT_STATUS_IS_ERR(smb_tree_disconnect(
983 state[i]->cli))) {
984 torture_comment(tctx, "ERROR: Tree "
985 "disconnect failed");
986 state[i]->mode=ERROR;
987 break;
989 state[i]->mode=FINISHED;
991 FALL_THROUGH;
992 case FINISHED:
993 finished++;
994 break;
995 default:
996 tevent_loop_once(ev);
1001 return success;