torture3: Test lock conflict and cleanup
authorVolker Lendecke <vl@samba.org>
Sun, 21 May 2017 06:56:01 +0000 (08:56 +0200)
committerVolker Lendecke <vl@samba.org>
Thu, 15 Jun 2017 11:19:14 +0000 (13:19 +0200)
Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
source3/selftest/tests.py
source3/torture/proto.h
source3/torture/test_g_lock.c
source3/torture/torture.c

index 07af4951a75b6407558b5676985bf650ef0bf156..8a8a62d1fb60866bd4d990af38021282d6fc8d1d 100755 (executable)
@@ -151,6 +151,7 @@ local_tests = [
     "LOCAL-G-LOCK1",
     "LOCAL-G-LOCK2",
     "LOCAL-G-LOCK3",
+    "LOCAL-G-LOCK4",
     "LOCAL-hex_encode_buf",
     "LOCAL-remove_duplicate_addrs2"]
 
index 046e9f9b4ede0e8bcbf86ee7ba3e42fed3a017f3..c945d92038c9f0298ad71fc72cbe7ab471d92e1a 100644 (file)
@@ -127,5 +127,6 @@ bool run_pthreadpool_tevent(int dummy);
 bool run_g_lock1(int dummy);
 bool run_g_lock2(int dummy);
 bool run_g_lock3(int dummy);
+bool run_g_lock4(int dummy);
 
 #endif /* __TORTURE_H__ */
index 154b1c168c2412c08709462c066f03b3801243e2..98fd01312f87f08f98aff57d0240c8035afae54e 100644 (file)
@@ -23,6 +23,7 @@
 #include "g_lock.h"
 #include "messages.h"
 #include "lib/util/server_id.h"
+#include "lib/util/sys_rw.h"
 
 static bool get_g_lock_ctx(TALLOC_CTX *mem_ctx,
                           struct tevent_context **ev,
@@ -311,6 +312,187 @@ bool run_g_lock3(int dummy)
        }
 
 
+       ret = true;
+fail:
+       TALLOC_FREE(ctx);
+       TALLOC_FREE(msg);
+       TALLOC_FREE(ev);
+       return ret;
+}
+
+static bool lock4_child(const char *lockname,
+                       int ready_pipe, int exit_pipe)
+{
+       struct tevent_context *ev = NULL;
+       struct messaging_context *msg = NULL;
+       struct g_lock_ctx *ctx = NULL;
+       NTSTATUS status;
+       ssize_t n;
+       bool ok;
+
+       ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
+       if (!ok) {
+               return false;
+       }
+
+       status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
+                            (struct timeval) { .tv_sec = 1 });
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "child: g_lock_lock returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+
+       n = sys_write(ready_pipe, &ok, sizeof(ok));
+       if (n != sizeof(ok)) {
+               fprintf(stderr, "child: write failed\n");
+               return false;
+       }
+
+       if (ok) {
+               n = sys_read(exit_pipe, &ok, sizeof(ok));
+               if (n != 0) {
+                       fprintf(stderr, "child: read failed\n");
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+static void lock4_done(struct tevent_req *subreq)
+{
+       int *done = tevent_req_callback_data_void(subreq);
+       NTSTATUS status;
+
+       status = g_lock_lock_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_lock_recv returned %s\n",
+                       nt_errstr(status));
+               *done = -1;
+               return;
+       }
+       *done = 1;
+}
+
+static void lock4_waited(struct tevent_req *subreq)
+{
+        int *exit_pipe = tevent_req_callback_data_void(subreq);
+       pid_t child;
+       int status;
+       bool ok;
+
+       printf("waited\n");
+
+       ok = tevent_wakeup_recv(subreq);
+       TALLOC_FREE(subreq);
+       if (!ok) {
+               fprintf(stderr, "tevent_wakeup_recv failed\n");
+       }
+       close(*exit_pipe);
+
+       child = wait(&status);
+
+       printf("child %d exited with %d\n", (int)child, status);
+}
+
+/*
+ * Test a lock conflict
+ */
+
+bool run_g_lock4(int dummy)
+{
+       struct tevent_context *ev = NULL;
+       struct messaging_context *msg = NULL;
+       struct g_lock_ctx *ctx = NULL;
+       const char *lockname = "lock4";
+       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, 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, lockname, 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, lockname, G_LOCK_READ,
+                            (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;
+       }
+
+       req = g_lock_lock_send(ev, ev, ctx, lockname, 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;
+               }
+       }
+
        ret = true;
 fail:
        TALLOC_FREE(ctx);
index 4661da95d78d52a3221bbc1336354da86a98c3fe..81d180e5a367cc60d99bfab34e56eb585a9606fb 100644 (file)
@@ -11480,6 +11480,7 @@ static struct {
        { "LOCAL-G-LOCK1", run_g_lock1, 0 },
        { "LOCAL-G-LOCK2", run_g_lock2, 0 },
        { "LOCAL-G-LOCK3", run_g_lock3, 0 },
+       { "LOCAL-G-LOCK4", run_g_lock4, 0 },
        { "LOCAL-CANONICALIZE-PATH", run_local_canonicalize_path, 0 },
        { "qpathinfo-bufsize", run_qpathinfo_bufsize, 0 },
        {NULL, NULL, 0}};