LCOV - code coverage report
Current view: top level - source4/torture/basic - misc.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 0 553 0.0 %
Date: 2024-02-28 12:06:22 Functions: 0 18 0.0 %

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

Generated by: LCOV version 1.14