2 * Unix SMB/CIFS implementation.
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/>.
21 #include "torture/proto.h"
22 #include "system/filesys.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
= server_event_context();
35 fprintf(stderr
, "tevent_context_init failed\n");
38 *msg
= server_messaging_context();
40 fprintf(stderr
, "messaging_init failed\n");
44 *ctx
= g_lock_ctx_init(*ev
, *msg
);
46 fprintf(stderr
, "g_lock_ctx_init failed\n");
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";
65 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
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",
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",
86 status
= g_lock_unlock(ctx
, lockname
);
87 if (!NT_STATUS_IS_OK(status
)) {
88 fprintf(stderr
, "g_lock_unlock failed: %s\n",
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",
108 struct lock2_parser_state
{
113 static void lock2_parser(const struct g_lock_rec
*locks
,
119 struct lock2_parser_state
*state
= private_data
;
121 if (datalen
!= sizeof(uint8_t)) {
124 *state
->rdata
= *data
;
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";
140 struct lock2_parser_state state
= { .rdata
= &rdata
};
145 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
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",
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",
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",
172 status
= g_lock_unlock(ctx
, lockname
);
173 if (!NT_STATUS_IS_OK(status
)) {
174 fprintf(stderr
, "g_lock_unlock failed: %s\n",
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",
187 fprintf(stderr
, "Could not parse data\n");
191 fprintf(stderr
, "Returned %"PRIu8
", expected %"PRIu8
"\n",
204 struct lock3_parser_state
{
205 struct server_id self
;
206 enum g_lock_type lock_type
;
210 static void lock3_parser(const struct g_lock_rec
*locks
,
216 struct lock3_parser_state
*state
= private_data
;
219 fprintf(stderr
, "datalen=%zu\n", datalen
);
222 if (num_locks
!= 1) {
223 fprintf(stderr
, "num_locks=%zu\n", num_locks
);
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
);
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
));
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
;
257 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
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",
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
));
280 state
.lock_type
= G_LOCK_READ
;
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",
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",
301 state
.lock_type
= G_LOCK_WRITE
;
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",
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
;
333 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
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",
346 n
= sys_write(ready_pipe
, &ok
, sizeof(ok
));
347 if (n
!= sizeof(ok
)) {
348 fprintf(stderr
, "child: write failed\n");
353 n
= sys_read(exit_pipe
, &ok
, sizeof(ok
));
355 fprintf(stderr
, "child: read failed\n");
363 static void lock4_done(struct tevent_req
*subreq
)
365 int *done
= tevent_req_callback_data_void(subreq
);
368 status
= g_lock_lock_recv(subreq
);
370 if (!NT_STATUS_IS_OK(status
)) {
371 fprintf(stderr
, "g_lock_lock_recv returned %s\n",
379 static void lock4_waited(struct tevent_req
*subreq
)
381 int *exit_pipe
= tevent_req_callback_data_void(subreq
);
388 ok
= tevent_wakeup_recv(subreq
);
391 fprintf(stderr
, "tevent_wakeup_recv failed\n");
395 child
= wait(&status
);
397 printf("child %d exited with %d\n", (int)child
, status
);
400 struct lock4_check_state
{
405 static void lock4_check(const struct g_lock_rec
*locks
,
411 struct lock4_check_state
*state
= private_data
;
413 if (num_locks
!= 1) {
414 fprintf(stderr
, "num_locks=%zu\n", num_locks
);
418 if (!serverid_equal(&state
->me
, &locks
[0].pid
)) {
419 struct server_id_buf buf1
, buf2
;
420 fprintf(stderr
, "me=%s, locker=%s\n",
421 server_id_str_buf(state
->me
, &buf1
),
422 server_id_str_buf(locks
[0].pid
, &buf2
));
426 if (locks
[0].lock_type
!= G_LOCK_WRITE
) {
427 fprintf(stderr
, "wrong lock type: %d\n",
428 (int)locks
[0].lock_type
);
436 * Test a lock conflict
439 bool run_g_lock4(int dummy
)
441 struct tevent_context
*ev
= NULL
;
442 struct messaging_context
*msg
= NULL
;
443 struct g_lock_ctx
*ctx
= NULL
;
444 const char *lockname
= "lock4";
450 struct tevent_req
*req
;
454 if ((pipe(ready_pipe
) != 0) || (pipe(exit_pipe
) != 0)) {
455 perror("pipe failed");
461 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
467 perror("fork failed");
472 close(ready_pipe
[0]);
474 ok
= lock4_child(lockname
, ready_pipe
[1], exit_pipe
[0]);
478 close(ready_pipe
[1]);
481 if (sys_read(ready_pipe
[0], &ok
, sizeof(ok
)) != sizeof(ok
)) {
482 perror("read failed");
487 fprintf(stderr
, "child returned error\n");
491 status
= g_lock_lock(ctx
, lockname
, G_LOCK_WRITE
,
492 (struct timeval
) { .tv_usec
= 1 });
493 if (!NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
494 fprintf(stderr
, "g_lock_lock returned %s\n",
499 status
= g_lock_lock(ctx
, lockname
, G_LOCK_READ
,
500 (struct timeval
) { .tv_usec
= 1 });
501 if (!NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
502 fprintf(stderr
, "g_lock_lock returned %s\n",
507 req
= g_lock_lock_send(ev
, ev
, ctx
, lockname
, G_LOCK_WRITE
);
509 fprintf(stderr
, "g_lock_lock send failed\n");
512 tevent_req_set_callback(req
, lock4_done
, &done
);
514 req
= tevent_wakeup_send(ev
, ev
, timeval_current_ofs(1, 0));
516 fprintf(stderr
, "tevent_wakeup_send failed\n");
519 tevent_req_set_callback(req
, lock4_waited
, &exit_pipe
[1]);
524 int tevent_ret
= tevent_loop_once(ev
);
525 if (tevent_ret
!= 0) {
526 perror("tevent_loop_once failed");
532 struct lock4_check_state state
= {
533 .me
= messaging_server_id(msg
)
536 status
= g_lock_dump(ctx
, lockname
, lock4_check
, &state
);
537 if (!NT_STATUS_IS_OK(status
)) {
538 fprintf(stderr
, "g_lock_dump failed: %s\n",
543 fprintf(stderr
, "lock4_check failed\n");
556 struct lock5_parser_state
{
560 static void lock5_parser(const struct g_lock_rec
*locks
,
566 struct lock5_parser_state
*state
= private_data
;
567 state
->num_locks
= num_locks
;
571 * Test heuristic cleanup
574 bool run_g_lock5(int dummy
)
576 struct tevent_context
*ev
= NULL
;
577 struct messaging_context
*msg
= NULL
;
578 struct g_lock_ctx
*ctx
= NULL
;
579 const char *lockname
= "lock5";
581 int exit_pipe
[2], ready_pipe
[2];
591 if ((pipe(exit_pipe
) != 0) || (pipe(ready_pipe
) != 0)) {
592 perror("pipe failed");
596 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
598 fprintf(stderr
, "get_g_lock_ctx failed");
602 for (i
=0; i
<nprocs
; i
++) {
607 perror("fork failed");
614 status
= reinit_after_fork(msg
, ev
, false, "");
616 close(ready_pipe
[0]);
619 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
621 fprintf(stderr
, "get_g_lock_ctx failed");
624 status
= g_lock_lock(ctx
, lockname
, G_LOCK_READ
,
625 (struct timeval
) { .tv_sec
= 1 });
626 if (!NT_STATUS_IS_OK(status
)) {
628 "child g_lock_lock failed %s\n",
632 close(ready_pipe
[1]);
633 nread
= sys_read(exit_pipe
[0], &c
, sizeof(c
));
635 fprintf(stderr
, "sys_read returned %zu (%s)\n",
636 nread
, strerror(errno
));
643 close(ready_pipe
[1]);
645 nread
= sys_read(ready_pipe
[0], &c
, sizeof(c
));
647 fprintf(stderr
, "sys_read returned %zu (%s)\n",
648 nread
, strerror(errno
));
654 for (i
=0; i
<nprocs
; i
++) {
656 ret
= waitpid(-1, &child_status
, 0);
658 perror("waitpid failed");
663 for (i
=0; i
<nprocs
; i
++) {
664 struct lock5_parser_state state
;
666 status
= g_lock_dump(ctx
, lockname
, lock5_parser
, &state
);
667 if (!NT_STATUS_IS_OK(status
)) {
668 fprintf(stderr
, "g_lock_dump returned %s\n",
673 if (state
.num_locks
!= (nprocs
- i
)) {
674 fprintf(stderr
, "nlocks=%zu, expected %zu\n",
675 state
.num_locks
, (nprocs
-i
));
679 status
= g_lock_lock(ctx
, lockname
, G_LOCK_READ
,
680 (struct timeval
) { .tv_sec
= 1 });
681 if (!NT_STATUS_IS_OK(status
)) {
682 fprintf(stderr
, "g_lock_lock failed %s\n",
686 status
= g_lock_unlock(ctx
, lockname
);
687 if (!NT_STATUS_IS_OK(status
)) {
688 fprintf(stderr
, "g_lock_unlock failed %s\n",
698 struct lock6_parser_state
{
702 static void lock6_parser(const struct g_lock_rec
*locks
,
708 struct lock6_parser_state
*state
= private_data
;
709 state
->num_locks
= num_locks
;
713 * Test cleanup with contention and stale locks
716 bool run_g_lock6(int dummy
)
718 struct tevent_context
*ev
= NULL
;
719 struct messaging_context
*msg
= NULL
;
720 struct g_lock_ctx
*ctx
= NULL
;
721 const char *lockname
= "lock6";
723 int exit_pipe
[2], ready_pipe
[2];
731 if ((pipe(exit_pipe
) != 0) || (pipe(ready_pipe
) != 0)) {
732 perror("pipe failed");
736 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
738 fprintf(stderr
, "get_g_lock_ctx failed");
743 for (i
=0; i
<nprocs
; i
++) {
748 perror("fork failed");
755 status
= reinit_after_fork(msg
, ev
, false, "");
756 if (!NT_STATUS_IS_OK(status
)) {
757 fprintf(stderr
, "reinit_after_fork failed: %s\n",
762 close(ready_pipe
[0]);
765 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
767 fprintf(stderr
, "get_g_lock_ctx failed");
770 status
= g_lock_lock(ctx
, lockname
, G_LOCK_READ
,
771 (struct timeval
) { .tv_sec
= 1 });
772 if (!NT_STATUS_IS_OK(status
)) {
774 "child g_lock_lock failed %s\n",
781 close(ready_pipe
[1]);
782 nread
= sys_read(exit_pipe
[0], &c
, sizeof(c
));
784 fprintf(stderr
, "sys_read returned %zu (%s)\n",
785 nread
, strerror(errno
));
792 close(ready_pipe
[1]);
794 nread
= sys_read(ready_pipe
[0], &c
, sizeof(c
));
796 fprintf(stderr
, "sys_read returned %zd (%s)\n",
797 nread
, strerror(errno
));
803 ret
= waitpid(-1, &child_status
, 0);
805 perror("waitpid failed");
811 struct lock6_parser_state state
;
813 status
= g_lock_dump(ctx
, lockname
, lock6_parser
, &state
);
814 if (!NT_STATUS_IS_OK(status
)) {
815 fprintf(stderr
, "g_lock_dump returned %s\n",
820 if (state
.num_locks
!= nprocs
) {
821 fprintf(stderr
, "nlocks=%zu, expected %zu\n",
822 state
.num_locks
, nprocs
);
826 status
= g_lock_lock(ctx
, lockname
, G_LOCK_WRITE
,
827 (struct timeval
) { .tv_sec
= 1 });
828 if (!NT_STATUS_EQUAL(status
, NT_STATUS_IO_TIMEOUT
)) {
829 fprintf(stderr
, "g_lock_lock should have failed with %s - %s\n",
830 nt_errstr(NT_STATUS_IO_TIMEOUT
),
840 ret
= waitpid(-1, &child_status
, 0);
842 perror("waitpid failed");
850 extern int torture_numops
;
851 extern int torture_nprocs
;
853 static struct timeval tp1
, tp2
;
855 static void start_timer(void)
857 gettimeofday(&tp1
,NULL
);
860 static double end_timer(void)
862 gettimeofday(&tp2
,NULL
);
863 return (tp2
.tv_sec
+ (tp2
.tv_usec
*1.0e-6)) -
864 (tp1
.tv_sec
+ (tp1
.tv_usec
*1.0e-6));
871 bool run_g_lock_ping_pong(int dummy
)
873 struct tevent_context
*ev
= NULL
;
874 struct messaging_context
*msg
= NULL
;
875 struct g_lock_ctx
*ctx
= NULL
;
883 torture_nprocs
= MAX(2, torture_nprocs
);
885 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
892 snprintf(name
, sizeof(name
), "ping_pong_%d", i
);
894 status
= g_lock_lock(ctx
, name
, G_LOCK_WRITE
,
895 (struct timeval
) { .tv_sec
= 60 });
896 if (!NT_STATUS_IS_OK(status
)) {
897 fprintf(stderr
, "g_lock_lock failed: %s\n",
902 for (i
=0; i
<torture_numops
; i
++) {
904 name
[10] = '0' + ((i
+1) % torture_nprocs
);
906 status
= g_lock_lock(ctx
, name
, G_LOCK_WRITE
,
907 (struct timeval
) { .tv_sec
= 60 });
908 if (!NT_STATUS_IS_OK(status
)) {
909 fprintf(stderr
, "g_lock_lock failed: %s\n",
914 name
[10] = '0' + ((i
) % torture_nprocs
);
916 status
= g_lock_unlock(ctx
, name
);
917 if (!NT_STATUS_IS_OK(status
)) {
918 fprintf(stderr
, "g_lock_unlock failed: %s\n",
925 if (end_timer() > 1.0) {
926 printf("%8u locks/sec\r",
927 (unsigned)(2*count
/end_timer()));