From: Volker Lendecke Date: Sun, 22 Dec 2019 13:05:17 +0000 (+0100) Subject: torture3: Add a test that contends with a READ, not a WRITE lock X-Git-Tag: ldb-2.1.0~144 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=12638d48a63e90d7d5568d00e39c7041f96675ae;p=thirdparty%2Fsamba.git torture3: Add a test that contends with a READ, not a WRITE lock 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 Reviewed-by: Jeremy Allison --- diff --git a/selftest/knownfail.d/g-lock4a b/selftest/knownfail.d/g-lock4a new file mode 100644 index 00000000000..fd5537d869d --- /dev/null +++ b/selftest/knownfail.d/g-lock4a @@ -0,0 +1 @@ +samba3.smbtorture_s3.LOCAL-G-LOCK4A \ No newline at end of file diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 25aa08a79f5..7f51d344bab 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -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", diff --git a/source3/torture/proto.h b/source3/torture/proto.h index 48c127c30d5..73a28991735 100644 --- a/source3/torture/proto.h +++ b/source3/torture/proto.h @@ -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); diff --git a/source3/torture/test_g_lock.c b/source3/torture/test_g_lock.c index 945b32fb8e5..05b6cecfc41 100644 --- a/source3/torture/test_g_lock.c +++ b/source3/torture/test_g_lock.c @@ -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; }; diff --git a/source3/torture/torture.c b/source3/torture/torture.c index db5d07bf584..2ff735b3d22 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -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,