root/source4/torture/basic/misc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wait_lock
  2. rw_torture
  3. run_torture
  4. run_pipe_number
  5. torture_holdcon
  6. run_maxfidtest
  7. torture_ioctl_test
  8. init_benchrw_params
  9. benchrw_close
  10. benchrw_rw_callback
  11. benchrw_readwrite
  12. benchrw_open
  13. benchrw_mkdir
  14. benchrw_callback
  15. async_open_callback
  16. torture_connect_async
  17. run_benchrw

   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 
  39 extern struct cli_credentials *cmdline_credentials;
  40         
  41 static bool wait_lock(struct smbcli_state *c, int fnum, uint32_t offset, uint32_t len)
     /* [<][>][^][v][top][bottom][index][help] */
  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 
  50 static bool rw_torture(struct torture_context *tctx, struct smbcli_state *c)
     /* [<][>][^][v][top][bottom][index][help] */
  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 
 144 bool run_torture(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
     /* [<][>][^][v][top][bottom][index][help] */
 145 {
 146         return rw_torture(tctx, cli);
 147 }
 148 
 149 
 150 /*
 151   see how many RPC pipes we can open at once
 152 */
 153 bool run_pipe_number(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 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  */
 187 bool torture_holdcon(struct torture_context *tctx)
     /* [<][>][^][v][top][bottom][index][help] */
 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 /*
 236 test how many open files this server supports on the one socket
 237 */
 238 bool run_maxfidtest(struct torture_context *tctx, struct smbcli_state *cli, int dummy)
     /* [<][>][^][v][top][bottom][index][help] */
 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  */
 344 bool torture_ioctl_test(struct torture_context *tctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 386 static void benchrw_callback(struct smbcli_request *req);
 387 enum 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 
 402 struct 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 */
 434 static int init_benchrw_params(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 495 static NTSTATUS benchrw_close(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 518 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
 519                                   struct benchrw_state *state);
 520 static void benchrw_callback(struct smbcli_request *req);
 521 
 522 static void benchrw_rw_callback(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 553 static NTSTATUS benchrw_readwrite(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 607 static NTSTATUS benchrw_open(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 654 static NTSTATUS benchrw_mkdir(struct torture_context *tctx,
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 702 static void benchrw_callback(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 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*/
 776 static void async_open_callback(struct composite_context *con)
     /* [<][>][^][v][top][bottom][index][help] */
 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 */
 807 static struct composite_context *torture_connect_async(
     /* [<][>][^][v][top][bottom][index][help] */
 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 
 835 bool run_benchrw(struct torture_context *tctx)
     /* [<][>][^][v][top][bottom][index][help] */
 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 

/* [<][>][^][v][top][bottom][index][help] */