624f7cdd46e978855e67f3f69b9ca24155e775c6
[nivanova/samba-autobuild/.git] / source3 / torture / test_g_lock.c
1 /*
2  * Unix SMB/CIFS implementation.
3  * Test g_lock API
4  * Copyright (C) Volker Lendecke 2017
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
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
29 static bool get_g_lock_ctx(TALLOC_CTX *mem_ctx,
30                            struct tevent_context **ev,
31                            struct messaging_context **msg,
32                            struct g_lock_ctx **ctx)
33 {
34         *ev = server_event_context();
35         if (*ev == NULL) {
36                 fprintf(stderr, "tevent_context_init failed\n");
37                 return false;
38         }
39         *msg = server_messaging_context();
40         if (*msg == NULL) {
41                 fprintf(stderr, "messaging_init failed\n");
42                 TALLOC_FREE(*ev);
43                 return false;
44         }
45         *ctx = g_lock_ctx_init(*ev, *msg);
46         if (*ctx == NULL) {
47                 fprintf(stderr, "g_lock_ctx_init failed\n");
48                 TALLOC_FREE(*msg);
49                 TALLOC_FREE(*ev);
50                 return false;
51         }
52
53         return true;
54 }
55
56 bool run_g_lock1(int dummy)
57 {
58         struct tevent_context *ev = NULL;
59         struct messaging_context *msg = NULL;
60         struct g_lock_ctx *ctx = NULL;
61         const char *lockname = "lock1";
62         NTSTATUS status;
63         bool ret = false;
64         bool ok;
65
66         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
67         if (!ok) {
68                 goto fail;
69         }
70
71         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_READ,
72                              (struct timeval) { .tv_sec = 1 });
73         if (!NT_STATUS_IS_OK(status)) {
74                 fprintf(stderr, "g_lock_lock failed: %s\n",
75                         nt_errstr(status));
76                 goto fail;
77         }
78
79         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_READ,
80                              (struct timeval) { .tv_sec = 1 });
81         if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
82                 fprintf(stderr, "Double lock got %s\n",
83                         nt_errstr(status));
84                 goto fail;
85         }
86
87         status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
88         if (!NT_STATUS_IS_OK(status)) {
89                 fprintf(stderr, "g_lock_unlock failed: %s\n",
90                         nt_errstr(status));
91                 goto fail;
92         }
93
94         status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
95         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
96                 fprintf(stderr, "g_lock_unlock returned: %s\n",
97                         nt_errstr(status));
98                 goto fail;
99         }
100
101         ret = true;
102 fail:
103         TALLOC_FREE(ctx);
104         TALLOC_FREE(msg);
105         TALLOC_FREE(ev);
106         return ret;
107 }
108
109 struct lock2_parser_state {
110         uint8_t *rdata;
111         bool ok;
112 };
113
114 static void lock2_parser(const struct g_lock_rec *locks,
115                          size_t num_locks,
116                          const uint8_t *data,
117                          size_t datalen,
118                          void *private_data)
119 {
120         struct lock2_parser_state *state = private_data;
121
122         if (datalen != sizeof(uint8_t)) {
123                 return;
124         }
125         *state->rdata = *data;
126         state->ok = true;
127 }
128
129 /*
130  * Test g_lock_write_data
131  */
132
133 bool run_g_lock2(int dummy)
134 {
135         struct tevent_context *ev = NULL;
136         struct messaging_context *msg = NULL;
137         struct g_lock_ctx *ctx = NULL;
138         const char *lockname = "lock2";
139         uint8_t data = 42;
140         uint8_t rdata;
141         struct lock2_parser_state state = { .rdata = &rdata };
142         NTSTATUS status;
143         bool ret = false;
144         bool ok;
145
146         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
147         if (!ok) {
148                 goto fail;
149         }
150
151         status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
152                                    &data, sizeof(data));
153         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_LOCKED)) {
154                 fprintf(stderr, "unlocked g_lock_write_data returned %s\n",
155                         nt_errstr(status));
156                 goto fail;
157         }
158
159         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
160                              (struct timeval) { .tv_sec = 1 });
161         if (!NT_STATUS_IS_OK(status)) {
162                 fprintf(stderr, "g_lock_lock returned %s\n",
163                         nt_errstr(status));
164                 goto fail;
165         }
166
167         status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
168                                    &data, sizeof(data));
169         if (!NT_STATUS_IS_OK(status)) {
170                 fprintf(stderr, "g_lock_write_data failed: %s\n",
171                         nt_errstr(status));
172                 goto fail;
173         }
174
175         status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
176         if (!NT_STATUS_IS_OK(status)) {
177                 fprintf(stderr, "g_lock_unlock failed: %s\n",
178                         nt_errstr(status));
179                 goto fail;
180         }
181
182         status = g_lock_dump(ctx, string_term_tdb_data(lockname),
183                              lock2_parser, &state);
184         if (!NT_STATUS_IS_OK(status)) {
185                 fprintf(stderr, "g_lock_dump failed: %s\n",
186                         nt_errstr(status));
187                 goto fail;
188         }
189
190         if (!state.ok) {
191                 fprintf(stderr, "Could not parse data\n");
192                 goto fail;
193         }
194         if (rdata != data) {
195                 fprintf(stderr, "Returned %"PRIu8", expected %"PRIu8"\n",
196                         rdata, data);
197                 goto fail;
198         }
199
200         ret = true;
201 fail:
202         TALLOC_FREE(ctx);
203         TALLOC_FREE(msg);
204         TALLOC_FREE(ev);
205         return ret;
206 }
207
208 struct lock3_parser_state {
209         struct server_id self;
210         enum g_lock_type lock_type;
211         bool ok;
212 };
213
214 static void lock3_parser(const struct g_lock_rec *locks,
215                          size_t num_locks,
216                          const uint8_t *data,
217                          size_t datalen,
218                          void *private_data)
219 {
220         struct lock3_parser_state *state = private_data;
221
222         if (datalen != 0) {
223                 fprintf(stderr, "datalen=%zu\n", datalen);
224                 return;
225         }
226         if (num_locks != 1) {
227                 fprintf(stderr, "num_locks=%zu\n", num_locks);
228                 return;
229         }
230         if (locks[0].lock_type != state->lock_type) {
231                 fprintf(stderr, "found type %d, expected %d\n",
232                         (int)locks[0].lock_type, (int)state->lock_type);
233                 return;
234         }
235         if (!server_id_equal(&locks[0].pid, &state->self)) {
236                 struct server_id_buf tmp1, tmp2;
237                 fprintf(stderr, "found pid %s, expected %s\n",
238                         server_id_str_buf(locks[0].pid, &tmp1),
239                         server_id_str_buf(state->self, &tmp2));
240                 return;
241         }
242
243         state->ok = true;
244 }
245
246 /*
247  * Test lock upgrade/downgrade
248  */
249
250 bool run_g_lock3(int dummy)
251 {
252         struct tevent_context *ev = NULL;
253         struct messaging_context *msg = NULL;
254         struct g_lock_ctx *ctx = NULL;
255         const char *lockname = "lock3";
256         struct lock3_parser_state state;
257         NTSTATUS status;
258         bool ret = false;
259         bool ok;
260
261         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
262         if (!ok) {
263                 goto fail;
264         }
265
266         state.self = messaging_server_id(msg);
267
268         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_READ,
269                              (struct timeval) { .tv_sec = 1 });
270         if (!NT_STATUS_IS_OK(status)) {
271                 fprintf(stderr, "g_lock_lock returned %s\n",
272                         nt_errstr(status));
273                 goto fail;
274         }
275
276         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_READ,
277                              (struct timeval) { .tv_sec = 1 });
278         if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
279                 fprintf(stderr, "g_lock_lock returned %s, expected %s\n",
280                         nt_errstr(status), nt_errstr(NT_STATUS_WAS_LOCKED));
281                 goto fail;
282         }
283
284         state.lock_type = G_LOCK_READ;
285         state.ok = false;
286
287         status = g_lock_dump(ctx, string_term_tdb_data(lockname),
288                              lock3_parser, &state);
289         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
290                 fprintf(stderr, "g_lock_dump returned %s\n",
291                         nt_errstr(status));
292                 goto fail;
293         }
294         if (!state.ok) {
295                 goto fail;
296         }
297
298         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
299                              (struct timeval) { .tv_sec = 1 });
300         if (!NT_STATUS_IS_OK(status)) {
301                 fprintf(stderr, "g_lock_lock returned %s\n",
302                         nt_errstr(status));
303                 goto fail;
304         }
305
306         state.lock_type = G_LOCK_WRITE;
307         state.ok = false;
308
309         status = g_lock_dump(ctx, string_term_tdb_data(lockname),
310                              lock3_parser, &state);
311         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
312                 fprintf(stderr, "g_lock_dump returned %s\n",
313                         nt_errstr(status));
314                 goto fail;
315         }
316         if (!state.ok) {
317                 goto fail;
318         }
319
320
321         ret = true;
322 fail:
323         TALLOC_FREE(ctx);
324         TALLOC_FREE(msg);
325         TALLOC_FREE(ev);
326         return ret;
327 }
328
329 static bool lock4_child(const char *lockname,
330                         int ready_pipe, int exit_pipe)
331 {
332         struct tevent_context *ev = NULL;
333         struct messaging_context *msg = NULL;
334         struct g_lock_ctx *ctx = NULL;
335         NTSTATUS status;
336         ssize_t n;
337         bool ok;
338
339         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
340         if (!ok) {
341                 return false;
342         }
343
344         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
345                              (struct timeval) { .tv_sec = 1 });
346         if (!NT_STATUS_IS_OK(status)) {
347                 fprintf(stderr, "child: g_lock_lock returned %s\n",
348                         nt_errstr(status));
349                 return false;
350         }
351
352         n = sys_write(ready_pipe, &ok, sizeof(ok));
353         if (n != sizeof(ok)) {
354                 fprintf(stderr, "child: write failed\n");
355                 return false;
356         }
357
358         if (ok) {
359                 n = sys_read(exit_pipe, &ok, sizeof(ok));
360                 if (n != 0) {
361                         fprintf(stderr, "child: read failed\n");
362                         return false;
363                 }
364         }
365
366         return true;
367 }
368
369 static void lock4_done(struct tevent_req *subreq)
370 {
371         int *done = tevent_req_callback_data_void(subreq);
372         NTSTATUS status;
373
374         status = g_lock_lock_recv(subreq);
375         TALLOC_FREE(subreq);
376         if (!NT_STATUS_IS_OK(status)) {
377                 fprintf(stderr, "g_lock_lock_recv returned %s\n",
378                         nt_errstr(status));
379                 *done = -1;
380                 return;
381         }
382         *done = 1;
383 }
384
385 static void lock4_waited(struct tevent_req *subreq)
386 {
387         int *exit_pipe = tevent_req_callback_data_void(subreq);
388         pid_t child;
389         int status;
390         bool ok;
391
392         printf("waited\n");
393
394         ok = tevent_wakeup_recv(subreq);
395         TALLOC_FREE(subreq);
396         if (!ok) {
397                 fprintf(stderr, "tevent_wakeup_recv failed\n");
398         }
399         close(*exit_pipe);
400
401         child = wait(&status);
402
403         printf("child %d exited with %d\n", (int)child, status);
404 }
405
406 struct lock4_check_state {
407         struct server_id me;
408         bool ok;
409 };
410
411 static void lock4_check(const struct g_lock_rec *locks,
412                         size_t num_locks,
413                         const uint8_t *data,
414                         size_t datalen,
415                         void *private_data)
416 {
417         struct lock4_check_state *state = private_data;
418
419         if (num_locks != 1) {
420                 fprintf(stderr, "num_locks=%zu\n", num_locks);
421                 return;
422         }
423
424         if (!serverid_equal(&state->me, &locks[0].pid)) {
425                 struct server_id_buf buf1, buf2;
426                 fprintf(stderr, "me=%s, locker=%s\n",
427                         server_id_str_buf(state->me, &buf1),
428                         server_id_str_buf(locks[0].pid, &buf2));
429                 return;
430         }
431
432         if (locks[0].lock_type != G_LOCK_WRITE) {
433                 fprintf(stderr, "wrong lock type: %d\n",
434                         (int)locks[0].lock_type);
435                 return;
436         }
437
438         state->ok = true;
439 }
440
441 /*
442  * Test a lock conflict
443  */
444
445 bool run_g_lock4(int dummy)
446 {
447         struct tevent_context *ev = NULL;
448         struct messaging_context *msg = NULL;
449         struct g_lock_ctx *ctx = NULL;
450         const char *lockname = "lock4";
451         pid_t child;
452         int ready_pipe[2];
453         int exit_pipe[2];
454         NTSTATUS status;
455         bool ret = false;
456         struct tevent_req *req;
457         bool ok;
458         int done;
459
460         if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
461                 perror("pipe failed");
462                 return false;
463         }
464
465         child = fork();
466
467         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
468         if (!ok) {
469                 goto fail;
470         }
471
472         if (child == -1) {
473                 perror("fork failed");
474                 return false;
475         }
476
477         if (child == 0) {
478                 close(ready_pipe[0]);
479                 close(exit_pipe[1]);
480                 ok = lock4_child(lockname, ready_pipe[1], exit_pipe[0]);
481                 exit(ok ? 0 : 1);
482         }
483
484         close(ready_pipe[1]);
485         close(exit_pipe[0]);
486
487         if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
488                 perror("read failed");
489                 return false;
490         }
491
492         if (!ok) {
493                 fprintf(stderr, "child returned error\n");
494                 return false;
495         }
496
497         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
498                              (struct timeval) { .tv_usec = 1 });
499         if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
500                 fprintf(stderr, "g_lock_lock returned %s\n",
501                         nt_errstr(status));
502                 goto fail;
503         }
504
505         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_READ,
506                              (struct timeval) { .tv_usec = 1 });
507         if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
508                 fprintf(stderr, "g_lock_lock returned %s\n",
509                         nt_errstr(status));
510                 goto fail;
511         }
512
513         req = g_lock_lock_send(ev, ev, ctx, string_term_tdb_data(lockname),
514                                G_LOCK_WRITE);
515         if (req == NULL) {
516                 fprintf(stderr, "g_lock_lock send failed\n");
517                 goto fail;
518         }
519         tevent_req_set_callback(req, lock4_done, &done);
520
521         req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
522         if (req == NULL) {
523                 fprintf(stderr, "tevent_wakeup_send failed\n");
524                 goto fail;
525         }
526         tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
527
528         done = 0;
529
530         while (done == 0) {
531                 int tevent_ret = tevent_loop_once(ev);
532                 if (tevent_ret != 0) {
533                         perror("tevent_loop_once failed");
534                         goto fail;
535                 }
536         }
537
538         {
539                 struct lock4_check_state state = {
540                         .me = messaging_server_id(msg)
541                 };
542
543                 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
544                                      lock4_check, &state);
545                 if (!NT_STATUS_IS_OK(status)) {
546                         fprintf(stderr, "g_lock_dump failed: %s\n",
547                                 nt_errstr(status));
548                         goto fail;
549                 }
550                 if (!state.ok) {
551                         fprintf(stderr, "lock4_check failed\n");
552                         goto fail;
553                 }
554         }
555
556         ret = true;
557 fail:
558         TALLOC_FREE(ctx);
559         TALLOC_FREE(msg);
560         TALLOC_FREE(ev);
561         return ret;
562 }
563
564 struct lock5_parser_state {
565         size_t num_locks;
566 };
567
568 static void lock5_parser(const struct g_lock_rec *locks,
569                          size_t num_locks,
570                          const uint8_t *data,
571                          size_t datalen,
572                          void *private_data)
573 {
574         struct lock5_parser_state *state = private_data;
575         state->num_locks = num_locks;
576 }
577
578 /*
579  * Test heuristic cleanup
580  */
581
582 bool run_g_lock5(int dummy)
583 {
584         struct tevent_context *ev = NULL;
585         struct messaging_context *msg = NULL;
586         struct g_lock_ctx *ctx = NULL;
587         const char *lockname = "lock5";
588         pid_t child;
589         int exit_pipe[2], ready_pipe[2];
590         NTSTATUS status;
591         size_t i, nprocs;
592         int ret;
593         bool ok;
594         ssize_t nread;
595         char c;
596
597         nprocs = 5;
598
599         if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
600                 perror("pipe failed");
601                 return false;
602         }
603
604         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
605         if (!ok) {
606                 fprintf(stderr, "get_g_lock_ctx failed");
607                 return false;
608         }
609
610         for (i=0; i<nprocs; i++) {
611
612                 child = fork();
613
614                 if (child == -1) {
615                         perror("fork failed");
616                         return false;
617                 }
618
619                 if (child == 0) {
620                         TALLOC_FREE(ctx);
621
622                         status = reinit_after_fork(msg, ev, false, "");
623
624                         close(ready_pipe[0]);
625                         close(exit_pipe[1]);
626
627                         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
628                         if (!ok) {
629                                 fprintf(stderr, "get_g_lock_ctx failed");
630                                 exit(1);
631                         }
632                         status = g_lock_lock(ctx,
633                                              string_term_tdb_data(lockname),
634                                              G_LOCK_READ,
635                                              (struct timeval) { .tv_sec = 1 });
636                         if (!NT_STATUS_IS_OK(status)) {
637                                 fprintf(stderr,
638                                         "child g_lock_lock failed %s\n",
639                                         nt_errstr(status));
640                                 exit(1);
641                         }
642                         close(ready_pipe[1]);
643                         nread = sys_read(exit_pipe[0], &c, sizeof(c));
644                         if (nread != 0) {
645                                 fprintf(stderr, "sys_read returned %zu (%s)\n",
646                                         nread, strerror(errno));
647                                 exit(1);
648                         }
649                         exit(0);
650                 }
651         }
652
653         close(ready_pipe[1]);
654
655         nread = sys_read(ready_pipe[0], &c, sizeof(c));
656         if (nread != 0) {
657                 fprintf(stderr, "sys_read returned %zu (%s)\n",
658                         nread, strerror(errno));
659                 return false;
660         }
661
662         close(exit_pipe[1]);
663
664         for (i=0; i<nprocs; i++) {
665                 int child_status;
666                 ret = waitpid(-1, &child_status, 0);
667                 if (ret == -1) {
668                         perror("waitpid failed");
669                         return false;
670                 }
671         }
672
673         for (i=0; i<nprocs; i++) {
674                 struct lock5_parser_state state;
675
676                 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
677                                      lock5_parser, &state);
678                 if (!NT_STATUS_IS_OK(status)) {
679                         fprintf(stderr, "g_lock_dump returned %s\n",
680                                 nt_errstr(status));
681                         return false;
682                 }
683
684                 if (state.num_locks != (nprocs - i)) {
685                         fprintf(stderr, "nlocks=%zu, expected %zu\n",
686                                 state.num_locks, (nprocs-i));
687                         return false;
688                 }
689
690                 status = g_lock_lock(ctx, string_term_tdb_data(lockname),
691                                      G_LOCK_READ,
692                                      (struct timeval) { .tv_sec = 1 });
693                 if (!NT_STATUS_IS_OK(status)) {
694                         fprintf(stderr, "g_lock_lock failed %s\n",
695                                 nt_errstr(status));
696                         return false;
697                 }
698                 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
699                 if (!NT_STATUS_IS_OK(status)) {
700                         fprintf(stderr, "g_lock_unlock failed %s\n",
701                                 nt_errstr(status));
702                         return false;
703                 }
704         }
705
706
707         return true;
708 }
709
710 struct lock6_parser_state {
711         size_t num_locks;
712 };
713
714 static void lock6_parser(const struct g_lock_rec *locks,
715                          size_t num_locks,
716                          const uint8_t *data,
717                          size_t datalen,
718                          void *private_data)
719 {
720         struct lock6_parser_state *state = private_data;
721         state->num_locks = num_locks;
722 }
723
724 /*
725  * Test cleanup with contention and stale locks
726  */
727
728 bool run_g_lock6(int dummy)
729 {
730         struct tevent_context *ev = NULL;
731         struct messaging_context *msg = NULL;
732         struct g_lock_ctx *ctx = NULL;
733         TDB_DATA lockname = string_term_tdb_data("lock6");
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;
742
743         if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
744                 perror("pipe failed");
745                 return false;
746         }
747
748         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
749         if (!ok) {
750                 fprintf(stderr, "get_g_lock_ctx failed");
751                 return false;
752         }
753
754         /*
755          * Wipe all stale locks -- in clustered mode there's no
756          * CLEAR_IF_FIRST
757          */
758         status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
759                              (struct timeval) { .tv_sec = 1 });
760         if (!NT_STATUS_IS_OK(status)) {
761                 fprintf(stderr, "g_lock_lock failed: %s\n",
762                         nt_errstr(status));
763                 return false;
764         }
765         status = g_lock_unlock(ctx, lockname);
766         if (!NT_STATUS_IS_OK(status)) {
767                 fprintf(stderr, "g_lock_unlock failed: %s\n",
768                         nt_errstr(status));
769                 return false;
770         }
771
772         nprocs = 2;
773         for (i=0; i<nprocs; i++) {
774
775                 child = fork();
776
777                 if (child == -1) {
778                         perror("fork failed");
779                         return false;
780                 }
781
782                 if (child == 0) {
783                         TALLOC_FREE(ctx);
784
785                         status = reinit_after_fork(msg, ev, false, "");
786                         if (!NT_STATUS_IS_OK(status)) {
787                                 fprintf(stderr, "reinit_after_fork failed: %s\n",
788                                         nt_errstr(status));
789                                 exit(1);
790                         }
791
792                         close(ready_pipe[0]);
793                         close(exit_pipe[1]);
794
795                         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
796                         if (!ok) {
797                                 fprintf(stderr, "get_g_lock_ctx failed");
798                                 exit(1);
799                         }
800                         status = g_lock_lock(ctx,
801                                              lockname,
802                                              G_LOCK_READ,
803                                              (struct timeval) { .tv_sec = 1 });
804                         if (!NT_STATUS_IS_OK(status)) {
805                                 fprintf(stderr,
806                                         "child g_lock_lock failed %s\n",
807                                         nt_errstr(status));
808                                 exit(1);
809                         }
810                         if (i == 0) {
811                                 exit(0);
812                         }
813                         close(ready_pipe[1]);
814                         nread = sys_read(exit_pipe[0], &c, sizeof(c));
815                         if (nread != 0) {
816                                 fprintf(stderr, "sys_read returned %zu (%s)\n",
817                                         nread, strerror(errno));
818                                 exit(1);
819                         }
820                         exit(0);
821                 }
822         }
823
824         close(ready_pipe[1]);
825
826         nread = sys_read(ready_pipe[0], &c, sizeof(c));
827         if (nread != 0) {
828                 fprintf(stderr, "sys_read returned %zd (%s)\n",
829                         nread, strerror(errno));
830                 return false;
831         }
832
833         {
834                 int child_status;
835                 ret = waitpid(-1, &child_status, 0);
836                 if (ret == -1) {
837                         perror("waitpid failed");
838                         return false;
839                 }
840         }
841
842         {
843                 struct lock6_parser_state state;
844
845                 status = g_lock_dump(ctx, lockname, lock6_parser, &state);
846                 if (!NT_STATUS_IS_OK(status)) {
847                         fprintf(stderr, "g_lock_dump returned %s\n",
848                                 nt_errstr(status));
849                         return false;
850                 }
851
852                 if (state.num_locks != nprocs) {
853                         fprintf(stderr, "nlocks=%zu, expected %zu\n",
854                                 state.num_locks, nprocs);
855                         return false;
856                 }
857
858                 status = g_lock_lock(ctx,
859                                      lockname,
860                                      G_LOCK_WRITE,
861                                      (struct timeval) { .tv_sec = 1 });
862                 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
863                         fprintf(stderr, "g_lock_lock should have failed with %s - %s\n",
864                                 nt_errstr(NT_STATUS_IO_TIMEOUT),
865                                 nt_errstr(status));
866                         return false;
867                 }
868
869                 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
870                                      (struct timeval) { .tv_sec = 1 });
871                 if (!NT_STATUS_IS_OK(status)) {
872                         fprintf(stderr, "g_lock_lock failed: %s\n",
873                                 nt_errstr(status));
874                         return false;
875                 }
876         }
877
878         close(exit_pipe[1]);
879
880         {
881                 int child_status;
882                 ret = waitpid(-1, &child_status, 0);
883                 if (ret == -1) {
884                         perror("waitpid failed");
885                         return false;
886                 }
887         }
888
889         status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
890                              (struct timeval) { .tv_sec = 1 });
891         if (!NT_STATUS_IS_OK(status)) {
892                 fprintf(stderr, "g_lock_lock failed: %s\n",
893                         nt_errstr(status));
894                 return false;
895         }
896
897         return true;
898 }
899
900 extern int torture_numops;
901 extern int torture_nprocs;
902
903 static struct timeval tp1, tp2;
904
905 static void start_timer(void)
906 {
907         gettimeofday(&tp1,NULL);
908 }
909
910 static double end_timer(void)
911 {
912         gettimeofday(&tp2,NULL);
913         return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) -
914                 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
915 }
916
917 /*
918  * g_lock ping_pong
919  */
920
921 bool run_g_lock_ping_pong(int dummy)
922 {
923         struct tevent_context *ev = NULL;
924         struct messaging_context *msg = NULL;
925         struct g_lock_ctx *ctx = NULL;
926         fstring name;
927         NTSTATUS status;
928         int i = 0;
929         bool ret = false;
930         bool ok;
931         unsigned count = 0;
932
933         torture_nprocs = MAX(2, torture_nprocs);
934
935         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
936         if (!ok) {
937                 goto fail;
938         }
939
940         start_timer();
941
942         snprintf(name, sizeof(name), "ping_pong_%d", i);
943
944         status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_WRITE,
945                              (struct timeval) { .tv_sec = 60 });
946         if (!NT_STATUS_IS_OK(status)) {
947                 fprintf(stderr, "g_lock_lock failed: %s\n",
948                         nt_errstr(status));
949                 goto fail;
950         }
951
952         for (i=0; i<torture_numops; i++) {
953
954                 name[10] = '0' + ((i+1) % torture_nprocs);
955
956                 status = g_lock_lock(ctx, string_term_tdb_data(name),
957                                      G_LOCK_WRITE,
958                                      (struct timeval) { .tv_sec = 60 });
959                 if (!NT_STATUS_IS_OK(status)) {
960                         fprintf(stderr, "g_lock_lock failed: %s\n",
961                                 nt_errstr(status));
962                         goto fail;
963                 }
964
965                 name[10] = '0' + ((i) % torture_nprocs);
966
967                 status = g_lock_unlock(ctx, string_term_tdb_data(name));
968                 if (!NT_STATUS_IS_OK(status)) {
969                         fprintf(stderr, "g_lock_unlock failed: %s\n",
970                                 nt_errstr(status));
971                         goto fail;
972                 }
973
974                 count++;
975
976                 if (end_timer() > 1.0) {
977                         printf("%8u locks/sec\r",
978                                (unsigned)(2*count/end_timer()));
979                         fflush(stdout);
980                         start_timer();
981                         count=0;
982                 }
983         }
984
985         ret = true;
986 fail:
987         TALLOC_FREE(ctx);
988         TALLOC_FREE(msg);
989         TALLOC_FREE(ev);
990         return ret;
991 }