2 Unix SMB/CIFS implementation.
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/>.
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;
48 static bool rw_torture(struct torture_context
*tctx
, struct smbcli_state
*c
)
50 const char *lockfname
= "\\torture.lck";
54 pid_t pid2
, pid
= getpid();
59 fnum2
= smbcli_open(c
->tree
, lockfname
, O_RDWR
| O_CREAT
| O_EXCL
,
62 fnum2
= smbcli_open(c
->tree
, lockfname
, O_RDWR
, DENY_NONE
);
64 torture_comment(tctx
, "open of %s failed (%s)\n", lockfname
, smbcli_errstr(c
->tree
));
68 generate_random_buffer(buf
, sizeof(buf
));
70 for (i
=0;i
<torture_numops
;i
++) {
71 unsigned int n
= (unsigned int)random()%10;
75 if (torture_setting_bool(tctx
, "progress", true)) {
76 torture_comment(tctx
, "%d\r", i
);
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))) {
87 fnum
= smbcli_open(c
->tree
, fname
, O_RDWR
| O_CREAT
| O_TRUNC
, DENY_ALL
);
89 torture_comment(tctx
, "open failed (%s)\n", smbcli_errstr(c
->tree
));
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
));
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
));
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
));
116 torture_comment(tctx
, "data corruption!\n");
120 if (NT_STATUS_IS_ERR(smbcli_close(c
->tree
, fnum
))) {
121 torture_comment(tctx
, "close failed (%s)\n", smbcli_errstr(c
->tree
));
125 if (NT_STATUS_IS_ERR(smbcli_unlink(c
->tree
, fname
))) {
126 torture_comment(tctx
, "unlink failed (%s)\n", smbcli_errstr(c
->tree
));
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
));
137 smbcli_close(c
->tree
, fnum2
);
138 smbcli_unlink(c
->tree
, lockfname
);
140 torture_comment(tctx
, "%d\n", i
);
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";
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);
166 torture_comment(tctx
, "Open of pipe %s failed with error (%s)\n", pipe_name
, smbcli_errstr(cli1
->tree
));
170 if (torture_setting_bool(tctx
, "progress", true)) {
171 torture_comment(tctx
, "%d\r", num_pipes
);
176 torture_comment(tctx
, "pipe_number test - we can open %d %s pipes.\n", num_pipes
, pipe_name
);
184 open N connections to the server and just hold them open
185 used for testing performance when there are N idle users
188 bool torture_holdcon(struct torture_context
*tctx
)
191 struct smbcli_state
**cli
;
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
)) {
202 if (torture_setting_bool(tctx
, "progress", true)) {
203 torture_comment(tctx
, "opened %d connections\r", i
+1);
208 torture_comment(tctx
, "\nStarting pings\n");
211 for (i
=0;i
<torture_numops
;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
);
224 if (num_dead
== torture_numops
) {
225 torture_comment(tctx
, "All connections dead - finishing\n");
229 torture_comment(tctx
, ".");
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
241 bool torture_holdopen(struct torture_context
*tctx
,
242 struct smbcli_state
*cli
)
245 const char *fname
= "\\holdopen.dat";
248 smbcli_unlink(cli
->tree
, fname
);
250 fnum
= smbcli_open(cli
->tree
, fname
, O_RDWR
|O_CREAT
|O_EXCL
, DENY_NONE
);
252 torture_comment(tctx
, "open of %s failed (%s)\n", fname
, smbcli_errstr(cli
->tree
));
256 smbcli_close(cli
->tree
, fnum
);
258 for (i
=0;i
<torture_numops
;i
++) {
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
);
279 if (torture_setting_bool(tctx
, "progress", true)) {
280 torture_comment(tctx
, "opened %d file\r", i
);
285 torture_comment(tctx
, "\nStarting pings\n");
290 status
= smb_raw_echo(cli
->transport
, &ec
);
291 torture_comment(tctx
, ".");
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"
304 int fnums
[0x11000], i
;
305 int retries
=4, maxfid
;
310 torture_comment(tctx
, "failed to connect\n");
314 if (smbcli_deltree(cli
->tree
, "\\maxfid") == -1) {
315 torture_comment(tctx
, "Failed to deltree \\maxfid - %s\n",
316 smbcli_errstr(cli
->tree
));
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
));
325 torture_comment(tctx
, "Testing maximum number of open files\n");
327 for (i
=0; i
<0x11000; i
++) {
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
));
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
)) ==
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
);
349 if (torture_setting_bool(tctx
, "progress", true)) {
350 torture_comment(tctx
, "%6d\r", i
);
354 torture_comment(tctx
, "%6d\n", 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
));
372 if (torture_setting_bool(tctx
, "progress", true)) {
373 torture_comment(tctx
, "%6d\r", i
);
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
));
385 torture_comment(tctx
, "maxfid test finished\n");
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
;
401 const char *fname
= "\\ioctl.dat";
403 union smb_ioctl parms
;
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
);
412 torture_comment(tctx
, "open of %s failed (%s)\n", fname
, smbcli_errstr(cli
->tree
));
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
);
438 static void benchrw_callback(struct smbcli_request
*req
);
454 struct bench_params
{
459 const char *workgroup
;
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
;
473 struct smbcli_tree
*cli
;
478 int num_parallel_requests
;
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;
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
);
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 "
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){
520 if (!smbcli_parse_unc(
521 unc_list
[conn_index
% num_unc_names
],
524 tctx
, "Failed to parse UNC "
526 unc_list
[conn_index
% num_unc_names
]);
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
;
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",
540 lpar
->unc
[0]->share
= torture_setting_string(tctx
, "share",
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
;
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
)) {
587 state
->num_parallel_requests
--;
589 if ((state
->completed
>= torture_numops
)
590 && (state
->num_parallel_requests
== 0)) {
591 benchrw_callback(req
);
598 if (state
->completed
+ state
->num_parallel_requests
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
;
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
;
626 req
= smb_raw_write_send(state
->cli
,&wr
);
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
){
644 /*start reading from beginn of file*/
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
;
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
)
666 if(state
->mode
== OPEN_FILE
){
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
;
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
;
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
;
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
;
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
;
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
) {
770 if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx
, req
,state
))) {
771 torture_comment(tctx
, "Failed to create the test "
773 nt_errstr(req
->status
));
780 if (!NT_STATUS_IS_OK(benchrw_open(tctx
, req
,state
))){
781 torture_comment(tctx
, "Failed to open/write the "
783 nt_errstr(req
->status
));
789 case READ_WRITE_DATA
:
790 while (state
->num_parallel_requests
791 < state
->lpcfg_params
->num_parallel_requests
) {
793 status
= benchrw_readwrite(tctx
,state
);
794 if (!NT_STATUS_IS_OK(status
)){
795 torture_comment(tctx
, "Failed to read/write "
797 nt_errstr(req
->status
));
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 "
807 nt_errstr(req
->status
));
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 "
817 nt_errstr(req
->status
));
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
;
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
);
849 torture_comment(tctx
, "Failed to open connection "
851 state
->nr
, nt_errstr(con
->status
));
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
,
865 struct tevent_context
*ev
,
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
;
901 int torture_nprocs
= torture_setting_int(tctx
, "nprocs", 4);
903 torture_comment(tctx
, "Start BENCH-READWRITE num_ops=%d "
905 torture_numops
, torture_nprocs
);
907 /*init talloc context*/
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
;
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
){
932 for(i
= 0; i
<torture_nprocs
;i
++){
933 switch (state
[i
]->mode
){
934 /*open multiple connections with the same userid */
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
,
945 /* register callback fn + private data */
946 req1
->async
.fn
= async_open_callback
;
947 req1
->async
.private_data
=state
[i
];
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) {
957 "Unable to delete %s - %s\n",
959 smbcli_errstr(state
[i
]->cli
));
960 state
[i
]->mode
=ERROR
;
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
];
971 /* error occurred , finish */
976 /* cleanup , close connection */
978 torture_comment(tctx
, "Deleting test dir %s "
979 "%d/%d\n",state
[i
]->dname
,
981 smbcli_deltree(state
[i
]->cli
,state
[i
]->dname
);
982 if (NT_STATUS_IS_ERR(smb_tree_disconnect(
984 torture_comment(tctx
, "ERROR: Tree "
985 "disconnect failed");
986 state
[i
]->mode
=ERROR
;
989 state
[i
]->mode
=FINISHED
;
996 tevent_loop_once(ev
);