torture3: Add a test that contends with a READ, not a WRITE lock
authorVolker Lendecke <vl@samba.org>
Sun, 22 Dec 2019 13:05:17 +0000 (14:05 +0100)
committerJeremy Allison <jra@samba.org>
Sun, 22 Dec 2019 17:29:28 +0000 (17:29 +0000)
This walks different code paths in the subsequent locker. And the one
that we did not test so far is in fact buggy

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
selftest/knownfail.d/g-lock4a [new file with mode: 0644]
source3/selftest/tests.py
source3/torture/proto.h
source3/torture/test_g_lock.c
source3/torture/torture.c

diff --git a/selftest/knownfail.d/g-lock4a b/selftest/knownfail.d/g-lock4a
new file mode 100644 (file)
index 0000000..fd5537d
--- /dev/null
@@ -0,0 +1 @@
+samba3.smbtorture_s3.LOCAL-G-LOCK4A
\ No newline at end of file
index 25aa08a79f51020b8c018b1b28f2b3814d31e2fc..7f51d344babd4894e4fbaee5c85d42b2ac8b15c5 100755 (executable)
@@ -220,6 +220,7 @@ local_tests = [
     "LOCAL-G-LOCK2",
     "LOCAL-G-LOCK3",
     "LOCAL-G-LOCK4",
+    "LOCAL-G-LOCK4A",
     "LOCAL-G-LOCK5",
     "LOCAL-G-LOCK6",
     "LOCAL-G-LOCK7",
index 48c127c30d5c7a08a59c18a285bcf8811de6d823..73a28991735b2de58e420311d9e7b2376b176697 100644 (file)
@@ -135,6 +135,7 @@ bool run_g_lock1(int dummy);
 bool run_g_lock2(int dummy);
 bool run_g_lock3(int dummy);
 bool run_g_lock4(int dummy);
+bool run_g_lock4a(int dummy);
 bool run_g_lock5(int dummy);
 bool run_g_lock6(int dummy);
 bool run_g_lock7(int dummy);
index 945b32fb8e501418f2df59f2dae7802e9285a75a..05b6cecfc41e5f466a4e749a4ea375f0a852dc4c 100644 (file)
@@ -451,7 +451,7 @@ static void lock4_check(struct server_id exclusive,
 }
 
 /*
- * Test a lock conflict
+ * Test a lock conflict: Contend with a WRITE lock
  */
 
 bool run_g_lock4(int dummy)
@@ -573,6 +573,137 @@ fail:
        return ret;
 }
 
+/*
+ * Test a lock conflict: Contend with a READ lock
+ */
+
+bool run_g_lock4a(int dummy)
+{
+       struct tevent_context *ev = NULL;
+       struct messaging_context *msg = NULL;
+       struct g_lock_ctx *ctx = NULL;
+       const char *lockname = "lock4a";
+       TDB_DATA key = string_term_tdb_data(lockname);
+       pid_t child;
+       int ready_pipe[2];
+       int exit_pipe[2];
+       NTSTATUS status;
+       bool ret = false;
+       struct tevent_req *req;
+       bool ok;
+       int done;
+
+       if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
+               perror("pipe failed");
+               return false;
+       }
+
+       child = fork();
+
+       ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
+       if (!ok) {
+               goto fail;
+       }
+
+       if (child == -1) {
+               perror("fork failed");
+               return false;
+       }
+
+       if (child == 0) {
+               close(ready_pipe[0]);
+               close(exit_pipe[1]);
+               ok = lock4_child(
+                       lockname, G_LOCK_READ, ready_pipe[1], exit_pipe[0]);
+               exit(ok ? 0 : 1);
+       }
+
+       close(ready_pipe[1]);
+       close(exit_pipe[0]);
+
+       if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
+               perror("read failed");
+               return false;
+       }
+
+       if (!ok) {
+               fprintf(stderr, "child returned error\n");
+               return false;
+       }
+
+       status = g_lock_lock(
+               ctx, key, G_LOCK_WRITE, (struct timeval) { .tv_usec = 1 });
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               fprintf(stderr, "g_lock_lock returned %s\n",
+                       nt_errstr(status));
+               goto fail;
+       }
+
+       status = g_lock_lock(
+               ctx, key, G_LOCK_READ, (struct timeval) { .tv_usec = 1 });
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_lock returned %s\n",
+                       nt_errstr(status));
+               goto fail;
+       }
+
+       status = g_lock_unlock(ctx, key);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr,
+                       "g_lock_unlock returned %s\n",
+                       nt_errstr(status));
+               goto fail;
+       }
+
+       req = g_lock_lock_send(ev, ev, ctx, key, G_LOCK_WRITE);
+       if (req == NULL) {
+               fprintf(stderr, "g_lock_lock send failed\n");
+               goto fail;
+       }
+       tevent_req_set_callback(req, lock4_done, &done);
+
+       req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
+       if (req == NULL) {
+               fprintf(stderr, "tevent_wakeup_send failed\n");
+               goto fail;
+       }
+       tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
+
+       done = 0;
+
+       while (done == 0) {
+               int tevent_ret = tevent_loop_once(ev);
+               if (tevent_ret != 0) {
+                       perror("tevent_loop_once failed");
+                       goto fail;
+               }
+       }
+
+       {
+               struct lock4_check_state state = {
+                       .me = messaging_server_id(msg)
+               };
+
+               status = g_lock_dump(ctx, key, lock4_check, &state);
+               if (!NT_STATUS_IS_OK(status)) {
+                       fprintf(stderr, "g_lock_dump failed: %s\n",
+                               nt_errstr(status));
+                       goto fail;
+               }
+               if (!state.ok) {
+                       fprintf(stderr, "lock4_check failed\n");
+                       goto fail;
+               }
+       }
+
+       ret = true;
+fail:
+       TALLOC_FREE(ctx);
+       TALLOC_FREE(msg);
+       TALLOC_FREE(ev);
+       return ret;
+}
+
 struct lock5_parser_state {
        size_t num_locks;
 };
index db5d07bf58479d5520c9a09160740907679ca94d..2ff735b3d22a176bca4089800d52f61aa729a6c1 100644 (file)
@@ -14811,6 +14811,10 @@ static struct {
                .name  = "LOCAL-G-LOCK4",
                .fn    = run_g_lock4,
        },
+       {
+               .name  = "LOCAL-G-LOCK4A",
+               .fn    = run_g_lock4a,
+       },
        {
                .name  = "LOCAL-G-LOCK5",
                .fn    = run_g_lock5,