~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/torture/basic/misc.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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)
 
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)
 
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)
 
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, 
 
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)
 
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)
 
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, 
 
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,
 
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,
 
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)
 
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,
 
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,
 
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,
 
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)
 
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)
 
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(
 
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)
 
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