torture3: add LOCAL-G-LOCK7 test
authorStefan Metzmacher <metze@samba.org>
Wed, 20 Dec 2017 18:36:59 +0000 (19:36 +0100)
committerStefan Metzmacher <metze@samba.org>
Tue, 29 Oct 2019 13:33:03 +0000 (14:33 +0100)
source3/selftest/tests.py
source3/torture/proto.h
source3/torture/test_g_lock.c
source3/torture/torture.c

index a7b098d6518c2c9a9ab53d903f38032dba2a145d..66c0ff58708d47dbad2566ba3241ad7b22a3ddbc 100755 (executable)
@@ -221,6 +221,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",
index f1896d5624ee4576175a0be5c2ca908a9ab7410e..6c86bc617e92121b06023fb96c55515ab6de9fc7 100644 (file)
@@ -136,6 +136,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);
index 352121e41944ae1f1e1a15e60360ee1a5fc37f8c..dfacef5146cc1ffe86b1ef0c9d8c20d097c58092 100644 (file)
@@ -897,6 +897,416 @@ bool run_g_lock6(int dummy)
        return true;
 }
 
+struct lock7_parser_state {
+       const char *location;
+       enum g_lock_type lock_type;
+       size_t num_locks;
+       bool unexpected_pid;
+       struct server_id self;
+       bool ok;
+};
+
+static void lock7_parser(const struct g_lock_rec *locks,
+                        size_t num_locks,
+                        const uint8_t *data,
+                        size_t datalen,
+                        void *private_data)
+{
+       struct lock7_parser_state *state = private_data;
+       bool found_pid = false;
+       size_t i;
+
+       state->ok = false;
+
+       if (datalen != 0) {
+               fprintf(stderr, "%s: datalen=%zu\n", state->location, datalen);
+               return;
+       }
+
+       if (state->num_locks != num_locks) {
+               fprintf(stderr, "%s: state->num_locks=%zu != num_locks=%zu\n",
+                       state->location, state->num_locks, num_locks);
+               return;
+       }
+
+       if (state->num_locks == 0) {
+               state->ok = true;
+               return;
+       }
+
+       for (i = 0; i < num_locks; i++) {
+               if (locks[i].lock_type != state->lock_type) {
+                       fprintf(stderr, "%s:[%zu] found type %d, expected %d\n",
+                               state->location, i,
+                               (int)locks[i].lock_type, (int)state->lock_type);
+                       return;
+               }
+
+               if (server_id_equal(&locks[i].pid, &state->self)) {
+                       struct server_id_buf tmp;
+
+                       if (found_pid) {
+                               fprintf(stderr, "%s:[%zu] found pid %s, twice\n",
+                                       state->location, i,
+                                       server_id_str_buf(state->self, &tmp));
+                               return;
+                       }
+
+                       if (state->unexpected_pid) {
+                               fprintf(stderr, "%s:[%zu] found pid %s unexpected\n",
+                                       state->location, i,
+                                       server_id_str_buf(state->self, &tmp));
+                               return;
+                       }
+
+                       found_pid = true;
+               }
+       }
+
+       if (!state->unexpected_pid && !found_pid) {
+               struct server_id_buf tmp;
+
+               fprintf(stderr, "%s: not found pid %s\n",
+                       state->location,
+                       server_id_str_buf(state->self, &tmp));
+               return;
+       }
+
+       state->ok = true;
+}
+
+/*
+ * Test cleanup with contention and stale locks
+ */
+
+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";
+       pid_t child;
+       int exit_pipe[2], ready_pipe[2];
+       NTSTATUS status;
+       int ret;
+       bool ok;
+       ssize_t nread;
+       char c;
+       struct lock7_parser_state state;
+       int child_status;
+
+       if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
+               perror("pipe failed");
+               return false;
+       }
+
+       ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
+       if (!ok) {
+               fprintf(stderr, "get_g_lock_ctx failed");
+               return false;
+       }
+
+       child = fork();
+
+       if (child == -1) {
+               perror("fork failed");
+               return false;
+       }
+
+       if (child == 0) {
+               TALLOC_FREE(ctx);
+
+               status = reinit_after_fork(msg, ev, false, "");
+
+               close(ready_pipe[0]);
+               close(exit_pipe[1]);
+
+               ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
+               if (!ok) {
+                       fprintf(stderr, "get_g_lock_ctx failed");
+                       exit(1);
+               }
+               status = g_lock_lock(ctx, lockname, G_LOCK_READ,
+                                    (struct timeval) { .tv_sec = 1 });
+               if (!NT_STATUS_IS_OK(status)) {
+                       fprintf(stderr,
+                               "child g_lock_lock failed %s\n",
+                               nt_errstr(status));
+                       exit(1);
+               }
+               close(ready_pipe[1]);
+               nread = sys_read(exit_pipe[0], &c, sizeof(c));
+               if (nread != 0) {
+                       fprintf(stderr, "sys_read returned %zu (%s)\n",
+                               nread, strerror(errno));
+                       exit(1);
+               }
+               exit(0);
+       }
+
+       close(ready_pipe[1]);
+
+       nread = sys_read(ready_pipe[0], &c, sizeof(c));
+       if (nread != 0) {
+               fprintf(stderr, "sys_read returned %zu (%s)\n",
+                       nread, strerror(errno));
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 1,
+               .lock_type = G_LOCK_READ,
+               .unexpected_pid = true,
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.ok) {
+               return false;
+       }
+
+       status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
+                            (struct timeval) { .tv_sec = 1 });
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               fprintf(stderr, "g_lock_lock should have failed with %s - %s\n",
+                       nt_errstr(NT_STATUS_IO_TIMEOUT),
+                       nt_errstr(status));
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 1,
+               .lock_type = G_LOCK_READ,
+               .unexpected_pid = true,
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.ok) {
+               return false;
+       }
+
+       status = g_lock_lock(ctx, lockname, G_LOCK_READ,
+                            (struct timeval) { .tv_sec = 1 });
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_lock failed with %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 2,
+               .lock_type = G_LOCK_READ,
+               .self = messaging_server_id(msg),
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.ok) {
+               return false;
+       }
+
+       status = g_lock_lock(ctx, lockname, G_LOCK_READ,
+                            (struct timeval) { .tv_sec = 1 });
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
+               fprintf(stderr, "g_lock_lock should have failed with %s - %s\n",
+                       nt_errstr(NT_STATUS_WAS_LOCKED),
+                       nt_errstr(status));
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 2,
+               .lock_type = G_LOCK_READ,
+               .self = messaging_server_id(msg),
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.ok) {
+               return false;
+       }
+
+       status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
+                            (struct timeval) { .tv_sec = 1 });
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+               fprintf(stderr, "g_lock_lock should have failed with %s - %s\n",
+                       nt_errstr(NT_STATUS_IO_TIMEOUT),
+                       nt_errstr(status));
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 2,
+               .lock_type = G_LOCK_READ,
+               .unexpected_pid = true,
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.ok) {
+               return false;
+       }
+
+       close(exit_pipe[1]);
+
+       ret = waitpid(-1, &child_status, 0);
+       if (ret == -1) {
+               perror("waitpid failed");
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 2,
+               .lock_type = G_LOCK_READ,
+               .self = messaging_server_id(msg),
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.ok) {
+               return false;
+       }
+
+       status = g_lock_lock(ctx, lockname, G_LOCK_READ,
+                            (struct timeval) { .tv_sec = 1 });
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
+               fprintf(stderr, "g_lock_lock should have failed with %s - %s\n",
+                       nt_errstr(NT_STATUS_WAS_LOCKED),
+                       nt_errstr(status));
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 1,
+               .lock_type = G_LOCK_READ,
+               .self = messaging_server_id(msg),
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.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, "g_lock_lock failed with %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 1,
+               .lock_type = G_LOCK_WRITE,
+               .self = messaging_server_id(msg),
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.ok) {
+               return false;
+       }
+
+       status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
+                            (struct timeval) { .tv_sec = 1 });
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
+               fprintf(stderr, "g_lock_lock should have failed with %s - %s\n",
+                       nt_errstr(NT_STATUS_WAS_LOCKED),
+                       nt_errstr(status));
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 1,
+               .lock_type = G_LOCK_WRITE,
+               .self = messaging_server_id(msg),
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.ok) {
+               return false;
+       }
+
+       status = g_lock_lock(ctx, lockname, G_LOCK_READ,
+                            (struct timeval) { .tv_sec = 1 });
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_lock failed with %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+
+       state = (struct lock7_parser_state) {
+               .location = __location__,
+               .num_locks = 1,
+               .lock_type = G_LOCK_READ,
+               .self = messaging_server_id(msg),
+       };
+       status = g_lock_dump(ctx, lockname, lock7_parser, &state);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_dump returned %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+       if (!state.ok) {
+               return false;
+       }
+
+       status = g_lock_unlock(ctx, lockname);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "g_lock_unlock failed: %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+
+       status = g_lock_unlock(ctx, lockname);
+       if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+               fprintf(stderr, "g_lock_unlock returned: %s\n",
+                       nt_errstr(status));
+               return false;
+       }
+
+       return true;
+}
+
 extern int torture_numops;
 extern int torture_nprocs;
 
index bfc2a2e24c95b6f498918b19e92c6c30418e741b..3340b42aeef2d8caca50141323282c69a4ff9cb5 100644 (file)
@@ -14811,6 +14811,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,