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
= samba_tevent_context_init(mem_ctx
);
35 fprintf(stderr
, "tevent_context_init failed\n");
38 *msg
= messaging_init(*ev
, *ev
);
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
);
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";
415 struct tevent_req
*req
;
419 if ((pipe(ready_pipe
) != 0) || (pipe(exit_pipe
) != 0)) {
420 perror("pipe failed");
426 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
432 perror("fork failed");
437 close(ready_pipe
[0]);
439 ok
= lock4_child(lockname
, ready_pipe
[1], exit_pipe
[0]);
443 close(ready_pipe
[1]);
446 if (sys_read(ready_pipe
[0], &ok
, sizeof(ok
)) != sizeof(ok
)) {
447 perror("read failed");
452 fprintf(stderr
, "child returned error\n");
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",
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",
472 req
= g_lock_lock_send(ev
, ev
, ctx
, lockname
, G_LOCK_WRITE
);
474 fprintf(stderr
, "g_lock_lock send failed\n");
477 tevent_req_set_callback(req
, lock4_done
, &done
);
479 req
= tevent_wakeup_send(ev
, ev
, timeval_current_ofs(1, 0));
481 fprintf(stderr
, "tevent_wakeup_send failed\n");
484 tevent_req_set_callback(req
, lock4_waited
, &exit_pipe
[1]);
489 int tevent_ret
= tevent_loop_once(ev
);
490 if (tevent_ret
!= 0) {
491 perror("tevent_loop_once failed");
504 struct lock5_parser_state
{
508 static void lock5_parser(const struct g_lock_rec
*locks
,
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";
529 int exit_pipe
[2], ready_pipe
[2];
539 if ((pipe(exit_pipe
) != 0) || (pipe(ready_pipe
) != 0)) {
540 perror("pipe failed");
544 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
546 fprintf(stderr
, "get_g_lock_ctx failed");
550 for (i
=0; i
<nprocs
; i
++) {
555 perror("fork failed");
564 close(ready_pipe
[0]);
567 ok
= get_g_lock_ctx(talloc_tos(), &ev
, &msg
, &ctx
);
569 fprintf(stderr
, "get_g_lock_ctx failed");
572 status
= g_lock_lock(ctx
, lockname
, G_LOCK_READ
,
573 (struct timeval
) { .tv_sec
= 1 });
574 if (!NT_STATUS_IS_OK(status
)) {
576 "child g_lock_lock failed %s\n",
580 close(ready_pipe
[1]);
581 nread
= sys_read(exit_pipe
[0], &c
, sizeof(c
));
583 fprintf(stderr
, "sys_read returned %zu (%s)\n",
584 nread
, strerror(errno
));
591 close(ready_pipe
[1]);
593 nread
= sys_read(ready_pipe
[0], &c
, sizeof(c
));
595 fprintf(stderr
, "sys_read returned %zu (%s)\n",
596 nread
, strerror(errno
));
602 for (i
=0; i
<nprocs
; i
++) {
604 ret
= waitpid(-1, &child_status
, 0);
606 perror("waitpid failed");
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",
621 if (state
.num_locks
!= (nprocs
- i
)) {
622 fprintf(stderr
, "nlocks=%zu, expected %zu\n",
623 state
.num_locks
, (nprocs
-i
));
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",
634 status
= g_lock_unlock(ctx
, lockname
);
635 if (!NT_STATUS_IS_OK(status
)) {
636 fprintf(stderr
, "g_lock_unlock failed %s\n",