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 torture_result(tctx, TORTURE_FAIL, __location__": wrong value for %s got 0x%x - should be 0x%x", \
32 #v, (int)v, (int)correct); \
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)); \
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 torture_context
*tctx
,
130 struct smbcli_state
*cli1
, struct smbcli_state
*cli2
, TALLOC_CTX
*mem_ctx
)
132 const char *fname
= BASEDIR
"\\test_oplock.dat";
136 union smb_unlink unl
;
138 union smb_setfileinfo sfi
;
139 uint16_t fnum
=0, fnum2
=0;
143 smbcli_unlink(cli1
->tree
, fname
);
145 smbcli_oplock_handler(cli1
->transport
, oplock_handler_ack_to_levelII
, cli1
->tree
);
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);
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);
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);
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 */
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");
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 */
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
);
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
);
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
);
719 smbcli_close(cli1
->tree
, fnum
);
720 smbcli_close(cli2
->tree
, fnum2
);
721 smbcli_unlink(cli1
->tree
, fname
);
727 basic testing of oplocks
729 BOOL
torture_raw_oplock(struct torture_context
*torture
)
731 struct smbcli_state
*cli1
, *cli2
;
735 if (!torture_open_connection(&cli1
, 0)) {
739 if (!torture_open_connection_ev(
740 &cli2
, 1, cli1
->transport
->socket
->event
.ctx
)) {
744 if (!torture_setup_dir(cli1
, BASEDIR
)) {
748 mem_ctx
= talloc_init("torture_raw_oplock");
750 if (!test_oplock(torture
, cli1
, cli2
, mem_ctx
)) {
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
);
764 stress testing of oplocks
766 BOOL
torture_bench_oplock(struct torture_context
*torture
)
768 struct smbcli_state
**cli
;
770 TALLOC_CTX
*mem_ctx
= talloc_new(torture
);
771 int torture_nprocs
= lp_parm_int(-1, "torture", "nprocs", 4);
773 int timelimit
= torture_setting_int(torture
, "timelimit", 10);
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
)) {
785 talloc_steal(mem_ctx
, cli
[i
]);
786 smbcli_oplock_handler(cli
[i
]->transport
, oplock_handler_close
,
790 if (!torture_setup_dir(cli
[0], BASEDIR
)) {
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
++) {
826 status
= smb_raw_open(cli
[i
]->tree
, mem_ctx
, &io
);
827 CHECK_STATUS(torture
, status
, NT_STATUS_OK
);
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
);
838 smb_raw_exit(cli
[0]->session
);
839 smbcli_deltree(cli
[0]->tree
, BASEDIR
);
840 talloc_free(mem_ctx
);