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.
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 printf("(%d) wrong value for %s got 0x%x - should be 0x%x\n", \
32 __LINE__, #v, (int)v, (int)correct); \
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)); \
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;
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,
77 struct smbcli_tree *tree = private;
78 break_info.fnum = fnum;
79 break_info.level = level;
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)
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)
104 struct smbcli_tree *tree = private;
105 struct smbcli_request *req;
107 break_info.fnum = fnum;
108 break_info.level = level;
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);
116 printf("failed to send close in oplock_handler_close\n");
120 req->async.fn = oplock_handler_close_recv;
121 req->async.private = NULL;
129 static BOOL test_oplock(struct smbcli_state *cli1, struct smbcli_state *cli2, TALLOC_CTX *mem_ctx)
131 const char *fname = BASEDIR "\\test_oplock.dat";
135 union smb_unlink unl;
137 union smb_setfileinfo sfi;
138 uint16_t fnum=0, fnum2=0;
142 smbcli_unlink(cli1->tree, fname);
144 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
149 io.generic.level = RAW_OPEN_NTCREATEX;
150 io.ntcreatex.in.root_fid = 0;
151 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
152 io.ntcreatex.in.alloc_size = 0;
153 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
154 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
155 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
156 io.ntcreatex.in.create_options = 0;
157 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
158 io.ntcreatex.in.security_flags = 0;
159 io.ntcreatex.in.fname = fname;
161 printf("open a file with a normal oplock\n");
162 ZERO_STRUCT(break_info);
163 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED | NTCREATEX_FLAGS_REQUEST_OPLOCK;
165 status = smb_raw_open(cli1->tree, mem_ctx, &io);
166 CHECK_STATUS(status, NT_STATUS_OK);
167 fnum = io.ntcreatex.out.file.fnum;
168 CHECK_VAL(io.ntcreatex.out.oplock_level, EXCLUSIVE_OPLOCK_RETURN);
170 printf("a 2nd open should not cause a break\n");
171 status = smb_raw_open(cli2->tree, mem_ctx, &io);
172 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
173 CHECK_VAL(break_info.count, 0);
174 CHECK_VAL(break_info.failures, 0);
176 printf("unlink it - should also be no break\n");
177 unl.unlink.in.pattern = fname;
178 unl.unlink.in.attrib = 0;
179 status = smb_raw_unlink(cli2->tree, &unl);
180 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
181 CHECK_VAL(break_info.count, 0);
182 CHECK_VAL(break_info.failures, 0);
184 smbcli_close(cli1->tree, fnum);
187 with a batch oplock we get a break
189 printf("open with batch oplock\n");
190 ZERO_STRUCT(break_info);
191 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
192 NTCREATEX_FLAGS_REQUEST_OPLOCK |
193 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
194 status = smb_raw_open(cli1->tree, mem_ctx, &io);
195 CHECK_STATUS(status, NT_STATUS_OK);
196 fnum = io.ntcreatex.out.file.fnum;
197 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
199 printf("unlink should generate a break\n");
200 unl.unlink.in.pattern = fname;
201 unl.unlink.in.attrib = 0;
202 status = smb_raw_unlink(cli2->tree, &unl);
203 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
205 CHECK_VAL(break_info.count, 1);
206 CHECK_VAL(break_info.fnum, fnum);
207 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
208 CHECK_VAL(break_info.failures, 0);
210 printf("2nd unlink should not generate a break\n");
211 ZERO_STRUCT(break_info);
212 status = smb_raw_unlink(cli2->tree, &unl);
213 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
215 CHECK_VAL(break_info.count, 0);
217 printf("writing should generate a self break to none\n");
218 smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
220 smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
222 CHECK_VAL(break_info.count, 1);
223 CHECK_VAL(break_info.fnum, fnum);
224 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_NONE);
225 CHECK_VAL(break_info.failures, 0);
227 smbcli_close(cli1->tree, fnum);
230 printf("open with batch oplock\n");
231 ZERO_STRUCT(break_info);
232 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
233 NTCREATEX_FLAGS_REQUEST_OPLOCK |
234 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
235 status = smb_raw_open(cli1->tree, mem_ctx, &io);
236 CHECK_STATUS(status, NT_STATUS_OK);
237 fnum = io.ntcreatex.out.file.fnum;
238 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
240 printf("unlink should generate a break, which we ack as break to none\n");
241 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_none, cli1->tree);
242 unl.unlink.in.pattern = fname;
243 unl.unlink.in.attrib = 0;
244 status = smb_raw_unlink(cli2->tree, &unl);
245 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
247 CHECK_VAL(break_info.count, 1);
248 CHECK_VAL(break_info.fnum, fnum);
249 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
250 CHECK_VAL(break_info.failures, 0);
252 printf("2nd unlink should not generate a break\n");
253 ZERO_STRUCT(break_info);
254 status = smb_raw_unlink(cli2->tree, &unl);
255 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
257 CHECK_VAL(break_info.count, 0);
259 printf("writing should not generate a break\n");
260 smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
262 smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
264 CHECK_VAL(break_info.count, 0);
266 smbcli_close(cli1->tree, fnum);
268 printf("if we close on break then the unlink can succeed\n");
269 ZERO_STRUCT(break_info);
270 smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
271 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
272 NTCREATEX_FLAGS_REQUEST_OPLOCK |
273 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
274 status = smb_raw_open(cli1->tree, mem_ctx, &io);
275 CHECK_STATUS(status, NT_STATUS_OK);
276 fnum = io.ntcreatex.out.file.fnum;
277 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
279 unl.unlink.in.pattern = fname;
280 unl.unlink.in.attrib = 0;
281 ZERO_STRUCT(break_info);
282 status = smb_raw_unlink(cli2->tree, &unl);
283 CHECK_STATUS(status, NT_STATUS_OK);
285 CHECK_VAL(break_info.count, 1);
286 CHECK_VAL(break_info.fnum, fnum);
287 CHECK_VAL(break_info.level, 1);
288 CHECK_VAL(break_info.failures, 0);
290 printf("a self read should not cause a break\n");
291 ZERO_STRUCT(break_info);
292 smbcli_close(cli1->tree, fnum);
293 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
295 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
296 NTCREATEX_FLAGS_REQUEST_OPLOCK |
297 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
298 status = smb_raw_open(cli1->tree, mem_ctx, &io);
299 CHECK_STATUS(status, NT_STATUS_OK);
300 fnum = io.ntcreatex.out.file.fnum;
301 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
303 rd.read.level = RAW_READ_READ;
304 rd.read.in.file.fnum = fnum;
305 rd.read.in.count = 1;
306 rd.read.in.offset = 0;
307 rd.read.in.remaining = 0;
308 status = smb_raw_read(cli1->tree, &rd);
309 CHECK_STATUS(status, NT_STATUS_OK);
310 CHECK_VAL(break_info.count, 0);
311 CHECK_VAL(break_info.failures, 0);
313 printf("a 2nd open should give a break\n");
314 ZERO_STRUCT(break_info);
315 smbcli_close(cli1->tree, fnum);
316 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
318 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
319 NTCREATEX_FLAGS_REQUEST_OPLOCK |
320 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
321 status = smb_raw_open(cli1->tree, mem_ctx, &io);
322 CHECK_STATUS(status, NT_STATUS_OK);
323 fnum = io.ntcreatex.out.file.fnum;
324 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
326 ZERO_STRUCT(break_info);
328 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
329 status = smb_raw_open(cli2->tree, mem_ctx, &io);
330 CHECK_STATUS(status, NT_STATUS_SHARING_VIOLATION);
332 CHECK_VAL(break_info.count, 1);
333 CHECK_VAL(break_info.fnum, fnum);
334 CHECK_VAL(break_info.level, 1);
335 CHECK_VAL(break_info.failures, 0);
338 printf("a 2nd open should give a break to level II if the first open allowed shared read\n");
339 ZERO_STRUCT(break_info);
340 smbcli_close(cli1->tree, fnum);
341 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
342 smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
344 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_READ | SEC_RIGHTS_FILE_WRITE;
345 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE;
346 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
347 NTCREATEX_FLAGS_REQUEST_OPLOCK |
348 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
349 status = smb_raw_open(cli1->tree, mem_ctx, &io);
350 CHECK_STATUS(status, NT_STATUS_OK);
351 fnum = io.ntcreatex.out.file.fnum;
352 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
354 ZERO_STRUCT(break_info);
356 status = smb_raw_open(cli2->tree, mem_ctx, &io);
357 CHECK_STATUS(status, NT_STATUS_OK);
358 fnum2 = io.ntcreatex.out.file.fnum;
359 CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
361 CHECK_VAL(break_info.count, 1);
362 CHECK_VAL(break_info.fnum, fnum);
363 CHECK_VAL(break_info.level, 1);
364 CHECK_VAL(break_info.failures, 0);
365 ZERO_STRUCT(break_info);
367 printf("write should trigger a break to none on both\n");
368 smbcli_write(cli1->tree, fnum, 0, &c, 0, 1);
370 smbcli_write(cli1->tree, fnum, 0, &c, 1, 1);
372 CHECK_VAL(break_info.count, 2);
373 CHECK_VAL(break_info.level, 0);
374 CHECK_VAL(break_info.failures, 0);
376 smbcli_close(cli1->tree, fnum);
377 smbcli_close(cli2->tree, fnum2);
379 printf("a 2nd open should get an oplock when we close instead of ack\n");
380 ZERO_STRUCT(break_info);
381 smbcli_oplock_handler(cli1->transport, oplock_handler_close, cli1->tree);
383 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
384 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
385 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
386 NTCREATEX_FLAGS_REQUEST_OPLOCK |
387 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
388 status = smb_raw_open(cli1->tree, mem_ctx, &io);
389 CHECK_STATUS(status, NT_STATUS_OK);
390 fnum2 = io.ntcreatex.out.file.fnum;
391 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
393 ZERO_STRUCT(break_info);
395 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
396 NTCREATEX_FLAGS_REQUEST_OPLOCK |
397 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
398 status = smb_raw_open(cli2->tree, mem_ctx, &io);
399 CHECK_STATUS(status, NT_STATUS_OK);
400 fnum = io.ntcreatex.out.file.fnum;
401 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
403 CHECK_VAL(break_info.count, 1);
404 CHECK_VAL(break_info.fnum, fnum2);
405 CHECK_VAL(break_info.level, 1);
406 CHECK_VAL(break_info.failures, 0);
408 smbcli_close(cli2->tree, fnum);
410 printf("open with batch oplock\n");
411 ZERO_STRUCT(break_info);
412 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
414 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
415 NTCREATEX_FLAGS_REQUEST_OPLOCK |
416 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
417 status = smb_raw_open(cli1->tree, mem_ctx, &io);
418 CHECK_STATUS(status, NT_STATUS_OK);
419 fnum = io.ntcreatex.out.file.fnum;
420 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
422 ZERO_STRUCT(break_info);
423 printf("second open with attributes only shouldn't cause oplock break\n");
425 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
426 NTCREATEX_FLAGS_REQUEST_OPLOCK |
427 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
428 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
429 status = smb_raw_open(cli2->tree, mem_ctx, &io);
430 CHECK_STATUS(status, NT_STATUS_OK);
431 fnum2 = io.ntcreatex.out.file.fnum;
432 CHECK_VAL(io.ntcreatex.out.oplock_level, NO_OPLOCK_RETURN);
433 CHECK_VAL(break_info.count, 0);
434 CHECK_VAL(break_info.failures, 0);
436 smbcli_close(cli1->tree, fnum);
437 smbcli_close(cli2->tree, fnum2);
438 smbcli_unlink(cli1->tree, fname);
440 printf("open with attributes only can create file\n");
442 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
443 NTCREATEX_FLAGS_REQUEST_OPLOCK |
444 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
445 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
446 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
447 status = smb_raw_open(cli1->tree, mem_ctx, &io);
448 CHECK_STATUS(status, NT_STATUS_OK);
449 fnum = io.ntcreatex.out.file.fnum;
450 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
452 printf("Subsequent normal open should break oplock on attribute only open to level II\n");
454 ZERO_STRUCT(break_info);
455 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
457 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
458 NTCREATEX_FLAGS_REQUEST_OPLOCK |
459 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
460 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
461 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
462 status = smb_raw_open(cli2->tree, mem_ctx, &io);
463 CHECK_STATUS(status, NT_STATUS_OK);
464 fnum2 = io.ntcreatex.out.file.fnum;
465 CHECK_VAL(break_info.count, 1);
466 CHECK_VAL(break_info.fnum, fnum);
467 CHECK_VAL(break_info.failures, 0);
468 CHECK_VAL(break_info.level, OPLOCK_BREAK_TO_LEVEL_II);
469 CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
470 smbcli_close(cli2->tree, fnum2);
472 printf("third oplocked open should grant level2 without break\n");
473 ZERO_STRUCT(break_info);
474 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
475 smbcli_oplock_handler(cli2->transport, oplock_handler_ack_to_levelII, cli2->tree);
476 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
477 NTCREATEX_FLAGS_REQUEST_OPLOCK |
478 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
479 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
480 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
481 status = smb_raw_open(cli2->tree, mem_ctx, &io);
482 CHECK_STATUS(status, NT_STATUS_OK);
483 fnum2 = io.ntcreatex.out.file.fnum;
484 CHECK_VAL(break_info.count, 0);
485 CHECK_VAL(break_info.failures, 0);
486 CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
488 ZERO_STRUCT(break_info);
490 printf("write should trigger a break to none on both\n");
491 smbcli_write(cli2->tree, fnum2, 0, &c, 0, 1);
493 /* Now the oplock break request comes in. But right now we can't
494 * answer it. Do another write */
497 smbcli_write(cli2->tree, fnum2, 0, &c, 1, 1);
499 CHECK_VAL(break_info.count, 2);
500 CHECK_VAL(break_info.level, 0);
501 CHECK_VAL(break_info.failures, 0);
503 smbcli_close(cli1->tree, fnum);
504 smbcli_close(cli2->tree, fnum2);
506 ZERO_STRUCT(break_info);
507 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
509 printf("Open with oplock after a on-oplock open should grant level2\n");
510 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED;
511 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
512 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
513 NTCREATEX_SHARE_ACCESS_WRITE|
514 NTCREATEX_SHARE_ACCESS_DELETE;
515 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
516 status = smb_raw_open(cli1->tree, mem_ctx, &io);
517 CHECK_STATUS(status, NT_STATUS_OK);
518 fnum = io.ntcreatex.out.file.fnum;
519 CHECK_VAL(break_info.count, 0);
520 CHECK_VAL(break_info.failures, 0);
521 CHECK_VAL(io.ntcreatex.out.oplock_level, 0);
523 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
524 NTCREATEX_FLAGS_REQUEST_OPLOCK |
525 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
526 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
527 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
528 NTCREATEX_SHARE_ACCESS_WRITE|
529 NTCREATEX_SHARE_ACCESS_DELETE;
530 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
531 status = smb_raw_open(cli2->tree, mem_ctx, &io);
532 CHECK_STATUS(status, NT_STATUS_OK);
533 fnum2 = io.ntcreatex.out.file.fnum;
534 CHECK_VAL(break_info.count, 0);
535 CHECK_VAL(break_info.failures, 0);
536 CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
538 printf("write should trigger a break to none\n");
541 wr.write.level = RAW_WRITE_WRITE;
542 wr.write.in.file.fnum = fnum;
543 wr.write.in.count = 1;
544 wr.write.in.offset = 0;
545 wr.write.in.remaining = 0;
546 wr.write.in.data = (const uint8_t *)"x";
547 status = smb_raw_write(cli1->tree, &wr);
548 CHECK_STATUS(status, NT_STATUS_OK);
551 /* Now the oplock break request comes in. But right now we can't
552 * answer it. Do another write */
558 wr.write.level = RAW_WRITE_WRITE;
559 wr.write.in.file.fnum = fnum;
560 wr.write.in.count = 1;
561 wr.write.in.offset = 0;
562 wr.write.in.remaining = 0;
563 wr.write.in.data = (const uint8_t *)"x";
564 status = smb_raw_write(cli1->tree, &wr);
565 CHECK_STATUS(status, NT_STATUS_OK);
568 CHECK_VAL(break_info.count, 1);
569 CHECK_VAL(break_info.fnum, fnum2);
570 CHECK_VAL(break_info.level, 0);
571 CHECK_VAL(break_info.failures, 0);
573 smbcli_close(cli1->tree, fnum);
574 smbcli_close(cli2->tree, fnum2);
575 smbcli_unlink(cli1->tree, fname);
577 /* Test if a set-eof on pathname breaks an exclusive oplock. */
578 printf("Test if setpathinfo set EOF breaks oplocks.\n");
580 ZERO_STRUCT(break_info);
581 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
583 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
584 NTCREATEX_FLAGS_REQUEST_OPLOCK |
585 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
586 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
587 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
588 NTCREATEX_SHARE_ACCESS_WRITE|
589 NTCREATEX_SHARE_ACCESS_DELETE;
590 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
591 status = smb_raw_open(cli1->tree, mem_ctx, &io);
592 CHECK_STATUS(status, NT_STATUS_OK);
593 fnum = io.ntcreatex.out.file.fnum;
594 CHECK_VAL(break_info.count, 0);
595 CHECK_VAL(break_info.failures, 0);
596 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
599 sfi.generic.level = RAW_SFILEINFO_END_OF_FILE_INFORMATION;
600 sfi.generic.in.file.path = fname;
601 sfi.end_of_file_info.in.size = 100;
603 status = smb_raw_setpathinfo(cli2->tree, &sfi);
605 CHECK_STATUS(status, NT_STATUS_OK);
606 CHECK_VAL(break_info.count, 1);
607 CHECK_VAL(break_info.failures, 0);
608 CHECK_VAL(break_info.level, 0);
610 smbcli_close(cli1->tree, fnum);
611 smbcli_unlink(cli1->tree, fname);
613 /* Test if a set-allocation size on pathname breaks an exclusive oplock. */
614 printf("Test if setpathinfo allocation size breaks oplocks.\n");
616 ZERO_STRUCT(break_info);
617 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
619 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
620 NTCREATEX_FLAGS_REQUEST_OPLOCK |
621 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
622 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
623 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|
624 NTCREATEX_SHARE_ACCESS_WRITE|
625 NTCREATEX_SHARE_ACCESS_DELETE;
626 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
627 status = smb_raw_open(cli1->tree, mem_ctx, &io);
628 CHECK_STATUS(status, NT_STATUS_OK);
629 fnum = io.ntcreatex.out.file.fnum;
630 CHECK_VAL(break_info.count, 0);
631 CHECK_VAL(break_info.failures, 0);
632 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
635 sfi.generic.level = SMB_SFILEINFO_ALLOCATION_INFORMATION;
636 sfi.generic.in.file.path = fname;
637 sfi.allocation_info.in.alloc_size = 65536 * 8;
639 status = smb_raw_setpathinfo(cli2->tree, &sfi);
641 CHECK_STATUS(status, NT_STATUS_OK);
642 CHECK_VAL(break_info.count, 1);
643 CHECK_VAL(break_info.failures, 0);
644 CHECK_VAL(break_info.level, 0);
646 smbcli_close(cli1->tree, fnum);
647 smbcli_close(cli2->tree, fnum2);
648 smbcli_unlink(cli1->tree, fname);
650 printf("open with batch oplock\n");
651 ZERO_STRUCT(break_info);
652 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
654 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
655 NTCREATEX_FLAGS_REQUEST_OPLOCK |
656 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
657 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
658 status = smb_raw_open(cli1->tree, mem_ctx, &io);
659 CHECK_STATUS(status, NT_STATUS_OK);
660 fnum = io.ntcreatex.out.file.fnum;
661 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
663 ZERO_STRUCT(break_info);
665 printf("second open with attributes only and NTCREATEX_DISP_OVERWRITE dispostion causes oplock break\n");
667 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
668 NTCREATEX_FLAGS_REQUEST_OPLOCK |
669 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
670 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
671 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
672 status = smb_raw_open(cli2->tree, mem_ctx, &io);
673 CHECK_STATUS(status, NT_STATUS_OK);
674 fnum2 = io.ntcreatex.out.file.fnum;
675 CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
676 CHECK_VAL(break_info.count, 1);
677 CHECK_VAL(break_info.failures, 0);
679 smbcli_close(cli1->tree, fnum);
680 smbcli_close(cli2->tree, fnum2);
681 smbcli_unlink(cli1->tree, fname);
683 printf("open with batch oplock\n");
684 ZERO_STRUCT(break_info);
685 smbcli_oplock_handler(cli1->transport, oplock_handler_ack_to_levelII, cli1->tree);
687 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
688 NTCREATEX_FLAGS_REQUEST_OPLOCK |
689 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
690 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_CREATE;
691 status = smb_raw_open(cli1->tree, mem_ctx, &io);
692 CHECK_STATUS(status, NT_STATUS_OK);
693 fnum = io.ntcreatex.out.file.fnum;
694 CHECK_VAL(io.ntcreatex.out.oplock_level, BATCH_OPLOCK_RETURN);
696 ZERO_STRUCT(break_info);
698 printf("second open with attributes only and NTCREATEX_DISP_SUPERSEDE dispostion causes oplock break\n");
700 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
701 NTCREATEX_FLAGS_REQUEST_OPLOCK |
702 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
703 io.ntcreatex.in.access_mask = SEC_FILE_READ_ATTRIBUTE|SEC_FILE_WRITE_ATTRIBUTE|SEC_STD_SYNCHRONIZE;
704 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE;
705 status = smb_raw_open(cli2->tree, mem_ctx, &io);
706 CHECK_STATUS(status, NT_STATUS_OK);
707 fnum2 = io.ntcreatex.out.file.fnum;
708 CHECK_VAL(io.ntcreatex.out.oplock_level, LEVEL_II_OPLOCK_RETURN);
709 CHECK_VAL(break_info.count, 1);
710 CHECK_VAL(break_info.failures, 0);
712 smbcli_close(cli1->tree, fnum);
713 smbcli_close(cli2->tree, fnum2);
714 smbcli_unlink(cli1->tree, fname);
718 smbcli_close(cli1->tree, fnum);
719 smbcli_close(cli2->tree, fnum2);
720 smbcli_unlink(cli1->tree, fname);
726 basic testing of oplocks
728 BOOL torture_raw_oplock(struct torture_context *torture)
730 struct smbcli_state *cli1, *cli2;
734 if (!torture_open_connection(&cli1, 0)) {
738 if (!torture_open_connection_ev(
739 &cli2, 1, cli1->transport->socket->event.ctx)) {
743 if (!torture_setup_dir(cli1, BASEDIR)) {
747 mem_ctx = talloc_init("torture_raw_oplock");
749 if (!test_oplock(cli1, cli2, mem_ctx)) {
753 smb_raw_exit(cli1->session);
754 smbcli_deltree(cli1->tree, BASEDIR);
755 torture_close_connection(cli1);
756 torture_close_connection(cli2);
757 talloc_free(mem_ctx);
763 stress testing of oplocks
765 BOOL torture_bench_oplock(struct torture_context *torture)
767 struct smbcli_state **cli;
769 TALLOC_CTX *mem_ctx = talloc_new(torture);
770 extern int torture_nprocs;
772 int timelimit = torture_setting_int(torture, "timelimit", 10);
775 struct event_context *ev = event_context_find(mem_ctx);
777 cli = talloc_array(mem_ctx, struct smbcli_state *, torture_nprocs);
779 printf("Opening %d connections\n", torture_nprocs);
780 for (i=0;i<torture_nprocs;i++) {
781 if (!torture_open_connection_ev(&cli[i], i, ev)) {
784 talloc_steal(mem_ctx, cli[i]);
785 smbcli_oplock_handler(cli[i]->transport, oplock_handler_close,
789 if (!torture_setup_dir(cli[0], BASEDIR)) {
794 io.ntcreatex.level = RAW_OPEN_NTCREATEX;
795 io.ntcreatex.in.root_fid = 0;
796 io.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
797 io.ntcreatex.in.alloc_size = 0;
798 io.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
799 io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_NONE;
800 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
801 io.ntcreatex.in.create_options = 0;
802 io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS;
803 io.ntcreatex.in.security_flags = 0;
804 io.ntcreatex.in.fname = BASEDIR "\\test.dat";
805 io.ntcreatex.in.flags = NTCREATEX_FLAGS_EXTENDED |
806 NTCREATEX_FLAGS_REQUEST_OPLOCK |
807 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
809 tv = timeval_current();
812 we open the same file with SHARE_ACCESS_NONE from all the
813 connections in a round robin fashion. Each open causes an
814 oplock break on the previous connection, which is answered
815 by the oplock_handler_close() to close the file.
817 This measures how fast we can pass on oplocks, and stresses
818 the oplock handling code
820 printf("Running for %d seconds\n", timelimit);
821 while (timeval_elapsed(&tv) < timelimit) {
822 for (i=0;i<torture_nprocs;i++) {
825 status = smb_raw_open(cli[i]->tree, mem_ctx, &io);
826 CHECK_STATUS(status, NT_STATUS_OK);
829 printf("%.2f ops/second\r", count/timeval_elapsed(&tv));
832 printf("%.2f ops/second\n", count/timeval_elapsed(&tv));
834 smb_raw_exit(cli[torture_nprocs-1]->session);
837 smb_raw_exit(cli[0]->session);
838 smbcli_deltree(cli[0]->tree, BASEDIR);
839 talloc_free(mem_ctx);