LATER? s4:torture: Add smb2.replay.replay8 test to examine server behaviour when...
authorAnubhav Rakshit <anubhav.rakshit@gmail.com>
Thu, 7 Aug 2014 07:22:50 +0000 (12:52 +0530)
committerStefan Metzmacher <metze@samba.org>
Mon, 10 Feb 2020 13:37:55 +0000 (14:37 +0100)
Signed-off-by: Anubhav Rakshit <anubhav.rakshit@gmail.com>
LATER? sq replay8 doesn't work (on a single CPU server?)

LATER? bla replay8...

source4/torture/smb2/replay.c

index 387ef544dae0b13905e3053456b85843543775d2..63f126d2650aa901b4f04d6195cb2a98f9eebbbd 100644 (file)
@@ -2389,6 +2389,275 @@ done:
        }
        smb2_deltree(tree, BASEDIR);
        talloc_free(tree);
+
+       talloc_free(mem_ctx);
+
+       return ret;
+}
+
+/**
+ * Test Write Replay Fencing when there's an outstanding Write
+ */
+struct test_replay8_state {
+       struct torture_context *tctx;
+       uint16_t channel_seq;
+       struct smb2_tree *tree;
+       struct test_replay8_request {
+               struct test_replay8_state *state;
+               size_t idx;
+               struct smb2_write wr;
+               struct smb2_session *session;
+               struct smb2_request *req;
+               uint16_t channel_seq;
+               bool replay;
+               NTSTATUS status;
+               bool done;
+       } reqs[65];
+       size_t num_replies;
+};
+
+static void test_replay8_callback(struct smb2_request *req)
+{
+       struct test_replay8_request *r =
+               (struct test_replay8_request *)req->async.private_data;
+
+       r->state->num_replies++;
+       r->done = true;
+       r->status = smb2_write_recv(req, &r->wr);
+       torture_comment(r->state->tctx, "%s: Write %ju returned status %s\n",
+                       __func__, r->idx, nt_errstr(r->status));
+}
+
+static bool test_replay8(struct torture_context *tctx, struct smb2_tree *tree1)
+{
+       const char *host = torture_setting_string(tctx, "host", NULL);
+       const char *share = torture_setting_string(tctx, "share", NULL);
+       struct cli_credentials *credentials = popt_get_cmdline_credentials();
+       NTSTATUS status;
+       TALLOC_CTX *mem_ctx = talloc_new(tctx);
+       struct smb2_handle _h1;
+       struct smb2_handle *h1 = NULL;
+       struct smb2_create io;
+       struct GUID create_guid = GUID_random();
+       const int wr_len = 60*1024;
+       struct smb2_write wr;
+       size_t i;
+       bool ret = true;
+       const char *fname = BASEDIR "\\replay8.dat";
+       struct smb2_tree *tree2 = NULL;
+       struct smb2_transport *transport1 = tree1->session->transport;
+       struct smb2_transport *transport2 = NULL;
+       struct smb2_session *session1_1 = tree1->session;
+       struct smb2_session *session1_2 = NULL;
+       struct test_replay8_state state = {
+               .tctx = tctx,
+               .channel_seq = smb2cli_session_reset_channel_sequence(session1_1->smbXcli, 0),
+               .tree = tree1,
+       };
+
+       if (smbXcli_conn_protocol(transport1->conn) < PROTOCOL_SMB3_00) {
+               torture_skip(tctx, "SMB 3.X Dialect family required for Replay tests\n");
+       }
+
+       ZERO_STRUCT(break_info);
+       transport1->oplock.handler = torture_oplock_ack_handler;
+       transport1->oplock.private_data = tree1;
+
+       smb2cli_conn_set_max_credits(transport1->conn, UINT16_MAX);
+
+       smb2cli_session_reset_channel_sequence(session1_1->smbXcli, state.channel_seq);
+
+       torture_comment(tctx, "Write Replay fencing for Multi Channel\n");
+
+       status = torture_smb2_testdir(tree1, BASEDIR, &_h1);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       smb2_util_close(tree1, _h1);
+       smb2_util_unlink(tree1, fname);
+
+       /*
+        * use the 1st channel, 1st session
+        */
+       smb2_oplock_create_share(&io, fname,
+                       smb2_util_share_access(""),
+                       smb2_util_oplock_level("b"));
+       io.in.durable_open = false;
+       io.in.durable_open_v2 = true;
+       io.in.persistent_open = false;
+       io.in.create_guid = create_guid;
+       io.in.timeout = UINT32_MAX;
+
+       tree1->session = session1_1;
+       status = smb2_create(tree1, mem_ctx, &io);
+       CHECK_STATUS(status, NT_STATUS_OK);
+       _h1 = io.out.file.handle;
+       h1 = &_h1;
+       CHECK_CREATED(&io, CREATED, FILE_ATTRIBUTE_ARCHIVE);
+       CHECK_VAL(io.out.oplock_level, smb2_util_oplock_level("b"));
+       CHECK_VAL(io.out.durable_open, false);
+       CHECK_VAL(io.out.durable_open_v2, true);
+       CHECK_VAL(io.out.timeout, io.in.timeout);
+
+       status = smb2_connect(tctx,
+                       host,
+                       lpcfg_smb_ports(tctx->lp_ctx),
+                       share,
+                       lpcfg_resolve_context(tctx->lp_ctx),
+                       credentials,
+                       &tree2,
+                       tctx->ev,
+                       &transport1->options,
+                       lpcfg_socket_options(tctx->lp_ctx),
+                       lpcfg_gensec_settings(tctx, tctx->lp_ctx)
+                       );
+       torture_assert_ntstatus_ok_goto(tctx, status, ret, done,
+                       "smb2_connect failed");
+       transport2 = tree2->session->transport;
+
+       smb2cli_conn_set_max_credits(transport2->conn, UINT16_MAX);
+
+       /*
+        * Now bind the 1st session to 2nd transport channel
+        */
+       session1_2 = smb2_session_channel(transport2,
+                       lpcfg_gensec_settings(tctx, tctx->lp_ctx),
+                       tree2, session1_1);
+       torture_assert(tctx, session1_2 != NULL, "smb2_session_channel failed");
+
+       status = smb2_session_setup_spnego(session1_2,
+                       popt_get_cmdline_credentials(),
+                       0 /* previous_session_id */);
+       CHECK_STATUS(status, NT_STATUS_OK);
+
+       tree1->session = session1_1;
+       smb2_util_unlink(tree1, "__none__");
+       smb2_util_unlink(tree1, "__none__");
+       smb2_util_unlink(tree1, "__none__");
+       smb2_util_unlink(tree1, "__none__");
+       tree1->session = session1_2;
+       smb2_util_unlink(tree1, "__none__");
+       smb2_util_unlink(tree1, "__none__");
+       smb2_util_unlink(tree1, "__none__");
+       smb2_util_unlink(tree1, "__none__");
+       tree1->session = session1_1;
+
+       wr = (struct smb2_write) {
+               .in.file.handle = *h1,
+               .in.offset = 0,
+               .in.data = data_blob_talloc(mem_ctx, NULL, wr_len)
+       };
+
+       if (wr.in.data.data == NULL) {
+               torture_comment(tctx, "talloc failed\n");
+       }
+
+       torture_comment(tctx, "METZE:%s\n", __location__);
+       for (i=0; i < ARRAY_SIZE(state.reqs)/2; i++) {
+               struct test_replay8_request *r = &state.reqs[i];
+               /*
+                * Queue multiple writes on 1st Channel
+                */
+               r->idx = i;
+               r->state = &state;
+               r->wr = wr;
+               r->session = session1_1;
+               r->channel_seq = r->state->channel_seq;
+               r->replay = false;
+       }
+       for (; i < (ARRAY_SIZE(state.reqs)/2)+1; i++) {
+               struct test_replay8_request *r = &state.reqs[i];
+               /*
+                * Queue one write with channel_seq + 1 on 2nd Channel
+                */
+               r->idx = i;
+               r->state = &state;
+               r->wr = wr;
+               r->session = session1_1;
+               r->channel_seq = r->state->channel_seq + 1;
+               r->replay = false;
+       }
+       for (; i < ARRAY_SIZE(state.reqs); i++) {
+               struct test_replay8_request *r = &state.reqs[i];
+               /*
+                * Queue multiple writes on 1st Channel
+                */
+               r->idx = i;
+               r->state = &state;
+               r->wr = wr;
+               r->session = session1_1;
+               r->channel_seq = r->state->channel_seq;
+               r->replay = false;
+       }
+
+       for (i=0; i < ARRAY_SIZE(state.reqs); i++) {
+               struct test_replay8_request *r = &state.reqs[i];
+
+               torture_comment(tctx, "Start %ju chseq[%u/%p] replay[%u]\n",
+                               i, r->channel_seq, r->session, r->replay);
+
+               r->state->tree->session = r->session;
+               smb2cli_session_reset_channel_sequence(r->session->smbXcli,
+                                                      r->channel_seq);
+               if (r->replay) {
+                       smb2cli_session_start_replay(r->session->smbXcli);
+               }
+
+               r->req = smb2_write_send(tree1, &r->wr);
+               r->req->async.fn = test_replay8_callback;
+               r->req->async.private_data = r;
+
+               smb2cli_session_reset_channel_sequence(r->session->smbXcli,
+                                                      r->state->channel_seq);
+               smb2cli_session_stop_replay(r->session->smbXcli);
+       }
+
+       tree1->session = session1_1;
+
+       torture_comment(tctx, "METZE:%s\n", __location__);
+       while (state.num_replies < ARRAY_SIZE(state.reqs)) {
+               if (!smbXcli_conn_is_connected(transport1->conn)) {
+                       torture_comment(tctx, "transport1 disconnected\n");
+                       ret = false;
+                       goto done;
+               }
+
+               if (!smbXcli_conn_is_connected(transport2->conn)) {
+                       torture_comment(tctx, "transport2 disconnected\n");
+                       ret = false;
+                       goto done;
+               }
+
+               if (tevent_loop_once(tctx->ev) != 0) {
+                       torture_comment(tctx, "tevent_loop_once failed\n");
+                       ret = false;
+                       goto done;
+               }
+       }
+
+       torture_comment(tctx, "METZE:%s\n", __location__);
+
+       for (i=0; i < ARRAY_SIZE(state.reqs); i++) {
+               struct test_replay8_request *r = &state.reqs[i];
+
+               torture_comment(tctx, "Write %ju returned done[%d] status %s\n",
+                               i, r->done, nt_errstr(r->status));
+       }
+
+       tree1->session = session1_1;
+       smb2_util_close(tree1, *h1);
+       h1 = NULL;
+
+done:
+       talloc_free(tree2);
+       tree1->session = session1_1;
+
+       if (h1 != NULL) {
+               smb2_util_close(tree1, *h1);
+       }
+
+       smb2_util_unlink(tree1, fname);
+       smb2_deltree(tree1, BASEDIR);
+
+       talloc_free(tree1);
        talloc_free(mem_ctx);
 
        return ret;
@@ -2415,6 +2684,7 @@ struct torture_suite *torture_smb2_replay_init(TALLOC_CTX *ctx)
        torture_suite_add_1smb2_test(suite, "replay5", test_replay5);
        torture_suite_add_1smb2_test(suite, "replay6", test_replay6);
        torture_suite_add_1smb2_test(suite, "replay7", test_replay7);
+       torture_suite_add_1smb2_test(suite, "replay8", test_replay8);
 
        suite->description = talloc_strdup(suite, "SMB2 REPLAY tests");