r21707: Finally merge my (long-living) perlselftest branch.
[jelmer/samba4-debian.git] / source / 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                 torture_result(tctx, TORTURE_FAIL, __location__": wrong value for %s got 0x%x - should be 0x%x", \
32                                 #v, (int)v, (int)correct); \
33                 ret = False; \
34         }} while (0)
35
36 #define CHECK_STATUS(tctx, status, correct) do { \
37         if (!NT_STATUS_EQUAL(status, correct)) { \
38                 torture_result(tctx, TORTURE_FAIL, __location__": Incorrect status %s - should be %s", \
39                        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. Ack it as a break to level II if possible
56 */
57 static BOOL oplock_handler_ack_to_levelII(struct smbcli_transport *transport, uint16_t tid, 
58                                uint16_t fnum, uint8_t level, void *private)
59 {
60         struct smbcli_tree *tree = private;
61         break_info.fnum = fnum;
62         break_info.level = level;
63         break_info.count++;
64
65         printf("Acking to level II in oplock handler\n");
66
67         return smbcli_oplock_ack(tree, fnum, level);
68 }
69
70 /*
71   a handler function for oplock break requests. Ack it as a break to none
72 */
73 static BOOL oplock_handler_ack_to_none(struct smbcli_transport *transport, uint16_t tid, 
74                                     uint16_t fnum, uint8_t level, 
75                                     void *private)
76 {
77         struct smbcli_tree *tree = private;
78         break_info.fnum = fnum;
79         break_info.level = level;
80         break_info.count++;
81
82         printf("Acking to none in oplock handler\n");
83
84         return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
85 }
86
87 static void oplock_handler_close_recv(struct smbcli_request *req)
88 {
89         NTSTATUS status;
90         status = smbcli_request_simple_recv(req);
91         if (!NT_STATUS_IS_OK(status)) {
92                 printf("close failed in oplock_handler_close\n");
93                 break_info.failures++;
94         }
95 }
96
97 /*
98   a handler function for oplock break requests - close the file
99 */
100 static BOOL oplock_handler_close(struct smbcli_transport *transport, uint16_t tid, 
101                                  uint16_t fnum, uint8_t level, void *private)
102 {
103         union smb_close io;
104         struct smbcli_tree *tree = private;
105         struct smbcli_request *req;
106
107         break_info.fnum = fnum;
108         break_info.level = level;
109         break_info.count++;
110
111         io.close.level = RAW_CLOSE_CLOSE;
112         io.close.in.file.fnum = fnum;
113         io.close.in.write_time = 0;
114         req = smb_raw_close_send(tree, &io);
115         if (req == NULL) {
116                 printf("failed to send close in oplock_handler_close\n");
117                 return False;
118         }
119
120         req->async.fn = oplock_handler_close_recv;
121         req->async.private = NULL;
122
123         return True;
124 }
125
126 /*
127   test oplock ops
128 */
129 static BOOL test_oplock(struct torture_context *tctx, 
130                                                 struct smbcli_state *cli1, struct smbcli_state *cli2, TALLOC_CTX *mem_ctx)
131 {
132         const char *fname = BASEDIR "\\test_oplock.dat";
133         NTSTATUS status;
134         BOOL ret = True;
135         union smb_open io;
136         union smb_unlink unl;
137         union smb_read rd;
138         union smb_setfileinfo sfi;
139         uint16_t fnum=0, fnum2=0;
140         char c = 0;
141
142         /* cleanup */
143         smbcli_unlink(cli1->tree, fname);
144
145         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
146
147         /*
148           base ntcreatex parms
149         */
150         io.generic.level = RAW_OPEN_NTCREATEX;
151         io.ntcreatex.in.root_fid = 0;
152         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
153         io.ntcreatex.in.alloc_size = 0;
154         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
155         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
156         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
157         io.ntcreatex.in.create_options = 0;
158         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
159         io.ntcreatex.in.security_flags = 0;
160         io.ntcreatex.in.fname = fname;
161
162         torture_comment(tctx, "open a file with a normal oplock\n");
163         ZERO_STRUCT(break_info);
164         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
165
166         status = smb_raw_open(cli1->tree, mem_ctx, &io);
167         CHECK_STATUS(tctx, status, NT_STATUS_OK);
168         fnum = io.ntcreatex.out.file.fnum;
169         CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
170
171         torture_comment(tctx, "a 2nd open should not cause a break\n");
172         status = smb_raw_open(cli2->tree, mem_ctx, &io);
173         CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
174         CHECK_VAL(break_info.count, 0);
175         CHECK_VAL(break_info.failures, 0);
176
177         torture_comment(tctx, "unlink it - should also be no break\n");
178         unl.unlink.in.pattern = fname;
179         unl.unlink.in.attrib = 0;
180         status = smb_raw_unlink(cli2->tree, &unl);
181         CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
182         CHECK_VAL(break_info.count, 0);
183         CHECK_VAL(break_info.failures, 0);
184
185         smbcli_close(cli1->tree, fnum);
186
187         /*
188           with a batch oplock we get a break
189         */
190         torture_comment(tctx, "open with batch oplock\n");
191         ZERO_STRUCT(break_info);
192         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
193                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
194                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
195         status = smb_raw_open(cli1->tree, mem_ctx, &io);
196         CHECK_STATUS(tctx, status, NT_STATUS_OK);
197         fnum = io.ntcreatex.out.file.fnum;
198         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
199
200         torture_comment(tctx, "unlink should generate a break\n");
201         unl.unlink.in.pattern = fname;
202         unl.unlink.in.attrib = 0;
203         status = smb_raw_unlink(cli2->tree, &unl);
204         CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
205
206         CHECK_VAL(break_info.count, 1);
207         CHECK_VAL(break_info.fnum, fnum);
208         CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
209         CHECK_VAL(break_info.failures, 0);
210
211         torture_comment(tctx, "2nd unlink should not generate a break\n");
212         ZERO_STRUCT(break_info);
213         status = smb_raw_unlink(cli2->tree, &unl);
214         CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
215
216         CHECK_VAL(break_info.count, 0);
217
218         torture_comment(tctx, "writing should generate a self break to none\n");
219         smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
220         msleep(100);
221         smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
222
223         CHECK_VAL(break_info.count, 1);
224         CHECK_VAL(break_info.fnum, fnum);
225         CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
226         CHECK_VAL(break_info.failures, 0);
227
228         smbcli_close(cli1->tree, fnum);
229
230
231         torture_comment(tctx, "open with batch oplock\n");
232         ZERO_STRUCT(break_info);
233         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
234                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
235                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
236         status = smb_raw_open(cli1->tree, mem_ctx, &io);
237         CHECK_STATUS(tctx, status, NT_STATUS_OK);
238         fnum = io.ntcreatex.out.file.fnum;
239         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
240
241         torture_comment(tctx, "unlink should generate a break, which we ack as break to none\n");
242         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none, cli1->tree);
243         unl.unlink.in.pattern = fname;
244         unl.unlink.in.attrib = 0;
245         status = smb_raw_unlink(cli2->tree, &unl);
246         CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
247
248         CHECK_VAL(break_info.count, 1);
249         CHECK_VAL(break_info.fnum, fnum);
250         CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
251         CHECK_VAL(break_info.failures, 0);
252
253         torture_comment(tctx, "2nd unlink should not generate a break\n");
254         ZERO_STRUCT(break_info);
255         status = smb_raw_unlink(cli2->tree, &unl);
256         CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
257
258         CHECK_VAL(break_info.count, 0);
259
260         torture_comment(tctx, "writing should not generate a break\n");
261         smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
262         msleep(100);
263         smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
264
265         CHECK_VAL(break_info.count, 0);
266
267         smbcli_close(cli1->tree, fnum);
268
269         torture_comment(tctx, "if we close on break then the unlink can succeed\n");
270         ZERO_STRUCT(break_info);
271         smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
272         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
273                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
274                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
275         status = smb_raw_open(cli1->tree, mem_ctx, &io);
276         CHECK_STATUS(tctx, status, NT_STATUS_OK);
277         fnum = io.ntcreatex.out.file.fnum;
278         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
279
280         unl.unlink.in.pattern = fname;
281         unl.unlink.in.attrib = 0;
282         ZERO_STRUCT(break_info);
283         status = smb_raw_unlink(cli2->tree, &unl);
284         CHECK_STATUS(tctx, status, NT_STATUS_OK);
285
286         CHECK_VAL(break_info.count, 1);
287         CHECK_VAL(break_info.fnum, fnum);
288         CHECK_VAL(break_info.level, 1);
289         CHECK_VAL(break_info.failures, 0);
290
291         torture_comment(tctx, "a self read should not cause a break\n");
292         ZERO_STRUCT(break_info);
293         smbcli_close(cli1->tree, fnum);
294         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
295
296         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
297                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
298                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
299         status = smb_raw_open(cli1->tree, mem_ctx, &io);
300         CHECK_STATUS(tctx, status, NT_STATUS_OK);
301         fnum = io.ntcreatex.out.file.fnum;
302         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
303
304         rd.read.level = RAW_READ_READ;
305         rd.read.in.file.fnum = fnum;
306         rd.read.in.count = 1;
307         rd.read.in.offset = 0;
308         rd.read.in.remaining = 0;
309         status = smb_raw_read(cli1->tree, &rd);
310         CHECK_STATUS(tctx, status, NT_STATUS_OK);
311         CHECK_VAL(break_info.count, 0);
312         CHECK_VAL(break_info.failures, 0);
313
314         torture_comment(tctx, "a 2nd open should give a break\n");
315         ZERO_STRUCT(break_info);
316         smbcli_close(cli1->tree, fnum);
317         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
318
319         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
320                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
321                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
322         status = smb_raw_open(cli1->tree, mem_ctx, &io);
323         CHECK_STATUS(tctx, status, NT_STATUS_OK);
324         fnum = io.ntcreatex.out.file.fnum;
325         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
326
327         ZERO_STRUCT(break_info);
328
329         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
330         status = smb_raw_open(cli2->tree, mem_ctx, &io);
331         CHECK_STATUS(tctx, status, NT_STATUS_SHARING_VIOLATION);
332
333         CHECK_VAL(break_info.count, 1);
334         CHECK_VAL(break_info.fnum, fnum);
335         CHECK_VAL(break_info.level, 1);
336         CHECK_VAL(break_info.failures, 0);
337
338
339         torture_comment(tctx, "a 2nd open should give a break to level II if the first open allowed shared read\n");
340         ZERO_STRUCT(break_info);
341         smbcli_close(cli1->tree, fnum);
342         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
343         smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
344
345         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
346         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
347         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
348                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
349                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
350         status = smb_raw_open(cli1->tree, mem_ctx, &io);
351         CHECK_STATUS(tctx, status, NT_STATUS_OK);
352         fnum = io.ntcreatex.out.file.fnum;
353         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
354
355         ZERO_STRUCT(break_info);
356
357         status = smb_raw_open(cli2->tree, mem_ctx, &io);
358         CHECK_STATUS(tctx, status, NT_STATUS_OK);
359         fnum2 = io.ntcreatex.out.file.fnum;
360         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
361
362         CHECK_VAL(break_info.count, 1);
363         CHECK_VAL(break_info.fnum, fnum);
364         CHECK_VAL(break_info.level, 1);
365         CHECK_VAL(break_info.failures, 0);
366         ZERO_STRUCT(break_info);
367
368         torture_comment(tctx, "write should trigger a break to none on both\n");
369         smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
370         msleep(100);
371         smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
372
373         CHECK_VAL(break_info.count, 2);
374         CHECK_VAL(break_info.level, 0);
375         CHECK_VAL(break_info.failures, 0);
376
377         smbcli_close(cli1->tree, fnum);
378         smbcli_close(cli2->tree, fnum2);
379
380         torture_comment(tctx, "a 2nd open should get an oplock when we close instead of ack\n");
381         ZERO_STRUCT(break_info);
382         smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
383
384         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
385         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
386         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
387                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
388                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
389         status = smb_raw_open(cli1->tree, mem_ctx, &io);
390         CHECK_STATUS(tctx, status, NT_STATUS_OK);
391         fnum2 = io.ntcreatex.out.file.fnum;
392         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
393
394         ZERO_STRUCT(break_info);
395
396         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
397                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
398                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
399         status = smb_raw_open(cli2->tree, mem_ctx, &io);
400         CHECK_STATUS(tctx, status, NT_STATUS_OK);
401         fnum = io.ntcreatex.out.file.fnum;
402         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
403
404         CHECK_VAL(break_info.count, 1);
405         CHECK_VAL(break_info.fnum, fnum2);
406         CHECK_VAL(break_info.level, 1);
407         CHECK_VAL(break_info.failures, 0);
408         
409         smbcli_close(cli2->tree, fnum);
410
411         torture_comment(tctx, "open with batch oplock\n");
412         ZERO_STRUCT(break_info);
413         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
414
415         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
416                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
417                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
418         status = smb_raw_open(cli1->tree, mem_ctx, &io);
419         CHECK_STATUS(tctx, status, NT_STATUS_OK);
420         fnum = io.ntcreatex.out.file.fnum;
421         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
422
423         ZERO_STRUCT(break_info);
424         torture_comment(tctx, "second open with attributes only shouldn't cause oplock break\n");
425
426         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
427                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
428                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
429         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
430         status = smb_raw_open(cli2->tree, mem_ctx, &io);
431         CHECK_STATUS(tctx, status, NT_STATUS_OK);
432         fnum2 = io.ntcreatex.out.file.fnum;
433         CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
434         CHECK_VAL(break_info.count, 0);
435         CHECK_VAL(break_info.failures, 0);
436
437         smbcli_close(cli1->tree, fnum);
438         smbcli_close(cli2->tree, fnum2);
439         smbcli_unlink(cli1->tree, fname);
440
441         torture_comment(tctx, "open with attributes only can create file\n");
442
443         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
444                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
445                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
446         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
447         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
448         status = smb_raw_open(cli1->tree, mem_ctx, &io);
449         CHECK_STATUS(tctx, status, NT_STATUS_OK);
450         fnum = io.ntcreatex.out.file.fnum;
451         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
452
453         torture_comment(tctx, "Subsequent normal open should break oplock on attribute only open to level II\n");
454
455         ZERO_STRUCT(break_info);
456         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
457
458         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
459                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
460                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
461         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
462         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
463         status = smb_raw_open(cli2->tree, mem_ctx, &io);
464         CHECK_STATUS(tctx, status, NT_STATUS_OK);
465         fnum2 = io.ntcreatex.out.file.fnum;
466         CHECK_VAL(break_info.count, 1);
467         CHECK_VAL(break_info.fnum, fnum);
468         CHECK_VAL(break_info.failures, 0);
469         CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
470         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
471         smbcli_close(cli2->tree, fnum2);
472
473         torture_comment(tctx, "third oplocked open should grant level2 without break\n");
474         ZERO_STRUCT(break_info);
475         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
476         smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
477         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
478                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
479                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
480         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
481         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
482         status = smb_raw_open(cli2->tree, mem_ctx, &io);
483         CHECK_STATUS(tctx, status, NT_STATUS_OK);
484         fnum2 = io.ntcreatex.out.file.fnum;
485         CHECK_VAL(break_info.count, 0);
486         CHECK_VAL(break_info.failures, 0);
487         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
488
489         ZERO_STRUCT(break_info);
490
491         torture_comment(tctx, "write should trigger a break to none on both\n");
492         smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
493
494         /* Now the oplock break request comes in. But right now we can't
495          * answer it. Do another write */
496
497         msleep(100);
498         smbcli_write(cli2->tree, fnum2, 0, &c, 1, 1);
499
500         CHECK_VAL(break_info.count, 2);
501         CHECK_VAL(break_info.level, 0);
502         CHECK_VAL(break_info.failures, 0);
503
504         smbcli_close(cli1->tree, fnum);
505         smbcli_close(cli2->tree, fnum2);
506
507         ZERO_STRUCT(break_info);
508         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
509
510         torture_comment(tctx, "Open with oplock after a on-oplock open should grant level2\n");
511         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
512         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
513         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
514                 NTCREATEX_SHARE_ACCESS_WRITE|
515                 NTCREATEX_SHARE_ACCESS_DELETE;
516         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
517         status = smb_raw_open(cli1->tree, mem_ctx, &io);
518         CHECK_STATUS(tctx, status, NT_STATUS_OK);
519         fnum = io.ntcreatex.out.file.fnum;
520         CHECK_VAL(break_info.count, 0);
521         CHECK_VAL(break_info.failures, 0);
522         CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
523
524         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
525                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
526                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
527         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
528         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
529                 NTCREATEX_SHARE_ACCESS_WRITE|
530                 NTCREATEX_SHARE_ACCESS_DELETE;
531         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
532         status = smb_raw_open(cli2->tree, mem_ctx, &io);
533         CHECK_STATUS(tctx, status, NT_STATUS_OK);
534         fnum2 = io.ntcreatex.out.file.fnum;
535         CHECK_VAL(break_info.count, 0);
536         CHECK_VAL(break_info.failures, 0);
537         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
538
539         torture_comment(tctx, "write should trigger a break to none\n");
540         {
541                 union smb_write wr;
542                 wr.write.level = RAW_WRITE_WRITE;
543                 wr.write.in.file.fnum = fnum;
544                 wr.write.in.count = 1;
545                 wr.write.in.offset = 0;
546                 wr.write.in.remaining = 0;
547                 wr.write.in.data = (const uint8_t *)"x";
548                 status = smb_raw_write(cli1->tree, &wr);
549                 CHECK_STATUS(tctx, status, NT_STATUS_OK);
550         }
551
552         /* Now the oplock break request comes in. But right now we can't
553          * answer it. Do another write */
554
555         msleep(100);
556         
557         {
558                 union smb_write wr;
559                 wr.write.level = RAW_WRITE_WRITE;
560                 wr.write.in.file.fnum = fnum;
561                 wr.write.in.count = 1;
562                 wr.write.in.offset = 0;
563                 wr.write.in.remaining = 0;
564                 wr.write.in.data = (const uint8_t *)"x";
565                 status = smb_raw_write(cli1->tree, &wr);
566                 CHECK_STATUS(tctx, status, NT_STATUS_OK);
567         }
568
569         CHECK_VAL(break_info.count, 1);
570         CHECK_VAL(break_info.fnum, fnum2);
571         CHECK_VAL(break_info.level, 0);
572         CHECK_VAL(break_info.failures, 0);
573
574         smbcli_close(cli1->tree, fnum);
575         smbcli_close(cli2->tree, fnum2);
576         smbcli_unlink(cli1->tree, fname);
577
578         /* Test if a set-eof on pathname breaks an exclusive oplock. */
579         torture_comment(tctx, "Test if setpathinfo set EOF breaks oplocks.\n");
580
581         ZERO_STRUCT(break_info);
582         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
583
584         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
585                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
586                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
587         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
588         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
589                 NTCREATEX_SHARE_ACCESS_WRITE|
590                 NTCREATEX_SHARE_ACCESS_DELETE;
591         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
592         status = smb_raw_open(cli1->tree, mem_ctx, &io);
593         CHECK_STATUS(tctx, status, NT_STATUS_OK);
594         fnum = io.ntcreatex.out.file.fnum;
595         CHECK_VAL(break_info.count, 0);
596         CHECK_VAL(break_info.failures, 0);
597         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
598         
599         ZERO_STRUCT(sfi);
600         sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
601         sfi.generic.in.file.path = fname;
602         sfi.end_of_file_info.in.size = 100;
603
604         status = smb_raw_setpathinfo(cli2->tree, &sfi);
605
606         CHECK_STATUS(tctx, status, NT_STATUS_OK);
607         CHECK_VAL(break_info.count, 1);
608         CHECK_VAL(break_info.failures, 0);
609         CHECK_VAL(break_info.level, 0);
610
611         smbcli_close(cli1->tree, fnum);
612         smbcli_unlink(cli1->tree, fname);
613
614         /* Test if a set-allocation size on pathname breaks an exclusive oplock. */
615         torture_comment(tctx, "Test if setpathinfo allocation size breaks oplocks.\n");
616
617         ZERO_STRUCT(break_info);
618         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
619
620         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
621                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
622                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
623         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
624         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
625                 NTCREATEX_SHARE_ACCESS_WRITE|
626                 NTCREATEX_SHARE_ACCESS_DELETE;
627         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
628         status = smb_raw_open(cli1->tree, mem_ctx, &io);
629         CHECK_STATUS(tctx, status, NT_STATUS_OK);
630         fnum = io.ntcreatex.out.file.fnum;
631         CHECK_VAL(break_info.count, 0);
632         CHECK_VAL(break_info.failures, 0);
633         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
634         
635         ZERO_STRUCT(sfi);
636         sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
637         sfi.generic.in.file.path = fname;
638         sfi.allocation_info.in.alloc_size = 65536 * 8;
639
640         status = smb_raw_setpathinfo(cli2->tree, &sfi);
641
642         CHECK_STATUS(tctx, status, NT_STATUS_OK);
643         CHECK_VAL(break_info.count, 1);
644         CHECK_VAL(break_info.failures, 0);
645         CHECK_VAL(break_info.level, 0);
646
647         smbcli_close(cli1->tree, fnum);
648         smbcli_close(cli2->tree, fnum2);
649         smbcli_unlink(cli1->tree, fname);
650
651         torture_comment(tctx, "open with batch oplock\n");
652         ZERO_STRUCT(break_info);
653         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
654
655         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
656                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
657                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
658         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
659         status = smb_raw_open(cli1->tree, mem_ctx, &io);
660         CHECK_STATUS(tctx, status, NT_STATUS_OK);
661         fnum = io.ntcreatex.out.file.fnum;
662         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
663
664         ZERO_STRUCT(break_info);
665
666         torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE dispostion causes oplock break\n");
667
668         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
669                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
670                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
671         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
672         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
673         status = smb_raw_open(cli2->tree, mem_ctx, &io);
674         CHECK_STATUS(tctx, status, NT_STATUS_OK);
675         fnum2 = io.ntcreatex.out.file.fnum;
676         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
677         CHECK_VAL(break_info.count, 1);
678         CHECK_VAL(break_info.failures, 0);
679
680         smbcli_close(cli1->tree, fnum);
681         smbcli_close(cli2->tree, fnum2);
682         smbcli_unlink(cli1->tree, fname);
683
684         torture_comment(tctx, "open with batch oplock\n");
685         ZERO_STRUCT(break_info);
686         smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
687
688         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
689                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
690                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
691         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
692         status = smb_raw_open(cli1->tree, mem_ctx, &io);
693         CHECK_STATUS(tctx, status, NT_STATUS_OK);
694         fnum = io.ntcreatex.out.file.fnum;
695         CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
696
697         ZERO_STRUCT(break_info);
698
699         torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_SUPERSEDE dispostion causes oplock break\n");
700
701         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
702                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
703                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
704         io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
705         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
706         status = smb_raw_open(cli2->tree, mem_ctx, &io);
707         CHECK_STATUS(tctx, status, NT_STATUS_OK);
708         fnum2 = io.ntcreatex.out.file.fnum;
709         CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
710         CHECK_VAL(break_info.count, 1);
711         CHECK_VAL(break_info.failures, 0);
712
713         smbcli_close(cli1->tree, fnum);
714         smbcli_close(cli2->tree, fnum2);
715         smbcli_unlink(cli1->tree, fname);
716
717
718 done:
719         smbcli_close(cli1->tree, fnum);
720         smbcli_close(cli2->tree, fnum2);
721         smbcli_unlink(cli1->tree, fname);
722         return ret;
723 }
724
725
726 /* 
727    basic testing of oplocks
728 */
729 BOOL torture_raw_oplock(struct torture_context *torture)
730 {
731         struct smbcli_state *cli1, *cli2;
732         BOOL ret = True;
733         TALLOC_CTX *mem_ctx;
734
735         if (!torture_open_connection(&cli1, 0)) {
736                 return False;
737         }
738
739         if (!torture_open_connection_ev(
740                     &cli2, 1, cli1->transport->socket->event.ctx)) {
741                 return False;
742         }
743
744         if (!torture_setup_dir(cli1, BASEDIR)) {
745                 return False;
746         }
747
748         mem_ctx = talloc_init("torture_raw_oplock");
749
750         if (!test_oplock(torture, cli1, cli2, mem_ctx)) {
751                 ret = False;
752         }
753
754         smb_raw_exit(cli1->session);
755         smbcli_deltree(cli1->tree, BASEDIR);
756         torture_close_connection(cli1);
757         torture_close_connection(cli2);
758         talloc_free(mem_ctx);
759         return ret;
760 }
761
762
763 /* 
764    stress testing of oplocks
765 */
766 BOOL torture_bench_oplock(struct torture_context *torture)
767 {
768         struct smbcli_state **cli;
769         BOOL ret = True;
770         TALLOC_CTX *mem_ctx = talloc_new(torture);
771         int torture_nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
772         int i, count=0;
773         int timelimit = torture_setting_int(torture, "timelimit", 10);
774         union smb_open io;
775         struct timeval tv;
776         struct event_context *ev = event_context_find(mem_ctx);
777
778         cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
779
780         torture_comment(torture, "Opening %d connections\n", torture_nprocs);
781         for (i=0;i<torture_nprocs;i++) {
782                 if (!torture_open_connection_ev(&cli[i], i, ev)) {
783                         return False;
784                 }
785                 talloc_steal(mem_ctx, cli[i]);
786                 smbcli_oplock_handler(cli[i]->transport, oplock_handler_close, 
787                                       cli[i]->tree);
788         }
789
790         if (!torture_setup_dir(cli[0], BASEDIR)) {
791                 ret = False;
792                 goto done;
793         }
794
795         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
796         io.ntcreatex.in.root_fid = 0;
797         io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
798         io.ntcreatex.in.alloc_size = 0;
799         io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
800         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
801         io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
802         io.ntcreatex.in.create_options = 0;
803         io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
804         io.ntcreatex.in.security_flags = 0;
805         io.ntcreatex.in.fname = BASEDIR "\\test.dat";
806         io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | 
807                 NTCREATEX_FLAGS_REQUEST_OPLOCK | 
808                 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
809
810         tv = timeval_current(); 
811
812         /*
813           we open the same file with SHARE_ACCESS_NONE from all the
814           connections in a round robin fashion. Each open causes an
815           oplock break on the previous connection, which is answered
816           by the oplock_handler_close() to close the file.
817
818           This measures how fast we can pass on oplocks, and stresses
819           the oplock handling code
820         */
821         torture_comment(torture, "Running for %d seconds\n", timelimit);
822         while (timeval_elapsed(&tv) < timelimit) {
823                 for (i=0;i<torture_nprocs;i++) {
824                         NTSTATUS status;
825
826                         status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
827                         CHECK_STATUS(torture, status, NT_STATUS_OK);
828                         count++;
829                 }
830                 torture_comment(torture, "%.2f ops/second\r", count/timeval_elapsed(&tv));
831         }
832
833         torture_comment(torture, "%.2f ops/second\n", count/timeval_elapsed(&tv));
834
835         smb_raw_exit(cli[torture_nprocs-1]->session);
836         
837 done:
838         smb_raw_exit(cli[0]->session);
839         smbcli_deltree(cli[0]->tree, BASEDIR);
840         talloc_free(mem_ctx);
841         return ret;
842 }