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