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;