selftest: Give tmux a bit of time to establish
[Samba.git] / source3 / torture / test_g_lock.c
blobca373123e118518fb580919efe2b73d9d8527dfb
1 /*
2 * Unix SMB/CIFS implementation.
3 * Test g_lock API
4 * Copyright (C) Volker Lendecke 2017
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "includes.h"
21 #include "torture/proto.h"
22 #include "system/filesys.h"
23 #include "g_lock.h"
24 #include "messages.h"
25 #include "lib/util/server_id.h"
26 #include "lib/util/sys_rw.h"
28 static bool get_g_lock_ctx(TALLOC_CTX *mem_ctx,
29 struct tevent_context **ev,
30 struct messaging_context **msg,
31 struct g_lock_ctx **ctx)
33 *ev = samba_tevent_context_init(mem_ctx);
34 if (*ev == NULL) {
35 fprintf(stderr, "tevent_context_init failed\n");
36 return false;
38 *msg = messaging_init(*ev, *ev);
39 if (*msg == NULL) {
40 fprintf(stderr, "messaging_init failed\n");
41 TALLOC_FREE(*ev);
42 return false;
44 *ctx = g_lock_ctx_init(*ev, *msg);
45 if (*ctx == NULL) {
46 fprintf(stderr, "g_lock_ctx_init failed\n");
47 TALLOC_FREE(*msg);
48 TALLOC_FREE(*ev);
49 return false;
52 return true;
55 bool run_g_lock1(int dummy)
57 struct tevent_context *ev = NULL;
58 struct messaging_context *msg = NULL;
59 struct g_lock_ctx *ctx = NULL;
60 const char *lockname = "lock1";
61 NTSTATUS status;
62 bool ret = false;
63 bool ok;
65 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
66 if (!ok) {
67 goto fail;
70 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
71 (struct timeval) { .tv_sec = 1 });
72 if (!NT_STATUS_IS_OK(status)) {
73 fprintf(stderr, "g_lock_lock failed: %s\n",
74 nt_errstr(status));
75 goto fail;
78 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
79 (struct timeval) { .tv_sec = 1 });
80 if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
81 fprintf(stderr, "Double lock got %s\n",
82 nt_errstr(status));
83 goto fail;
86 status = g_lock_unlock(ctx, lockname);
87 if (!NT_STATUS_IS_OK(status)) {
88 fprintf(stderr, "g_lock_unlock failed: %s\n",
89 nt_errstr(status));
90 goto fail;
93 status = g_lock_unlock(ctx, lockname);
94 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
95 fprintf(stderr, "g_lock_unlock returned: %s\n",
96 nt_errstr(status));
97 goto fail;
100 ret = true;
101 fail:
102 TALLOC_FREE(ctx);
103 TALLOC_FREE(msg);
104 TALLOC_FREE(ev);
105 return ret;
108 struct lock2_parser_state {
109 uint8_t *rdata;
110 bool ok;
113 static void lock2_parser(const struct g_lock_rec *locks,
114 size_t num_locks,
115 const uint8_t *data,
116 size_t datalen,
117 void *private_data)
119 struct lock2_parser_state *state = private_data;
121 if (datalen != sizeof(uint8_t)) {
122 return;
124 *state->rdata = *data;
125 state->ok = true;
129 * Test g_lock_write_data
132 bool run_g_lock2(int dummy)
134 struct tevent_context *ev = NULL;
135 struct messaging_context *msg = NULL;
136 struct g_lock_ctx *ctx = NULL;
137 const char *lockname = "lock2";
138 uint8_t data = 42;
139 uint8_t rdata;
140 struct lock2_parser_state state = { .rdata = &rdata };
141 NTSTATUS status;
142 bool ret = false;
143 bool ok;
145 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
146 if (!ok) {
147 goto fail;
150 status = g_lock_write_data(ctx, lockname, &data, sizeof(data));
151 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_LOCKED)) {
152 fprintf(stderr, "unlocked g_lock_write_data returned %s\n",
153 nt_errstr(status));
154 goto fail;
157 status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
158 (struct timeval) { .tv_sec = 1 });
159 if (!NT_STATUS_IS_OK(status)) {
160 fprintf(stderr, "g_lock_lock returned %s\n",
161 nt_errstr(status));
162 goto fail;
165 status = g_lock_write_data(ctx, lockname, &data, sizeof(data));
166 if (!NT_STATUS_IS_OK(status)) {
167 fprintf(stderr, "g_lock_write_data failed: %s\n",
168 nt_errstr(status));
169 goto fail;
172 status = g_lock_unlock(ctx, lockname);
173 if (!NT_STATUS_IS_OK(status)) {
174 fprintf(stderr, "g_lock_unlock failed: %s\n",
175 nt_errstr(status));
176 goto fail;
179 status = g_lock_dump(ctx, lockname, lock2_parser, &state);
180 if (!NT_STATUS_IS_OK(status)) {
181 fprintf(stderr, "g_lock_dump failed: %s\n",
182 nt_errstr(status));
183 goto fail;
186 if (!state.ok) {
187 fprintf(stderr, "Could not parse data\n");
188 goto fail;
190 if (rdata != data) {
191 fprintf(stderr, "Returned %"PRIu8", expected %"PRIu8"\n",
192 rdata, data);
193 goto fail;
196 ret = true;
197 fail:
198 TALLOC_FREE(ctx);
199 TALLOC_FREE(msg);
200 TALLOC_FREE(ev);
201 return ret;
204 struct lock3_parser_state {
205 struct server_id self;
206 enum g_lock_type lock_type;
207 bool ok;
210 static void lock3_parser(const struct g_lock_rec *locks,
211 size_t num_locks,
212 const uint8_t *data,
213 size_t datalen,
214 void *private_data)
216 struct lock3_parser_state *state = private_data;
218 if (datalen != 0) {
219 fprintf(stderr, "datalen=%zu\n", datalen);
220 return;
222 if (num_locks != 1) {
223 fprintf(stderr, "num_locks=%zu\n", num_locks);
224 return;
226 if (locks[0].lock_type != state->lock_type) {
227 fprintf(stderr, "found type %d, expected %d\n",
228 (int)locks[0].lock_type, (int)state->lock_type);
229 return;
231 if (!server_id_equal(&locks[0].pid, &state->self)) {
232 struct server_id_buf tmp1, tmp2;
233 fprintf(stderr, "found pid %s, expected %s\n",
234 server_id_str_buf(locks[0].pid, &tmp1),
235 server_id_str_buf(state->self, &tmp2));
236 return;
239 state->ok = true;
243 * Test lock upgrade/downgrade
246 bool run_g_lock3(int dummy)
248 struct tevent_context *ev = NULL;
249 struct messaging_context *msg = NULL;
250 struct g_lock_ctx *ctx = NULL;
251 const char *lockname = "lock3";
252 struct lock3_parser_state state;
253 NTSTATUS status;
254 bool ret = false;
255 bool ok;
257 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
258 if (!ok) {
259 goto fail;
262 state.self = messaging_server_id(msg);
264 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
265 (struct timeval) { .tv_sec = 1 });
266 if (!NT_STATUS_IS_OK(status)) {
267 fprintf(stderr, "g_lock_lock returned %s\n",
268 nt_errstr(status));
269 goto fail;
272 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
273 (struct timeval) { .tv_sec = 1 });
274 if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
275 fprintf(stderr, "g_lock_lock returned %s, expected %s\n",
276 nt_errstr(status), nt_errstr(NT_STATUS_WAS_LOCKED));
277 goto fail;
280 state.lock_type = G_LOCK_READ;
281 state.ok = false;
283 status = g_lock_dump(ctx, lockname, lock3_parser, &state);
284 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
285 fprintf(stderr, "g_lock_dump returned %s\n",
286 nt_errstr(status));
287 goto fail;
289 if (!state.ok) {
290 goto fail;
293 status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
294 (struct timeval) { .tv_sec = 1 });
295 if (!NT_STATUS_IS_OK(status)) {
296 fprintf(stderr, "g_lock_lock returned %s\n",
297 nt_errstr(status));
298 goto fail;
301 state.lock_type = G_LOCK_WRITE;
302 state.ok = false;
304 status = g_lock_dump(ctx, lockname, lock3_parser, &state);
305 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
306 fprintf(stderr, "g_lock_dump returned %s\n",
307 nt_errstr(status));
308 goto fail;
310 if (!state.ok) {
311 goto fail;
315 ret = true;
316 fail:
317 TALLOC_FREE(ctx);
318 TALLOC_FREE(msg);
319 TALLOC_FREE(ev);
320 return ret;
323 static bool lock4_child(const char *lockname,
324 int ready_pipe, int exit_pipe)
326 struct tevent_context *ev = NULL;
327 struct messaging_context *msg = NULL;
328 struct g_lock_ctx *ctx = NULL;
329 NTSTATUS status;
330 ssize_t n;
331 bool ok;
333 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
334 if (!ok) {
335 return false;
338 status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
339 (struct timeval) { .tv_sec = 1 });
340 if (!NT_STATUS_IS_OK(status)) {
341 fprintf(stderr, "child: g_lock_lock returned %s\n",
342 nt_errstr(status));
343 return false;
346 n = sys_write(ready_pipe, &ok, sizeof(ok));
347 if (n != sizeof(ok)) {
348 fprintf(stderr, "child: write failed\n");
349 return false;
352 if (ok) {
353 n = sys_read(exit_pipe, &ok, sizeof(ok));
354 if (n != 0) {
355 fprintf(stderr, "child: read failed\n");
356 return false;
360 return true;
363 static void lock4_done(struct tevent_req *subreq)
365 int *done = tevent_req_callback_data_void(subreq);
366 NTSTATUS status;
368 status = g_lock_lock_recv(subreq);
369 TALLOC_FREE(subreq);
370 if (!NT_STATUS_IS_OK(status)) {
371 fprintf(stderr, "g_lock_lock_recv returned %s\n",
372 nt_errstr(status));
373 *done = -1;
374 return;
376 *done = 1;
379 static void lock4_waited(struct tevent_req *subreq)
381 int *exit_pipe = tevent_req_callback_data_void(subreq);
382 pid_t child;
383 int status;
384 bool ok;
386 printf("waited\n");
388 ok = tevent_wakeup_recv(subreq);
389 TALLOC_FREE(subreq);
390 if (!ok) {
391 fprintf(stderr, "tevent_wakeup_recv failed\n");
393 close(*exit_pipe);
395 child = wait(&status);
397 printf("child %d exited with %d\n", (int)child, status);
401 * Test a lock conflict
404 bool run_g_lock4(int dummy)
406 struct tevent_context *ev = NULL;
407 struct messaging_context *msg = NULL;
408 struct g_lock_ctx *ctx = NULL;
409 const char *lockname = "lock4";
410 pid_t child;
411 int ready_pipe[2];
412 int exit_pipe[2];
413 NTSTATUS status;
414 bool ret = false;
415 struct tevent_req *req;
416 bool ok;
417 int done;
419 if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
420 perror("pipe failed");
421 return false;
424 child = fork();
426 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
427 if (!ok) {
428 goto fail;
431 if (child == -1) {
432 perror("fork failed");
433 return false;
436 if (child == 0) {
437 close(ready_pipe[0]);
438 close(exit_pipe[1]);
439 ok = lock4_child(lockname, ready_pipe[1], exit_pipe[0]);
440 exit(ok ? 0 : 1);
443 close(ready_pipe[1]);
444 close(exit_pipe[0]);
446 if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
447 perror("read failed");
448 return false;
451 if (!ok) {
452 fprintf(stderr, "child returned error\n");
453 return false;
456 status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
457 (struct timeval) { .tv_usec = 1 });
458 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
459 fprintf(stderr, "g_lock_lock returned %s\n",
460 nt_errstr(status));
461 goto fail;
464 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
465 (struct timeval) { .tv_usec = 1 });
466 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
467 fprintf(stderr, "g_lock_lock returned %s\n",
468 nt_errstr(status));
469 goto fail;
472 req = g_lock_lock_send(ev, ev, ctx, lockname, G_LOCK_WRITE);
473 if (req == NULL) {
474 fprintf(stderr, "g_lock_lock send failed\n");
475 goto fail;
477 tevent_req_set_callback(req, lock4_done, &done);
479 req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
480 if (req == NULL) {
481 fprintf(stderr, "tevent_wakeup_send failed\n");
482 goto fail;
484 tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
486 done = 0;
488 while (done == 0) {
489 int tevent_ret = tevent_loop_once(ev);
490 if (tevent_ret != 0) {
491 perror("tevent_loop_once failed");
492 goto fail;
496 ret = true;
497 fail:
498 TALLOC_FREE(ctx);
499 TALLOC_FREE(msg);
500 TALLOC_FREE(ev);
501 return ret;
504 struct lock5_parser_state {
505 size_t num_locks;
508 static void lock5_parser(const struct g_lock_rec *locks,
509 size_t num_locks,
510 const uint8_t *data,
511 size_t datalen,
512 void *private_data)
514 struct lock5_parser_state *state = private_data;
515 state->num_locks = num_locks;
519 * Test heuristic cleanup
522 bool run_g_lock5(int dummy)
524 struct tevent_context *ev = NULL;
525 struct messaging_context *msg = NULL;
526 struct g_lock_ctx *ctx = NULL;
527 const char *lockname = "lock5";
528 pid_t child;
529 int exit_pipe[2], ready_pipe[2];
530 NTSTATUS status;
531 size_t i, nprocs;
532 int ret;
533 bool ok;
534 ssize_t nread;
535 char c;
537 nprocs = 5;
539 if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
540 perror("pipe failed");
541 return false;
544 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
545 if (!ok) {
546 fprintf(stderr, "get_g_lock_ctx failed");
547 return false;
550 for (i=0; i<nprocs; i++) {
552 child = fork();
554 if (child == -1) {
555 perror("fork failed");
556 return false;
559 if (child == 0) {
560 TALLOC_FREE(ctx);
561 TALLOC_FREE(msg);
562 TALLOC_FREE(ev);
564 close(ready_pipe[0]);
565 close(exit_pipe[1]);
567 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
568 if (!ok) {
569 fprintf(stderr, "get_g_lock_ctx failed");
570 exit(1);
572 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
573 (struct timeval) { .tv_sec = 1 });
574 if (!NT_STATUS_IS_OK(status)) {
575 fprintf(stderr,
576 "child g_lock_lock failed %s\n",
577 nt_errstr(status));
578 exit(1);
580 close(ready_pipe[1]);
581 nread = sys_read(exit_pipe[0], &c, sizeof(c));
582 if (nread != 0) {
583 fprintf(stderr, "sys_read returned %zu (%s)\n",
584 nread, strerror(errno));
585 exit(1);
587 exit(0);
591 close(ready_pipe[1]);
593 nread = sys_read(ready_pipe[0], &c, sizeof(c));
594 if (nread != 0) {
595 fprintf(stderr, "sys_read returned %zu (%s)\n",
596 nread, strerror(errno));
597 return false;
600 close(exit_pipe[1]);
602 for (i=0; i<nprocs; i++) {
603 int child_status;
604 ret = waitpid(-1, &child_status, 0);
605 if (ret == -1) {
606 perror("waitpid failed");
607 return false;
611 for (i=0; i<nprocs; i++) {
612 struct lock5_parser_state state;
614 status = g_lock_dump(ctx, lockname, lock5_parser, &state);
615 if (!NT_STATUS_IS_OK(status)) {
616 fprintf(stderr, "g_lock_dump returned %s\n",
617 nt_errstr(status));
618 return false;
621 if (state.num_locks != (nprocs - i)) {
622 fprintf(stderr, "nlocks=%zu, expected %zu\n",
623 state.num_locks, (nprocs-i));
624 return false;
627 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
628 (struct timeval) { .tv_sec = 1 });
629 if (!NT_STATUS_IS_OK(status)) {
630 fprintf(stderr, "g_lock_lock failed %s\n",
631 nt_errstr(status));
632 return false;
634 status = g_lock_unlock(ctx, lockname);
635 if (!NT_STATUS_IS_OK(status)) {
636 fprintf(stderr, "g_lock_unlock failed %s\n",
637 nt_errstr(status));
638 return false;
643 return true;