Clean up tests for lease breaks over multichannel
authorSachin Prabhu <sprabhu@redhat.com>
Fri, 2 Feb 2018 08:39:39 +0000 (14:09 +0530)
committerSachin Prabhu <sprabhu@redhat.com>
Tue, 17 Jul 2018 20:46:27 +0000 (21:46 +0100)
Signed-off-by: Sachin Prabhu <sprabhu@redhat.com>
source4/torture/smb2/multichannel.c

index b4d5929fdffabaee10af389d102b00bcaeb4088f..679716d0b7f5e2013c352f73186ea9a354a43cce 100644 (file)
@@ -815,6 +815,7 @@ done:
 
 static const uint64_t LEASE1F1 = 0xBADC0FFEE0DDF00Dull;
 static const uint64_t LEASE1F2 = 0xBADC0FFEE0DDD00Dull;
+static const uint64_t LEASE1F3 = 0xDADC0FFEE0DDD00Dull;
 static const uint64_t LEASE2F1 = 0xDEADBEEFFEEDBEADull;
 static const uint64_t LEASE2F2 = 0xDAD0FFEDD00DF00Dull;
 static const uint64_t LEASE2F3 = 0xBAD0FFEDD00DF00Dull;
@@ -894,6 +895,9 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
        transport1->lease.private_data = tree1;
        torture_comment(tctx, "transport1  [%p]\n", transport1);
 
+       local_port = torture_get_local_port_from_transport(transport1);
+       torture_comment(tctx, "transport1 uses tcp port: %d\n", local_port);
+
        status = torture_smb2_testdir(tree1, BASEDIR, &_h);
        CHECK_STATUS(status, NT_STATUS_OK);
        smb2_util_close(tree1, _h);
@@ -902,6 +906,18 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
        smb2_util_unlink(tree1, fname3);
        CHECK_VAL(lease_break_info.count, 0);
 
+       /*
+        * Test 1:
+        *      open file1 in session 2A
+        *      open file2 in session 2B
+        *      open file3 in session 2B
+        *      open file1 in session 1
+        *              lease break sent to 2A
+        *      open file2 in session 2
+        *              lease break sent to 2B
+        */
+       torture_comment(tctx, "Test 1 start \n");
+
        smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
                          smb2_util_lease_state("RHW"));
        io1.in.durable_open = false;
@@ -946,12 +962,16 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
        transport2A = tree2A->session->transport;
        session2A = tree2A->session;
 
+
        transport2A->lease.handler = torture_lease_handler;
        transport2A->lease.private_data = tree2A;
        torture_comment(tctx, "transport2A [%p]\n", transport2A);
 
        torture_comment(tctx, "established transport 2A\n");
 
+       local_port = torture_get_local_port_from_transport(transport2A);
+       torture_comment(tctx, "transport2A uses tcp port: %d\n", local_port);
+
        status = smb2_connect(tctx,
                        host,
                        lpcfg_smb_ports(tctx->lp_ctx),
@@ -986,6 +1006,9 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
 
        torture_comment(tctx, "established transport 2B\n");
 
+       local_port = torture_get_local_port_from_transport(transport2B);
+       torture_comment(tctx, "transport2B uses tcp port: %d\n", local_port);
+
        status = smb2_session_setup_spnego(session2B,
                        popt_get_cmdline_credentials(),
                        0 /* previous_session_id */);
@@ -1024,6 +1047,19 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
        CHECK_VAL(io2.out.durable_open, false);
        CHECK_VAL(lease_break_info.count, 0);
 
+       torture_comment(tctx, "client2 opens fname3 via session 2B\n");
+       /* 2b opens file3 */
+       smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
+                         smb2_util_lease_state("RHW"));
+       status = smb2_create(tree2B, mem_ctx, &io3);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client2_file3 = io3.out.file.handle;
+       CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
+       CHECK_VAL(io3.out.durable_open_v2, false);
+       CHECK_VAL(io3.out.timeout, io3.in.timeout);
+       CHECK_VAL(io3.out.durable_open, false);
+       CHECK_VAL(lease_break_info.count, 0);
 
        /*
         * 1 opens file1
@@ -1084,6 +1120,18 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
        smb2_util_unlink(tree1, fname3);
        CHECK_VAL(lease_break_info.count, 0);
 
+       /*
+        * Test 2:
+        *      open file1 in session 2A
+        *      open file2 in session 2B
+        *      open file3 in session 2C
+        *      open file1 in session 1
+        *              lease break sent to 2A
+        *      open file2 in session 2
+        *              lease break sent to 2B
+        */
+       torture_comment(tctx, "Test 2 start \n");
+
        /* now add a third channel and repeat the test */
        status = smb2_connect(tctx,
                        host,
@@ -1136,7 +1184,6 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
        smb2_keepalive(transport2C);
 
        local_port = torture_get_local_port_from_transport(transport2C);
-
        torture_comment(tctx, "transport2C uses tcp port: %d\n", local_port);
 
        torture_comment(tctx, "client2 opens fname1 via session 2A\n");
@@ -1150,7 +1197,7 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
        h_client2_file1 = io1.out.file.handle;
        CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
        CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
-       CHECK_VAL(io1.out.durable_open_v2, false); //true);
+       CHECK_VAL(io1.out.durable_open_v2, false);
        CHECK_VAL(io1.out.timeout, io1.in.timeout);
        CHECK_VAL(io1.out.durable_open, false);
        CHECK_VAL(lease_break_info.count, 0);
@@ -1166,67 +1213,29 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
        h_client2_file2 = io2.out.file.handle;
        CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
        CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
-       CHECK_VAL(io2.out.durable_open_v2, false); //true);
+       CHECK_VAL(io2.out.durable_open_v2, false);
        CHECK_VAL(io2.out.timeout, io2.in.timeout);
        CHECK_VAL(io2.out.durable_open, false);
        CHECK_VAL(lease_break_info.count, 0);
 
+       torture_comment(tctx, "client2 opens fname3 via session 2C\n");
 
-       block_ok = torture_block_tcp_transport(tctx, transport2A);
-       block_ok = torture_block_tcp_transport(tctx, transport2B);
-       block_ok = torture_block_tcp_transport(tctx, transport2C);
-       smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
+       /* 2c opens file3 */
+       smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
                          smb2_util_lease_state("RHW"));
-       {
-               struct smb2_request *req;
-       //      uint32_t pkts2A = 0;
-       //      uint32_t pkts2B = 0;
-       //      uint32_t pkts2C = 0;
-               uint32_t pkts2Ainit = 0;
-               uint32_t pkts2Binit = 0;
-               uint32_t pkts2Cinit = 0;
-               req = smb2_create_send(tree1, &io1);
-
-               while (req->cancel.can_cancel == false) {
-                       tevent_loop_once(tctx->ev);
-               }
-
-               smb_msleep(1000);
-               torture_list_tcp_transport(tctx, transport2A, &pkts2Ainit);
-               torture_list_tcp_transport(tctx, transport2B, &pkts2Binit);
-               torture_list_tcp_transport(tctx, transport2C, &pkts2Cinit);
-#if 0
-               for (int i = 0; i < 10; i++) {
-
-                       smb_msleep(1000);
-                       torture_list_tcp_transport(tctx, transport2A, &pkts2A);
-                       torture_list_tcp_transport(tctx, transport2B, &pkts2B);
-                       torture_list_tcp_transport(tctx, transport2C, &pkts2C);
-               }
-#endif
-               if (pkts2Ainit == 0) {
-                       unblock_ok = torture_unblock_tcp_transport(tctx, transport2A);
-               }
-
-               if (pkts2Binit == 0) {
-                       unblock_ok = torture_unblock_tcp_transport(tctx, transport2B);
-               }
-
-               if (pkts2Cinit == 0) {
-                       unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
-               }
-
-               smb_msleep(40000);
-       }
-       unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
-       unblock_ok = torture_unblock_tcp_transport(tctx, transport2A);
-       unblock_ok = torture_unblock_tcp_transport(tctx, transport2B);
-       torture_unblock_cleanup(tctx);
-       exit(0);
+       status = smb2_create(tree2C, mem_ctx, &io3);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client2_file3 = io3.out.file.handle;
+       CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
+       CHECK_VAL(io3.out.durable_open_v2, false);
+       CHECK_VAL(io3.out.timeout, io2.in.timeout);
+       CHECK_VAL(io3.out.durable_open, false);
+       CHECK_VAL(lease_break_info.count, 0);
 
        /*
         * 1 opens file1
-        * batchoplock break?
+        * lease break?
         */
 
        torture_comment(tctx, "client1 opens fname1 via session 1\n");
@@ -1247,15 +1256,6 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
 
        torture_reset_lease_break_info(tctx, &lease_break_info);
 
-
-       for (int i = 0; i < 25; i++) {
-               torture_list_tcp_transport(tctx, transport2A, NULL);
-               torture_list_tcp_transport(tctx, transport2B, NULL);
-               torture_list_tcp_transport(tctx, transport2C, NULL);
-               smb_msleep(1000);
-       }
-       torture_assert(tctx, block_ok, "we could not block tcp transport");
-
        /*
         * 1 opens file2
         * lease break?
@@ -1269,73 +1269,150 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
        CHECK_STATUS(status, NT_STATUS_OK);
        h_client1_file2 = io2.out.file.handle;
        CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
-       CHECK_LEASE(&io2, "RHW", true, LEASE1F2, 0);
-//     CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
+       CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
+       CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
        CHECK_VAL(io2.out.durable_open_v2, false);
        CHECK_VAL(io2.out.timeout, 0);
        CHECK_VAL(io2.out.durable_open, false);
+       CHECK_VAL(lease_break_info.count, 1);
+       CHECK_PTR(lease_break_info.lease_transport, transport2A);
+
+       /* cleanup everything */
+       torture_reset_lease_break_info(tctx, &lease_break_info);
+
+       smb2_util_close(tree1, h_client1_file1);
+       smb2_util_close(tree1, h_client1_file2);
+       smb2_util_close(tree1, h_client1_file3);
+       smb2_util_close(tree2A, h_client2_file1);
+       smb2_util_close(tree2A, h_client2_file2);
+       smb2_util_close(tree2A, h_client2_file3);
+
+       smb2_util_unlink(tree1, fname1);
+       smb2_util_unlink(tree1, fname2);
+       smb2_util_unlink(tree1, fname3);
+       CHECK_VAL(lease_break_info.count, 0);
 
        /*
-        * FIXME LEASES! Important: when filtered, Windows will really let the open succeed
-        * and *NOT* send a new oplock break over the remaining channels, thus
-        * the break info count stays at one.
+        * Test 3:
+        *      open file1 in session 2A
+        *      open file2 in session 2B
+        *      open file3 in session 2C
+        *      block 2B 2C
+        *      open file2 in session 1
+        *              lease break reaches through session 2A
+        *      server allows session 1 to open file1
+        *      unblock 2B 2C, send keep alive
+        *      open file1 in session 1
+        *              lease break sent to 2A
         */
+       torture_comment(tctx, "Test 3 start \n");
 
-       CHECK_VAL(lease_break_info.count, 1);
+       /* 2a opens file1 */
 
-       torture_reset_lease_break_info(tctx, &lease_break_info);
+       torture_comment(tctx, "client2 opens fname1 via session 2A\n");
 
-       blob = data_blob_string_const("Here I am");
+       smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
+                         smb2_util_lease_state("RHW"));
+       status = smb2_create(tree2A, mem_ctx, &io1);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client2_file1 = io1.out.file.handle;
+       CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
+       CHECK_VAL(io1.out.durable_open_v2, false); //true);
+       CHECK_VAL(io1.out.timeout, io1.in.timeout);
+       CHECK_VAL(io1.out.durable_open, false);
+       CHECK_VAL(lease_break_info.count, 0);
 
-       torture_comment(tctx, "Trying write to file2 on tree2B\n");
 
-       status = smb2_util_write(tree2B,
-                                h_client2_file2,
-                                blob.data,
-                                0,
-                                blob.length);
-       torture_assert_ntstatus_ok(tctx, status,
-               "failed to write file2 via channel 2B");
+       torture_comment(tctx, "client2 opens fname2 via session 2B\n");
 
-       smb2_util_close(tree1, h_client1_file2);
+       /* 2b opens file2 */
+       smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
+                         smb2_util_lease_state("RHW"));
+       status = smb2_create(tree2B, mem_ctx, &io2);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client2_file2 = io2.out.file.handle;
+       CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
+       CHECK_VAL(io2.out.durable_open_v2, false); //true);
+       CHECK_VAL(io2.out.timeout, io2.in.timeout);
+       CHECK_VAL(io2.out.durable_open, false);
+       CHECK_VAL(lease_break_info.count, 0);
+
+
+       torture_comment(tctx, "Blocking 2B and 2C\n");
+       /* Block 2A, 2B and 2C */
+       //block_ok = torture_block_tcp_transport(tctx, transport2A);
+       block_ok = torture_block_tcp_transport(tctx, transport2B);
+       block_ok |= torture_block_tcp_transport(tctx, transport2C);
+       torture_assert(tctx, block_ok, "we could not block tcp transport");
 
+       /*
+        * 1 opens file2
+        * batchoplock break?
+        */
+
+       torture_comment(tctx, "Client opens fname2 with session 1 with 2B and 2C blocked\n");
        smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
                          smb2_util_lease_state("RHW"));
        status = smb2_create(tree1, mem_ctx, &io2);
        CHECK_STATUS(status, NT_STATUS_OK);
        h_client1_file2 = io2.out.file.handle;
-       io2.out.alloc_size = 0;
-       io2.out.size = 0;
        CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
        CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
        CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
        CHECK_VAL(io2.out.durable_open_v2, false);
        CHECK_VAL(io2.out.timeout, 0);
        CHECK_VAL(io2.out.durable_open, false);
+
        CHECK_VAL(lease_break_info.count, 1);
-       CHECK_PTR(lease_break_info.lease_transport, transport1);
+       torture_reset_lease_break_info(tctx, &lease_break_info);
 
-       unblock_ok = torture_unblock_tcp_transport(tctx, transport2C);
-       unblock_ok = torture_unblock_tcp_transport(tctx, transport2A);
+       /* Unblock 2B and 2C */
+       torture_comment(tctx, "Unblocking 2B and 2C\n");
        unblock_ok = torture_unblock_tcp_transport(tctx, transport2B);
+       unblock_ok |= torture_unblock_tcp_transport(tctx, transport2C);
        torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
+       torture_unblock_cleanup(tctx);
 
-       /* next test: disconnect 2C and trigger break */
+       /* Will this trigger pending break? */
+       smb2_keepalive(transport2B);
+       smb2_keepalive(transport2C);
+       CHECK_VAL(lease_break_info.count, 0);
 
-       torture_reset_lease_break_info(tctx, &lease_break_info);
 
        /*
-        * now add a third channel and repeat the test, we need to reestablish
-        * transport2C because the remote end has invalidated our connection
+        * 1 opens file2
+        * lease break?
         */
 
+       torture_comment(tctx, "client opens fname1 via session 1\n");
+
+       smb2_lease_create(&io1, &ls1, false, fname1, LEASE1F1,
+                         smb2_util_lease_state("RHW"));
+       status = smb2_create(tree1, mem_ctx, &io1);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client1_file1 = io1.out.file.handle;
+       CHECK_CREATED(&io1, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_LEASE(&io1, "RH", true, LEASE1F1, 0);
+       CHECK_BREAK_INFO("RHW", "RH", LEASE2F1);
+       CHECK_VAL(io1.out.durable_open_v2, false);
+       CHECK_VAL(io1.out.timeout, 0);
+       CHECK_VAL(io1.out.durable_open, false);
+       CHECK_VAL(lease_break_info.count, 1);
+
+
+       torture_comment(tctx, "Reconnecting session 2B\n");
+       talloc_free(transport2B);
+       talloc_free(session2B);
+       talloc_free(tree2B);
        status = smb2_connect(tctx,
                        host,
                        lpcfg_smb_ports(tctx->lp_ctx),
                        share,
                        lpcfg_resolve_context(tctx->lp_ctx),
                        credentials,
-                       &tree2C,
+                       &tree2B,
                        tctx->ev,
                        &transport2_options,
                        lpcfg_socket_options(tctx->lp_ctx),
@@ -1343,66 +1420,185 @@ static bool test_multichannel_lease_break(struct torture_context *tctx,
                        );
        torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
                        "smb2_connect failed");
-       transport2C = tree2C->session->transport;
+       transport2B = tree2B->session->transport;
 
-       torture_comment(tctx, "transport2C [%p]\n", transport2C);
-       /*
-        * Now bind the session2 to the transport2C
-        */
-       session2C = smb2_session_channel(transport2C,
+       session2B = smb2_session_channel(transport2B,
                        lpcfg_gensec_settings(tctx, tctx->lp_ctx),
                        tree2A, session2A);
 
-       tree2C->smbXcli = tree2A->smbXcli;
-       tree2C->session = session2C;
+       tree2B->smbXcli = tree2A->smbXcli;
+       tree2B->session = session2B;
 
-       torture_assert(tctx, session2C != NULL, "smb2_session_channel failed");
+       torture_assert(tctx, session2B != NULL, "smb2_session_channel failed");
 
-       transport2C->lease.handler = torture_lease_handler;
-       transport2C->lease.private_data = tree2C;
-       torture_comment(tctx, "transport2C [%p]\n", transport2C);
+       transport2B->lease.handler = torture_lease_handler;
+       transport2B->lease.private_data = tree2B;
+       torture_comment(tctx, "transport2B [%p]\n", transport2B);
 
-       torture_comment(tctx, "established transport 2C\n");
+       torture_comment(tctx, "established transport 2B\n");
 
-       status = smb2_session_setup_spnego(session2C,
+       local_port = torture_get_local_port_from_transport(transport2B);
+       torture_comment(tctx, "transport2B uses tcp port: %d\n", local_port);
+
+       status = smb2_session_setup_spnego(session2B,
                        popt_get_cmdline_credentials(),
                        0 /* previous_session_id */);
        CHECK_STATUS(status, NT_STATUS_OK);
 
-       torture_comment(tctx, "bound session2C to session2A\n");
+       torture_comment(tctx, "bound session2B to session2A\n");
 
-       torture_comment(tctx, "client 2 opening fname3 over newly established transport2C\n");
+       torture_comment(tctx, "client closes fname1 via session 2A\n");
+       status = smb2_util_close(tree2A, h_client2_file1);
+       CHECK_STATUS(status, NT_STATUS_OK);
 
+       torture_reset_lease_break_info(tctx, &lease_break_info);
+       smb2_util_close(tree1, h_client1_file1);
+       smb2_util_close(tree1, h_client1_file2);
+       smb2_util_close(tree1, h_client1_file3);
+       smb2_util_close(tree2A, h_client2_file1);
+       smb2_util_close(tree2A, h_client2_file2);
+       smb2_util_close(tree2A, h_client2_file3);
+
+       smb2_util_unlink(tree1, fname1);
+       smb2_util_unlink(tree1, fname2);
+       smb2_util_unlink(tree1, fname3);
+       CHECK_VAL(lease_break_info.count, 0);
+
+       /*
+        * Test 4:
+        *      open file1 in session 2A
+        *      open file2 in session 2B
+        *      open file3 in session 2C
+        *      Disconnect 2C
+        *      open file3 in session 1
+        *              lease break?
+        *      server allows session 1 to open file1
+        *      Block 2B
+        *      open file2 in session 1
+        *              no oplock break because 2B blocked.
+        *      session 1 allowed to open file2
+        *      2A writes "Here I am to file 2"
+        *      Recieve break on 1 drop oplock.
+        */
+       torture_comment(tctx, "Test 4 start \n");
+
+       /* 2a opens file1 */
+       torture_comment(tctx, "client2 opens fname1 via session 2A\n");
+       smb2_lease_create(&io1, &ls1, false, fname1, LEASE2F1,
+                         smb2_util_lease_state("RHW"));
+       status = smb2_create(tree2A, mem_ctx, &io1);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client2_file1 = io1.out.file.handle;
+       CHECK_CREATED(&io1, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_LEASE(&io1, "RHW", true, LEASE2F1, 0);
+       CHECK_VAL(io1.out.durable_open_v2, false); //true);
+       CHECK_VAL(io1.out.timeout, io1.in.timeout);
+       CHECK_VAL(io1.out.durable_open, false);
+       CHECK_VAL(lease_break_info.count, 0);
+
+       /* 2b opens file2 */
+       torture_comment(tctx, "client2 opens fname2 via session 2B\n");
+       smb2_lease_create(&io2, &ls2, false, fname2, LEASE2F2,
+                         smb2_util_lease_state("RHW"));
+       status = smb2_create(tree2B, mem_ctx, &io2);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client2_file2 = io2.out.file.handle;
+       CHECK_CREATED(&io2, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_LEASE(&io2, "RHW", true, LEASE2F2, 0);
+       CHECK_VAL(io2.out.durable_open_v2, false); //true);
+       CHECK_VAL(io2.out.timeout, io2.in.timeout);
+       CHECK_VAL(io2.out.durable_open, false);
+       CHECK_VAL(lease_break_info.count, 0);
+
+       /* 2c opens file3 */
+       torture_comment(tctx, "client2 opens fname3 via session 2C\n");
+       smb2_lease_create(&io3, &ls3, false, fname3, LEASE2F3,
+                         smb2_util_lease_state("RHW"));
        status = smb2_create(tree2C, mem_ctx, &io3);
        CHECK_STATUS(status, NT_STATUS_OK);
        h_client2_file3 = io3.out.file.handle;
        CHECK_CREATED(&io3, CREATED, FILE_ATTRIBUTE_ARCHIVE);
-       CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("b"));
-       CHECK_VAL(io3.out.durable_open_v2, true);
-       CHECK_VAL(io3.out.timeout, io3.in.timeout);
+       CHECK_LEASE(&io3, "RHW", true, LEASE2F3, 0);
+       CHECK_VAL(io3.out.durable_open_v2, false);
+       CHECK_VAL(io3.out.timeout, io2.in.timeout);
        CHECK_VAL(io3.out.durable_open, false);
-       CHECK_VAL(break_info.count, 0);
+       CHECK_VAL(lease_break_info.count, 0);
 
+       /* Disconnect 2C */
+       torture_comment(tctx, "Disconnect 2C\n");
        torture_comment(tctx, "explicit disconnect of transport2C\n");
        smbXcli_conn_disconnect(transport2C->conn, NT_STATUS_FOOBAR);
 
-       torture_comment(tctx, "client1 opens fname3 via session 1\n");
-
+       /*
+        * 1 opens file3
+        * batchoplock break?
+        */
+       torture_comment(tctx, "Client opens fname3 with session 1\n");
+       smb2_lease_create(&io3, &ls3, false, fname3, LEASE1F3,
+                         smb2_util_lease_state("RHW"));
        status = smb2_create(tree1, mem_ctx, &io3);
        CHECK_STATUS(status, NT_STATUS_OK);
        h_client1_file3 = io3.out.file.handle;
        CHECK_CREATED(&io3, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
-       CHECK_VAL(io3.out.oplock_level, smb2_util_oplock_level("s"));
-       CHECK_VAL(io3.out.durable_open_v2, false);
-       CHECK_VAL(io3.out.timeout, 0);
-       CHECK_VAL(io3.out.durable_open, false);
+       CHECK_LEASE(&io3, "RH", true, LEASE1F3, 0);
+       CHECK_BREAK_INFO("RHW", "RH", LEASE2F3);
+       CHECK_VAL(io1.out.durable_open_v2, false);
+       CHECK_VAL(io1.out.timeout, 0);
+       CHECK_VAL(io1.out.durable_open, false);
        CHECK_VAL(lease_break_info.count, 1);
-       CHECK_PTR(lease_break_info.lease_transport, transport2B);
 
-       if (h != NULL) {
-               smb2_util_close(tree1, *h);
-               h = NULL;
-       }
+       torture_reset_lease_break_info(tctx, &lease_break_info);
+
+       /* Block 2B */
+       block_ok = torture_block_tcp_transport(tctx, transport2B);
+       torture_assert(tctx, block_ok, "we could not block tcp transport");
+
+       /*
+        * 1 opens file2
+        * batchoplock break?
+        */
+       torture_comment(tctx, "client opens fname2 via session 1\n");
+       smb2_lease_create(&io2, &ls2, false, fname2, LEASE1F2,
+                         smb2_util_lease_state("RHW"));
+       status = smb2_create(tree1, mem_ctx, &io2);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       h_client1_file2 = io2.out.file.handle;
+       CHECK_CREATED(&io2, EXISTED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_LEASE(&io2, "RH", true, LEASE1F2, 0);
+       CHECK_BREAK_INFO("RHW", "RH", LEASE2F2);
+       CHECK_VAL(io2.out.durable_open_v2, false);
+       CHECK_VAL(io2.out.timeout, 0);
+       CHECK_VAL(io2.out.durable_open, false);
+       CHECK_VAL(lease_break_info.count, 1);
+
+       /* 2A writes "Here I am to file 2" */
+
+       torture_comment(tctx, "Trying write to file2 on tree2A\n");
+       blob = data_blob_string_const("Here I am");
+       status = smb2_util_write(tree2A,
+                                h_client2_file2,
+                                blob.data,
+                                0,
+                                blob.length);
+       torture_assert_ntstatus_ok(tctx, status,
+               "failed to write file2 via channel 2A");
+
+       /* Unblock 2B */
+       unblock_ok = torture_unblock_tcp_transport(tctx, transport2B);
+       torture_assert(tctx, unblock_ok, "we could not unblock tcp transport");
+
+       torture_reset_lease_break_info(tctx, &lease_break_info);
+       smb2_util_close(tree1, h_client1_file1);
+       smb2_util_close(tree1, h_client1_file2);
+       smb2_util_close(tree1, h_client1_file3);
+       smb2_util_close(tree2A, h_client2_file1);
+       smb2_util_close(tree2A, h_client2_file2);
+       smb2_util_close(tree2A, h_client2_file3);
+
+       smb2_util_unlink(tree1, fname1);
+       smb2_util_unlink(tree1, fname2);
+       smb2_util_unlink(tree1, fname3);
+       CHECK_VAL(lease_break_info.count, 0);
 
  done:
        if (block_ok && !unblock_ok) {