s3: libsmb: In cli_qpathinfo_send() (SMBtrans2:TRANSACT2_QPATHINFO) check for DFS...
[Samba.git] / source3 / torture / test_g_lock.c
blob5113339396091e9e67abcbb710a232171d225ac8
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 if (!NT_STATUS_IS_OK(status)) {
76 fprintf(stderr, "g_lock_lock failed: %s\n",
77 nt_errstr(status));
78 goto fail;
81 status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
82 (struct timeval) { .tv_sec = 1 });
83 if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
84 fprintf(stderr, "Double lock got %s\n",
85 nt_errstr(status));
86 goto fail;
89 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
90 if (!NT_STATUS_IS_OK(status)) {
91 fprintf(stderr, "g_lock_unlock failed: %s\n",
92 nt_errstr(status));
93 goto fail;
96 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
97 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
98 fprintf(stderr, "g_lock_unlock returned: %s\n",
99 nt_errstr(status));
100 goto fail;
103 ret = true;
104 fail:
105 TALLOC_FREE(ctx);
106 TALLOC_FREE(msg);
107 TALLOC_FREE(ev);
108 return ret;
111 struct lock2_parser_state {
112 uint8_t *rdata;
113 bool ok;
116 static void lock2_parser(struct server_id exclusive,
117 size_t num_shared,
118 const struct server_id *shared,
119 const uint8_t *data,
120 size_t datalen,
121 void *private_data)
123 struct lock2_parser_state *state = private_data;
125 if (datalen != sizeof(uint8_t)) {
126 return;
128 *state->rdata = *data;
129 state->ok = true;
133 * Test g_lock_write_data
136 bool run_g_lock2(int dummy)
138 struct tevent_context *ev = NULL;
139 struct messaging_context *msg = NULL;
140 struct g_lock_ctx *ctx = NULL;
141 const char *lockname = "lock2";
142 uint8_t data = 42;
143 uint8_t rdata;
144 struct lock2_parser_state state = { .rdata = &rdata };
145 NTSTATUS status;
146 bool ret = false;
147 bool ok;
149 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
150 if (!ok) {
151 goto fail;
154 status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
155 &data, sizeof(data));
156 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_LOCKED)) {
157 fprintf(stderr, "unlocked g_lock_write_data returned %s\n",
158 nt_errstr(status));
159 goto fail;
162 status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
163 (struct timeval) { .tv_sec = 1 });
164 if (!NT_STATUS_IS_OK(status)) {
165 fprintf(stderr, "g_lock_lock returned %s\n",
166 nt_errstr(status));
167 goto fail;
170 status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
171 &data, sizeof(data));
172 if (!NT_STATUS_IS_OK(status)) {
173 fprintf(stderr, "g_lock_write_data failed: %s\n",
174 nt_errstr(status));
175 goto fail;
178 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
179 if (!NT_STATUS_IS_OK(status)) {
180 fprintf(stderr, "g_lock_unlock failed: %s\n",
181 nt_errstr(status));
182 goto fail;
185 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
186 lock2_parser, &state);
187 if (!NT_STATUS_IS_OK(status)) {
188 fprintf(stderr, "g_lock_dump failed: %s\n",
189 nt_errstr(status));
190 goto fail;
193 if (!state.ok) {
194 fprintf(stderr, "Could not parse data\n");
195 goto fail;
197 if (rdata != data) {
198 fprintf(stderr, "Returned %"PRIu8", expected %"PRIu8"\n",
199 rdata, data);
200 goto fail;
203 ret = true;
204 fail:
205 TALLOC_FREE(ctx);
206 TALLOC_FREE(msg);
207 TALLOC_FREE(ev);
208 return ret;
211 struct lock3_parser_state {
212 struct server_id self;
213 enum g_lock_type lock_type;
214 bool ok;
217 static void lock3_parser(struct server_id exclusive,
218 size_t num_shared,
219 const struct server_id *shared,
220 const uint8_t *data,
221 size_t datalen,
222 void *private_data)
224 struct lock3_parser_state *state = private_data;
225 size_t num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
226 const struct server_id *pid;
228 if (datalen != 0) {
229 fprintf(stderr, "datalen=%zu\n", datalen);
230 return;
232 if (num_locks != 1) {
233 fprintf(stderr, "num_locks=%zu\n", num_locks);
234 return;
237 if (state->lock_type == G_LOCK_WRITE) {
238 if (exclusive.pid == 0) {
239 fprintf(stderr, "Found READ, expected WRITE\n");
240 return;
242 } else {
243 if (exclusive.pid != 0) {
244 fprintf(stderr, "Found WRITE, expected READ\n");
245 return;
249 pid = (exclusive.pid != 0) ? &exclusive : &shared[0];
251 if (!server_id_equal(pid, &state->self)) {
252 struct server_id_buf tmp1, tmp2;
253 fprintf(stderr, "found pid %s, expected %s\n",
254 server_id_str_buf(*pid, &tmp1),
255 server_id_str_buf(state->self, &tmp2));
256 return;
259 state->ok = true;
263 * Test lock upgrade/downgrade
266 bool run_g_lock3(int dummy)
268 struct tevent_context *ev = NULL;
269 struct messaging_context *msg = NULL;
270 struct g_lock_ctx *ctx = NULL;
271 const char *lockname = "lock3";
272 struct lock3_parser_state state;
273 NTSTATUS status;
274 bool ret = false;
275 bool ok;
277 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
278 if (!ok) {
279 goto fail;
282 state.self = messaging_server_id(msg);
284 status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_READ,
285 (struct timeval) { .tv_sec = 1 });
286 if (!NT_STATUS_IS_OK(status)) {
287 fprintf(stderr, "g_lock_lock returned %s\n",
288 nt_errstr(status));
289 goto fail;
292 state.lock_type = G_LOCK_READ;
293 state.ok = false;
295 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
296 lock3_parser, &state);
297 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
298 fprintf(stderr, "g_lock_dump returned %s\n",
299 nt_errstr(status));
300 goto fail;
302 if (!state.ok) {
303 goto fail;
306 status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_UPGRADE,
307 (struct timeval) { .tv_sec = 1 });
308 if (!NT_STATUS_IS_OK(status)) {
309 fprintf(stderr, "g_lock_lock returned %s\n",
310 nt_errstr(status));
311 goto fail;
314 state.lock_type = G_LOCK_WRITE;
315 state.ok = false;
317 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
318 lock3_parser, &state);
319 if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
320 fprintf(stderr, "g_lock_dump returned %s\n",
321 nt_errstr(status));
322 goto fail;
324 if (!state.ok) {
325 goto fail;
329 ret = true;
330 fail:
331 TALLOC_FREE(ctx);
332 TALLOC_FREE(msg);
333 TALLOC_FREE(ev);
334 return ret;
337 static bool lock4_child(const char *lockname,
338 enum g_lock_type lock_type,
339 int ready_pipe,
340 int exit_pipe)
342 struct tevent_context *ev = NULL;
343 struct messaging_context *msg = NULL;
344 struct g_lock_ctx *ctx = NULL;
345 NTSTATUS status;
346 ssize_t n;
347 bool ok;
349 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
350 if (!ok) {
351 return false;
354 status = g_lock_lock(
355 ctx,
356 string_term_tdb_data(lockname),
357 lock_type,
358 (struct timeval) { .tv_sec = 1 });
359 if (!NT_STATUS_IS_OK(status)) {
360 fprintf(stderr, "child: g_lock_lock returned %s\n",
361 nt_errstr(status));
362 return false;
365 n = sys_write(ready_pipe, &ok, sizeof(ok));
366 if (n != sizeof(ok)) {
367 fprintf(stderr, "child: write failed\n");
368 return false;
371 if (ok) {
372 n = sys_read(exit_pipe, &ok, sizeof(ok));
373 if (n != 0) {
374 fprintf(stderr, "child: read failed\n");
375 return false;
379 return true;
382 static void lock4_done(struct tevent_req *subreq)
384 int *done = tevent_req_callback_data_void(subreq);
385 NTSTATUS status;
387 status = g_lock_lock_recv(subreq);
388 TALLOC_FREE(subreq);
389 if (!NT_STATUS_IS_OK(status)) {
390 fprintf(stderr, "g_lock_lock_recv returned %s\n",
391 nt_errstr(status));
392 *done = -1;
393 return;
395 *done = 1;
398 static void lock4_waited(struct tevent_req *subreq)
400 int *exit_pipe = tevent_req_callback_data_void(subreq);
401 pid_t child;
402 int status;
403 bool ok;
405 printf("waited\n");
407 ok = tevent_wakeup_recv(subreq);
408 TALLOC_FREE(subreq);
409 if (!ok) {
410 fprintf(stderr, "tevent_wakeup_recv failed\n");
412 close(*exit_pipe);
414 child = wait(&status);
416 printf("child %d exited with %d\n", (int)child, status);
419 struct lock4_check_state {
420 struct server_id me;
421 bool ok;
424 static void lock4_check(struct server_id exclusive,
425 size_t num_shared,
426 const struct server_id *shared,
427 const uint8_t *data,
428 size_t datalen,
429 void *private_data)
431 struct lock4_check_state *state = private_data;
432 size_t num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
434 if (num_locks != 1) {
435 fprintf(stderr, "num_locks=%zu\n", num_locks);
436 return;
439 if (exclusive.pid == 0) {
440 fprintf(stderr, "Wrong lock type, not WRITE\n");
441 return;
444 if (!server_id_equal(&state->me, &exclusive)) {
445 struct server_id_buf buf1, buf2;
446 fprintf(stderr, "me=%s, locker=%s\n",
447 server_id_str_buf(state->me, &buf1),
448 server_id_str_buf(exclusive, &buf2));
449 return;
452 state->ok = true;
456 * Test a lock conflict: Contend with a WRITE lock
459 bool run_g_lock4(int dummy)
461 struct tevent_context *ev = NULL;
462 struct messaging_context *msg = NULL;
463 struct g_lock_ctx *ctx = NULL;
464 const char *lockname = "lock4";
465 TDB_DATA key = string_term_tdb_data(lockname);
466 pid_t child;
467 int ready_pipe[2];
468 int exit_pipe[2];
469 NTSTATUS status;
470 bool ret = false;
471 struct tevent_req *req;
472 bool ok;
473 int done;
475 if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
476 perror("pipe failed");
477 return false;
480 child = fork();
482 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
483 if (!ok) {
484 goto fail;
487 if (child == -1) {
488 perror("fork failed");
489 return false;
492 if (child == 0) {
493 close(ready_pipe[0]);
494 close(exit_pipe[1]);
495 ok = lock4_child(
496 lockname, G_LOCK_WRITE, ready_pipe[1], exit_pipe[0]);
497 exit(ok ? 0 : 1);
500 close(ready_pipe[1]);
501 close(exit_pipe[0]);
503 if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
504 perror("read failed");
505 return false;
508 if (!ok) {
509 fprintf(stderr, "child returned error\n");
510 return false;
513 status = g_lock_lock(
514 ctx, key, G_LOCK_WRITE, (struct timeval) { .tv_usec = 1 });
515 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
516 fprintf(stderr, "g_lock_lock returned %s\n",
517 nt_errstr(status));
518 goto fail;
521 status = g_lock_lock(
522 ctx, key, G_LOCK_READ, (struct timeval) { .tv_usec = 1 });
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 req = g_lock_lock_send(ev, ev, ctx, key, G_LOCK_WRITE);
530 if (req == NULL) {
531 fprintf(stderr, "g_lock_lock send failed\n");
532 goto fail;
534 tevent_req_set_callback(req, lock4_done, &done);
536 req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
537 if (req == NULL) {
538 fprintf(stderr, "tevent_wakeup_send failed\n");
539 goto fail;
541 tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
543 done = 0;
545 while (done == 0) {
546 int tevent_ret = tevent_loop_once(ev);
547 if (tevent_ret != 0) {
548 perror("tevent_loop_once failed");
549 goto fail;
554 struct lock4_check_state state = {
555 .me = messaging_server_id(msg)
558 status = g_lock_dump(ctx, key, lock4_check, &state);
559 if (!NT_STATUS_IS_OK(status)) {
560 fprintf(stderr, "g_lock_dump failed: %s\n",
561 nt_errstr(status));
562 goto fail;
564 if (!state.ok) {
565 fprintf(stderr, "lock4_check failed\n");
566 goto fail;
570 ret = true;
571 fail:
572 TALLOC_FREE(ctx);
573 TALLOC_FREE(msg);
574 TALLOC_FREE(ev);
575 return ret;
579 * Test a lock conflict: Contend with a READ lock
582 bool run_g_lock4a(int dummy)
584 struct tevent_context *ev = NULL;
585 struct messaging_context *msg = NULL;
586 struct g_lock_ctx *ctx = NULL;
587 const char *lockname = "lock4a";
588 TDB_DATA key = string_term_tdb_data(lockname);
589 pid_t child;
590 int ready_pipe[2];
591 int exit_pipe[2];
592 NTSTATUS status;
593 bool ret = false;
594 struct tevent_req *req;
595 bool ok;
596 int done;
598 if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
599 perror("pipe failed");
600 return false;
603 child = fork();
605 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
606 if (!ok) {
607 goto fail;
610 if (child == -1) {
611 perror("fork failed");
612 return false;
615 if (child == 0) {
616 close(ready_pipe[0]);
617 close(exit_pipe[1]);
618 ok = lock4_child(
619 lockname, G_LOCK_READ, ready_pipe[1], exit_pipe[0]);
620 exit(ok ? 0 : 1);
623 close(ready_pipe[1]);
624 close(exit_pipe[0]);
626 if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
627 perror("read failed");
628 return false;
631 if (!ok) {
632 fprintf(stderr, "child returned error\n");
633 return false;
636 status = g_lock_lock(
637 ctx, key, G_LOCK_WRITE, (struct timeval) { .tv_usec = 1 });
638 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
639 fprintf(stderr, "g_lock_lock returned %s\n",
640 nt_errstr(status));
641 goto fail;
644 status = g_lock_lock(
645 ctx, key, G_LOCK_READ, (struct timeval) { .tv_usec = 1 });
646 if (!NT_STATUS_IS_OK(status)) {
647 fprintf(stderr, "g_lock_lock returned %s\n",
648 nt_errstr(status));
649 goto fail;
652 status = g_lock_unlock(ctx, key);
653 if (!NT_STATUS_IS_OK(status)) {
654 fprintf(stderr,
655 "g_lock_unlock returned %s\n",
656 nt_errstr(status));
657 goto fail;
660 req = g_lock_lock_send(ev, ev, ctx, key, G_LOCK_WRITE);
661 if (req == NULL) {
662 fprintf(stderr, "g_lock_lock send failed\n");
663 goto fail;
665 tevent_req_set_callback(req, lock4_done, &done);
667 req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
668 if (req == NULL) {
669 fprintf(stderr, "tevent_wakeup_send failed\n");
670 goto fail;
672 tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
674 done = 0;
676 while (done == 0) {
677 int tevent_ret = tevent_loop_once(ev);
678 if (tevent_ret != 0) {
679 perror("tevent_loop_once failed");
680 goto fail;
685 struct lock4_check_state state = {
686 .me = messaging_server_id(msg)
689 status = g_lock_dump(ctx, key, lock4_check, &state);
690 if (!NT_STATUS_IS_OK(status)) {
691 fprintf(stderr, "g_lock_dump failed: %s\n",
692 nt_errstr(status));
693 goto fail;
695 if (!state.ok) {
696 fprintf(stderr, "lock4_check failed\n");
697 goto fail;
701 ret = true;
702 fail:
703 TALLOC_FREE(ctx);
704 TALLOC_FREE(msg);
705 TALLOC_FREE(ev);
706 return ret;
709 struct lock5_parser_state {
710 size_t num_locks;
713 static void lock5_parser(struct server_id exclusive,
714 size_t num_shared,
715 const struct server_id *shared,
716 const uint8_t *data,
717 size_t datalen,
718 void *private_data)
720 struct lock5_parser_state *state = private_data;
721 state->num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
725 * Test heuristic cleanup
728 bool run_g_lock5(int dummy)
730 struct tevent_context *ev = NULL;
731 struct messaging_context *msg = NULL;
732 struct g_lock_ctx *ctx = NULL;
733 const char *lockname = "lock5";
734 pid_t child;
735 int exit_pipe[2], ready_pipe[2];
736 NTSTATUS status;
737 size_t i, nprocs;
738 int ret;
739 bool ok;
740 ssize_t nread;
741 char c;
743 nprocs = 5;
745 if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
746 perror("pipe failed");
747 return false;
750 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
751 if (!ok) {
752 fprintf(stderr, "get_g_lock_ctx failed");
753 return false;
756 for (i=0; i<nprocs; i++) {
758 child = fork();
760 if (child == -1) {
761 perror("fork failed");
762 return false;
765 if (child == 0) {
766 TALLOC_FREE(ctx);
768 status = reinit_after_fork(msg, ev, false, "");
770 close(ready_pipe[0]);
771 close(exit_pipe[1]);
773 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
774 if (!ok) {
775 fprintf(stderr, "get_g_lock_ctx failed");
776 exit(1);
778 status = g_lock_lock(ctx,
779 string_term_tdb_data(lockname),
780 G_LOCK_READ,
781 (struct timeval) { .tv_sec = 1 });
782 if (!NT_STATUS_IS_OK(status)) {
783 fprintf(stderr,
784 "child g_lock_lock failed %s\n",
785 nt_errstr(status));
786 exit(1);
788 close(ready_pipe[1]);
789 nread = sys_read(exit_pipe[0], &c, sizeof(c));
790 if (nread != 0) {
791 fprintf(stderr, "sys_read returned %zu (%s)\n",
792 nread, strerror(errno));
793 exit(1);
795 exit(0);
799 close(ready_pipe[1]);
801 nread = sys_read(ready_pipe[0], &c, sizeof(c));
802 if (nread != 0) {
803 fprintf(stderr, "sys_read returned %zu (%s)\n",
804 nread, strerror(errno));
805 return false;
808 close(exit_pipe[1]);
810 for (i=0; i<nprocs; i++) {
811 int child_status;
812 ret = waitpid(-1, &child_status, 0);
813 if (ret == -1) {
814 perror("waitpid failed");
815 return false;
819 for (i=0; i<nprocs; i++) {
820 struct lock5_parser_state state;
822 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
823 lock5_parser, &state);
824 if (!NT_STATUS_IS_OK(status)) {
825 fprintf(stderr, "g_lock_dump returned %s\n",
826 nt_errstr(status));
827 return false;
830 if (state.num_locks != (nprocs - i)) {
831 fprintf(stderr, "nlocks=%zu, expected %zu\n",
832 state.num_locks, (nprocs-i));
833 return false;
836 status = g_lock_lock(ctx, string_term_tdb_data(lockname),
837 G_LOCK_READ,
838 (struct timeval) { .tv_sec = 1 });
839 if (!NT_STATUS_IS_OK(status)) {
840 fprintf(stderr, "g_lock_lock failed %s\n",
841 nt_errstr(status));
842 return false;
844 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
845 if (!NT_STATUS_IS_OK(status)) {
846 fprintf(stderr, "g_lock_unlock failed %s\n",
847 nt_errstr(status));
848 return false;
853 return true;
856 struct lock6_parser_state {
857 size_t num_locks;
860 static void lock6_parser(struct server_id exclusive,
861 size_t num_shared,
862 const struct server_id *shared,
863 const uint8_t *data,
864 size_t datalen,
865 void *private_data)
867 struct lock6_parser_state *state = private_data;
868 state->num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
872 * Test cleanup with contention and stale locks
875 bool run_g_lock6(int dummy)
877 struct tevent_context *ev = NULL;
878 struct messaging_context *msg = NULL;
879 struct g_lock_ctx *ctx = NULL;
880 TDB_DATA lockname = string_term_tdb_data("lock6");
881 pid_t child;
882 int exit_pipe[2], ready_pipe[2];
883 NTSTATUS status;
884 size_t i, nprocs;
885 int ret;
886 bool ok;
887 ssize_t nread;
888 char c;
890 if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
891 perror("pipe failed");
892 return false;
895 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
896 if (!ok) {
897 fprintf(stderr, "get_g_lock_ctx failed");
898 return false;
902 * Wipe all stale locks -- in clustered mode there's no
903 * CLEAR_IF_FIRST
905 status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
906 (struct timeval) { .tv_sec = 1 });
907 if (!NT_STATUS_IS_OK(status)) {
908 fprintf(stderr, "g_lock_lock failed: %s\n",
909 nt_errstr(status));
910 return false;
912 status = g_lock_unlock(ctx, lockname);
913 if (!NT_STATUS_IS_OK(status)) {
914 fprintf(stderr, "g_lock_unlock failed: %s\n",
915 nt_errstr(status));
916 return false;
919 nprocs = 2;
920 for (i=0; i<nprocs; i++) {
922 child = fork();
924 if (child == -1) {
925 perror("fork failed");
926 return false;
929 if (child == 0) {
930 TALLOC_FREE(ctx);
932 status = reinit_after_fork(msg, ev, false, "");
933 if (!NT_STATUS_IS_OK(status)) {
934 fprintf(stderr, "reinit_after_fork failed: %s\n",
935 nt_errstr(status));
936 exit(1);
939 close(ready_pipe[0]);
940 close(exit_pipe[1]);
942 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
943 if (!ok) {
944 fprintf(stderr, "get_g_lock_ctx failed");
945 exit(1);
947 status = g_lock_lock(ctx,
948 lockname,
949 G_LOCK_READ,
950 (struct timeval) { .tv_sec = 1 });
951 if (!NT_STATUS_IS_OK(status)) {
952 fprintf(stderr,
953 "child g_lock_lock failed %s\n",
954 nt_errstr(status));
955 exit(1);
957 if (i == 0) {
958 exit(0);
960 close(ready_pipe[1]);
961 nread = sys_read(exit_pipe[0], &c, sizeof(c));
962 if (nread != 0) {
963 fprintf(stderr, "sys_read returned %zu (%s)\n",
964 nread, strerror(errno));
965 exit(1);
967 exit(0);
971 close(ready_pipe[1]);
973 nread = sys_read(ready_pipe[0], &c, sizeof(c));
974 if (nread != 0) {
975 fprintf(stderr, "sys_read returned %zd (%s)\n",
976 nread, strerror(errno));
977 return false;
981 int child_status;
982 ret = waitpid(-1, &child_status, 0);
983 if (ret == -1) {
984 perror("waitpid failed");
985 return false;
990 struct lock6_parser_state state;
992 status = g_lock_dump(ctx, lockname, lock6_parser, &state);
993 if (!NT_STATUS_IS_OK(status)) {
994 fprintf(stderr, "g_lock_dump returned %s\n",
995 nt_errstr(status));
996 return false;
999 if (state.num_locks != nprocs) {
1000 fprintf(stderr, "nlocks=%zu, expected %zu\n",
1001 state.num_locks, nprocs);
1002 return false;
1005 status = g_lock_lock(ctx,
1006 lockname,
1007 G_LOCK_WRITE,
1008 (struct timeval) { .tv_sec = 1 });
1009 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
1010 fprintf(stderr, "g_lock_lock should have failed with %s - %s\n",
1011 nt_errstr(NT_STATUS_IO_TIMEOUT),
1012 nt_errstr(status));
1013 return false;
1016 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
1017 (struct timeval) { .tv_sec = 1 });
1018 if (!NT_STATUS_IS_OK(status)) {
1019 fprintf(stderr, "g_lock_lock failed: %s\n",
1020 nt_errstr(status));
1021 return false;
1025 close(exit_pipe[1]);
1028 int child_status;
1029 ret = waitpid(-1, &child_status, 0);
1030 if (ret == -1) {
1031 perror("waitpid failed");
1032 return false;
1036 status = g_lock_lock(ctx, lockname, G_LOCK_UPGRADE,
1037 (struct timeval) { .tv_sec = 1 });
1038 if (!NT_STATUS_IS_OK(status)) {
1039 fprintf(stderr, "g_lock_lock failed: %s\n",
1040 nt_errstr(status));
1041 return false;
1044 return true;
1048 * Test upgrade deadlock
1051 bool run_g_lock7(int dummy)
1053 struct tevent_context *ev = NULL;
1054 struct messaging_context *msg = NULL;
1055 struct g_lock_ctx *ctx = NULL;
1056 const char *lockname = "lock7";
1057 TDB_DATA key = string_term_tdb_data(lockname);
1058 pid_t child;
1059 int ready_pipe[2];
1060 int down_pipe[2];
1061 ssize_t n;
1062 NTSTATUS status;
1063 bool ret = false;
1064 bool ok = true;
1066 if ((pipe(ready_pipe) != 0) || (pipe(down_pipe) != 0)) {
1067 perror("pipe failed");
1068 return false;
1071 child = fork();
1073 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
1074 if (!ok) {
1075 goto fail;
1078 if (child == -1) {
1079 perror("fork failed");
1080 return false;
1083 if (child == 0) {
1084 struct tevent_req *req = NULL;
1086 close(ready_pipe[0]);
1087 ready_pipe[0] = -1;
1088 close(down_pipe[1]);
1089 down_pipe[1] = -1;
1091 status = reinit_after_fork(msg, ev, false, "");
1092 if (!NT_STATUS_IS_OK(status)) {
1093 fprintf(stderr,
1094 "reinit_after_fork failed: %s\n",
1095 nt_errstr(status));
1096 exit(1);
1099 printf("%d: locking READ\n", (int)getpid());
1101 status = g_lock_lock(
1102 ctx,
1103 key,
1104 G_LOCK_READ,
1105 (struct timeval) { .tv_usec = 1 });
1106 if (!NT_STATUS_IS_OK(status)) {
1107 fprintf(stderr,
1108 "g_lock_lock(READ) failed: %s\n",
1109 nt_errstr(status));
1110 exit(1);
1113 ok = true;
1115 n = sys_write(ready_pipe[1], &ok, sizeof(ok));
1116 if (n != sizeof(ok)) {
1117 fprintf(stderr,
1118 "sys_write failed: %s\n",
1119 strerror(errno));
1120 exit(1);
1123 n = sys_read(down_pipe[0], &ok, sizeof(ok));
1124 if (n != sizeof(ok)) {
1125 fprintf(stderr,
1126 "sys_read failed: %s\n",
1127 strerror(errno));
1128 exit(1);
1131 printf("%d: starting UPGRADE\n", (int)getpid());
1133 req = g_lock_lock_send(
1134 msg,
1136 ctx,
1137 key,
1138 G_LOCK_UPGRADE);
1139 if (req == NULL) {
1140 fprintf(stderr, "g_lock_lock_send(UPGRADE) failed\n");
1141 exit(1);
1144 n = sys_write(ready_pipe[1], &ok, sizeof(ok));
1145 if (n != sizeof(ok)) {
1146 fprintf(stderr,
1147 "sys_write failed: %s\n",
1148 strerror(errno));
1149 exit(1);
1152 exit(0);
1155 close(ready_pipe[1]);
1156 close(down_pipe[0]);
1158 if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
1159 perror("read failed");
1160 return false;
1162 if (!ok) {
1163 fprintf(stderr, "child returned error\n");
1164 return false;
1167 status = g_lock_lock(
1168 ctx,
1169 key,
1170 G_LOCK_READ,
1171 (struct timeval) { .tv_usec = 1 });
1172 if (!NT_STATUS_IS_OK(status)) {
1173 fprintf(stderr,
1174 "g_lock_lock(READ) failed: %s\n",
1175 nt_errstr(status));
1176 goto fail;
1179 n = sys_write(down_pipe[1], &ok, sizeof(ok));
1180 if (n != sizeof(ok)) {
1181 fprintf(stderr,
1182 "sys_write failed: %s\n",
1183 strerror(errno));
1184 goto fail;
1187 if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
1188 perror("read failed");
1189 goto fail;
1192 status = g_lock_lock(
1193 ctx,
1194 key,
1195 G_LOCK_UPGRADE,
1196 (struct timeval) { .tv_sec = 10 });
1197 if (!NT_STATUS_EQUAL(status, NT_STATUS_POSSIBLE_DEADLOCK)) {
1198 fprintf(stderr,
1199 "g_lock_lock returned %s\n",
1200 nt_errstr(status));
1201 goto fail;
1204 ret = true;
1205 fail:
1206 TALLOC_FREE(ctx);
1207 TALLOC_FREE(msg);
1208 TALLOC_FREE(ev);
1209 return ret;
1212 bool run_g_lock8(int dummy)
1214 struct tevent_context *ev = NULL;
1215 struct messaging_context *msg = NULL;
1216 struct g_lock_ctx *ctx = NULL;
1217 struct tevent_req *req = NULL;
1218 TDB_DATA lockname = string_term_tdb_data("lock8");
1219 NTSTATUS status;
1220 bool ok;
1222 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
1223 if (!ok) {
1224 fprintf(stderr, "get_g_lock_ctx failed");
1225 return false;
1228 req = g_lock_watch_data_send(
1229 ev, ev, ctx, lockname, (struct server_id) { .pid = 0 });
1230 if (req == NULL) {
1231 fprintf(stderr, "get_g_lock_ctx failed");
1232 return false;
1235 status = g_lock_lock(
1236 ctx,
1237 lockname,
1238 G_LOCK_WRITE,
1239 (struct timeval) { .tv_sec = 999 });
1240 if (!NT_STATUS_IS_OK(status)) {
1241 fprintf(stderr,
1242 "g_lock_lock failed: %s\n",
1243 nt_errstr(status));
1244 return false;
1247 status = g_lock_write_data(
1248 ctx, lockname, lockname.dptr, lockname.dsize);
1249 if (!NT_STATUS_IS_OK(status)) {
1250 fprintf(stderr,
1251 "g_lock_write_data failed: %s\n",
1252 nt_errstr(status));
1253 return false;
1256 status = g_lock_write_data(ctx, lockname, NULL, 0);
1257 if (!NT_STATUS_IS_OK(status)) {
1258 fprintf(stderr,
1259 "g_lock_write_data failed: %s\n",
1260 nt_errstr(status));
1261 return false;
1264 status = g_lock_unlock(ctx, lockname);
1265 if (!NT_STATUS_IS_OK(status)) {
1266 fprintf(stderr,
1267 "g_lock_unlock failed: %s\n",
1268 nt_errstr(status));
1269 return false;
1272 ok = tevent_req_poll_ntstatus(req, ev, &status);
1273 if (!ok) {
1274 fprintf(stderr, "tevent_req_poll_ntstatus failed\n");
1275 return false;
1277 if (!NT_STATUS_IS_OK(status)) {
1278 fprintf(stderr,
1279 "tevent_req_poll_ntstatus failed: %s\n",
1280 nt_errstr(status));
1281 return false;
1284 return true;
1287 extern int torture_numops;
1288 extern int torture_nprocs;
1290 static struct timeval tp1, tp2;
1292 static void start_timer(void)
1294 gettimeofday(&tp1,NULL);
1297 static double end_timer(void)
1299 gettimeofday(&tp2,NULL);
1300 return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) -
1301 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
1305 * g_lock ping_pong
1308 bool run_g_lock_ping_pong(int dummy)
1310 struct tevent_context *ev = NULL;
1311 struct messaging_context *msg = NULL;
1312 struct g_lock_ctx *ctx = NULL;
1313 fstring name;
1314 NTSTATUS status;
1315 int i = 0;
1316 bool ret = false;
1317 bool ok;
1318 unsigned count = 0;
1320 torture_nprocs = MAX(2, torture_nprocs);
1322 ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
1323 if (!ok) {
1324 goto fail;
1327 start_timer();
1329 snprintf(name, sizeof(name), "ping_pong_%d", i);
1331 status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_WRITE,
1332 (struct timeval) { .tv_sec = 60 });
1333 if (!NT_STATUS_IS_OK(status)) {
1334 fprintf(stderr, "g_lock_lock failed: %s\n",
1335 nt_errstr(status));
1336 goto fail;
1339 for (i=0; i<torture_numops; i++) {
1341 name[10] = '0' + ((i+1) % torture_nprocs);
1343 status = g_lock_lock(ctx, string_term_tdb_data(name),
1344 G_LOCK_WRITE,
1345 (struct timeval) { .tv_sec = 60 });
1346 if (!NT_STATUS_IS_OK(status)) {
1347 fprintf(stderr, "g_lock_lock failed: %s\n",
1348 nt_errstr(status));
1349 goto fail;
1352 name[10] = '0' + ((i) % torture_nprocs);
1354 status = g_lock_unlock(ctx, string_term_tdb_data(name));
1355 if (!NT_STATUS_IS_OK(status)) {
1356 fprintf(stderr, "g_lock_unlock failed: %s\n",
1357 nt_errstr(status));
1358 goto fail;
1361 count++;
1363 if (end_timer() > 1.0) {
1364 printf("%8u locks/sec\r",
1365 (unsigned)(2*count/end_timer()));
1366 fflush(stdout);
1367 start_timer();
1368 count=0;
1372 ret = true;
1373 fail:
1374 TALLOC_FREE(ctx);
1375 TALLOC_FREE(msg);
1376 TALLOC_FREE(ev);
1377 return ret;