torture3: Test blocking posix locks
authorVolker Lendecke <vl@samba.org>
Sat, 15 Jun 2019 04:55:09 +0000 (21:55 -0700)
committerJeremy Allison <jra@samba.org>
Thu, 20 Jun 2019 17:18:18 +0000 (17:18 +0000)
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
selftest/skip
source3/selftest/tests.py
source3/torture/torture.c

index e628d7ccc85a2afb25c9028757b515394ae25faf..bdf3c71893d827f73e4dc77e1e6cf84dc1fca55c 100644 (file)
@@ -49,6 +49,7 @@
 ^samba3.smbtorture_s3.plain.POSIX-OFD-LOCK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain.POSIX-STREAM-DELETE\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain.POSIX-MKDIR\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server
+^samba3.smbtorture_s3.plain.POSIX-BLOCKING-LOCK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain.WINDOWS-BAD-SYMLINK\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain.RENAME-ACCESS\(ad_dc_ntvfs\) # Fails against the s4 ntvfs server
 ^samba3.smbtorture_s3.plain.OWNER-RIGHTS\(ad_dc_ntvfs\) # Don't test against the s4 ntvfs server anymore
index 9dec692cb5a358a7d92190db3c16d1e826d1fbfe..df30cb49cecddddd6da07fafcf26e6731cff2632 100755 (executable)
@@ -156,7 +156,9 @@ for s in shares:
     plansmbtorture4testsuite(t, "simpleserver", "//%s/%s %s" % ('$SERVER_IP', s, ' -U$USERNAME%$PASSWORD'), description=s)
 
 posix_tests = ["POSIX", "POSIX-APPEND", "POSIX-SYMLINK-ACL", "POSIX-SYMLINK-EA", "POSIX-OFD-LOCK",
-               "POSIX-STREAM-DELETE", "WINDOWS-BAD-SYMLINK", "POSIX-MKDIR"]
+               "POSIX-STREAM-DELETE", "WINDOWS-BAD-SYMLINK", "POSIX-MKDIR",
+               "POSIX-BLOCKING-LOCK",
+              ]
 
 for t in posix_tests:
     plantestsuite("samba3.smbtorture_s3.plain.%s" % t, "nt4_dc", [os.path.join(samba3srcdir, "script/tests/test_smbtorture_s3.sh"), t, '//$SERVER_IP/posix_share', '$USERNAME', '$PASSWORD', smbtorture3, "", "-l $LOCAL_PATH"])
index a74598f68c22ca7fcd65dc33b19f7e74bc6adeae..d5043750be66e7ac38707e54bb23a9e15f73427a 100644 (file)
@@ -7479,6 +7479,283 @@ static bool run_posix_ofd_lock_test(int dummy)
        return correct;
 }
 
+struct posix_blocking_state {
+       struct tevent_context *ev;
+       struct cli_state *cli1;
+       uint16_t fnum1;
+       struct cli_state *cli2;
+       uint16_t fnum2;
+       bool gotblocked;
+       bool gotecho;
+};
+
+static void posix_blocking_locked(struct tevent_req *subreq);
+static void posix_blocking_gotblocked(struct tevent_req *subreq);
+static void posix_blocking_gotecho(struct tevent_req *subreq);
+static void posix_blocking_unlocked(struct tevent_req *subreq);
+
+static struct tevent_req *posix_blocking_send(
+       TALLOC_CTX *mem_ctx,
+       struct tevent_context *ev,
+       struct cli_state *cli1,
+       uint16_t fnum1,
+       struct cli_state *cli2,
+       uint16_t fnum2)
+{
+       struct tevent_req *req = NULL, *subreq = NULL;
+       struct posix_blocking_state *state = NULL;
+
+       req = tevent_req_create(mem_ctx, &state, struct posix_blocking_state);
+       if (req == NULL) {
+               return NULL;
+       }
+       state->ev = ev;
+       state->cli1 = cli1;
+       state->fnum1 = fnum1;
+       state->cli2 = cli2;
+       state->fnum2 = fnum2;
+
+       subreq = cli_posix_lock_send(
+               state,
+               state->ev,
+               state->cli1,
+               state->fnum1,
+               0,
+               1,
+               false,
+               WRITE_LOCK);
+       if (tevent_req_nomem(subreq, req)) {
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, posix_blocking_locked, req);
+       return req;
+}
+
+static void posix_blocking_locked(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct posix_blocking_state *state = tevent_req_data(
+               req, struct posix_blocking_state);
+       NTSTATUS status;
+
+       status = cli_posix_lock_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+
+       subreq = cli_posix_lock_send(
+               state,
+               state->ev,
+               state->cli2,
+               state->fnum2,
+               0,
+               1,
+               true,
+               WRITE_LOCK);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, posix_blocking_gotblocked, req);
+
+       /* Make sure the blocking request is delivered */
+       subreq = cli_echo_send(
+               state,
+               state->ev,
+               state->cli2,
+               1,
+               (DATA_BLOB) { .data = (uint8_t *)state, .length = 1 });
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, posix_blocking_gotecho, req);
+}
+
+static void posix_blocking_gotblocked(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct posix_blocking_state *state = tevent_req_data(
+               req, struct posix_blocking_state);
+       NTSTATUS status;
+
+       status = cli_posix_lock_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       if (!state->gotecho) {
+               printf("blocked req got through before echo\n");
+               tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
+               return;
+       }
+       tevent_req_done(req);
+}
+
+static void posix_blocking_gotecho(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       struct posix_blocking_state *state = tevent_req_data(
+               req, struct posix_blocking_state);
+       NTSTATUS status;
+
+       status = cli_echo_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       if (state->gotblocked) {
+               printf("blocked req got through before echo\n");
+               tevent_req_nterror(req, NT_STATUS_INVALID_LOCK_SEQUENCE);
+               return;
+       }
+       state->gotecho = true;
+
+       subreq = cli_posix_lock_send(
+               state,
+               state->ev,
+               state->cli1,
+               state->fnum1,
+               0,
+               1,
+               false,
+               UNLOCK_LOCK);
+       if (tevent_req_nomem(subreq, req)) {
+               return;
+       }
+       tevent_req_set_callback(subreq, posix_blocking_unlocked, req);
+}
+
+static void posix_blocking_unlocked(struct tevent_req *subreq)
+{
+       struct tevent_req *req = tevent_req_callback_data(
+               subreq, struct tevent_req);
+       NTSTATUS status;
+
+       status = cli_posix_lock_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (tevent_req_nterror(req, status)) {
+               return;
+       }
+       /* tevent_req_done in posix_blocking_gotlocked */
+}
+
+static NTSTATUS posix_blocking_recv(struct tevent_req *req)
+{
+       return tevent_req_simple_recv_ntstatus(req);
+}
+
+static bool run_posix_blocking_lock(int dummy)
+{
+       struct tevent_context *ev = NULL;
+       struct cli_state *cli1 = NULL, *cli2 = NULL;
+       const char *fname = "posix_blocking";
+       uint16_t fnum1 = UINT16_MAX, fnum2 = UINT16_MAX;
+       struct tevent_req *req = NULL;
+       NTSTATUS status;
+       bool ret = false;
+       bool ok;
+
+       printf("Starting posix blocking lock test\n");
+
+       ev = samba_tevent_context_init(NULL);
+       if (ev == NULL) {
+               return false;
+       }
+
+       ok = torture_open_connection(&cli1, 0);
+       if (!ok) {
+               goto fail;
+       }
+       ok = torture_open_connection(&cli2, 0);
+       if (!ok) {
+               goto fail;
+       }
+
+       smbXcli_conn_set_sockopt(cli1->conn, sockops);
+
+       status = torture_setup_unix_extensions(cli1);
+       if (!NT_STATUS_IS_OK(status)) {
+               return false;
+       }
+
+       cli_setatr(cli1, fname, 0, 0);
+       cli_posix_unlink(cli1, fname);
+
+       status = cli_posix_open(cli1, fname, O_RDWR|O_CREAT|O_EXCL,
+                               0600, &fnum1);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("First POSIX open of %s failed: %s\n",
+                      fname,
+                      nt_errstr(status));
+               goto fail;
+       }
+
+       status = cli_posix_open(cli2, fname, O_RDWR, 0600, &fnum2);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Second POSIX open of %s failed: %s\n",
+                      fname,
+                      nt_errstr(status));
+               goto fail;
+       }
+
+       req = posix_blocking_send(ev, ev, cli1, fnum1, cli2, fnum2);
+       if (req == NULL) {
+               printf("cli_posix_blocking failed\n");
+               goto fail;
+       }
+
+       ok = tevent_req_poll_ntstatus(req, ev, &status);
+       if (!ok) {
+               printf("tevent_req_poll_ntstatus failed: %s\n",
+                      nt_errstr(status));
+               goto fail;
+       }
+       status = posix_blocking_recv(req);
+       TALLOC_FREE(req);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("posix_blocking_recv returned %s\n",
+                      nt_errstr(status));
+               goto fail;
+       }
+
+       ret = true;
+fail:
+
+       if (fnum1 != UINT16_MAX) {
+               cli_close(cli1, fnum1);
+               fnum1 = UINT16_MAX;
+       }
+       if (fnum2 != UINT16_MAX) {
+               cli_close(cli2, fnum2);
+               fnum2 = UINT16_MAX;
+       }
+
+       if (cli1 != NULL) {
+               cli_setatr(cli1, fname, 0, 0);
+               cli_posix_unlink(cli1, fname);
+       }
+
+       ok = true;
+
+       if (cli1 != NULL) {
+               ok &= torture_close_connection(cli1);
+               cli1 = NULL;
+       }
+       if (cli2 != NULL) {
+               ok &= torture_close_connection(cli2);
+               cli2 = NULL;
+       }
+
+       if (!ok) {
+               ret = false;
+       }
+       TALLOC_FREE(ev);
+       return ret;
+}
+
 /*
   Test POSIX mkdir is case-sensitive.
  */
@@ -12400,6 +12677,10 @@ static struct {
                .name  = "POSIX-OFD-LOCK",
                .fn    = run_posix_ofd_lock_test,
        },
+       {
+               .name  = "POSIX-BLOCKING-LOCK",
+               .fn    = run_posix_blocking_lock,
+       },
        {
                .name  = "POSIX-MKDIR",
                .fn    = run_posix_mkdir_test,