source: trunk/server/source4/torture/basic/misc.c

Last change on this file was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 28.3 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 SMB torture tester
4 Copyright (C) Andrew Tridgell 1997-2003
5 Copyright (C) Jelmer Vernooij 2006
6
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.
11
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.
16
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/>.
19*/
20
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"
36
37extern struct cli_credentials *cmdline_credentials;
38
39static bool wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
40{
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;
43 }
44 return true;
45}
46
47
48static bool rw_torture(struct torture_context *tctx, struct smbcli_state *c)
49{
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;
58
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;
66 }
67
68 generate_random_buffer(buf, sizeof(buf));
69
70 for (i=0;i<torture_numops;i++) {
71 unsigned int n = (unsigned int)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);
76 }
77 }
78 asprintf(&fname, "\\torture.%u", n);
79
80 if (!wait_lock(c, fnum2, n*sizeof(int), sizeof(int))) {
81 return false;
82 }
83
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;
89 }
90
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;
94 }
95
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;
102 }
103 }
104
105 pid2 = 0;
106
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;
110 }
111
112 if (pid2 != pid) {
113 torture_comment(tctx, "data corruption!\n");
114 correct = false;
115 }
116
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;
120 }
121
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;
125 }
126
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;
130 }
131 free(fname);
132 }
133
134 smbcli_close(c->tree, fnum2);
135 smbcli_unlink(c->tree, lockfname);
136
137 torture_comment(tctx, "%d\n", i);
138
139 return correct;
140}
141
142bool run_torture(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
143{
144 return rw_torture(tctx, cli);
145}
146
147
148/*
149 see how many RPC pipes we can open at once
150*/
151bool run_pipe_number(struct torture_context *tctx,
152 struct smbcli_state *cli1)
153{
154 const char *pipe_name = "\\WKSSVC";
155 int fnum;
156 int num_pipes = 0;
157
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);
161
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;
165 }
166 num_pipes++;
167 if (torture_setting_bool(tctx, "progress", true)) {
168 torture_comment(tctx, "%d\r", num_pipes);
169 fflush(stdout);
170 }
171 }
172
173 torture_comment(tctx, "pipe_number test - we can open %d %s pipes.\n", num_pipes, pipe_name );
174 return true;
175}
176
177
178
179
180/*
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
184 */
185bool torture_holdcon(struct torture_context *tctx)
186{
187 int i;
188 struct smbcli_state **cli;
189 int num_dead = 0;
190
191 torture_comment(tctx, "Opening %d connections\n", torture_numops);
192
193 cli = malloc_array_p(struct smbcli_state *, torture_numops);
194
195 for (i=0;i<torture_numops;i++) {
196 if (!torture_open_connection(&cli[i], tctx, i)) {
197 return false;
198 }
199 if (torture_setting_bool(tctx, "progress", true)) {
200 torture_comment(tctx, "opened %d connections\r", i);
201 fflush(stdout);
202 }
203 }
204
205 torture_comment(tctx, "\nStarting pings\n");
206
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++;
216 }
217 usleep(100);
218 }
219 }
220
221 if (num_dead == torture_numops) {
222 torture_comment(tctx, "All connections dead - finishing\n");
223 break;
224 }
225
226 torture_comment(tctx, ".");
227 fflush(stdout);
228 }
229
230 return true;
231}
232
233/*
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
237 */
238bool torture_holdopen(struct torture_context *tctx,
239 struct smbcli_state *cli)
240{
241 int i, fnum;
242 const char *fname = "\\holdopen.dat";
243 NTSTATUS status;
244
245 smbcli_unlink(cli->tree, fname);
246
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;
251 }
252
253 smbcli_close(cli->tree, fnum);
254
255 for (i=0;i<torture_numops;i++) {
256 union smb_open op;
257
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;
274 }
275
276 if (torture_setting_bool(tctx, "progress", true)) {
277 torture_comment(tctx, "opened %d file\r", i);
278 fflush(stdout);
279 }
280 }
281
282 torture_comment(tctx, "\nStarting pings\n");
283
284 while (1) {
285 struct smb_echo ec;
286
287 status = smb_raw_echo(cli->transport, &ec);
288 torture_comment(tctx, ".");
289 fflush(stdout);
290 sleep(15);
291 }
292}
293
294/*
295test how many open files this server supports on the one socket
296*/
297bool run_maxfidtest(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
298{
299#define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
300 char *fname;
301 int fnums[0x11000], i;
302 int retries=4, maxfid;
303 bool correct = true;
304
305 if (retries <= 0) {
306 torture_comment(tctx, "failed to connect\n");
307 return false;
308 }
309
310 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
311 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
312 smbcli_errstr(cli->tree));
313 return false;
314 }
315 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, "\\maxfid"))) {
316 torture_comment(tctx, "Failed to mkdir \\maxfid, error=%s\n",
317 smbcli_errstr(cli->tree));
318 return false;
319 }
320
321 torture_comment(tctx, "Testing maximum number of open files\n");
322
323 for (i=0; i<0x11000; i++) {
324 if (i % 1000 == 0) {
325 asprintf(&fname, "\\maxfid\\fid%d", i/1000);
326 if (NT_STATUS_IS_ERR(smbcli_mkdir(cli->tree, fname))) {
327 torture_comment(tctx, "Failed to mkdir %s, error=%s\n",
328 fname, smbcli_errstr(cli->tree));
329 return false;
330 }
331 free(fname);
332 }
333 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
334 if ((fnums[i] = smbcli_open(cli->tree, fname,
335 O_RDWR|O_CREAT|O_TRUNC, DENY_NONE)) ==
336 -1) {
337 torture_comment(tctx, "open of %s failed (%s)\n",
338 fname, smbcli_errstr(cli->tree));
339 torture_comment(tctx, "maximum fnum is %d\n", i);
340 break;
341 }
342 free(fname);
343 if (torture_setting_bool(tctx, "progress", true)) {
344 torture_comment(tctx, "%6d\r", i);
345 fflush(stdout);
346 }
347 }
348 torture_comment(tctx, "%6d\n", i);
349 i--;
350
351 maxfid = i;
352
353 torture_comment(tctx, "cleaning up\n");
354 for (i=0;i<maxfid/2;i++) {
355 asprintf(&fname, MAXFID_TEMPLATE, i/1000, i,(int)getpid());
356 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[i]))) {
357 torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[i], smbcli_errstr(cli->tree));
358 }
359 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
360 torture_comment(tctx, "unlink of %s failed (%s)\n",
361 fname, smbcli_errstr(cli->tree));
362 correct = false;
363 }
364 free(fname);
365
366 asprintf(&fname, MAXFID_TEMPLATE, (maxfid-i)/1000, maxfid-i,(int)getpid());
367 if (NT_STATUS_IS_ERR(smbcli_close(cli->tree, fnums[maxfid-i]))) {
368 torture_comment(tctx, "Close of fnum %d failed - %s\n", fnums[maxfid-i], smbcli_errstr(cli->tree));
369 }
370 if (NT_STATUS_IS_ERR(smbcli_unlink(cli->tree, fname))) {
371 torture_comment(tctx, "unlink of %s failed (%s)\n",
372 fname, smbcli_errstr(cli->tree));
373 correct = false;
374 }
375 free(fname);
376
377 if (torture_setting_bool(tctx, "progress", true)) {
378 torture_comment(tctx, "%6d %6d\r", i, maxfid-i);
379 fflush(stdout);
380 }
381 }
382 torture_comment(tctx, "%6d\n", 0);
383
384 if (smbcli_deltree(cli->tree, "\\maxfid") == -1) {
385 torture_comment(tctx, "Failed to deltree \\maxfid - %s\n",
386 smbcli_errstr(cli->tree));
387 return false;
388 }
389
390 torture_comment(tctx, "maxfid test finished\n");
391 if (!torture_close_connection(cli)) {
392 correct = false;
393 }
394 return correct;
395#undef MAXFID_TEMPLATE
396}
397
398
399
400/*
401 sees what IOCTLs are supported
402 */
403bool torture_ioctl_test(struct torture_context *tctx,
404 struct smbcli_state *cli)
405{
406 uint16_t device, function;
407 int fnum;
408 const char *fname = "\\ioctl.dat";
409 NTSTATUS status;
410 union smb_ioctl parms;
411 TALLOC_CTX *mem_ctx;
412
413 mem_ctx = talloc_named_const(tctx, 0, "ioctl_test");
414
415 smbcli_unlink(cli->tree, fname);
416
417 fnum = smbcli_open(cli->tree, fname, O_RDWR|O_CREAT|O_EXCL, DENY_NONE);
418 if (fnum == -1) {
419 torture_comment(tctx, "open of %s failed (%s)\n", fname, smbcli_errstr(cli->tree));
420 return false;
421 }
422
423 parms.ioctl.level = RAW_IOCTL_IOCTL;
424 parms.ioctl.in.file.fnum = fnum;
425 parms.ioctl.in.request = IOCTL_QUERY_JOB_INFO;
426 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
427 torture_comment(tctx, "ioctl job info: %s\n", smbcli_errstr(cli->tree));
428
429 for (device=0;device<0x100;device++) {
430 torture_comment(tctx, "Testing device=0x%x\n", device);
431 for (function=0;function<0x100;function++) {
432 parms.ioctl.in.request = (device << 16) | function;
433 status = smb_raw_ioctl(cli->tree, mem_ctx, &parms);
434
435 if (NT_STATUS_IS_OK(status)) {
436 torture_comment(tctx, "ioctl device=0x%x function=0x%x OK : %d bytes\n",
437 device, function, (int)parms.ioctl.out.blob.length);
438 }
439 }
440 }
441
442 return true;
443}
444
445static void benchrw_callback(struct smbcli_request *req);
446enum benchrw_stage {
447 START,
448 OPEN_CONNECTION,
449 CLEANUP_TESTDIR,
450 MK_TESTDIR,
451 OPEN_FILE,
452 INITIAL_WRITE,
453 READ_WRITE_DATA,
454 MAX_OPS_REACHED,
455 ERROR,
456 CLOSE_FILE,
457 CLEANUP,
458 FINISHED
459};
460
461struct benchrw_state {
462 struct torture_context *tctx;
463 char *dname;
464 char *fname;
465 uint16_t fnum;
466 int nr;
467 struct smbcli_tree *cli;
468 uint8_t *buffer;
469 int writecnt;
470 int readcnt;
471 int completed;
472 int num_parallel_requests;
473 void *req_params;
474 enum benchrw_stage mode;
475 struct params{
476 struct unclist{
477 const char *host;
478 const char *share;
479 } **unc;
480 const char *workgroup;
481 int retry;
482 unsigned int writeblocks;
483 unsigned int blocksize;
484 unsigned int writeratio;
485 int num_parallel_requests;
486 } *lpcfg_params;
487};
488
489/*
490 init params using lpcfg_parm_xxx
491 return number of unclist entries
492*/
493static int init_benchrw_params(struct torture_context *tctx,
494 struct params *lpar)
495{
496 char **unc_list = NULL;
497 int num_unc_names = 0, conn_index=0, empty_lines=0;
498 const char *p;
499 lpar->retry = torture_setting_int(tctx, "retry",3);
500 lpar->blocksize = torture_setting_int(tctx, "blocksize",65535);
501 lpar->writeblocks = torture_setting_int(tctx, "writeblocks",15);
502 lpar->writeratio = torture_setting_int(tctx, "writeratio",5);
503 lpar->num_parallel_requests = torture_setting_int(
504 tctx, "parallel_requests", 5);
505 lpar->workgroup = lpcfg_workgroup(tctx->lp_ctx);
506
507 p = torture_setting_string(tctx, "unclist", NULL);
508 if (p) {
509 char *h, *s;
510 unc_list = file_lines_load(p, &num_unc_names, 0, NULL);
511 if (!unc_list || num_unc_names <= 0) {
512 torture_comment(tctx, "Failed to load unc names list "
513 "from '%s'\n", p);
514 exit(1);
515 }
516
517 lpar->unc = talloc_array(tctx, struct unclist *,
518 (num_unc_names-empty_lines));
519 for(conn_index = 0; conn_index < num_unc_names; conn_index++) {
520 /* ignore empty lines */
521 if(strlen(unc_list[conn_index % num_unc_names])==0){
522 empty_lines++;
523 continue;
524 }
525 if (!smbcli_parse_unc(
526 unc_list[conn_index % num_unc_names],
527 NULL, &h, &s)) {
528 torture_comment(
529 tctx, "Failed to parse UNC "
530 "name %s\n",
531 unc_list[conn_index % num_unc_names]);
532 exit(1);
533 }
534 lpar->unc[conn_index-empty_lines] =
535 talloc(tctx, struct unclist);
536 lpar->unc[conn_index-empty_lines]->host = h;
537 lpar->unc[conn_index-empty_lines]->share = s;
538 }
539 return num_unc_names-empty_lines;
540 }else{
541 lpar->unc = talloc_array(tctx, struct unclist *, 1);
542 lpar->unc[0] = talloc(tctx,struct unclist);
543 lpar->unc[0]->host = torture_setting_string(tctx, "host",
544 NULL);
545 lpar->unc[0]->share = torture_setting_string(tctx, "share",
546 NULL);
547 return 1;
548 }
549}
550
551/*
552 Called when the reads & writes are finished. closes the file.
553*/
554static NTSTATUS benchrw_close(struct torture_context *tctx,
555 struct smbcli_request *req,
556 struct benchrw_state *state)
557{
558 union smb_close close_parms;
559
560 NT_STATUS_NOT_OK_RETURN(req->status);
561
562 torture_comment(tctx, "Close file %d (%d)\n",state->nr,state->fnum);
563 close_parms.close.level = RAW_CLOSE_CLOSE;
564 close_parms.close.in.file.fnum = state->fnum ;
565 close_parms.close.in.write_time = 0;
566 state->mode=CLOSE_FILE;
567
568 req = smb_raw_close_send(state->cli, &close_parms);
569 NT_STATUS_HAVE_NO_MEMORY(req);
570 /*register the callback function!*/
571 req->async.fn = benchrw_callback;
572 req->async.private_data = state;
573
574 return NT_STATUS_OK;
575}
576
577static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
578 struct benchrw_state *state);
579static void benchrw_callback(struct smbcli_request *req);
580
581static void benchrw_rw_callback(struct smbcli_request *req)
582{
583 struct benchrw_state *state = req->async.private_data;
584 struct torture_context *tctx = state->tctx;
585
586 if (!NT_STATUS_IS_OK(req->status)) {
587 state->mode = ERROR;
588 return;
589 }
590
591 state->completed++;
592 state->num_parallel_requests--;
593
594 if ((state->completed >= torture_numops)
595 && (state->num_parallel_requests == 0)) {
596 benchrw_callback(req);
597 talloc_free(req);
598 return;
599 }
600
601 talloc_free(req);
602
603 if (state->completed + state->num_parallel_requests
604 < torture_numops) {
605 benchrw_readwrite(tctx, state);
606 }
607}
608
609/*
610 Called when the initial write is completed is done. write or read a file.
611*/
612static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
613 struct benchrw_state *state)
614{
615 struct smbcli_request *req;
616 union smb_read rd;
617 union smb_write wr;
618
619 /* randomize between writes and reads*/
620 if (random() % state->lpcfg_params->writeratio == 0) {
621 torture_comment(tctx, "Callback WRITE file:%d (%d/%d)\n",
622 state->nr,state->completed,torture_numops);
623 wr.generic.level = RAW_WRITE_WRITEX ;
624 wr.writex.in.file.fnum = state->fnum ;
625 wr.writex.in.offset = 0;
626 wr.writex.in.wmode = 0 ;
627 wr.writex.in.remaining = 0;
628 wr.writex.in.count = state->lpcfg_params->blocksize;
629 wr.writex.in.data = state->buffer;
630 state->readcnt=0;
631 req = smb_raw_write_send(state->cli,&wr);
632 }
633 else {
634 torture_comment(tctx,
635 "Callback READ file:%d (%d/%d) Offset:%d\n",
636 state->nr,state->completed,torture_numops,
637 (state->readcnt*state->lpcfg_params->blocksize));
638 rd.generic.level = RAW_READ_READX;
639 rd.readx.in.file.fnum = state->fnum ;
640 rd.readx.in.offset = state->readcnt*state->lpcfg_params->blocksize;
641 rd.readx.in.mincnt = state->lpcfg_params->blocksize;
642 rd.readx.in.maxcnt = rd.readx.in.mincnt;
643 rd.readx.in.remaining = 0 ;
644 rd.readx.out.data = state->buffer;
645 rd.readx.in.read_for_execute = false;
646 if(state->readcnt < state->lpcfg_params->writeblocks){
647 state->readcnt++;
648 }else{
649 /*start reading from beginn of file*/
650 state->readcnt=0;
651 }
652 req = smb_raw_read_send(state->cli,&rd);
653 }
654 state->num_parallel_requests += 1;
655 NT_STATUS_HAVE_NO_MEMORY(req);
656 /*register the callback function!*/
657 req->async.fn = benchrw_rw_callback;
658 req->async.private_data = state;
659
660 return NT_STATUS_OK;
661}
662
663/*
664 Called when the open is done. writes to the file.
665*/
666static NTSTATUS benchrw_open(struct torture_context *tctx,
667 struct smbcli_request *req,
668 struct benchrw_state *state)
669{
670 union smb_write wr;
671 if(state->mode == OPEN_FILE){
672 NTSTATUS status;
673 status = smb_raw_open_recv(req,tctx,(
674 union smb_open*)state->req_params);
675 NT_STATUS_NOT_OK_RETURN(status);
676
677 state->fnum = ((union smb_open*)state->req_params)
678 ->openx.out.file.fnum;
679 torture_comment(tctx, "File opened (%d)\n",state->fnum);
680 state->mode=INITIAL_WRITE;
681 }
682
683 torture_comment(tctx, "Write initial test file:%d (%d/%d)\n",state->nr,
684 (state->writecnt+1)*state->lpcfg_params->blocksize,
685 (state->lpcfg_params->writeblocks*state->lpcfg_params->blocksize));
686 wr.generic.level = RAW_WRITE_WRITEX ;
687 wr.writex.in.file.fnum = state->fnum ;
688 wr.writex.in.offset = state->writecnt *
689 state->lpcfg_params->blocksize;
690 wr.writex.in.wmode = 0 ;
691 wr.writex.in.remaining = (state->lpcfg_params->writeblocks *
692 state->lpcfg_params->blocksize)-
693 ((state->writecnt+1)*state->
694 lpcfg_params->blocksize);
695 wr.writex.in.count = state->lpcfg_params->blocksize;
696 wr.writex.in.data = state->buffer;
697 state->writecnt++;
698 if(state->writecnt == state->lpcfg_params->writeblocks){
699 state->mode=READ_WRITE_DATA;
700 }
701 req = smb_raw_write_send(state->cli,&wr);
702 NT_STATUS_HAVE_NO_MEMORY(req);
703
704 /*register the callback function!*/
705 req->async.fn = benchrw_callback;
706 req->async.private_data = state;
707 return NT_STATUS_OK;
708}
709
710/*
711 Called when the mkdir is done. Opens a file.
712*/
713static NTSTATUS benchrw_mkdir(struct torture_context *tctx,
714 struct smbcli_request *req,
715 struct benchrw_state *state)
716{
717 union smb_open *open_parms;
718 uint8_t *writedata;
719
720 NT_STATUS_NOT_OK_RETURN(req->status);
721
722 /* open/create the files */
723 torture_comment(tctx, "Open File %d/%d\n",state->nr+1,
724 torture_setting_int(tctx, "nprocs", 4));
725 open_parms=talloc_zero(tctx, union smb_open);
726 NT_STATUS_HAVE_NO_MEMORY(open_parms);
727 open_parms->openx.level = RAW_OPEN_OPENX;
728 open_parms->openx.in.flags = 0;
729 open_parms->openx.in.open_mode = OPENX_MODE_ACCESS_RDWR;
730 open_parms->openx.in.search_attrs =
731 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
732 open_parms->openx.in.file_attrs = 0;
733 open_parms->openx.in.write_time = 0;
734 open_parms->openx.in.open_func = OPENX_OPEN_FUNC_CREATE;
735 open_parms->openx.in.size = 0;
736 open_parms->openx.in.timeout = 0;
737 open_parms->openx.in.fname = state->fname;
738
739 writedata = talloc_size(tctx,state->lpcfg_params->blocksize);
740 NT_STATUS_HAVE_NO_MEMORY(writedata);
741 generate_random_buffer(writedata,state->lpcfg_params->blocksize);
742 state->buffer=writedata;
743 state->writecnt=1;
744 state->readcnt=0;
745 state->req_params=open_parms;
746 state->mode=OPEN_FILE;
747
748 req = smb_raw_open_send(state->cli,open_parms);
749 NT_STATUS_HAVE_NO_MEMORY(req);
750
751 /*register the callback function!*/
752 req->async.fn = benchrw_callback;
753 req->async.private_data = state;
754
755 return NT_STATUS_OK;
756}
757
758/*
759 handler for completion of a sub-request of the bench-rw test
760*/
761static void benchrw_callback(struct smbcli_request *req)
762{
763 struct benchrw_state *state = req->async.private_data;
764 struct torture_context *tctx = state->tctx;
765
766 /*dont send new requests when torture_numops is reached*/
767 if ((state->mode == READ_WRITE_DATA)
768 && (state->completed >= torture_numops)) {
769 state->mode=MAX_OPS_REACHED;
770 }
771
772 switch (state->mode) {
773
774 case MK_TESTDIR:
775 if (!NT_STATUS_IS_OK(benchrw_mkdir(tctx, req,state))) {
776 torture_comment(tctx, "Failed to create the test "
777 "directory - %s\n",
778 nt_errstr(req->status));
779 state->mode=ERROR;
780 return;
781 }
782 break;
783 case OPEN_FILE:
784 case INITIAL_WRITE:
785 if (!NT_STATUS_IS_OK(benchrw_open(tctx, req,state))){
786 torture_comment(tctx, "Failed to open/write the "
787 "file - %s\n",
788 nt_errstr(req->status));
789 state->mode=ERROR;
790 state->readcnt=0;
791 return;
792 }
793 break;
794 case READ_WRITE_DATA:
795 while (state->num_parallel_requests
796 < state->lpcfg_params->num_parallel_requests) {
797 NTSTATUS status;
798 status = benchrw_readwrite(tctx,state);
799 if (!NT_STATUS_IS_OK(status)){
800 torture_comment(tctx, "Failed to read/write "
801 "the file - %s\n",
802 nt_errstr(req->status));
803 state->mode=ERROR;
804 return;
805 }
806 }
807 break;
808 case MAX_OPS_REACHED:
809 if (!NT_STATUS_IS_OK(benchrw_close(tctx,req,state))){
810 torture_comment(tctx, "Failed to read/write/close "
811 "the file - %s\n",
812 nt_errstr(req->status));
813 state->mode=ERROR;
814 return;
815 }
816 break;
817 case CLOSE_FILE:
818 torture_comment(tctx, "File %d closed\n",state->nr);
819 if (!NT_STATUS_IS_OK(req->status)) {
820 torture_comment(tctx, "Failed to close the "
821 "file - %s\n",
822 nt_errstr(req->status));
823 state->mode=ERROR;
824 return;
825 }
826 state->mode=CLEANUP;
827 return;
828 default:
829 break;
830 }
831
832}
833
834/* open connection async callback function*/
835static void async_open_callback(struct composite_context *con)
836{
837 struct benchrw_state *state = con->async.private_data;
838 struct torture_context *tctx = state->tctx;
839 int retry = state->lpcfg_params->retry;
840
841 if (NT_STATUS_IS_OK(con->status)) {
842 state->cli=((struct smb_composite_connect*)
843 state->req_params)->out.tree;
844 state->mode=CLEANUP_TESTDIR;
845 }else{
846 if(state->writecnt < retry){
847 torture_comment(tctx, "Failed to open connection: "
848 "%d, Retry (%d/%d)\n",
849 state->nr,state->writecnt,retry);
850 state->writecnt++;
851 state->mode=START;
852 usleep(1000);
853 }else{
854 torture_comment(tctx, "Failed to open connection "
855 "(%d) - %s\n",
856 state->nr, nt_errstr(con->status));
857 state->mode=ERROR;
858 }
859 return;
860 }
861}
862
863/*
864 establishs a smbcli_tree from scratch (async)
865*/
866static struct composite_context *torture_connect_async(
867 struct torture_context *tctx,
868 struct smb_composite_connect *smb,
869 TALLOC_CTX *mem_ctx,
870 struct tevent_context *ev,
871 const char *host,
872 const char *share,
873 const char *workgroup)
874{
875 torture_comment(tctx, "Open Connection to %s/%s\n",host,share);
876 smb->in.dest_host=talloc_strdup(mem_ctx,host);
877 smb->in.service=talloc_strdup(mem_ctx,share);
878 smb->in.dest_ports=lpcfg_smb_ports(tctx->lp_ctx);
879 smb->in.socket_options = lpcfg_socket_options(tctx->lp_ctx);
880 smb->in.called_name = strupper_talloc(mem_ctx, host);
881 smb->in.service_type=NULL;
882 smb->in.credentials=cmdline_credentials;
883 smb->in.fallback_to_anonymous=false;
884 smb->in.gensec_settings = lpcfg_gensec_settings(mem_ctx, tctx->lp_ctx);
885 smb->in.workgroup=workgroup;
886 lpcfg_smbcli_options(tctx->lp_ctx, &smb->in.options);
887 lpcfg_smbcli_session_options(tctx->lp_ctx, &smb->in.session_options);
888
889 return smb_composite_connect_send(smb,mem_ctx,
890 lpcfg_resolve_context(tctx->lp_ctx),ev);
891}
892
893bool run_benchrw(struct torture_context *tctx)
894{
895 struct smb_composite_connect *smb_con;
896 const char *fname = "\\rwtest.dat";
897 struct smbcli_request *req;
898 struct benchrw_state **state;
899 int i , num_unc_names;
900 struct tevent_context *ev ;
901 struct composite_context *req1;
902 struct params lpparams;
903 union smb_mkdir parms;
904 int finished = 0;
905 bool success=true;
906 int torture_nprocs = torture_setting_int(tctx, "nprocs", 4);
907
908 torture_comment(tctx, "Start BENCH-READWRITE num_ops=%d "
909 "num_nprocs=%d\n",
910 torture_numops, torture_nprocs);
911
912 /*init talloc context*/
913 ev = tctx->ev;
914 state = talloc_array(tctx, struct benchrw_state *, torture_nprocs);
915
916 /* init params using lpcfg_parm_xxx */
917 num_unc_names = init_benchrw_params(tctx,&lpparams);
918
919 /* init private data structs*/
920 for(i = 0; i<torture_nprocs;i++){
921 state[i]=talloc(tctx,struct benchrw_state);
922 state[i]->tctx = tctx;
923 state[i]->completed=0;
924 state[i]->num_parallel_requests=0;
925 state[i]->lpcfg_params=&lpparams;
926 state[i]->nr=i;
927 state[i]->dname=talloc_asprintf(tctx,"benchrw%d",i);
928 state[i]->fname=talloc_asprintf(tctx,"%s%s",
929 state[i]->dname,fname);
930 state[i]->mode=START;
931 state[i]->writecnt=0;
932 }
933
934 torture_comment(tctx, "Starting async requests\n");
935 while(finished != torture_nprocs){
936 finished=0;
937 for(i = 0; i<torture_nprocs;i++){
938 switch (state[i]->mode){
939 /*open multiple connections with the same userid */
940 case START:
941 smb_con = talloc(
942 tctx,struct smb_composite_connect) ;
943 state[i]->req_params=smb_con;
944 state[i]->mode=OPEN_CONNECTION;
945 req1 = torture_connect_async(
946 tctx, smb_con, tctx,ev,
947 lpparams.unc[i % num_unc_names]->host,
948 lpparams.unc[i % num_unc_names]->share,
949 lpparams.workgroup);
950 /* register callback fn + private data */
951 req1->async.fn = async_open_callback;
952 req1->async.private_data=state[i];
953 break;
954 /*setup test dirs (sync)*/
955 case CLEANUP_TESTDIR:
956 torture_comment(tctx, "Setup test dir %d\n",i);
957 smb_raw_exit(state[i]->cli->session);
958 if (smbcli_deltree(state[i]->cli,
959 state[i]->dname) == -1) {
960 torture_comment(
961 tctx,
962 "Unable to delete %s - %s\n",
963 state[i]->dname,
964 smbcli_errstr(state[i]->cli));
965 state[i]->mode=ERROR;
966 break;
967 }
968 state[i]->mode=MK_TESTDIR;
969 parms.mkdir.level = RAW_MKDIR_MKDIR;
970 parms.mkdir.in.path = state[i]->dname;
971 req = smb_raw_mkdir_send(state[i]->cli,&parms);
972 /* register callback fn + private data */
973 req->async.fn = benchrw_callback;
974 req->async.private_data=state[i];
975 break;
976 /* error occured , finish */
977 case ERROR:
978 finished++;
979 success=false;
980 break;
981 /* cleanup , close connection */
982 case CLEANUP:
983 torture_comment(tctx, "Deleting test dir %s "
984 "%d/%d\n",state[i]->dname,
985 i+1,torture_nprocs);
986 smbcli_deltree(state[i]->cli,state[i]->dname);
987 if (NT_STATUS_IS_ERR(smb_tree_disconnect(
988 state[i]->cli))) {
989 torture_comment(tctx, "ERROR: Tree "
990 "disconnect failed");
991 state[i]->mode=ERROR;
992 break;
993 }
994 state[i]->mode=FINISHED;
995 case FINISHED:
996 finished++;
997 break;
998 default:
999 event_loop_once(ev);
1000 }
1001 }
1002 }
1003
1004 return success;
1005}
1006
Note: See TracBrowser for help on using the repository browser.