From: Volker Lendecke Date: Wed, 20 Nov 2019 15:03:37 +0000 (+0100) Subject: torture: Test g_lock deadlock detection X-Git-Tag: ldb-2.1.0~614 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9aa03be946467698ac7509251f366e165672feaa;p=thirdparty%2Fsamba.git torture: Test g_lock deadlock detection Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Sat Nov 23 01:25:12 UTC 2019 on sn-devel-184 --- diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py index 44d14feb5d2..a4851004fa7 100755 --- a/source3/selftest/tests.py +++ b/source3/selftest/tests.py @@ -222,6 +222,7 @@ local_tests = [ "LOCAL-G-LOCK4", "LOCAL-G-LOCK5", "LOCAL-G-LOCK6", + "LOCAL-G-LOCK7", "LOCAL-NAMEMAP-CACHE1", "LOCAL-IDMAP-CACHE1", "LOCAL-hex_encode_buf", diff --git a/source3/torture/proto.h b/source3/torture/proto.h index e163e5c3ebf..48c127c30d5 100644 --- a/source3/torture/proto.h +++ b/source3/torture/proto.h @@ -137,6 +137,7 @@ bool run_g_lock3(int dummy); bool run_g_lock4(int dummy); bool run_g_lock5(int dummy); bool run_g_lock6(int dummy); +bool run_g_lock7(int dummy); bool run_g_lock_ping_pong(int dummy); bool run_local_namemap_cache1(int dummy); bool run_local_idmap_cache1(int dummy); diff --git a/source3/torture/test_g_lock.c b/source3/torture/test_g_lock.c index 91336352fcc..c720e7d6612 100644 --- a/source3/torture/test_g_lock.c +++ b/source3/torture/test_g_lock.c @@ -906,6 +906,171 @@ bool run_g_lock6(int dummy) return true; } +/* + * Test upgrade deadlock + */ + +bool run_g_lock7(int dummy) +{ + struct tevent_context *ev = NULL; + struct messaging_context *msg = NULL; + struct g_lock_ctx *ctx = NULL; + const char *lockname = "lock7"; + TDB_DATA key = string_term_tdb_data(lockname); + pid_t child; + int ready_pipe[2]; + int down_pipe[2]; + ssize_t n; + NTSTATUS status; + bool ret = false; + bool ok = true; + + if ((pipe(ready_pipe) != 0) || (pipe(down_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) { + struct tevent_req *req = NULL; + + close(ready_pipe[0]); + ready_pipe[0] = -1; + close(down_pipe[1]); + down_pipe[1] = -1; + + status = reinit_after_fork(msg, ev, false, ""); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, + "reinit_after_fork failed: %s\n", + nt_errstr(status)); + exit(1); + } + + printf("%d: locking READ\n", (int)getpid()); + + 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(READ) failed: %s\n", + nt_errstr(status)); + exit(1); + } + + ok = true; + + n = sys_write(ready_pipe[1], &ok, sizeof(ok)); + if (n != sizeof(ok)) { + fprintf(stderr, + "sys_write failed: %s\n", + strerror(errno)); + exit(1); + } + + n = sys_read(down_pipe[0], &ok, sizeof(ok)); + if (n != sizeof(ok)) { + fprintf(stderr, + "sys_read failed: %s\n", + strerror(errno)); + exit(1); + } + + printf("%d: starting UPGRADE\n", (int)getpid()); + + req = g_lock_lock_send( + msg, + ev, + ctx, + key, + G_LOCK_UPGRADE); + if (req == NULL) { + fprintf(stderr, "g_lock_lock_send(UPGRADE) failed\n"); + exit(1); + } + + n = sys_write(ready_pipe[1], &ok, sizeof(ok)); + if (n != sizeof(ok)) { + fprintf(stderr, + "sys_write failed: %s\n", + strerror(errno)); + exit(1); + } + + exit(0); + } + + close(ready_pipe[1]); + close(down_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_READ, + (struct timeval) { .tv_usec = 1 }); + if (!NT_STATUS_IS_OK(status)) { + fprintf(stderr, + "g_lock_lock(READ) failed: %s\n", + nt_errstr(status)); + goto fail; + } + + n = sys_write(down_pipe[1], &ok, sizeof(ok)); + if (n != sizeof(ok)) { + fprintf(stderr, + "sys_write failed: %s\n", + strerror(errno)); + goto fail; + } + + if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) { + perror("read failed"); + goto fail; + } + + status = g_lock_lock( + ctx, + key, + G_LOCK_UPGRADE, + (struct timeval) { .tv_sec = 10 }); + if (!NT_STATUS_EQUAL(status, NT_STATUS_POSSIBLE_DEADLOCK)) { + fprintf(stderr, + "g_lock_lock returned %s\n", + nt_errstr(status)); + goto fail; + } + + ret = true; +fail: + TALLOC_FREE(ctx); + TALLOC_FREE(msg); + TALLOC_FREE(ev); + return ret; +} + extern int torture_numops; extern int torture_nprocs; diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 2a66db02c6a..01c6c824342 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -14815,6 +14815,10 @@ static struct { .name = "LOCAL-G-LOCK6", .fn = run_g_lock6, }, + { + .name = "LOCAL-G-LOCK7", + .fn = run_g_lock7, + }, { .name = "LOCAL-G-LOCK-PING-PONG", .fn = run_g_lock_ping_pong,