From b20231a1abb6d790dcb667f7010ec3b0b1ecb00b Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Fri, 14 Jun 2019 21:55:09 -0700 Subject: torture3: Test blocking posix locks Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison --- source3/selftest/tests.py | 4 +- source3/torture/torture.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 284 insertions(+), 1 deletion(-) (limited to 'source3') diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 9dec692cb5a..df30cb49cec 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -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"]) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index a74598f68c2..d5043750be6 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -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, -- cgit v1.2.1