r21707: Finally merge my (long-living) perlselftest branch.
[Samba.git] / source / torture / raw / oplock.c
blob1e677fad453086c202c4f489c95c388e5a87e4c9
1 /*
2 Unix SMB/CIFS implementation.
3 basic raw test suite for oplocks
4 Copyright (C) Andrew Tridgell 2003
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.
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.
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.
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"
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)
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)
45 static struct {
46 int fnum;
47 uint8_t level;
48 int count;
49 int failures;
50 } break_info;
52 #define BASEDIR "\\test_notify"
55 a handler function for oplock break requests. Ack it as a break to level II if possible
57 static BOOL oplock_handler_ack_to_levelII(struct smbcli_transport *transport, uint16_t tid,
58 uint16_t fnum, uint8_t level, void *private)
60 struct smbcli_tree *tree = private;
61 break_info.fnum = fnum;
62 break_info.level = level;
63 break_info.count++;
65 printf("Acking to level II in oplock handler\n");
67 return smbcli_oplock_ack(tree, fnum, level);
71 a handler function for oplock break requests. Ack it as a break to none
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)
77 struct smbcli_tree *tree = private;
78 break_info.fnum = fnum;
79 break_info.level = level;
80 break_info.count++;
82 printf("Acking to none in oplock handler\n");
84 return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
87 static void oplock_handler_close_recv(struct smbcli_request *req)
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++;
98 a handler function for oplock break requests - close the file
100 static BOOL oplock_handler_close(struct smbcli_transport *transport, uint16_t tid,
101 uint16_t fnum, uint8_t level, void *private)
103 union smb_close io;
104 struct smbcli_tree *tree = private;
105 struct smbcli_request *req;
107 break_info.fnum = fnum;
108 break_info.level = level;
109 break_info.count++;
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;
120 req->async.fn = oplock_handler_close_recv;
121 req->async.private = NULL;
123 return True;
127 test oplock ops
129 static BOOL test_oplock(struct torture_context *tctx,
130 struct smbcli_state *cli1, struct smbcli_state *cli2, TALLOC_CTX *mem_ctx)
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;
142 /* cleanup */
143 smbcli_unlink(cli1->tree, fname);
145 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
148 base ntcreatex parms
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;
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;
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);
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);
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);
185 smbcli_close(cli1->tree, fnum);
188 with a batch oplock we get a break
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);
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);
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);
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);
216 CHECK_VAL(break_info.count, 0);
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);
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);
228 smbcli_close(cli1->tree, fnum);
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);
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);
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);
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);
258 CHECK_VAL(break_info.count, 0);
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);
265 CHECK_VAL(break_info.count, 0);
267 smbcli_close(cli1->tree, fnum);
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);
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);
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);
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);
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);
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);
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);
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);
327 ZERO_STRUCT(break_info);
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);
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);
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);
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);
355 ZERO_STRUCT(break_info);
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);
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);
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);
373 CHECK_VAL(break_info.count, 2);
374 CHECK_VAL(break_info.level, 0);
375 CHECK_VAL(break_info.failures, 0);
377 smbcli_close(cli1->tree, fnum);
378 smbcli_close(cli2->tree, fnum2);
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);
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);
394 ZERO_STRUCT(break_info);
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);
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);
409 smbcli_close(cli2->tree, fnum);
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);
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);
423 ZERO_STRUCT(break_info);
424 torture_comment(tctx, "second open with attributes only shouldn't cause oplock break\n");
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);
437 smbcli_close(cli1->tree, fnum);
438 smbcli_close(cli2->tree, fnum2);
439 smbcli_unlink(cli1->tree, fname);
441 torture_comment(tctx, "open with attributes only can create file\n");
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);
453 torture_comment(tctx, "Subsequent normal open should break oplock on attribute only open to level II\n");
455 ZERO_STRUCT(break_info);
456 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
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);
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);
489 ZERO_STRUCT(break_info);
491 torture_comment(tctx, "write should trigger a break to none on both\n");
492 smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
494 /* Now the oplock break request comes in. But right now we can't
495 * answer it. Do another write */
497 msleep(100);
498 smbcli_write(cli2->tree, fnum2, 0, &c, 1, 1);
500 CHECK_VAL(break_info.count, 2);
501 CHECK_VAL(break_info.level, 0);
502 CHECK_VAL(break_info.failures, 0);
504 smbcli_close(cli1->tree, fnum);
505 smbcli_close(cli2->tree, fnum2);
507 ZERO_STRUCT(break_info);
508 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
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);
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);
539 torture_comment(tctx, "write should trigger a break to none\n");
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);
552 /* Now the oplock break request comes in. But right now we can't
553 * answer it. Do another write */
555 msleep(100);
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);
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);
574 smbcli_close(cli1->tree, fnum);
575 smbcli_close(cli2->tree, fnum2);
576 smbcli_unlink(cli1->tree, fname);
578 /* Test if a set-eof on pathname breaks an exclusive oplock. */
579 torture_comment(tctx, "Test if setpathinfo set EOF breaks oplocks.\n");
581 ZERO_STRUCT(break_info);
582 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
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);
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;
604 status = smb_raw_setpathinfo(cli2->tree, &sfi);
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);
611 smbcli_close(cli1->tree, fnum);
612 smbcli_unlink(cli1->tree, fname);
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");
617 ZERO_STRUCT(break_info);
618 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
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);
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;
640 status = smb_raw_setpathinfo(cli2->tree, &sfi);
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);
647 smbcli_close(cli1->tree, fnum);
648 smbcli_close(cli2->tree, fnum2);
649 smbcli_unlink(cli1->tree, fname);
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);
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);
664 ZERO_STRUCT(break_info);
666 torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_OVERWRITE dispostion causes oplock break\n");
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);
680 smbcli_close(cli1->tree, fnum);
681 smbcli_close(cli2->tree, fnum2);
682 smbcli_unlink(cli1->tree, fname);
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);
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);
697 ZERO_STRUCT(break_info);
699 torture_comment(tctx, "second open with attributes only and NTCREATEX_DISP_SUPERSEDE dispostion causes oplock break\n");
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);
713 smbcli_close(cli1->tree, fnum);
714 smbcli_close(cli2->tree, fnum2);
715 smbcli_unlink(cli1->tree, fname);
718 done:
719 smbcli_close(cli1->tree, fnum);
720 smbcli_close(cli2->tree, fnum2);
721 smbcli_unlink(cli1->tree, fname);
722 return ret;
727 basic testing of oplocks
729 BOOL torture_raw_oplock(struct torture_context *torture)
731 struct smbcli_state *cli1, *cli2;
732 BOOL ret = True;
733 TALLOC_CTX *mem_ctx;
735 if (!torture_open_connection(&cli1, 0)) {
736 return False;
739 if (!torture_open_connection_ev(
740 &cli2, 1, cli1->transport->socket->event.ctx)) {
741 return False;
744 if (!torture_setup_dir(cli1, BASEDIR)) {
745 return False;
748 mem_ctx = talloc_init("torture_raw_oplock");
750 if (!test_oplock(torture, cli1, cli2, mem_ctx)) {
751 ret = False;
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;
764 stress testing of oplocks
766 BOOL torture_bench_oplock(struct torture_context *torture)
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);
778 cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
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;
785 talloc_steal(mem_ctx, cli[i]);
786 smbcli_oplock_handler(cli[i]->transport, oplock_handler_close,
787 cli[i]->tree);
790 if (!torture_setup_dir(cli[0], BASEDIR)) {
791 ret = False;
792 goto done;
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;
810 tv = timeval_current();
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.
818 This measures how fast we can pass on oplocks, and stresses
819 the oplock handling code
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;
826 status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
827 CHECK_STATUS(torture, status, NT_STATUS_OK);
828 count++;
830 torture_comment(torture, "%.2f ops/second\r", count/timeval_elapsed(&tv));
833 torture_comment(torture, "%.2f ops/second\n", count/timeval_elapsed(&tv));
835 smb_raw_exit(cli[torture_nprocs-1]->session);
837 done:
838 smb_raw_exit(cli[0]->session);
839 smbcli_deltree(cli[0]->tree, BASEDIR);
840 talloc_free(mem_ctx);
841 return ret;