tests: Check symlinks are readable as reparse points
[samba.git] / source3 / torture / test_g_lock.c
blobfee91270323b870744958ff9296cf9b470c06f03
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"
27 #include "lib/util/util_tdb.h"
28 #include "lib/util/tevent_ntstatus.h"
29 #include "lib/global_contexts.h"
31 static bool get_g_lock_ctx(TALLOC_CTX *mem_ctx,
32 struct tevent_context **ev,
33 struct messaging_context **msg,
34 struct g_lock_ctx **ctx)
36 *ev = global_event_context();
37 if (*ev == NULL) {
38 fprintf(stderr, "tevent_context_init failed\n");
39 return false;
41 *msg = global_messaging_context();
42 if (*msg == NULL) {
43 fprintf(stderr, "messaging_init failed\n");
44 TALLOC_FREE(*ev);
45 return false;
47 *ctx = g_lock_ctx_init(*ev, *msg);
48 if (*ctx == NULL) {
49 fprintf(stderr, "g_lock_ctx_init failed\n");
50 TALLOC_FREE(*msg);
51 TALLOC_FREE(*ev);
52 return false;
55 return true;
58 bool run_g_lock1(int dummy)
60 struct tevent_context *ev = NULL;
61 struct messaging_context *msg = NULL;
62 struct g_lock_ctx *ctx = NULL;
63 const char *lockname = "lock1";
64 NTSTATUS status;
65 bool ret = false;
66 bool ok;
68 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
69 if (!ok) {
70 goto fail;
73 status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
74 (struct timeval) { .tv_sec = 1 },
75 NULL, NULL);
76 if (!NT_STATUS_IS_OK(status)) {
77 fprintf(stderr, "g_lock_lock failed: %s\n",
78 nt_errstr(status));
79 goto fail;
82 status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
83 (struct timeval) { .tv_sec = 1 },
84 NULL, NULL);
85 if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
86 fprintf(stderr, "Double lock got %s\n",
87 nt_errstr(status));
88 goto fail;
91 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
92 if (!NT_STATUS_IS_OK(status)) {
93 fprintf(stderr, "g_lock_unlock failed: %s\n",
94 nt_errstr(status));
95 goto fail;
98 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
99 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
100 fprintf(stderr, "g_lock_unlock returned: %s\n",
101 nt_errstr(status));
102 goto fail;
105 ret = true;
106 fail:
107 TALLOC_FREE(ctx);
108 TALLOC_FREE(msg);
109 TALLOC_FREE(ev);
110 return ret;
113 struct lock2_parser_state {
114 uint8_t *rdata;
115 bool ok;
118 static void lock2_parser(struct server_id exclusive,
119 size_t num_shared,
120 const struct server_id *shared,
121 const uint8_t *data,
122 size_t datalen,
123 void *private_data)
125 struct lock2_parser_state *state = private_data;
127 if (datalen != sizeof(uint8_t)) {
128 return;
130 *state->rdata = *data;
131 state->ok = true;
135 * Test g_lock_write_data
138 bool run_g_lock2(int dummy)
140 struct tevent_context *ev = NULL;
141 struct messaging_context *msg = NULL;
142 struct g_lock_ctx *ctx = NULL;
143 const char *lockname = "lock2";
144 uint8_t data = 42;
145 uint8_t rdata;
146 struct lock2_parser_state state = { .rdata = &rdata };
147 NTSTATUS status;
148 bool ret = false;
149 bool ok;
151 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
152 if (!ok) {
153 goto fail;
156 status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
157 &data, sizeof(data));
158 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_LOCKED)) {
159 fprintf(stderr, "unlocked g_lock_write_data returned %s\n",
160 nt_errstr(status));
161 goto fail;
164 status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
165 (struct timeval) { .tv_sec = 1 },
166 NULL, NULL);
167 if (!NT_STATUS_IS_OK(status)) {
168 fprintf(stderr, "g_lock_lock returned %s\n",
169 nt_errstr(status));
170 goto fail;
173 status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
174 &data, sizeof(data));
175 if (!NT_STATUS_IS_OK(status)) {
176 fprintf(stderr, "g_lock_write_data failed: %s\n",
177 nt_errstr(status));
178 goto fail;
181 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
182 if (!NT_STATUS_IS_OK(status)) {
183 fprintf(stderr, "g_lock_unlock failed: %s\n",
184 nt_errstr(status));
185 goto fail;
188 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
189 lock2_parser, &state);
190 if (!NT_STATUS_IS_OK(status)) {
191 fprintf(stderr, "g_lock_dump failed: %s\n",
192 nt_errstr(status));
193 goto fail;
196 if (!state.ok) {
197 fprintf(stderr, "Could not parse data\n");
198 goto fail;
200 if (rdata != data) {
201 fprintf(stderr, "Returned %"PRIu8", expected %"PRIu8"\n",
202 rdata, data);
203 goto fail;
206 ret = true;
207 fail:
208 TALLOC_FREE(ctx);
209 TALLOC_FREE(msg);
210 TALLOC_FREE(ev);
211 return ret;
214 struct lock3_parser_state {
215 struct server_id self;
216 enum g_lock_type lock_type;
217 bool ok;
220 static void lock3_parser(struct server_id exclusive,
221 size_t num_shared,
222 const struct server_id *shared,
223 const uint8_t *data,
224 size_t datalen,
225 void *private_data)
227 struct lock3_parser_state *state = private_data;
228 size_t num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
229 const struct server_id *pid;
231 if (datalen != 0) {
232 fprintf(stderr, "datalen=%zu\n", datalen);
233 return;
235 if (num_locks != 1) {
236 fprintf(stderr, "num_locks=%zu\n", num_locks);
237 return;
240 if (state->lock_type == G_LOCK_WRITE) {
241 if (exclusive.pid == 0) {
242 fprintf(stderr, "Found READ, expected WRITE\n");
243 return;
245 } else {
246 if (exclusive.pid != 0) {
247 fprintf(stderr, "Found WRITE, expected READ\n");
248 return;
252 pid = (exclusive.pid != 0) ? &exclusive : &shared[0];
254 if (!server_id_equal(pid, &state->self)) {
255 struct server_id_buf tmp1, tmp2;
256 fprintf(stderr, "found pid %s, expected %s\n",
257 server_id_str_buf(*pid, &tmp1),
258 server_id_str_buf(state->self, &tmp2));
259 return;
262 state->ok = true;
266 * Test lock upgrade/downgrade
269 bool run_g_lock3(int dummy)
271 struct tevent_context *ev = NULL;
272 struct messaging_context *msg = NULL;
273 struct g_lock_ctx *ctx = NULL;
274 const char *lockname = "lock3";
275 struct lock3_parser_state state;
276 NTSTATUS status;
277 bool ret = false;
278 bool ok;
280 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
281 if (!ok) {
282 goto fail;
285 state.self = messaging_server_id(msg);
287 status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_READ,
288 (struct timeval) { .tv_sec = 1 },
289 NULL, NULL);
290 if (!NT_STATUS_IS_OK(status)) {
291 fprintf(stderr, "g_lock_lock returned %s\n",
292 nt_errstr(status));
293 goto fail;
296 state.lock_type = G_LOCK_READ;
297 state.ok = false;
299 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
300 lock3_parser, &state);
301 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
302 fprintf(stderr, "g_lock_dump returned %s\n",
303 nt_errstr(status));
304 goto fail;
306 if (!state.ok) {
307 goto fail;
310 status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_UPGRADE,
311 (struct timeval) { .tv_sec = 1 },
312 NULL, NULL);
313 if (!NT_STATUS_IS_OK(status)) {
314 fprintf(stderr, "g_lock_lock returned %s\n",
315 nt_errstr(status));
316 goto fail;
319 state.lock_type = G_LOCK_WRITE;
320 state.ok = false;
322 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
323 lock3_parser, &state);
324 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
325 fprintf(stderr, "g_lock_dump returned %s\n",
326 nt_errstr(status));
327 goto fail;
329 if (!state.ok) {
330 goto fail;
334 ret = true;
335 fail:
336 TALLOC_FREE(ctx);
337 TALLOC_FREE(msg);
338 TALLOC_FREE(ev);
339 return ret;
342 static bool lock4_child(const char *lockname,
343 enum g_lock_type lock_type,
344 int ready_pipe,
345 int exit_pipe)
347 struct tevent_context *ev = NULL;
348 struct messaging_context *msg = NULL;
349 struct g_lock_ctx *ctx = NULL;
350 NTSTATUS status;
351 ssize_t n;
352 bool ok;
354 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
355 if (!ok) {
356 return false;
359 status = g_lock_lock(
360 ctx,
361 string_term_tdb_data(lockname),
362 lock_type,
363 (struct timeval) { .tv_sec = 1 },
364 NULL,
365 NULL);
366 if (!NT_STATUS_IS_OK(status)) {
367 fprintf(stderr, "child: g_lock_lock returned %s\n",
368 nt_errstr(status));
369 return false;
372 n = sys_write(ready_pipe, &ok, sizeof(ok));
373 if (n != sizeof(ok)) {
374 fprintf(stderr, "child: write failed\n");
375 return false;
378 if (ok) {
379 n = sys_read(exit_pipe, &ok, sizeof(ok));
380 if (n != 0) {
381 fprintf(stderr, "child: read failed\n");
382 return false;
386 return true;
389 static void lock4_done(struct tevent_req *subreq)
391 int *done = tevent_req_callback_data_void(subreq);
392 NTSTATUS status;
394 status = g_lock_lock_recv(subreq);
395 TALLOC_FREE(subreq);
396 if (!NT_STATUS_IS_OK(status)) {
397 fprintf(stderr, "g_lock_lock_recv returned %s\n",
398 nt_errstr(status));
399 *done = -1;
400 return;
402 *done = 1;
405 static void lock4_waited(struct tevent_req *subreq)
407 int *exit_pipe = tevent_req_callback_data_void(subreq);
408 pid_t child;
409 int status;
410 bool ok;
412 printf("waited\n");
414 ok = tevent_wakeup_recv(subreq);
415 TALLOC_FREE(subreq);
416 if (!ok) {
417 fprintf(stderr, "tevent_wakeup_recv failed\n");
419 close(*exit_pipe);
421 child = wait(&status);
423 printf("child %d exited with %d\n", (int)child, status);
426 struct lock4_check_state {
427 struct server_id me;
428 bool ok;
431 static void lock4_check(struct server_id exclusive,
432 size_t num_shared,
433 const struct server_id *shared,
434 const uint8_t *data,
435 size_t datalen,
436 void *private_data)
438 struct lock4_check_state *state = private_data;
439 size_t num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
441 if (num_locks != 1) {
442 fprintf(stderr, "num_locks=%zu\n", num_locks);
443 return;
446 if (exclusive.pid == 0) {
447 fprintf(stderr, "Wrong lock type, not WRITE\n");
448 return;
451 if (!server_id_equal(&state->me, &exclusive)) {
452 struct server_id_buf buf1, buf2;
453 fprintf(stderr, "me=%s, locker=%s\n",
454 server_id_str_buf(state->me, &buf1),
455 server_id_str_buf(exclusive, &buf2));
456 return;
459 state->ok = true;
463 * Test a lock conflict: Contend with a WRITE lock
466 bool run_g_lock4(int dummy)
468 struct tevent_context *ev = NULL;
469 struct messaging_context *msg = NULL;
470 struct g_lock_ctx *ctx = NULL;
471 const char *lockname = "lock4";
472 TDB_DATA key = string_term_tdb_data(lockname);
473 pid_t child;
474 int ready_pipe[2];
475 int exit_pipe[2];
476 NTSTATUS status;
477 bool ret = false;
478 struct tevent_req *req;
479 bool ok;
480 int done;
482 if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
483 perror("pipe failed");
484 return false;
487 child = fork();
489 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
490 if (!ok) {
491 goto fail;
494 if (child == -1) {
495 perror("fork failed");
496 return false;
499 if (child == 0) {
500 close(ready_pipe[0]);
501 close(exit_pipe[1]);
502 ok = lock4_child(
503 lockname, G_LOCK_WRITE, ready_pipe[1], exit_pipe[0]);
504 exit(ok ? 0 : 1);
507 close(ready_pipe[1]);
508 close(exit_pipe[0]);
510 if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
511 perror("read failed");
512 return false;
515 if (!ok) {
516 fprintf(stderr, "child returned error\n");
517 return false;
520 status = g_lock_lock(ctx, key, G_LOCK_WRITE,
521 (struct timeval) { .tv_usec = 1 },
522 NULL, NULL);
523 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
524 fprintf(stderr, "g_lock_lock returned %s\n",
525 nt_errstr(status));
526 goto fail;
529 status = g_lock_lock(ctx, key, G_LOCK_READ,
530 (struct timeval) { .tv_usec = 1 },
531 NULL, NULL);
532 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
533 fprintf(stderr, "g_lock_lock returned %s\n",
534 nt_errstr(status));
535 goto fail;
538 req = g_lock_lock_send(ev, ev, ctx, key, G_LOCK_WRITE, NULL, NULL);
539 if (req == NULL) {
540 fprintf(stderr, "g_lock_lock send failed\n");
541 goto fail;
543 tevent_req_set_callback(req, lock4_done, &done);
545 req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
546 if (req == NULL) {
547 fprintf(stderr, "tevent_wakeup_send failed\n");
548 goto fail;
550 tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
552 done = 0;
554 while (done == 0) {
555 int tevent_ret = tevent_loop_once(ev);
556 if (tevent_ret != 0) {
557 perror("tevent_loop_once failed");
558 goto fail;
563 struct lock4_check_state state = {
564 .me = messaging_server_id(msg)
567 status = g_lock_dump(ctx, key, lock4_check, &state);
568 if (!NT_STATUS_IS_OK(status)) {
569 fprintf(stderr, "g_lock_dump failed: %s\n",
570 nt_errstr(status));
571 goto fail;
573 if (!state.ok) {
574 fprintf(stderr, "lock4_check failed\n");
575 goto fail;
579 ret = true;
580 fail:
581 TALLOC_FREE(ctx);
582 TALLOC_FREE(msg);
583 TALLOC_FREE(ev);
584 return ret;
588 * Test a lock conflict: Contend with a READ lock
591 bool run_g_lock4a(int dummy)
593 struct tevent_context *ev = NULL;
594 struct messaging_context *msg = NULL;
595 struct g_lock_ctx *ctx = NULL;
596 const char *lockname = "lock4a";
597 TDB_DATA key = string_term_tdb_data(lockname);
598 pid_t child;
599 int ready_pipe[2];
600 int exit_pipe[2];
601 NTSTATUS status;
602 bool ret = false;
603 struct tevent_req *req;
604 bool ok;
605 int done;
607 if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
608 perror("pipe failed");
609 return false;
612 child = fork();
614 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
615 if (!ok) {
616 goto fail;
619 if (child == -1) {
620 perror("fork failed");
621 return false;
624 if (child == 0) {
625 close(ready_pipe[0]);
626 close(exit_pipe[1]);
627 ok = lock4_child(
628 lockname, G_LOCK_READ, ready_pipe[1], exit_pipe[0]);
629 exit(ok ? 0 : 1);
632 close(ready_pipe[1]);
633 close(exit_pipe[0]);
635 if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
636 perror("read failed");
637 return false;
640 if (!ok) {
641 fprintf(stderr, "child returned error\n");
642 return false;
645 status = g_lock_lock(ctx, key, G_LOCK_WRITE,
646 (struct timeval) { .tv_usec = 1 },
647 NULL, NULL);
648 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
649 fprintf(stderr, "g_lock_lock returned %s\n",
650 nt_errstr(status));
651 goto fail;
654 status = g_lock_lock(ctx, key, G_LOCK_READ,
655 (struct timeval) { .tv_usec = 1 },
656 NULL, NULL);
657 if (!NT_STATUS_IS_OK(status)) {
658 fprintf(stderr, "g_lock_lock returned %s\n",
659 nt_errstr(status));
660 goto fail;
663 status = g_lock_unlock(ctx, key);
664 if (!NT_STATUS_IS_OK(status)) {
665 fprintf(stderr,
666 "g_lock_unlock returned %s\n",
667 nt_errstr(status));
668 goto fail;
671 req = g_lock_lock_send(ev, ev, ctx, key, G_LOCK_WRITE, NULL, NULL);
672 if (req == NULL) {
673 fprintf(stderr, "g_lock_lock send failed\n");
674 goto fail;
676 tevent_req_set_callback(req, lock4_done, &done);
678 req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
679 if (req == NULL) {
680 fprintf(stderr, "tevent_wakeup_send failed\n");
681 goto fail;
683 tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
685 done = 0;
687 while (done == 0) {
688 int tevent_ret = tevent_loop_once(ev);
689 if (tevent_ret != 0) {
690 perror("tevent_loop_once failed");
691 goto fail;
696 struct lock4_check_state state = {
697 .me = messaging_server_id(msg)
700 status = g_lock_dump(ctx, key, lock4_check, &state);
701 if (!NT_STATUS_IS_OK(status)) {
702 fprintf(stderr, "g_lock_dump failed: %s\n",
703 nt_errstr(status));
704 goto fail;
706 if (!state.ok) {
707 fprintf(stderr, "lock4_check failed\n");
708 goto fail;
712 ret = true;
713 fail:
714 TALLOC_FREE(ctx);
715 TALLOC_FREE(msg);
716 TALLOC_FREE(ev);
717 return ret;
720 struct lock5_parser_state {
721 size_t num_locks;
724 static void lock5_parser(struct server_id exclusive,
725 size_t num_shared,
726 const struct server_id *shared,
727 const uint8_t *data,
728 size_t datalen,
729 void *private_data)
731 struct lock5_parser_state *state = private_data;
732 state->num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
736 * Test heuristic cleanup
739 bool run_g_lock5(int dummy)
741 struct tevent_context *ev = NULL;
742 struct messaging_context *msg = NULL;
743 struct g_lock_ctx *ctx = NULL;
744 const char *lockname = "lock5";
745 pid_t child;
746 int exit_pipe[2], ready_pipe[2];
747 NTSTATUS status;
748 size_t i, nprocs;
749 int ret;
750 bool ok;
751 ssize_t nread;
752 char c;
754 nprocs = 5;
756 if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
757 perror("pipe failed");
758 return false;
761 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
762 if (!ok) {
763 fprintf(stderr, "get_g_lock_ctx failed");
764 return false;
767 for (i=0; i<nprocs; i++) {
769 child = fork();
771 if (child == -1) {
772 perror("fork failed");
773 return false;
776 if (child == 0) {
777 TALLOC_FREE(ctx);
779 status = reinit_after_fork(msg, ev, false);
781 close(ready_pipe[0]);
782 close(exit_pipe[1]);
784 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
785 if (!ok) {
786 fprintf(stderr, "get_g_lock_ctx failed");
787 exit(1);
789 status = g_lock_lock(ctx,
790 string_term_tdb_data(lockname),
791 G_LOCK_READ,
792 (struct timeval) { .tv_sec = 1 },
793 NULL, NULL);
794 if (!NT_STATUS_IS_OK(status)) {
795 fprintf(stderr,
796 "child g_lock_lock failed %s\n",
797 nt_errstr(status));
798 exit(1);
800 close(ready_pipe[1]);
801 nread = sys_read(exit_pipe[0], &c, sizeof(c));
802 if (nread != 0) {
803 fprintf(stderr, "sys_read returned %zu (%s)\n",
804 nread, strerror(errno));
805 exit(1);
807 exit(0);
811 close(ready_pipe[1]);
813 nread = sys_read(ready_pipe[0], &c, sizeof(c));
814 if (nread != 0) {
815 fprintf(stderr, "sys_read returned %zu (%s)\n",
816 nread, strerror(errno));
817 return false;
820 close(exit_pipe[1]);
822 for (i=0; i<nprocs; i++) {
823 int child_status;
824 ret = waitpid(-1, &child_status, 0);
825 if (ret == -1) {
826 perror("waitpid failed");
827 return false;
831 for (i=0; i<nprocs; i++) {
832 struct lock5_parser_state state;
834 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
835 lock5_parser, &state);
836 if (!NT_STATUS_IS_OK(status)) {
837 fprintf(stderr, "g_lock_dump returned %s\n",
838 nt_errstr(status));
839 return false;
842 if (state.num_locks != (nprocs - i)) {
843 fprintf(stderr, "nlocks=%zu, expected %zu\n",
844 state.num_locks, (nprocs-i));
845 return false;
848 status = g_lock_lock(ctx, string_term_tdb_data(lockname),
849 G_LOCK_READ,
850 (struct timeval) { .tv_sec = 1 },
851 NULL, NULL);
852 if (!NT_STATUS_IS_OK(status)) {
853 fprintf(stderr, "g_lock_lock failed %s\n",
854 nt_errstr(status));
855 return false;
857 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
858 if (!NT_STATUS_IS_OK(status)) {
859 fprintf(stderr, "g_lock_unlock failed %s\n",
860 nt_errstr(status));
861 return false;
866 return true;
869 struct lock6_parser_state {
870 size_t num_locks;
873 static void lock6_parser(struct server_id exclusive,
874 size_t num_shared,
875 const struct server_id *shared,
876 const uint8_t *data,
877 size_t datalen,
878 void *private_data)
880 struct lock6_parser_state *state = private_data;
881 state->num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
885 * Test cleanup with contention and stale locks
888 bool run_g_lock6(int dummy)
890 struct tevent_context *ev = NULL;
891 struct messaging_context *msg = NULL;
892 struct g_lock_ctx *ctx = NULL;
893 TDB_DATA lockname = string_term_tdb_data("lock6");
894 pid_t child;
895 int exit_pipe[2], ready_pipe[2];
896 NTSTATUS status;
897 size_t i, nprocs;
898 int ret;
899 bool ok;
900 ssize_t nread;
901 char c;
903 if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
904 perror("pipe failed");
905 return false;
908 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
909 if (!ok) {
910 fprintf(stderr, "get_g_lock_ctx failed");
911 return false;
915 * Wipe all stale locks -- in clustered mode there's no
916 * CLEAR_IF_FIRST
918 status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
919 (struct timeval) { .tv_sec = 1 },
920 NULL, NULL);
921 if (!NT_STATUS_IS_OK(status)) {
922 fprintf(stderr, "g_lock_lock failed: %s\n",
923 nt_errstr(status));
924 return false;
926 status = g_lock_unlock(ctx, lockname);
927 if (!NT_STATUS_IS_OK(status)) {
928 fprintf(stderr, "g_lock_unlock failed: %s\n",
929 nt_errstr(status));
930 return false;
933 nprocs = 2;
934 for (i=0; i<nprocs; i++) {
936 child = fork();
938 if (child == -1) {
939 perror("fork failed");
940 return false;
943 if (child == 0) {
944 TALLOC_FREE(ctx);
946 status = reinit_after_fork(msg, ev, false);
947 if (!NT_STATUS_IS_OK(status)) {
948 fprintf(stderr, "reinit_after_fork failed: %s\n",
949 nt_errstr(status));
950 exit(1);
953 close(ready_pipe[0]);
954 close(exit_pipe[1]);
956 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
957 if (!ok) {
958 fprintf(stderr, "get_g_lock_ctx failed");
959 exit(1);
961 status = g_lock_lock(ctx,
962 lockname,
963 G_LOCK_READ,
964 (struct timeval) { .tv_sec = 1 },
965 NULL, NULL);
966 if (!NT_STATUS_IS_OK(status)) {
967 fprintf(stderr,
968 "child g_lock_lock failed %s\n",
969 nt_errstr(status));
970 exit(1);
972 if (i == 0) {
973 exit(0);
975 close(ready_pipe[1]);
976 nread = sys_read(exit_pipe[0], &c, sizeof(c));
977 if (nread != 0) {
978 fprintf(stderr, "sys_read returned %zu (%s)\n",
979 nread, strerror(errno));
980 exit(1);
982 exit(0);
986 close(ready_pipe[1]);
988 nread = sys_read(ready_pipe[0], &c, sizeof(c));
989 if (nread != 0) {
990 fprintf(stderr, "sys_read returned %zd (%s)\n",
991 nread, strerror(errno));
992 return false;
996 int child_status;
997 ret = waitpid(-1, &child_status, 0);
998 if (ret == -1) {
999 perror("waitpid failed");
1000 return false;
1005 struct lock6_parser_state state;
1007 status = g_lock_dump(ctx, lockname, lock6_parser, &state);
1008 if (!NT_STATUS_IS_OK(status)) {
1009 fprintf(stderr, "g_lock_dump returned %s\n",
1010 nt_errstr(status));
1011 return false;
1014 if (state.num_locks != nprocs) {
1015 fprintf(stderr, "nlocks=%zu, expected %zu\n",
1016 state.num_locks, nprocs);
1017 return false;
1020 status = g_lock_lock(ctx,
1021 lockname,
1022 G_LOCK_WRITE,
1023 (struct timeval) { .tv_sec = 1 },
1024 NULL, NULL);
1025 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
1026 fprintf(stderr, "g_lock_lock should have failed with %s - %s\n",
1027 nt_errstr(NT_STATUS_IO_TIMEOUT),
1028 nt_errstr(status));
1029 return false;
1032 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
1033 (struct timeval) { .tv_sec = 1 },
1034 NULL, NULL);
1035 if (!NT_STATUS_IS_OK(status)) {
1036 fprintf(stderr, "g_lock_lock failed: %s\n",
1037 nt_errstr(status));
1038 return false;
1042 close(exit_pipe[1]);
1045 int child_status;
1046 ret = waitpid(-1, &child_status, 0);
1047 if (ret == -1) {
1048 perror("waitpid failed");
1049 return false;
1053 status = g_lock_lock(ctx, lockname, G_LOCK_UPGRADE,
1054 (struct timeval) { .tv_sec = 1 },
1055 NULL, NULL);
1056 if (!NT_STATUS_IS_OK(status)) {
1057 fprintf(stderr, "g_lock_lock failed: %s\n",
1058 nt_errstr(status));
1059 return false;
1062 return true;
1066 * Test upgrade deadlock
1069 bool run_g_lock7(int dummy)
1071 struct tevent_context *ev = NULL;
1072 struct messaging_context *msg = NULL;
1073 struct g_lock_ctx *ctx = NULL;
1074 const char *lockname = "lock7";
1075 TDB_DATA key = string_term_tdb_data(lockname);
1076 pid_t child;
1077 int ready_pipe[2];
1078 int down_pipe[2];
1079 ssize_t n;
1080 NTSTATUS status;
1081 bool ret = false;
1082 bool ok = true;
1084 if ((pipe(ready_pipe) != 0) || (pipe(down_pipe) != 0)) {
1085 perror("pipe failed");
1086 return false;
1089 child = fork();
1091 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
1092 if (!ok) {
1093 goto fail;
1096 if (child == -1) {
1097 perror("fork failed");
1098 return false;
1101 if (child == 0) {
1102 struct tevent_req *req = NULL;
1104 close(ready_pipe[0]);
1105 ready_pipe[0] = -1;
1106 close(down_pipe[1]);
1107 down_pipe[1] = -1;
1109 status = reinit_after_fork(msg, ev, false);
1110 if (!NT_STATUS_IS_OK(status)) {
1111 fprintf(stderr,
1112 "reinit_after_fork failed: %s\n",
1113 nt_errstr(status));
1114 exit(1);
1117 printf("%d: locking READ\n", (int)getpid());
1119 status = g_lock_lock(
1120 ctx,
1121 key,
1122 G_LOCK_READ,
1123 (struct timeval) { .tv_usec = 1 },
1124 NULL, NULL);
1125 if (!NT_STATUS_IS_OK(status)) {
1126 fprintf(stderr,
1127 "g_lock_lock(READ) failed: %s\n",
1128 nt_errstr(status));
1129 exit(1);
1132 ok = true;
1134 n = sys_write(ready_pipe[1], &ok, sizeof(ok));
1135 if (n != sizeof(ok)) {
1136 fprintf(stderr,
1137 "sys_write failed: %s\n",
1138 strerror(errno));
1139 exit(1);
1142 n = sys_read(down_pipe[0], &ok, sizeof(ok));
1143 if (n != sizeof(ok)) {
1144 fprintf(stderr,
1145 "sys_read failed: %s\n",
1146 strerror(errno));
1147 exit(1);
1150 printf("%d: starting UPGRADE\n", (int)getpid());
1152 req = g_lock_lock_send(
1153 msg,
1155 ctx,
1156 key,
1157 G_LOCK_UPGRADE,
1158 NULL, NULL);
1159 if (req == NULL) {
1160 fprintf(stderr, "g_lock_lock_send(UPGRADE) failed\n");
1161 exit(1);
1164 n = sys_write(ready_pipe[1], &ok, sizeof(ok));
1165 if (n != sizeof(ok)) {
1166 fprintf(stderr,
1167 "sys_write failed: %s\n",
1168 strerror(errno));
1169 exit(1);
1172 exit(0);
1175 close(ready_pipe[1]);
1176 close(down_pipe[0]);
1178 if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
1179 perror("read failed");
1180 return false;
1182 if (!ok) {
1183 fprintf(stderr, "child returned error\n");
1184 return false;
1187 status = g_lock_lock(
1188 ctx,
1189 key,
1190 G_LOCK_READ,
1191 (struct timeval) { .tv_usec = 1 },
1192 NULL, NULL);
1193 if (!NT_STATUS_IS_OK(status)) {
1194 fprintf(stderr,
1195 "g_lock_lock(READ) failed: %s\n",
1196 nt_errstr(status));
1197 goto fail;
1200 n = sys_write(down_pipe[1], &ok, sizeof(ok));
1201 if (n != sizeof(ok)) {
1202 fprintf(stderr,
1203 "sys_write failed: %s\n",
1204 strerror(errno));
1205 goto fail;
1208 if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
1209 perror("read failed");
1210 goto fail;
1213 status = g_lock_lock(
1214 ctx,
1215 key,
1216 G_LOCK_UPGRADE,
1217 (struct timeval) { .tv_sec = 10 },
1218 NULL, NULL);
1219 if (!NT_STATUS_EQUAL(status, NT_STATUS_POSSIBLE_DEADLOCK)) {
1220 fprintf(stderr,
1221 "g_lock_lock returned %s\n",
1222 nt_errstr(status));
1223 goto fail;
1226 ret = true;
1227 fail:
1228 TALLOC_FREE(ctx);
1229 TALLOC_FREE(msg);
1230 TALLOC_FREE(ev);
1231 return ret;
1234 bool run_g_lock8(int dummy)
1236 struct tevent_context *ev = NULL;
1237 struct messaging_context *msg = NULL;
1238 struct g_lock_ctx *ctx = NULL;
1239 struct tevent_req *req = NULL;
1240 TDB_DATA lockname = string_term_tdb_data("lock8");
1241 NTSTATUS status;
1242 bool ok;
1244 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
1245 if (!ok) {
1246 fprintf(stderr, "get_g_lock_ctx failed");
1247 return false;
1250 req = g_lock_watch_data_send(
1251 ev, ev, ctx, lockname, (struct server_id) { .pid = 0 });
1252 if (req == NULL) {
1253 fprintf(stderr, "get_g_lock_ctx failed");
1254 return false;
1257 status = g_lock_lock(
1258 ctx,
1259 lockname,
1260 G_LOCK_WRITE,
1261 (struct timeval) { .tv_sec = 999 },
1262 NULL, NULL);
1263 if (!NT_STATUS_IS_OK(status)) {
1264 fprintf(stderr,
1265 "g_lock_lock failed: %s\n",
1266 nt_errstr(status));
1267 return false;
1270 status = g_lock_write_data(
1271 ctx, lockname, lockname.dptr, lockname.dsize);
1272 if (!NT_STATUS_IS_OK(status)) {
1273 fprintf(stderr,
1274 "g_lock_write_data failed: %s\n",
1275 nt_errstr(status));
1276 return false;
1279 status = g_lock_write_data(ctx, lockname, NULL, 0);
1280 if (!NT_STATUS_IS_OK(status)) {
1281 fprintf(stderr,
1282 "g_lock_write_data failed: %s\n",
1283 nt_errstr(status));
1284 return false;
1287 status = g_lock_unlock(ctx, lockname);
1288 if (!NT_STATUS_IS_OK(status)) {
1289 fprintf(stderr,
1290 "g_lock_unlock failed: %s\n",
1291 nt_errstr(status));
1292 return false;
1295 ok = tevent_req_poll_ntstatus(req, ev, &status);
1296 if (!ok) {
1297 fprintf(stderr, "tevent_req_poll_ntstatus failed\n");
1298 return false;
1300 if (!NT_STATUS_IS_OK(status)) {
1301 fprintf(stderr,
1302 "tevent_req_poll_ntstatus failed: %s\n",
1303 nt_errstr(status));
1304 return false;
1307 return true;
1310 extern int torture_numops;
1311 extern int torture_nprocs;
1313 static struct timeval tp1, tp2;
1315 static void start_timer(void)
1317 gettimeofday(&tp1,NULL);
1320 static double end_timer(void)
1322 gettimeofday(&tp2,NULL);
1323 return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) -
1324 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
1328 * g_lock ping_pong
1331 bool run_g_lock_ping_pong(int dummy)
1333 struct tevent_context *ev = NULL;
1334 struct messaging_context *msg = NULL;
1335 struct g_lock_ctx *ctx = NULL;
1336 fstring name;
1337 NTSTATUS status;
1338 int i = 0;
1339 bool ret = false;
1340 bool ok;
1341 unsigned count = 0;
1343 torture_nprocs = MAX(2, torture_nprocs);
1345 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
1346 if (!ok) {
1347 goto fail;
1350 start_timer();
1352 snprintf(name, sizeof(name), "ping_pong_%d", i);
1354 status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_WRITE,
1355 (struct timeval) { .tv_sec = 60 },
1356 NULL, NULL);
1357 if (!NT_STATUS_IS_OK(status)) {
1358 fprintf(stderr, "g_lock_lock failed: %s\n",
1359 nt_errstr(status));
1360 goto fail;
1363 for (i=0; i<torture_numops; i++) {
1365 name[10] = '0' + ((i+1) % torture_nprocs);
1367 status = g_lock_lock(ctx, string_term_tdb_data(name),
1368 G_LOCK_WRITE,
1369 (struct timeval) { .tv_sec = 60 },
1370 NULL, NULL);
1371 if (!NT_STATUS_IS_OK(status)) {
1372 fprintf(stderr, "g_lock_lock failed: %s\n",
1373 nt_errstr(status));
1374 goto fail;
1377 name[10] = '0' + ((i) % torture_nprocs);
1379 status = g_lock_unlock(ctx, string_term_tdb_data(name));
1380 if (!NT_STATUS_IS_OK(status)) {
1381 fprintf(stderr, "g_lock_unlock failed: %s\n",
1382 nt_errstr(status));
1383 goto fail;
1386 count++;
1388 if (end_timer() > 1.0) {
1389 printf("%8u locks/sec\r",
1390 (unsigned)(2*count/end_timer()));
1391 fflush(stdout);
1392 start_timer();
1393 count=0;
1397 ret = true;
1398 fail:
1399 TALLOC_FREE(ctx);
1400 TALLOC_FREE(msg);
1401 TALLOC_FREE(ev);
1402 return ret;