r15016: add a test for a 2nd open with an exclusive oplock. It does not cause
[samba.git] / source4 / torture / raw / oplock.c
1 /* 
2    Unix SMB/CIFS implementation.
3    basic raw test suite for oplocks
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "torture/torture.h"
23 #include "librpc/gen_ndr/security.h"
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/libcli.h"
26 #include "torture/util.h"
27 #include "lib/events/events.h"
28
29 #define CHECK_VAL(v, correct) do { \
30         if ((v) != (correct)) { \
31                 printf("(%d) wrong value for %s  got 0x%x - should be 0x%x\n", \
32                        __LINE__, #v, (int)v, (int)correct); \
33                 ret = False; \
34         }} while (0)
35
36 #define CHECK_STATUS(status, correct) do { \
37         if (!NT_STATUS_EQUAL(status, correct)) { \
38                 printf("(%d) Incorrect status %s - should be %s\n", \
39                        __LINE__, nt_errstr(status), nt_errstr(correct)); \
40                 ret = False; \
41                 goto done; \
42         }} while (0)
43
44
45 static struct {
46         int fnum;
47         uint8_t level;
48         int count;
49         int failures;
50 } break_info;
51
52 #define BASEDIR "\\test_notify"
53
54 /*
55   a handler function for oplock break requests
56 */
57 static BOOL oplock_handler_ack(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private)
58 {
59         struct smbcli_tree *tree = private;
60         break_info.fnum = fnum;
61         break_info.level = level;
62         break_info.count++;
63
64         printf("Acking in oplock handler\n");
65
66         return smbcli_oplock_ack(tree, fnum, level);
67 }
68
69 static void oplock_handler_close_recv(struct smbcli_request *req)
70 {
71         NTSTATUS status;
72         status = smbcli_request_simple_recv(req);
73         if (!NT_STATUS_IS_OK(status)) {
74                 printf("close failed in oplock_handler_close\n");
75                 break_info.failures++;
76         }
77 }
78
79 /*
80   a handler function for oplock break requests - close the file
81 */
82 static BOOL oplock_handler_close(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private)
83 {
84         union smb_close io;
85         struct smbcli_tree *tree = private;
86         struct smbcli_request *req;
87
88         break_info.fnum = fnum;
89         break_info.level = level;
90         break_info.count++;
91
92         io.close.level = RAW_CLOSE_CLOSE;
93         io.close.in.file.fnum = fnum;
94         io.close.in.write_time = 0;
95         req = smb_raw_close_send(tree, &io);
96         if (req == NULL) {
97                 printf("failed to send close in oplock_handler_close\n");
98                 return False;
99         }
100
101         req->async.fn = oplock_handler_close_recv;
102         req->async.private = NULL;
103
104         return True;
105 }
106
107 /*
108   test oplock ops
109 */
110 static BOOL test_oplock(struct smbcli_state *cli, TALLOC_CTX *mem_ctx)
111 {
112         const char *fname = BASEDIR "\\test_oplock.dat";
113         NTSTATUS status;
114         BOOL ret = True;
115         union smb_open io;
116         union smb_unlink unl;
117         union smb_read rd;
118         uint16_t fnum=0, fnum2=0;
119
120         /* cleanup */
121         smbcli_unlink(cli->tree, fname);
122
123         smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
124
125         /*
126           base ntcreatex parms
127         */
128         io.generic.level = RAW_OPEN_NTCREATEX;
129         io.ntcreatex.in.root_fid = 0;
130         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
131         io.ntcreatex.in.alloc_size = 0;
132         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
133         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
134         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
135         io.ntcreatex.in.create_options = 0;
136         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
137         io.ntcreatex.in.security_flags = 0;
138         io.ntcreatex.in.fname = fname;
139
140         printf("open a file with a normal oplock\n");
141         ZERO_STRUCT(break_info);
142         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
143
144         status = smb_raw_open(cli->tree, mem_ctx, &io);
145         CHECK_STATUS(status, NT_STATUS_OK);
146         fnum = io.ntcreatex.out.file.fnum;
147         CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
148
149         printf("a 2nd open should not cause a break\n");
150         status = smb_raw_open(cli->tree, mem_ctx, &io);
151         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
152         CHECK_VAL(break_info.count, 0);
153         CHECK_VAL(break_info.failures, 0);
154
155         printf("unlink it - should also be no break\n");
156         unl.unlink.in.pattern = fname;
157         unl.unlink.in.attrib = 0;
158         status = smb_raw_unlink(cli->tree, &unl);
159         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
160         CHECK_VAL(break_info.count, 0);
161         CHECK_VAL(break_info.failures, 0);
162
163         smbcli_close(cli->tree, fnum);
164
165         /*
166           with a batch oplock we get a break
167         */
168         printf("open with batch oplock\n");
169         ZERO_STRUCT(break_info);
170         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
171                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
172                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
173         status = smb_raw_open(cli->tree, mem_ctx, &io);
174         CHECK_STATUS(status, NT_STATUS_OK);
175         fnum = io.ntcreatex.out.file.fnum;
176         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
177
178         printf("unlink should generate a break\n");
179         unl.unlink.in.pattern = fname;
180         unl.unlink.in.attrib = 0;
181         status = smb_raw_unlink(cli->tree, &unl);
182         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
183
184         CHECK_VAL(break_info.fnum, fnum);
185         CHECK_VAL(break_info.level, 1);
186         CHECK_VAL(break_info.count, 1);
187         CHECK_VAL(break_info.failures, 0);
188
189         smbcli_close(cli->tree, fnum);
190
191         printf("if we close on break then the unlink can succeed\n");
192         ZERO_STRUCT(break_info);
193         smbcli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
194         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
195                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
196                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
197         status = smb_raw_open(cli->tree, mem_ctx, &io);
198         CHECK_STATUS(status, NT_STATUS_OK);
199         fnum = io.ntcreatex.out.file.fnum;
200         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
201
202         unl.unlink.in.pattern = fname;
203         unl.unlink.in.attrib = 0;
204         ZERO_STRUCT(break_info);
205         status = smb_raw_unlink(cli->tree, &unl);
206         CHECK_STATUS(status, NT_STATUS_OK);
207
208         CHECK_VAL(break_info.fnum, fnum);
209         CHECK_VAL(break_info.level, 1);
210         CHECK_VAL(break_info.count, 1);
211         CHECK_VAL(break_info.failures, 0);
212
213         printf("a self read should not cause a break\n");
214         ZERO_STRUCT(break_info);
215         smbcli_close(cli->tree, fnum);
216         smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
217
218         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
219                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
220                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
221         status = smb_raw_open(cli->tree, mem_ctx, &io);
222         CHECK_STATUS(status, NT_STATUS_OK);
223         fnum = io.ntcreatex.out.file.fnum;
224         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
225
226         rd.read.level = RAW_READ_READ;
227         rd.read.in.file.fnum = fnum;
228         rd.read.in.count = 1;
229         rd.read.in.offset = 0;
230         rd.read.in.remaining = 0;
231         status = smb_raw_read(cli->tree, &rd);
232         CHECK_STATUS(status, NT_STATUS_OK);
233         CHECK_VAL(break_info.count, 0);
234         CHECK_VAL(break_info.failures, 0);
235
236         printf("a 2nd open should give a break\n");
237         ZERO_STRUCT(break_info);
238         smbcli_close(cli->tree, fnum);
239         smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
240
241         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
242                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
243                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
244         status = smb_raw_open(cli->tree, mem_ctx, &io);
245         CHECK_STATUS(status, NT_STATUS_OK);
246         fnum = io.ntcreatex.out.file.fnum;
247         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
248
249         ZERO_STRUCT(break_info);
250
251         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
252         status = smb_raw_open(cli->tree, mem_ctx, &io);
253         CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
254
255         CHECK_VAL(break_info.count, 1);
256         CHECK_VAL(break_info.fnum, fnum);
257         CHECK_VAL(break_info.level, 1);
258         CHECK_VAL(break_info.failures, 0);
259
260         printf("a 2nd open should get an oplock when we close instead of ack\n");
261         ZERO_STRUCT(break_info);
262         smbcli_close(cli->tree, fnum);
263         smbcli_oplock_handler(cli->transport, oplock_handler_close, cli->tree);
264
265         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
266                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
267                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
268         status = smb_raw_open(cli->tree, mem_ctx, &io);
269         CHECK_STATUS(status, NT_STATUS_OK);
270         fnum2 = io.ntcreatex.out.file.fnum;
271         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
272
273         ZERO_STRUCT(break_info);
274
275         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
276                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
277                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
278         status = smb_raw_open(cli->tree, mem_ctx, &io);
279         CHECK_STATUS(status, NT_STATUS_OK);
280         fnum = io.ntcreatex.out.file.fnum;
281         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
282
283         CHECK_VAL(break_info.count, 1);
284         CHECK_VAL(break_info.fnum, fnum2);
285         CHECK_VAL(break_info.level, 1);
286         CHECK_VAL(break_info.failures, 0);
287         
288         smbcli_close(cli->tree, fnum);
289
290         printf("open with batch oplock\n");
291         ZERO_STRUCT(break_info);
292         smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
293
294         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
295                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
296                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
297         status = smb_raw_open(cli->tree, mem_ctx, &io);
298         CHECK_STATUS(status, NT_STATUS_OK);
299         fnum = io.ntcreatex.out.file.fnum;
300         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
301
302         ZERO_STRUCT(break_info);
303         printf("second open with attributes only shouldn't cause oplock break\n");
304
305         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
306                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
307                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
308         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
309         status = smb_raw_open(cli->tree, mem_ctx, &io);
310         CHECK_STATUS(status, NT_STATUS_OK);
311         fnum2 = io.ntcreatex.out.file.fnum;
312         CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
313         CHECK_VAL(break_info.count, 0);
314         CHECK_VAL(break_info.fnum, 0);
315         CHECK_VAL(break_info.level, 0);
316         CHECK_VAL(break_info.failures, 0);
317
318         smbcli_close(cli->tree, fnum);
319         smbcli_close(cli->tree, fnum2);
320         smbcli_unlink(cli->tree, fname);
321
322         printf("open with attributes only can create file\n");
323         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
324                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
325                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
326         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
327         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
328         status = smb_raw_open(cli->tree, mem_ctx, &io);
329         CHECK_STATUS(status, NT_STATUS_OK);
330         fnum = io.ntcreatex.out.file.fnum;
331         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
332
333         printf("Subsequent normal open should break oplock on attribute only open to level II\n");
334
335         ZERO_STRUCT(break_info);
336         smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
337
338         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
339                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
340                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
341         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
342         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
343         status = smb_raw_open(cli->tree, mem_ctx, &io);
344         CHECK_STATUS(status, NT_STATUS_OK);
345         fnum2 = io.ntcreatex.out.file.fnum;
346         CHECK_VAL(break_info.count, 1);
347         CHECK_VAL(break_info.fnum, fnum);
348         CHECK_VAL(break_info.failures, 0);
349         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
350         smbcli_close(cli->tree, fnum2);
351
352         printf("third oplocked open should grant level2 without break\n");
353         ZERO_STRUCT(break_info);
354         smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
355         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
356                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
357                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
358         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
359         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
360         status = smb_raw_open(cli->tree, mem_ctx, &io);
361         CHECK_STATUS(status, NT_STATUS_OK);
362         fnum2 = io.ntcreatex.out.file.fnum;
363         CHECK_VAL(break_info.count, 0);
364         CHECK_VAL(break_info.failures, 0);
365         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
366
367         ZERO_STRUCT(break_info);
368
369         printf("write should trigger a break to none on both\n");
370         {
371                 union smb_write wr;
372                 wr.write.level = RAW_WRITE_WRITE;
373                 wr.write.in.file.fnum = fnum2;
374                 wr.write.in.count = 1;
375                 wr.write.in.offset = 0;
376                 wr.write.in.remaining = 0;
377                 wr.write.in.data = (const uint8_t *)"x";
378                 status = smb_raw_write(cli->tree, &wr);
379                 CHECK_STATUS(status, NT_STATUS_OK);
380         }
381
382         /* Now the oplock break request comes in. But right now we can't
383          * answer it. Do another write */
384
385         msleep(100);
386         
387         {
388                 union smb_write wr;
389                 wr.write.level = RAW_WRITE_WRITE;
390                 wr.write.in.file.fnum = fnum2;
391                 wr.write.in.count = 1;
392                 wr.write.in.offset = 0;
393                 wr.write.in.remaining = 0;
394                 wr.write.in.data = (const uint8_t *)"x";
395                 status = smb_raw_write(cli->tree, &wr);
396                 CHECK_STATUS(status, NT_STATUS_OK);
397         }
398
399         CHECK_VAL(break_info.count, 2);
400         CHECK_VAL(break_info.level, 0);
401         CHECK_VAL(break_info.failures, 0);
402
403         smbcli_close(cli->tree, fnum);
404         smbcli_close(cli->tree, fnum2);
405
406         ZERO_STRUCT(break_info);
407         smbcli_oplock_handler(cli->transport, oplock_handler_ack, cli->tree);
408
409         printf("Open with oplock after a on-oplock open should grant level2\n");
410         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
411         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
412         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
413                 NTCREATEX_SHARE_ACCESS_WRITE|
414                 NTCREATEX_SHARE_ACCESS_DELETE;
415         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
416         status = smb_raw_open(cli->tree, mem_ctx, &io);
417         CHECK_STATUS(status, NT_STATUS_OK);
418         fnum = io.ntcreatex.out.file.fnum;
419         CHECK_VAL(break_info.count, 0);
420         CHECK_VAL(break_info.fnum, 0);
421         CHECK_VAL(break_info.failures, 0);
422         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
423
424         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
425                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
426                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
427         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
428         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
429                 NTCREATEX_SHARE_ACCESS_WRITE|
430                 NTCREATEX_SHARE_ACCESS_DELETE;
431         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
432         status = smb_raw_open(cli->tree, mem_ctx, &io);
433         CHECK_STATUS(status, NT_STATUS_OK);
434         fnum2 = io.ntcreatex.out.file.fnum;
435         CHECK_VAL(break_info.count, 0);
436         CHECK_VAL(break_info.fnum, 0);
437         CHECK_VAL(break_info.failures, 0);
438         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
439
440         printf("write should trigger a break to none\n");
441         {
442                 union smb_write wr;
443                 wr.write.level = RAW_WRITE_WRITE;
444                 wr.write.in.file.fnum = fnum;
445                 wr.write.in.count = 1;
446                 wr.write.in.offset = 0;
447                 wr.write.in.remaining = 0;
448                 wr.write.in.data = (const uint8_t *)"x";
449                 status = smb_raw_write(cli->tree, &wr);
450                 CHECK_STATUS(status, NT_STATUS_OK);
451         }
452
453         /* Now the oplock break request comes in. But right now we can't
454          * answer it. Do another write */
455
456         msleep(100);
457         
458         {
459                 union smb_write wr;
460                 wr.write.level = RAW_WRITE_WRITE;
461                 wr.write.in.file.fnum = fnum;
462                 wr.write.in.count = 1;
463                 wr.write.in.offset = 0;
464                 wr.write.in.remaining = 0;
465                 wr.write.in.data = (const uint8_t *)"x";
466                 status = smb_raw_write(cli->tree, &wr);
467                 CHECK_STATUS(status, NT_STATUS_OK);
468         }
469
470         CHECK_VAL(break_info.count, 1);
471         CHECK_VAL(break_info.fnum, fnum2);
472         CHECK_VAL(break_info.level, 0);
473         CHECK_VAL(break_info.failures, 0);
474
475 done:
476         smbcli_close(cli->tree, fnum);
477         smbcli_close(cli->tree, fnum2);
478         smbcli_unlink(cli->tree, fname);
479         return ret;
480 }
481
482
483 /* 
484    basic testing of oplocks
485 */
486 BOOL torture_raw_oplock(struct torture_context *torture)
487 {
488         struct smbcli_state *cli;
489         BOOL ret = True;
490         TALLOC_CTX *mem_ctx;
491
492         if (!torture_open_connection(&cli)) {
493                 return False;
494         }
495
496         if (!torture_setup_dir(cli, BASEDIR)) {
497                 return False;
498         }
499
500         mem_ctx = talloc_init("torture_raw_oplock");
501
502         if (!test_oplock(cli, mem_ctx)) {
503                 ret = False;
504         }
505
506         smb_raw_exit(cli->session);
507         smbcli_deltree(cli->tree, BASEDIR);
508         torture_close_connection(cli);
509         talloc_free(mem_ctx);
510         return ret;
511 }
512
513
514 /* 
515    stress testing of oplocks
516 */
517 BOOL torture_bench_oplock(struct torture_context *torture)
518 {
519         struct smbcli_state **cli;
520         BOOL ret = True;
521         TALLOC_CTX *mem_ctx = talloc_new(torture);
522         extern int torture_nprocs;
523         int i, count=0;
524         int timelimit = lp_parm_int(-1, "torture", "timelimit", 10);
525         union smb_open io;
526         struct timeval tv;
527         struct event_context *ev = event_context_find(mem_ctx);
528
529         cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
530
531         printf("Opening %d connections\n", torture_nprocs);
532         for (i=0;i<torture_nprocs;i++) {
533                 if (!torture_open_connection_ev(&cli[i], ev)) {
534                         return False;
535                 }
536                 talloc_steal(mem_ctx, cli[i]);
537                 smbcli_oplock_handler(cli[i]->transport, oplock_handler_close, 
538                                       cli[i]->tree);
539         }
540
541         if (!torture_setup_dir(cli[0], BASEDIR)) {
542                 ret = False;
543                 goto done;
544         }
545
546         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
547         io.ntcreatex.in.root_fid = 0;
548         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
549         io.ntcreatex.in.alloc_size = 0;
550         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
551         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
552         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
553         io.ntcreatex.in.create_options = 0;
554         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
555         io.ntcreatex.in.security_flags = 0;
556         io.ntcreatex.in.fname = BASEDIR "\\test.dat";
557         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
558                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
559                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
560
561         tv = timeval_current(); 
562
563         /*
564           we open the same file with SHARE_ACCESS_NONE from all the
565           connections in a round robin fashion. Each open causes an
566           oplock break on the previous connection, which is answered
567           by the oplock_handler_close() to close the file.
568
569           This measures how fast we can pass on oplocks, and stresses
570           the oplock handling code
571         */
572         printf("Running for %d seconds\n", timelimit);
573         while (timeval_elapsed(&tv) < timelimit) {
574                 for (i=0;i<torture_nprocs;i++) {
575                         NTSTATUS status;
576
577                         status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
578                         CHECK_STATUS(status, NT_STATUS_OK);
579                         count++;
580                 }
581                 printf("%.2f ops/second\r", count/timeval_elapsed(&tv));
582         }
583
584         printf("%.2f ops/second\n", count/timeval_elapsed(&tv));
585
586         smb_raw_exit(cli[torture_nprocs-1]->session);
587         
588 done:
589         smb_raw_exit(cli[0]->session);
590         smbcli_deltree(cli[0]->tree, BASEDIR);
591         talloc_free(mem_ctx);
592         return ret;
593 }