diff options
author | Günther Deschner <gd@samba.org> | 2016-09-29 08:41:01 +0200 |
---|---|---|
committer | Ralph Boehme <slow@samba.org> | 2017-09-19 09:36:40 +0200 |
commit | 2c745cfac5ccabdceb28fb30eb84346bb2844d1d (patch) | |
tree | a1ed3c37f26df7ce8bca3883182c2c9321ac3dd7 /source4/torture/smb2 | |
parent | 68c3ea773bb22e811139900e425e01a3df8cb375 (diff) | |
download | samba-2c745cfac5ccabdceb28fb30eb84346bb2844d1d.tar.gz |
s4-torture: move lease break handler outside the lease testsuite.
Guenther
Signed-off-by: Guenther Deschner <gd@samba.org>
Pair-Programmed-With: Jose A. Rivera <jarrpa@samba.org>
Reviewed-by: Ralph Boehme <slow@samba.org>
Autobuild-User(master): Ralph Böhme <slow@samba.org>
Autobuild-Date(master): Tue Sep 19 09:36:40 CEST 2017 on sn-devel-144
Diffstat (limited to 'source4/torture/smb2')
-rw-r--r-- | source4/torture/smb2/lease.c | 440 | ||||
-rw-r--r-- | source4/torture/smb2/lease_break_handler.c | 134 | ||||
-rw-r--r-- | source4/torture/smb2/lease_break_handler.h | 120 | ||||
-rw-r--r-- | source4/torture/smb2/wscript_build | 1 |
4 files changed, 382 insertions, 313 deletions
diff --git a/source4/torture/smb2/lease.c b/source4/torture/smb2/lease.c index 6212c08261d..e8f6d3fa15e 100644 --- a/source4/torture/smb2/lease.c +++ b/source4/torture/smb2/lease.c @@ -29,6 +29,7 @@ #include "libcli/smb/smbXcli_base.h" #include "libcli/security/security.h" #include "lib/param/param.h" +#include "lease_break_handler.h" #define CHECK_VAL(v, correct) do { \ if ((v) != (correct)) { \ @@ -384,140 +385,6 @@ static bool test_lease_upgrade2(struct torture_context *tctx, } -#define CHECK_LEASE_BREAK(__lb, __oldstate, __state, __key) \ - do { \ - uint16_t __new = smb2_util_lease_state(__state); \ - uint16_t __old = smb2_util_lease_state(__oldstate); \ - CHECK_VAL((__lb)->new_lease_state, __new); \ - CHECK_VAL((__lb)->current_lease.lease_state, __old); \ - CHECK_VAL((__lb)->current_lease.lease_key.data[0], (__key)); \ - CHECK_VAL((__lb)->current_lease.lease_key.data[1], ~(__key)); \ - if (__old & (SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE)) { \ - CHECK_VAL((__lb)->break_flags, \ - SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED); \ - } else { \ - CHECK_VAL((__lb)->break_flags, 0); \ - } \ - } while(0) - -#define CHECK_LEASE_BREAK_ACK(__lba, __state, __key) \ - do { \ - CHECK_VAL((__lba)->out.reserved, 0); \ - CHECK_VAL((__lba)->out.lease.lease_key.data[0], (__key)); \ - CHECK_VAL((__lba)->out.lease.lease_key.data[1], ~(__key)); \ - CHECK_VAL((__lba)->out.lease.lease_state, smb2_util_lease_state(__state)); \ - CHECK_VAL((__lba)->out.lease.lease_flags, 0); \ - CHECK_VAL((__lba)->out.lease.lease_duration, 0); \ - } while(0) - -static struct torture_lease_break { - struct smb2_lease_break lease_break; - struct smb2_transport *lease_transport; - bool lease_skip_ack; - struct smb2_lease_break_ack lease_break_ack; - int count; - int failures; - - struct smb2_handle oplock_handle; - uint8_t held_oplock_level; - uint8_t oplock_level; - int oplock_count; - int oplock_failures; -} break_info; - -#define CHECK_NO_BREAK(tctx) \ - do { \ - torture_wait_for_lease_break(tctx); \ - CHECK_VAL(break_info.failures, 0); \ - CHECK_VAL(break_info.count, 0); \ - CHECK_VAL(break_info.oplock_failures, 0); \ - CHECK_VAL(break_info.oplock_count, 0); \ - } while(0) - -#define CHECK_OPLOCK_BREAK(__brokento) \ - do { \ - torture_wait_for_lease_break(tctx); \ - CHECK_VAL(break_info.oplock_count, 1); \ - CHECK_VAL(break_info.oplock_failures, 0); \ - CHECK_VAL(break_info.oplock_level, \ - smb2_util_oplock_level(__brokento)); \ - break_info.held_oplock_level = break_info.oplock_level; \ - } while(0) - -#define _CHECK_BREAK_INFO(__oldstate, __state, __key) \ - do { \ - torture_wait_for_lease_break(tctx); \ - CHECK_VAL(break_info.failures, 0); \ - CHECK_VAL(break_info.count, 1); \ - CHECK_LEASE_BREAK(&break_info.lease_break, (__oldstate), \ - (__state), (__key)); \ - if (!break_info.lease_skip_ack && \ - (break_info.lease_break.break_flags & \ - SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)) \ - { \ - torture_wait_for_lease_break(tctx); \ - CHECK_LEASE_BREAK_ACK(&break_info.lease_break_ack, \ - (__state), (__key)); \ - } \ - } while(0) - -#define CHECK_BREAK_INFO(__oldstate, __state, __key) \ - do { \ - _CHECK_BREAK_INFO(__oldstate, __state, __key); \ - CHECK_VAL(break_info.lease_break.new_epoch, 0); \ - } while(0) - -#define CHECK_BREAK_INFO_V2(__transport, __oldstate, __state, __key, __epoch) \ - do { \ - _CHECK_BREAK_INFO(__oldstate, __state, __key); \ - CHECK_VAL(break_info.lease_break.new_epoch, __epoch); \ - if (!TARGET_IS_SAMBA3(tctx)) { \ - CHECK_VAL((uintptr_t)break_info.lease_transport, \ - (uintptr_t)__transport); \ - } \ - } while(0) - -static void torture_lease_break_callback(struct smb2_request *req) -{ - NTSTATUS status; - - status = smb2_lease_break_ack_recv(req, &break_info.lease_break_ack); - if (!NT_STATUS_IS_OK(status)) - break_info.failures++; - - return; -} - -/* a lease break request handler */ -static bool torture_lease_handler(struct smb2_transport *transport, - const struct smb2_lease_break *lb, - void *private_data) -{ - struct smb2_tree *tree = private_data; - struct smb2_lease_break_ack io; - struct smb2_request *req; - - break_info.lease_transport = transport; - break_info.lease_break = *lb; - break_info.count++; - - if (break_info.lease_skip_ack) { - return true; - } - - if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) { - ZERO_STRUCT(io); - io.in.lease.lease_key = lb->current_lease.lease_key; - io.in.lease.lease_state = lb->new_lease_state; - - req = smb2_lease_break_ack_send(tree, &io); - req->async.fn = torture_lease_break_callback; - req->async.private_data = NULL; - } - - return true; -} - /** * upgrade3: * full matrix of lease upgrade combinations @@ -607,7 +474,7 @@ static bool test_lease_upgrade3(struct torture_context *tctx, smb2_util_unlink(tree, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* grab first lease */ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.held1)); @@ -626,8 +493,8 @@ static bool test_lease_upgrade3(struct torture_context *tctx, h2 = io.out.file.handle; /* no break has happened */ - CHECK_VAL(break_info.count, 0); - CHECK_VAL(break_info.failures, 0); + CHECK_VAL(lease_break_info.count, 0); + CHECK_VAL(lease_break_info.failures, 0); /* try to upgrade lease1 */ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(t.upgrade_to)); @@ -638,8 +505,8 @@ static bool test_lease_upgrade3(struct torture_context *tctx, hnew = io.out.file.handle; /* no break has happened */ - CHECK_VAL(break_info.count, 0); - CHECK_VAL(break_info.failures, 0); + CHECK_VAL(lease_break_info.count, 0); + CHECK_VAL(lease_break_info.failures, 0); smb2_util_close(tree, hnew); smb2_util_close(tree, h); @@ -661,59 +528,6 @@ static bool test_lease_upgrade3(struct torture_context *tctx, /* - Timer handler function notifies the registering function that time is up -*/ -static void timeout_cb(struct tevent_context *ev, - struct tevent_timer *te, - struct timeval current_time, - void *private_data) -{ - bool *timesup = (bool *)private_data; - *timesup = true; - return; -} - -/* - Wait a short period of time to receive a single oplock break request -*/ -static void torture_wait_for_lease_break(struct torture_context *tctx) -{ - TALLOC_CTX *tmp_ctx = talloc_new(NULL); - struct tevent_timer *te = NULL; - struct timeval ne; - bool timesup = false; - int old_count = break_info.count; - - /* Wait .1 seconds for an lease break */ - ne = tevent_timeval_current_ofs(0, 100000); - - te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, ×up); - if (te == NULL) { - torture_comment(tctx, "Failed to wait for an oplock break. " - "test results may not be accurate."); - goto done; - } - - while (!timesup && break_info.count < old_count + 1) { - if (tevent_loop_once(tctx->ev) != 0) { - torture_comment(tctx, "Failed to wait for an oplock " - "break. test results may not be " - "accurate."); - goto done; - } - } - -done: - /* We don't know if the timed event fired and was freed, we received - * our oplock break, or some other event triggered the loop. Thus, - * we create a tmp_ctx to be able to safely free/remove the timed - * event in all 3 cases. */ - talloc_free(tmp_ctx); - - return; -} - -/* break_results should be read as "held lease, new lease, hold broken to, new grant", i.e. { "RH", "RW", "RH", "R" } means that if key1 holds RH and key2 tries for RW, key1 will be broken to RH (in this case, not broken at all) @@ -778,7 +592,7 @@ static bool test_lease_break(struct torture_context *tctx, held, smb2_util_lease_state(held), contend, smb2_util_lease_state(contend), brokento, smb2_util_lease_state(brokento), granted, smb2_util_lease_state(granted)); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Grab lease. */ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held)); @@ -802,7 +616,7 @@ static bool test_lease_break(struct torture_context *tctx, CHECK_NO_BREAK(tctx); } - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Now verify that an attempt to upgrade LEASE1 results in no @@ -814,8 +628,8 @@ static bool test_lease_break(struct torture_context *tctx, h3 = io.out.file.handle; CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); CHECK_LEASE(&io, brokento, true, LEASE1, 0); - CHECK_VAL(break_info.count, 0); - CHECK_VAL(break_info.failures, 0); + CHECK_VAL(lease_break_info.count, 0); + CHECK_VAL(lease_break_info.failures, 0); smb2_util_close(tree, h); smb2_util_close(tree, h2); @@ -874,7 +688,7 @@ static bool test_lease_nobreakself(struct torture_context *tctx, h2 = io.out.file.handle; CHECK_LEASE(&io, "R", true, LEASE2, 0); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); tree->session->transport->lease.handler = torture_lease_handler; tree->session->transport->lease.private_data = tree; @@ -896,14 +710,14 @@ static bool test_lease_nobreakself(struct torture_context *tctx, /* Now break LEASE1 via h2 */ - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); status = smb2_util_write(tree, h2, &c, 0, 1); CHECK_STATUS(status, NT_STATUS_OK); CHECK_BREAK_INFO("R", "", LEASE1); /* .. and break LEASE2 via h1 */ - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); status = smb2_util_write(tree, h1, &c, 0, 1); CHECK_STATUS(status, NT_STATUS_OK); CHECK_BREAK_INFO("R", "", LEASE2); @@ -956,7 +770,7 @@ static bool test_lease_statopen(struct torture_context *tctx, h2 = io.out.file.handle; CHECK_LEASE(&io, "RWH", true, LEASE1, 0); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); tree->session->transport->lease.handler = torture_lease_handler; tree->session->transport->lease.private_data = tree; @@ -1014,7 +828,7 @@ static bool test_lease_statopen2(struct torture_context *tctx, } smb2_util_unlink(tree, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); tree->session->transport->lease.handler = torture_lease_handler; tree->session->transport->lease.private_data = tree; @@ -1095,7 +909,7 @@ static bool test_lease_statopen3(struct torture_context *tctx, } smb2_util_unlink(tree, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); tree->session->transport->lease.handler = torture_lease_handler; tree->session->transport->lease.private_data = tree; @@ -1149,7 +963,7 @@ static void torture_oplock_break_callback(struct smb2_request *req) ZERO_STRUCT(br); status = smb2_break_recv(req, &br); if (!NT_STATUS_IS_OK(status)) - break_info.oplock_failures++; + lease_break_info.oplock_failures++; return; } @@ -1163,20 +977,20 @@ static bool torture_oplock_handler(struct smb2_transport *transport, struct smb2_request *req; struct smb2_break br; - break_info.oplock_handle = *handle; - break_info.oplock_level = level; - break_info.oplock_count++; + lease_break_info.oplock_handle = *handle; + lease_break_info.oplock_level = level; + lease_break_info.oplock_count++; ZERO_STRUCT(br); br.in.file.handle = *handle; br.in.oplock_level = level; - if (break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) { + if (lease_break_info.held_oplock_level > SMB2_OPLOCK_LEVEL_II) { req = smb2_break_send(tree, &br); req->async.fn = torture_oplock_break_callback; req->async.private_data = NULL; } - break_info.held_oplock_level = level; + lease_break_info.held_oplock_level = level; return true; } @@ -1252,7 +1066,7 @@ static bool test_lease_oplock(struct torture_context *tctx, held, smb2_util_lease_state(held), contend, smb2_util_oplock_level(contend), brokento, smb2_util_lease_state(brokento), granted, smb2_util_oplock_level(granted)); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Grab lease. */ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(held)); @@ -1269,7 +1083,7 @@ static bool test_lease_oplock(struct torture_context *tctx, h2 = io.out.file.handle; CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(granted)); - break_info.held_oplock_level = io.out.oplock_level; + lease_break_info.held_oplock_level = io.out.oplock_level; if (smb2_util_lease_state(held) != smb2_util_lease_state(brokento)) { CHECK_BREAK_INFO(held, brokento, LEASE1); @@ -1294,7 +1108,7 @@ static bool test_lease_oplock(struct torture_context *tctx, held, smb2_util_oplock_level(held), contend, smb2_util_lease_state(contend), brokento, smb2_util_oplock_level(brokento), granted, smb2_util_lease_state(granted)); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Grab an oplock. */ smb2_oplock_create(&io, fname, smb2_util_oplock_level(held)); @@ -1303,7 +1117,7 @@ static bool test_lease_oplock(struct torture_context *tctx, h = io.out.file.handle; CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level(held)); - break_info.held_oplock_level = io.out.oplock_level; + lease_break_info.held_oplock_level = io.out.oplock_level; /* Grab lease. */ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state(contend)); @@ -1364,7 +1178,7 @@ static bool test_lease_multibreak(struct torture_context *tctx, smb2_util_unlink(tree, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Grab lease, upgrade to RHW .. */ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("RH")); @@ -1400,7 +1214,7 @@ static bool test_lease_multibreak(struct torture_context *tctx, status = smb2_util_close(tree, h3); CHECK_STATUS(status, NT_STATUS_OK); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Grab an R lease. */ smb2_lease_create(&io, &ls, false, fname, LEASE1, smb2_util_lease_state("R")); @@ -1417,7 +1231,7 @@ static bool test_lease_multibreak(struct torture_context *tctx, h2 = io.out.file.handle; CHECK_CREATED(&io, EXISTED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("s")); - break_info.held_oplock_level = io.out.oplock_level; + lease_break_info.held_oplock_level = io.out.oplock_level; /* Verify no breaks. */ CHECK_NO_BREAK(tctx); @@ -1430,7 +1244,7 @@ static bool test_lease_multibreak(struct torture_context *tctx, h3 = io.out.file.handle; CHECK_CREATED(&io, TRUNCATED, FILE_ATTRIBUTE_ARCHIVE); CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("")); - break_info.held_oplock_level = io.out.oplock_level; + lease_break_info.held_oplock_level = io.out.oplock_level; /* Sleep, use a write to clear the recv queue. */ smb_msleep(250); @@ -1487,7 +1301,7 @@ static bool test_lease_v2_request_parent(struct torture_context *tctx, smb2_util_unlink(tree, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(io); smb2_lease_v2_create_share(&io, &ls, false, fname, @@ -1540,7 +1354,7 @@ static bool test_lease_break_twice(struct torture_context *tctx, smb2_util_unlink(tree, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(io); smb2_lease_v2_create_share( @@ -1556,7 +1370,7 @@ static bool test_lease_break_twice(struct torture_context *tctx, tree->session->transport->lease.handler = torture_lease_handler; tree->session->transport->lease.private_data = tree; - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); smb2_lease_v2_create_share( &io, &ls2, false, fname, smb2_util_share_access("R"), @@ -1571,7 +1385,7 @@ static bool test_lease_break_twice(struct torture_context *tctx, &io, &ls2, false, fname, smb2_util_share_access("RWD"), LEASE2, NULL, smb2_util_lease_state("RWH"), 0x22); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); status = smb2_create(tree, mem_ctx, &io); CHECK_STATUS(status, NT_STATUS_OK); @@ -1628,7 +1442,7 @@ static bool test_lease_v2_request(struct torture_context *tctx, tree->session->transport->oplock.handler = torture_oplock_handler; tree->session->transport->oplock.private_data = tree; - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(io); smb2_lease_v2_create_share(&io, &ls1, false, fname, @@ -1686,7 +1500,7 @@ static bool test_lease_v2_request(struct torture_context *tctx, CHECK_BREAK_INFO_V2(tree->session->transport, "RH", "", LEASE2, ls2.lease_epoch + 2); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(io); smb2_lease_v2_create_share(&io, &ls2t, true, dname, @@ -1771,7 +1585,7 @@ static bool test_lease_v2_epoch1(struct torture_context *tctx, tree->session->transport->oplock.handler = torture_oplock_handler; tree->session->transport->oplock.private_data = tree; - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(io); smb2_lease_v2_create_share(&io, &ls, false, fname, @@ -1836,7 +1650,7 @@ static bool test_lease_v2_epoch2(struct torture_context *tctx, tree->session->transport->oplock.handler = torture_oplock_handler; tree->session->transport->oplock.private_data = tree; - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(io); smb2_lease_v2_create_share(&io, &ls1v2, false, fname, @@ -1941,7 +1755,7 @@ static bool test_lease_v2_epoch3(struct torture_context *tctx, tree->session->transport->oplock.handler = torture_oplock_handler; tree->session->transport->oplock.private_data = tree; - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(io); smb2_lease_create_share(&io, &ls1v1, false, fname, @@ -2046,8 +1860,8 @@ static bool test_lease_breaking1(struct torture_context *tctx, /* * we defer acking the lease break. */ - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; smb2_lease_create_share(&io1, &ls1, false, fname, smb2_util_share_access("RWD"), @@ -2075,10 +1889,10 @@ static bool test_lease_breaking1(struct torture_context *tctx, torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending"); ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; + lease_break_info.lease_break.current_lease.lease_key; ack.in.lease.lease_state = - break_info.lease_break.new_lease_state; - ZERO_STRUCT(break_info); + lease_break_info.lease_break.new_lease_state; + ZERO_STRUCT(lease_break_info); /* * a open using the same lease key is still works, @@ -2153,8 +1967,8 @@ static bool test_lease_breaking2(struct torture_context *tctx, /* * we defer acking the lease break. */ - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; smb2_lease_create_share(&io1, &ls1, false, fname, smb2_util_share_access("RWD"), @@ -2183,8 +1997,8 @@ static bool test_lease_breaking2(struct torture_context *tctx, torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending"); ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; - ZERO_STRUCT(break_info); + lease_break_info.lease_break.current_lease.lease_key; + ZERO_STRUCT(lease_break_info); /* * a open using the same lease key is still works, @@ -2286,7 +2100,7 @@ static bool test_lease_breaking3(struct torture_context *tctx, struct smb2_handle h3 = {}; struct smb2_request *req2 = NULL; struct smb2_request *req3 = NULL; - struct torture_lease_break break_info_tmp = {}; + struct lease_break_info lease_break_info_tmp = {}; struct smb2_lease_break_ack ack = {}; const char *fname = "lease_breaking3.dat"; bool ret = true; @@ -2308,8 +2122,8 @@ static bool test_lease_breaking3(struct torture_context *tctx, /* * we defer acking the lease break. */ - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; smb2_lease_create_share(&io1, &ls1, false, fname, smb2_util_share_access("RWD"), @@ -2351,22 +2165,22 @@ static bool test_lease_breaking3(struct torture_context *tctx, * a conflicting open with NTCREATEX_DISP_OVERWRITE * doesn't trigger an immediate lease break to none. */ - break_info_tmp = break_info; - ZERO_STRUCT(break_info); + lease_break_info_tmp = lease_break_info; + ZERO_STRUCT(lease_break_info); smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE); io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE; req3 = smb2_create_send(tree, &io3); torture_assert(tctx, req3 != NULL, "smb2_create_send"); CHECK_NO_BREAK(tctx); - break_info = break_info_tmp; + lease_break_info = lease_break_info_tmp; torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending"); ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; + lease_break_info.lease_break.current_lease.lease_key; ack.in.lease.lease_state = - break_info.lease_break.new_lease_state; - ZERO_STRUCT(break_info); + lease_break_info.lease_break.new_lease_state; + ZERO_STRUCT(lease_break_info); /* * a open using the same lease key is still works, @@ -2384,7 +2198,7 @@ static bool test_lease_breaking3(struct torture_context *tctx, /* * We ack the lease break, but defer acking the next break (to "R") */ - break_info.lease_skip_ack = true; + lease_break_info.lease_skip_ack = true; status = smb2_lease_break_ack(tree, &ack); CHECK_STATUS(status, NT_STATUS_OK); CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1); @@ -2396,10 +2210,10 @@ static bool test_lease_breaking3(struct torture_context *tctx, CHECK_BREAK_INFO("RH", "R", LEASE1); ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; + lease_break_info.lease_break.current_lease.lease_key; ack.in.lease.lease_state = - break_info.lease_break.new_lease_state; - ZERO_STRUCT(break_info); + lease_break_info.lease_break.new_lease_state; + ZERO_STRUCT(lease_break_info); /* * a open using the same lease key is still works, @@ -2434,7 +2248,7 @@ static bool test_lease_breaking3(struct torture_context *tctx, torture_assert(tctx, req3->cancel.can_cancel, "req3 can_cancel"); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); status = smb2_create_recv(req2, tctx, &io2); CHECK_STATUS(status, NT_STATUS_OK); @@ -2474,7 +2288,7 @@ static bool test_lease_v2_breaking3(struct torture_context *tctx, struct smb2_handle h3 = {}; struct smb2_request *req2 = NULL; struct smb2_request *req3 = NULL; - struct torture_lease_break break_info_tmp = {}; + struct lease_break_info lease_break_info_tmp = {}; struct smb2_lease_break_ack ack = {}; const char *fname = "v2_lease_breaking3.dat"; bool ret = true; @@ -2502,8 +2316,8 @@ static bool test_lease_v2_breaking3(struct torture_context *tctx, /* * we defer acking the lease break. */ - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; smb2_lease_v2_create_share(&io1, &ls1, false, fname, smb2_util_share_access("RWD"), @@ -2535,7 +2349,7 @@ static bool test_lease_v2_breaking3(struct torture_context *tctx, torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending"); /* On receiving a lease break, we must sync the new epoch. */ - ls1.lease_epoch = break_info.lease_break.new_epoch; + ls1.lease_epoch = lease_break_info.lease_break.new_epoch; /* * a open using the same lease key is still works, @@ -2552,22 +2366,22 @@ static bool test_lease_v2_breaking3(struct torture_context *tctx, * a conflicting open with NTCREATEX_DISP_OVERWRITE * doesn't trigger an immediate lease break to none. */ - break_info_tmp = break_info; - ZERO_STRUCT(break_info); + lease_break_info_tmp = lease_break_info; + ZERO_STRUCT(lease_break_info); smb2_oplock_create(&io3, fname, SMB2_OPLOCK_LEVEL_NONE); io3.in.create_disposition = NTCREATEX_DISP_OVERWRITE; req3 = smb2_create_send(tree, &io3); torture_assert(tctx, req3 != NULL, "smb2_create_send"); CHECK_NO_BREAK(tctx); - break_info = break_info_tmp; + lease_break_info = lease_break_info_tmp; torture_assert(tctx, req3->state == SMB2_REQUEST_RECV, "req3 pending"); ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; + lease_break_info.lease_break.current_lease.lease_key; ack.in.lease.lease_state = - break_info.lease_break.new_lease_state; - ZERO_STRUCT(break_info); + lease_break_info.lease_break.new_lease_state; + ZERO_STRUCT(lease_break_info); /* * a open using the same lease key is still works, @@ -2585,7 +2399,7 @@ static bool test_lease_v2_breaking3(struct torture_context *tctx, /* * We ack the lease break, but defer acking the next break (to "R") */ - break_info.lease_skip_ack = true; + lease_break_info.lease_skip_ack = true; status = smb2_lease_break_ack(tree, &ack); CHECK_STATUS(status, NT_STATUS_OK); CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1); @@ -2597,13 +2411,13 @@ static bool test_lease_v2_breaking3(struct torture_context *tctx, CHECK_BREAK_INFO_V2(tree->session->transport, "RH", "R", LEASE1, ls1.lease_epoch); /* On receiving a lease break, we must sync the new epoch. */ - ls1.lease_epoch = break_info.lease_break.new_epoch; + ls1.lease_epoch = lease_break_info.lease_break.new_epoch; ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; + lease_break_info.lease_break.current_lease.lease_key; ack.in.lease.lease_state = - break_info.lease_break.new_lease_state; - ZERO_STRUCT(break_info); + lease_break_info.lease_break.new_lease_state; + ZERO_STRUCT(lease_break_info); /* * a open using the same lease key is still works, @@ -2639,7 +2453,7 @@ static bool test_lease_v2_breaking3(struct torture_context *tctx, torture_assert(tctx, req3->cancel.can_cancel, "req3 can_cancel"); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); status = smb2_create_recv(req2, tctx, &io2); CHECK_STATUS(status, NT_STATUS_OK); @@ -2679,7 +2493,7 @@ static bool test_lease_breaking4(struct torture_context *tctx, struct smb2_handle h2 = {}; struct smb2_handle h3 = {}; struct smb2_request *req2 = NULL; - struct torture_lease_break break_info_tmp = {}; + struct lease_break_info lease_break_info_tmp = {}; struct smb2_lease_break_ack ack = {}; const char *fname = "lease_breaking4.dat"; bool ret = true; @@ -2701,8 +2515,8 @@ static bool test_lease_breaking4(struct torture_context *tctx, /* * we defer acking the lease break. */ - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; smb2_lease_create_share(&io1, &ls1, false, fname, smb2_util_share_access("RWD"), @@ -2731,8 +2545,8 @@ static bool test_lease_breaking4(struct torture_context *tctx, */ CHECK_BREAK_INFO("RH", "", LEASE1); - break_info_tmp = break_info; - ZERO_STRUCT(break_info); + lease_break_info_tmp = lease_break_info; + ZERO_STRUCT(lease_break_info); CHECK_NO_BREAK(tctx); torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done"); @@ -2787,13 +2601,13 @@ static bool test_lease_breaking4(struct torture_context *tctx, * We finally ack the lease break... */ CHECK_NO_BREAK(tctx); - break_info = break_info_tmp; + lease_break_info = lease_break_info_tmp; ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; + lease_break_info.lease_break.current_lease.lease_key; ack.in.lease.lease_state = - break_info.lease_break.new_lease_state; - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + lease_break_info.lease_break.new_lease_state; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; status = smb2_lease_break_ack(tree, &ack); CHECK_STATUS(status, NT_STATUS_OK); @@ -2824,7 +2638,7 @@ static bool test_lease_breaking5(struct torture_context *tctx, struct smb2_handle h2 = {}; struct smb2_handle h3 = {}; struct smb2_request *req2 = NULL; - struct torture_lease_break break_info_tmp = {}; + struct lease_break_info lease_break_info_tmp = {}; struct smb2_lease_break_ack ack = {}; const char *fname = "lease_breaking5.dat"; bool ret = true; @@ -2846,8 +2660,8 @@ static bool test_lease_breaking5(struct torture_context *tctx, /* * we defer acking the lease break. */ - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; smb2_lease_create_share(&io1, &ls1, false, fname, smb2_util_share_access("RWD"), @@ -2876,8 +2690,8 @@ static bool test_lease_breaking5(struct torture_context *tctx, */ CHECK_BREAK_INFO("R", "", LEASE1); - break_info_tmp = break_info; - ZERO_STRUCT(break_info); + lease_break_info_tmp = lease_break_info; + ZERO_STRUCT(lease_break_info); CHECK_NO_BREAK(tctx); torture_assert(tctx, req2->state == SMB2_REQUEST_DONE, "req2 done"); @@ -2909,12 +2723,12 @@ static bool test_lease_breaking5(struct torture_context *tctx, * We send an ack without without being asked. */ CHECK_NO_BREAK(tctx); - break_info = break_info_tmp; + lease_break_info = lease_break_info_tmp; ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; + lease_break_info.lease_break.current_lease.lease_key; ack.in.lease.lease_state = - break_info.lease_break.new_lease_state; - ZERO_STRUCT(break_info); + lease_break_info.lease_break.new_lease_state; + ZERO_STRUCT(lease_break_info); status = smb2_lease_break_ack(tree, &ack); CHECK_STATUS(status, NT_STATUS_UNSUCCESSFUL); @@ -2962,8 +2776,8 @@ static bool test_lease_breaking6(struct torture_context *tctx, /* * we defer acking the lease break. */ - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; smb2_lease_create_share(&io1, &ls1, false, fname, smb2_util_share_access("RWD"), @@ -2991,8 +2805,8 @@ static bool test_lease_breaking6(struct torture_context *tctx, torture_assert(tctx, req2->state == SMB2_REQUEST_RECV, "req2 pending"); ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; - ZERO_STRUCT(break_info); + lease_break_info.lease_break.current_lease.lease_key; + ZERO_STRUCT(lease_break_info); /* * a open using the same lease key is still works, @@ -3092,7 +2906,7 @@ static bool test_lease_lock1(struct torture_context *tctx, smb2_util_unlink(tree1a, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(lck); /* Open a handle on tree1a. */ @@ -3118,7 +2932,7 @@ static bool test_lease_lock1(struct torture_context *tctx, CHECK_LEASE(&io2, "RH", true, LEASE2, 0); /* And LEASE1 got broken to RH. */ CHECK_BREAK_INFO("RWH", "RH", LEASE1); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Now open a lease on a different client guid. */ smb2_lease_create_share(&io3, &ls3, false, fname, @@ -3155,8 +2969,8 @@ static bool test_lease_lock1(struct torture_context *tctx, torture_wait_for_lease_break(tctx); torture_wait_for_lease_break(tctx); - CHECK_VAL(break_info.failures, 0); \ - CHECK_VAL(break_info.count, 2); \ + CHECK_VAL(lease_break_info.failures, 0); \ + CHECK_VAL(lease_break_info.count, 2); \ /* Get state of the H1 (LEASE1) */ smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("")); @@ -3180,7 +2994,7 @@ static bool test_lease_lock1(struct torture_context *tctx, CHECK_LEASE(&io3, "", true, LEASE3, 0); smb2_util_close(tree2, io3.out.file.handle); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* * Try and get get an exclusive byte @@ -3197,7 +3011,7 @@ static bool test_lease_lock1(struct torture_context *tctx, CHECK_STATUS(status, NT_STATUS_OK); /* LEASE1 got broken to NONE. */ CHECK_BREAK_INFO("RH", "", LEASE1); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); done: smb2_util_close(tree1a, h1); @@ -3254,7 +3068,7 @@ static bool test_lease_complex1(struct torture_context *tctx, smb2_util_unlink(tree1a, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Grab R lease over connection 1a */ smb2_lease_create(&io1, &ls1, false, fname, LEASE1, smb2_util_lease_state("R")); @@ -3299,7 +3113,7 @@ static bool test_lease_complex1(struct torture_context *tctx, status = smb2_util_close(tree1b, h2); CHECK_STATUS(status, NT_STATUS_OK); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(w); w.in.file.handle = h; @@ -3312,7 +3126,7 @@ static bool test_lease_complex1(struct torture_context *tctx, ls2.lease_epoch += 1; CHECK_BREAK_INFO("R", "", LEASE2); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(w); w.in.file.handle = h3; @@ -3388,7 +3202,7 @@ static bool test_lease_v2_complex1(struct torture_context *tctx, smb2_util_unlink(tree1a, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Grab R lease over connection 1a */ smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL, @@ -3444,7 +3258,7 @@ static bool test_lease_v2_complex1(struct torture_context *tctx, status = smb2_util_close(tree1b, h2); CHECK_STATUS(status, NT_STATUS_OK); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(w); w.in.file.handle = h; @@ -3458,7 +3272,7 @@ static bool test_lease_v2_complex1(struct torture_context *tctx, CHECK_BREAK_INFO_V2(tree1a->session->transport, "R", "", LEASE2, ls2.lease_epoch); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(w); w.in.file.handle = h3; @@ -3535,7 +3349,7 @@ static bool test_lease_v2_complex2(struct torture_context *tctx, smb2_util_unlink(tree1a, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Grab RWH lease over connection 1a */ smb2_lease_v2_create(&io1, &ls1, false, fname, LEASE1, NULL, @@ -3551,8 +3365,8 @@ static bool test_lease_v2_complex2(struct torture_context *tctx, /* * we defer acking the lease break. */ - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; /* Ask for RWH on connection 1b, different lease. */ smb2_lease_v2_create(&io2, &ls2, false, fname, LEASE2, NULL, @@ -3567,14 +3381,14 @@ static bool test_lease_v2_complex2(struct torture_context *tctx, /* Send the break ACK on tree1b. */ ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; + lease_break_info.lease_break.current_lease.lease_key; ack.in.lease.lease_state = SMB2_LEASE_HANDLE|SMB2_LEASE_READ; status = smb2_lease_break_ack(tree1b, &ack); CHECK_STATUS(status, NT_STATUS_OK); CHECK_LEASE_BREAK_ACK(&ack, "RH", LEASE1); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); status = smb2_create_recv(req2, tctx, &io2); CHECK_STATUS(status, NT_STATUS_OK); @@ -3636,8 +3450,8 @@ static bool test_lease_timeout(struct torture_context *tctx, /* * Just don't ack the lease break. */ - ZERO_STRUCT(break_info); - break_info.lease_skip_ack = true; + ZERO_STRUCT(lease_break_info); + lease_break_info.lease_skip_ack = true; /* Break with a RWH request. */ smb2_lease_create(&io, &ls2, false, fname, LEASE2, smb2_util_lease_state("RWH")); @@ -3649,9 +3463,9 @@ static bool test_lease_timeout(struct torture_context *tctx, /* Copy the break request. */ ack.in.lease.lease_key = - break_info.lease_break.current_lease.lease_key; + lease_break_info.lease_break.current_lease.lease_key; ack.in.lease.lease_state = - break_info.lease_break.new_lease_state; + lease_break_info.lease_break.new_lease_state; /* Now wait for the timeout and get the reply. */ status = smb2_create_recv(req2, tctx, &io); @@ -3672,7 +3486,7 @@ static bool test_lease_timeout(struct torture_context *tctx, smb2_util_close(tree, io.out.file.handle); /* Write on the original handle and make sure it's still valid. */ - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(w); w.in.file.handle = h; w.in.offset = 0; @@ -3685,7 +3499,7 @@ static bool test_lease_timeout(struct torture_context *tctx, CHECK_BREAK_INFO("RH", "", LEASE2); /* Write on the new handle. */ - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(w); w.in.file.handle = hnew; w.in.offset = 0; @@ -3761,7 +3575,7 @@ static bool test_lease_v2_rename(struct torture_context *tctx, tree->session->transport->oplock.handler = torture_oplock_handler; tree->session->transport->oplock.private_data = tree; - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); ZERO_STRUCT(io); smb2_lease_v2_create_share(&io, &ls1, false, fname, @@ -3816,7 +3630,7 @@ static bool test_lease_v2_rename(struct torture_context *tctx, CHECK_BREAK_INFO_V2(tree->session->transport, "RWH", "RH", LEASE1, ls1.lease_epoch + 1); ls1.lease_epoch += 1; - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Now rename back. */ ZERO_STRUCT(sinfo); @@ -3942,7 +3756,7 @@ static bool test_lease_dynamic_share(struct torture_context *tctx, smb2_util_unlink(tree_3_0, fname); - ZERO_STRUCT(break_info); + ZERO_STRUCT(lease_break_info); /* Get RWH lease over connection 2_1 */ smb2_lease_create(&io, &ls1, false, fname, LEASE1, smb2_util_lease_state("RWH")); diff --git a/source4/torture/smb2/lease_break_handler.c b/source4/torture/smb2/lease_break_handler.c new file mode 100644 index 00000000000..b70234420bd --- /dev/null +++ b/source4/torture/smb2/lease_break_handler.c @@ -0,0 +1,134 @@ +/* + Unix SMB/CIFS implementation. + + test suite for SMB2 leases + + Copyright (C) Zachary Loafman 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include <tevent.h> +#include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "torture/torture.h" +#include "torture/smb2/proto.h" +#include "torture/util.h" +#include "libcli/smb/smbXcli_base.h" +#include "lease_break_handler.h" + +struct lease_break_info lease_break_info; + +void torture_lease_break_callback(struct smb2_request *req) +{ + NTSTATUS status; + + status = smb2_lease_break_ack_recv(req, &lease_break_info.lease_break_ack); + if (!NT_STATUS_IS_OK(status)) + lease_break_info.failures++; + + return; +} + +/* a lease break request handler */ +bool torture_lease_handler(struct smb2_transport *transport, + const struct smb2_lease_break *lb, + void *private_data) +{ + struct smb2_tree *tree = private_data; + struct smb2_lease_break_ack io; + struct smb2_request *req; + + lease_break_info.lease_transport = transport; + lease_break_info.lease_break = *lb; + lease_break_info.count++; + + if (lease_break_info.lease_skip_ack) { + return true; + } + + if (lb->break_flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED) { + ZERO_STRUCT(io); + io.in.lease.lease_key = lb->current_lease.lease_key; + io.in.lease.lease_state = lb->new_lease_state; + + req = smb2_lease_break_ack_send(tree, &io); + req->async.fn = torture_lease_break_callback; + req->async.private_data = NULL; + } + + return true; +} + +/* + Timer handler function notifies the registering function that time is up +*/ +static void timeout_cb(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval current_time, + void *private_data) +{ + bool *timesup = (bool *)private_data; + *timesup = true; + return; +} + +/* + Wait a short period of time to receive a single oplock break request +*/ +void torture_wait_for_lease_break(struct torture_context *tctx) +{ + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + struct tevent_timer *te = NULL; + struct timeval ne; + bool timesup = false; + int old_count = lease_break_info.count; + + /* Wait .1 seconds for an lease break */ + ne = tevent_timeval_current_ofs(0, 100000); + + te = tevent_add_timer(tctx->ev, tmp_ctx, ne, timeout_cb, ×up); + if (te == NULL) { + torture_comment(tctx, "Failed to wait for an oplock break. " + "test results may not be accurate."); + goto done; + } + + while (!timesup && lease_break_info.count < old_count + 1) { + if (tevent_loop_once(tctx->ev) != 0) { + torture_comment(tctx, "Failed to wait for an oplock " + "break. test results may not be " + "accurate."); + goto done; + } + } + +done: + /* We don't know if the timed event fired and was freed, we received + * our oplock break, or some other event triggered the loop. Thus, + * we create a tmp_ctx to be able to safely free/remove the timed + * event in all 3 cases. */ + talloc_free(tmp_ctx); + + return; +} + + void torture_reset_lease_break_info(struct torture_context *tctx, + struct lease_break_info *r) +{ + ZERO_STRUCTP(r); + r->tctx = tctx; +} + diff --git a/source4/torture/smb2/lease_break_handler.h b/source4/torture/smb2/lease_break_handler.h new file mode 100644 index 00000000000..54e615c3082 --- /dev/null +++ b/source4/torture/smb2/lease_break_handler.h @@ -0,0 +1,120 @@ +/* + Unix SMB/CIFS implementation. + + test suite for SMB2 leases + + Copyright (C) Zachary Loafman 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +struct lease_break_info { + struct torture_context *tctx; + + struct smb2_lease_break lease_break; + struct smb2_transport *lease_transport; + bool lease_skip_ack; + struct smb2_lease_break_ack lease_break_ack; + int count; + int failures; + + struct smb2_handle oplock_handle; + uint8_t held_oplock_level; + uint8_t oplock_level; + int oplock_count; + int oplock_failures; +}; + +#define CHECK_LEASE_BREAK(__lb, __oldstate, __state, __key) \ + do { \ + uint16_t __new = smb2_util_lease_state(__state); \ + uint16_t __old = smb2_util_lease_state(__oldstate); \ + CHECK_VAL((__lb)->new_lease_state, __new); \ + CHECK_VAL((__lb)->current_lease.lease_state, __old); \ + CHECK_VAL((__lb)->current_lease.lease_key.data[0], (__key)); \ + CHECK_VAL((__lb)->current_lease.lease_key.data[1], ~(__key)); \ + if (__old & (SMB2_LEASE_WRITE | SMB2_LEASE_HANDLE)) { \ + CHECK_VAL((__lb)->break_flags, \ + SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED); \ + } else { \ + CHECK_VAL((__lb)->break_flags, 0); \ + } \ + } while(0) + +#define CHECK_LEASE_BREAK_ACK(__lba, __state, __key) \ + do { \ + CHECK_VAL((__lba)->out.reserved, 0); \ + CHECK_VAL((__lba)->out.lease.lease_key.data[0], (__key)); \ + CHECK_VAL((__lba)->out.lease.lease_key.data[1], ~(__key)); \ + CHECK_VAL((__lba)->out.lease.lease_state, smb2_util_lease_state(__state)); \ + CHECK_VAL((__lba)->out.lease.lease_flags, 0); \ + CHECK_VAL((__lba)->out.lease.lease_duration, 0); \ + } while(0) + +#define CHECK_NO_BREAK(tctx) \ + do { \ + torture_wait_for_lease_break(tctx); \ + CHECK_VAL(lease_break_info.failures, 0); \ + CHECK_VAL(lease_break_info.count, 0); \ + CHECK_VAL(lease_break_info.oplock_failures, 0); \ + CHECK_VAL(lease_break_info.oplock_count, 0); \ + } while(0) + +#define CHECK_OPLOCK_BREAK(__brokento) \ + do { \ + torture_wait_for_lease_break(tctx); \ + CHECK_VAL(lease_break_info.oplock_count, 1); \ + CHECK_VAL(lease_break_info.oplock_failures, 0); \ + CHECK_VAL(lease_break_info.oplock_level, \ + smb2_util_oplock_level(__brokento)); \ + lease_break_info.held_oplock_level = lease_break_info.oplock_level; \ + } while(0) + +#define _CHECK_BREAK_INFO(__oldstate, __state, __key) \ + do { \ + torture_wait_for_lease_break(tctx); \ + CHECK_VAL(lease_break_info.failures, 0); \ + CHECK_VAL(lease_break_info.count, 1); \ + CHECK_LEASE_BREAK(&lease_break_info.lease_break, (__oldstate), \ + (__state), (__key)); \ + if (!lease_break_info.lease_skip_ack && \ + (lease_break_info.lease_break.break_flags & \ + SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)) \ + { \ + torture_wait_for_lease_break(tctx); \ + CHECK_LEASE_BREAK_ACK(&lease_break_info.lease_break_ack, \ + (__state), (__key)); \ + } \ + } while(0) + +#define CHECK_BREAK_INFO(__oldstate, __state, __key) \ + do { \ + _CHECK_BREAK_INFO(__oldstate, __state, __key); \ + CHECK_VAL(lease_break_info.lease_break.new_epoch, 0); \ + } while(0) + +#define CHECK_BREAK_INFO_V2(__transport, __oldstate, __state, __key, __epoch) \ + do { \ + _CHECK_BREAK_INFO(__oldstate, __state, __key); \ + CHECK_VAL(lease_break_info.lease_break.new_epoch, __epoch); \ + if (!TARGET_IS_SAMBA3(tctx)) { \ + CHECK_VAL((uintptr_t)lease_break_info.lease_transport, \ + (uintptr_t)__transport); \ + } \ + } while(0) + +extern struct lease_break_info lease_break_info; + +void torture_reset_lease_break_info(struct torture_context *tctx, + struct lease_break_info *r); diff --git a/source4/torture/smb2/wscript_build b/source4/torture/smb2/wscript_build index f5817490d5a..8b0060a2831 100644 --- a/source4/torture/smb2/wscript_build +++ b/source4/torture/smb2/wscript_build @@ -15,6 +15,7 @@ bld.SAMBA_MODULE('TORTURE_SMB2', getinfo.c ioctl.c lease.c + lease_break_handler.c lock.c maxfid.c maxwrite.c |