LCOV - code coverage report
Current view: top level - source3/torture - test_g_lock.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 475 775 61.3 %
Date: 2024-01-11 09:59:51 Functions: 18 21 85.7 %

          Line data    Source code
       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             : #include "lib/util/tevent_ntstatus.h"
      29             : #include "lib/global_contexts.h"
      30             : 
      31          21 : 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)
      35             : {
      36          21 :         *ev = global_event_context();
      37          21 :         if (*ev == NULL) {
      38           0 :                 fprintf(stderr, "tevent_context_init failed\n");
      39           0 :                 return false;
      40             :         }
      41          21 :         *msg = global_messaging_context();
      42          21 :         if (*msg == NULL) {
      43           0 :                 fprintf(stderr, "messaging_init failed\n");
      44           0 :                 TALLOC_FREE(*ev);
      45           0 :                 return false;
      46             :         }
      47          21 :         *ctx = g_lock_ctx_init(*ev, *msg);
      48          21 :         if (*ctx == NULL) {
      49           0 :                 fprintf(stderr, "g_lock_ctx_init failed\n");
      50           0 :                 TALLOC_FREE(*msg);
      51           0 :                 TALLOC_FREE(*ev);
      52           0 :                 return false;
      53             :         }
      54             : 
      55           0 :         return true;
      56             : }
      57             : 
      58           1 : bool run_g_lock1(int dummy)
      59             : {
      60           1 :         struct tevent_context *ev = NULL;
      61           1 :         struct messaging_context *msg = NULL;
      62           1 :         struct g_lock_ctx *ctx = NULL;
      63           1 :         const char *lockname = "lock1";
      64           1 :         NTSTATUS status;
      65           1 :         bool ret = false;
      66           1 :         bool ok;
      67             : 
      68           1 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
      69           1 :         if (!ok) {
      70           0 :                 goto fail;
      71             :         }
      72             : 
      73           1 :         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
      74           1 :                              (struct timeval) { .tv_sec = 1 },
      75             :                              NULL, NULL);
      76           1 :         if (!NT_STATUS_IS_OK(status)) {
      77           0 :                 fprintf(stderr, "g_lock_lock failed: %s\n",
      78             :                         nt_errstr(status));
      79           0 :                 goto fail;
      80             :         }
      81             : 
      82           1 :         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
      83           1 :                              (struct timeval) { .tv_sec = 1 },
      84             :                              NULL, NULL);
      85           1 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_WAS_LOCKED)) {
      86           0 :                 fprintf(stderr, "Double lock got %s\n",
      87             :                         nt_errstr(status));
      88           0 :                 goto fail;
      89             :         }
      90             : 
      91           1 :         status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
      92           1 :         if (!NT_STATUS_IS_OK(status)) {
      93           0 :                 fprintf(stderr, "g_lock_unlock failed: %s\n",
      94             :                         nt_errstr(status));
      95           0 :                 goto fail;
      96             :         }
      97             : 
      98           1 :         status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
      99           1 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     100           0 :                 fprintf(stderr, "g_lock_unlock returned: %s\n",
     101             :                         nt_errstr(status));
     102           0 :                 goto fail;
     103             :         }
     104             : 
     105           0 :         ret = true;
     106           1 : fail:
     107           1 :         TALLOC_FREE(ctx);
     108           1 :         TALLOC_FREE(msg);
     109           1 :         TALLOC_FREE(ev);
     110           1 :         return ret;
     111             : }
     112             : 
     113             : struct lock2_parser_state {
     114             :         uint8_t *rdata;
     115             :         bool ok;
     116             : };
     117             : 
     118           1 : 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)
     124             : {
     125           1 :         struct lock2_parser_state *state = private_data;
     126             : 
     127           1 :         if (datalen != sizeof(uint8_t)) {
     128           0 :                 return;
     129             :         }
     130           1 :         *state->rdata = *data;
     131           1 :         state->ok = true;
     132             : }
     133             : 
     134             : /*
     135             :  * Test g_lock_write_data
     136             :  */
     137             : 
     138           1 : bool run_g_lock2(int dummy)
     139             : {
     140           1 :         struct tevent_context *ev = NULL;
     141           1 :         struct messaging_context *msg = NULL;
     142           1 :         struct g_lock_ctx *ctx = NULL;
     143           1 :         const char *lockname = "lock2";
     144           1 :         uint8_t data = 42;
     145           1 :         uint8_t rdata;
     146           1 :         struct lock2_parser_state state = { .rdata = &rdata };
     147           1 :         NTSTATUS status;
     148           1 :         bool ret = false;
     149           1 :         bool ok;
     150             : 
     151           1 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
     152           1 :         if (!ok) {
     153           0 :                 goto fail;
     154             :         }
     155             : 
     156           1 :         status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
     157             :                                    &data, sizeof(data));
     158           1 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_LOCKED)) {
     159           0 :                 fprintf(stderr, "unlocked g_lock_write_data returned %s\n",
     160             :                         nt_errstr(status));
     161           0 :                 goto fail;
     162             :         }
     163             : 
     164           1 :         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
     165           1 :                              (struct timeval) { .tv_sec = 1 },
     166             :                              NULL, NULL);
     167           1 :         if (!NT_STATUS_IS_OK(status)) {
     168           0 :                 fprintf(stderr, "g_lock_lock returned %s\n",
     169             :                         nt_errstr(status));
     170           0 :                 goto fail;
     171             :         }
     172             : 
     173           1 :         status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
     174             :                                    &data, sizeof(data));
     175           1 :         if (!NT_STATUS_IS_OK(status)) {
     176           0 :                 fprintf(stderr, "g_lock_write_data failed: %s\n",
     177             :                         nt_errstr(status));
     178           0 :                 goto fail;
     179             :         }
     180             : 
     181           1 :         status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
     182           1 :         if (!NT_STATUS_IS_OK(status)) {
     183           0 :                 fprintf(stderr, "g_lock_unlock failed: %s\n",
     184             :                         nt_errstr(status));
     185           0 :                 goto fail;
     186             :         }
     187             : 
     188           1 :         status = g_lock_dump(ctx, string_term_tdb_data(lockname),
     189             :                              lock2_parser, &state);
     190           1 :         if (!NT_STATUS_IS_OK(status)) {
     191           0 :                 fprintf(stderr, "g_lock_dump failed: %s\n",
     192             :                         nt_errstr(status));
     193           0 :                 goto fail;
     194             :         }
     195             : 
     196           1 :         if (!state.ok) {
     197           0 :                 fprintf(stderr, "Could not parse data\n");
     198           0 :                 goto fail;
     199             :         }
     200           1 :         if (rdata != data) {
     201           0 :                 fprintf(stderr, "Returned %"PRIu8", expected %"PRIu8"\n",
     202             :                         rdata, data);
     203           0 :                 goto fail;
     204             :         }
     205             : 
     206           0 :         ret = true;
     207           1 : fail:
     208           1 :         TALLOC_FREE(ctx);
     209           1 :         TALLOC_FREE(msg);
     210           1 :         TALLOC_FREE(ev);
     211           1 :         return ret;
     212             : }
     213             : 
     214             : struct lock3_parser_state {
     215             :         struct server_id self;
     216             :         enum g_lock_type lock_type;
     217             :         bool ok;
     218             : };
     219             : 
     220           2 : 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)
     226             : {
     227           2 :         struct lock3_parser_state *state = private_data;
     228           2 :         size_t num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
     229           2 :         const struct server_id *pid;
     230             : 
     231           2 :         if (datalen != 0) {
     232           0 :                 fprintf(stderr, "datalen=%zu\n", datalen);
     233           0 :                 return;
     234             :         }
     235           2 :         if (num_locks != 1) {
     236           0 :                 fprintf(stderr, "num_locks=%zu\n", num_locks);
     237           0 :                 return;
     238             :         }
     239             : 
     240           2 :         if (state->lock_type == G_LOCK_WRITE) {
     241           1 :                 if (exclusive.pid == 0) {
     242           0 :                         fprintf(stderr, "Found READ, expected WRITE\n");
     243           0 :                         return;
     244             :                 }
     245             :         } else {
     246           1 :                 if (exclusive.pid != 0) {
     247           0 :                         fprintf(stderr, "Found WRITE, expected READ\n");
     248           0 :                         return;
     249             :                 }
     250             :         }
     251             : 
     252           2 :         pid = (exclusive.pid != 0) ? &exclusive : &shared[0];
     253             : 
     254           2 :         if (!server_id_equal(pid, &state->self)) {
     255           0 :                 struct server_id_buf tmp1, tmp2;
     256           0 :                 fprintf(stderr, "found pid %s, expected %s\n",
     257             :                         server_id_str_buf(*pid, &tmp1),
     258             :                         server_id_str_buf(state->self, &tmp2));
     259           0 :                 return;
     260             :         }
     261             : 
     262           2 :         state->ok = true;
     263             : }
     264             : 
     265             : /*
     266             :  * Test lock upgrade/downgrade
     267             :  */
     268             : 
     269           1 : bool run_g_lock3(int dummy)
     270             : {
     271           1 :         struct tevent_context *ev = NULL;
     272           1 :         struct messaging_context *msg = NULL;
     273           1 :         struct g_lock_ctx *ctx = NULL;
     274           1 :         const char *lockname = "lock3";
     275           1 :         struct lock3_parser_state state;
     276           1 :         NTSTATUS status;
     277           1 :         bool ret = false;
     278           1 :         bool ok;
     279             : 
     280           1 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
     281           1 :         if (!ok) {
     282           0 :                 goto fail;
     283             :         }
     284             : 
     285           1 :         state.self = messaging_server_id(msg);
     286             : 
     287           1 :         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_READ,
     288           1 :                              (struct timeval) { .tv_sec = 1 },
     289             :                              NULL, NULL);
     290           1 :         if (!NT_STATUS_IS_OK(status)) {
     291           0 :                 fprintf(stderr, "g_lock_lock returned %s\n",
     292             :                         nt_errstr(status));
     293           0 :                 goto fail;
     294             :         }
     295             : 
     296           1 :         state.lock_type = G_LOCK_READ;
     297           1 :         state.ok = false;
     298             : 
     299           1 :         status = g_lock_dump(ctx, string_term_tdb_data(lockname),
     300             :                              lock3_parser, &state);
     301           1 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
     302           0 :                 fprintf(stderr, "g_lock_dump returned %s\n",
     303             :                         nt_errstr(status));
     304           0 :                 goto fail;
     305             :         }
     306           1 :         if (!state.ok) {
     307           0 :                 goto fail;
     308             :         }
     309             : 
     310           1 :         status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_UPGRADE,
     311           1 :                              (struct timeval) { .tv_sec = 1 },
     312             :                              NULL, NULL);
     313           1 :         if (!NT_STATUS_IS_OK(status)) {
     314           0 :                 fprintf(stderr, "g_lock_lock returned %s\n",
     315             :                         nt_errstr(status));
     316           0 :                 goto fail;
     317             :         }
     318             : 
     319           1 :         state.lock_type = G_LOCK_WRITE;
     320           1 :         state.ok = false;
     321             : 
     322           1 :         status = g_lock_dump(ctx, string_term_tdb_data(lockname),
     323             :                              lock3_parser, &state);
     324           1 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_OK)) {
     325           0 :                 fprintf(stderr, "g_lock_dump returned %s\n",
     326             :                         nt_errstr(status));
     327           0 :                 goto fail;
     328             :         }
     329           1 :         if (!state.ok) {
     330           0 :                 goto fail;
     331             :         }
     332             : 
     333             : 
     334           0 :         ret = true;
     335           1 : fail:
     336           1 :         TALLOC_FREE(ctx);
     337           1 :         TALLOC_FREE(msg);
     338           1 :         TALLOC_FREE(ev);
     339           1 :         return ret;
     340             : }
     341             : 
     342           2 : static bool lock4_child(const char *lockname,
     343             :                         enum g_lock_type lock_type,
     344             :                         int ready_pipe,
     345             :                         int exit_pipe)
     346             : {
     347           2 :         struct tevent_context *ev = NULL;
     348           2 :         struct messaging_context *msg = NULL;
     349           2 :         struct g_lock_ctx *ctx = NULL;
     350           2 :         NTSTATUS status;
     351           2 :         ssize_t n;
     352           2 :         bool ok;
     353             : 
     354           2 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
     355           2 :         if (!ok) {
     356           0 :                 return false;
     357             :         }
     358             : 
     359           2 :         status = g_lock_lock(
     360             :                 ctx,
     361             :                 string_term_tdb_data(lockname),
     362             :                 lock_type,
     363           2 :                 (struct timeval) { .tv_sec = 1 },
     364             :                 NULL,
     365             :                 NULL);
     366           2 :         if (!NT_STATUS_IS_OK(status)) {
     367           0 :                 fprintf(stderr, "child: g_lock_lock returned %s\n",
     368             :                         nt_errstr(status));
     369           0 :                 return false;
     370             :         }
     371             : 
     372           2 :         n = sys_write(ready_pipe, &ok, sizeof(ok));
     373           2 :         if (n != sizeof(ok)) {
     374           0 :                 fprintf(stderr, "child: write failed\n");
     375           0 :                 return false;
     376             :         }
     377             : 
     378           2 :         if (ok) {
     379           2 :                 n = sys_read(exit_pipe, &ok, sizeof(ok));
     380           2 :                 if (n != 0) {
     381           0 :                         fprintf(stderr, "child: read failed\n");
     382           0 :                         return false;
     383             :                 }
     384             :         }
     385             : 
     386           0 :         return true;
     387             : }
     388             : 
     389           2 : static void lock4_done(struct tevent_req *subreq)
     390             : {
     391           2 :         int *done = tevent_req_callback_data_void(subreq);
     392           2 :         NTSTATUS status;
     393             : 
     394           2 :         status = g_lock_lock_recv(subreq);
     395           2 :         TALLOC_FREE(subreq);
     396           2 :         if (!NT_STATUS_IS_OK(status)) {
     397           0 :                 fprintf(stderr, "g_lock_lock_recv returned %s\n",
     398             :                         nt_errstr(status));
     399           0 :                 *done = -1;
     400           0 :                 return;
     401             :         }
     402           2 :         *done = 1;
     403             : }
     404             : 
     405           2 : static void lock4_waited(struct tevent_req *subreq)
     406             : {
     407           2 :         int *exit_pipe = tevent_req_callback_data_void(subreq);
     408           2 :         pid_t child;
     409           2 :         int status;
     410           2 :         bool ok;
     411             : 
     412           2 :         printf("waited\n");
     413             : 
     414           2 :         ok = tevent_wakeup_recv(subreq);
     415           2 :         TALLOC_FREE(subreq);
     416           2 :         if (!ok) {
     417           0 :                 fprintf(stderr, "tevent_wakeup_recv failed\n");
     418             :         }
     419           2 :         close(*exit_pipe);
     420             : 
     421           2 :         child = wait(&status);
     422             : 
     423           2 :         printf("child %d exited with %d\n", (int)child, status);
     424           2 : }
     425             : 
     426             : struct lock4_check_state {
     427             :         struct server_id me;
     428             :         bool ok;
     429             : };
     430             : 
     431           2 : 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)
     437             : {
     438           2 :         struct lock4_check_state *state = private_data;
     439           2 :         size_t num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
     440             : 
     441           2 :         if (num_locks != 1) {
     442           0 :                 fprintf(stderr, "num_locks=%zu\n", num_locks);
     443           0 :                 return;
     444             :         }
     445             : 
     446           2 :         if (exclusive.pid == 0) {
     447           0 :                 fprintf(stderr, "Wrong lock type, not WRITE\n");
     448           0 :                 return;
     449             :         }
     450             : 
     451           2 :         if (!server_id_equal(&state->me, &exclusive)) {
     452           0 :                 struct server_id_buf buf1, buf2;
     453           0 :                 fprintf(stderr, "me=%s, locker=%s\n",
     454             :                         server_id_str_buf(state->me, &buf1),
     455             :                         server_id_str_buf(exclusive, &buf2));
     456           0 :                 return;
     457             :         }
     458             : 
     459           2 :         state->ok = true;
     460             : }
     461             : 
     462             : /*
     463             :  * Test a lock conflict: Contend with a WRITE lock
     464             :  */
     465             : 
     466           1 : bool run_g_lock4(int dummy)
     467             : {
     468           1 :         struct tevent_context *ev = NULL;
     469           1 :         struct messaging_context *msg = NULL;
     470           1 :         struct g_lock_ctx *ctx = NULL;
     471           1 :         const char *lockname = "lock4";
     472           1 :         TDB_DATA key = string_term_tdb_data(lockname);
     473           1 :         pid_t child;
     474           1 :         int ready_pipe[2];
     475           1 :         int exit_pipe[2];
     476           1 :         NTSTATUS status;
     477           1 :         bool ret = false;
     478           1 :         struct tevent_req *req;
     479           1 :         bool ok;
     480           1 :         int done;
     481             : 
     482           1 :         if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
     483           0 :                 perror("pipe failed");
     484           0 :                 return false;
     485             :         }
     486             : 
     487           1 :         child = fork();
     488             : 
     489           2 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
     490           2 :         if (!ok) {
     491           0 :                 goto fail;
     492             :         }
     493             : 
     494           2 :         if (child == -1) {
     495           0 :                 perror("fork failed");
     496           0 :                 return false;
     497             :         }
     498             : 
     499           2 :         if (child == 0) {
     500           1 :                 close(ready_pipe[0]);
     501           1 :                 close(exit_pipe[1]);
     502           1 :                 ok = lock4_child(
     503             :                         lockname, G_LOCK_WRITE, ready_pipe[1], exit_pipe[0]);
     504           1 :                 exit(ok ? 0 : 1);
     505             :         }
     506             : 
     507           1 :         close(ready_pipe[1]);
     508           1 :         close(exit_pipe[0]);
     509             : 
     510           1 :         if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
     511           0 :                 perror("read failed");
     512           0 :                 return false;
     513             :         }
     514             : 
     515           1 :         if (!ok) {
     516           0 :                 fprintf(stderr, "child returned error\n");
     517           0 :                 return false;
     518             :         }
     519             : 
     520           2 :         status = g_lock_lock(ctx, key, G_LOCK_WRITE,
     521           1 :                              (struct timeval) { .tv_usec = 1 },
     522             :                               NULL, NULL);
     523           1 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
     524           0 :                 fprintf(stderr, "g_lock_lock returned %s\n",
     525             :                         nt_errstr(status));
     526           0 :                 goto fail;
     527             :         }
     528             : 
     529           2 :         status = g_lock_lock(ctx, key, G_LOCK_READ,
     530           1 :                              (struct timeval) { .tv_usec = 1 },
     531             :                              NULL, NULL);
     532           1 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
     533           0 :                 fprintf(stderr, "g_lock_lock returned %s\n",
     534             :                         nt_errstr(status));
     535           0 :                 goto fail;
     536             :         }
     537             : 
     538           1 :         req = g_lock_lock_send(ev, ev, ctx, key, G_LOCK_WRITE, NULL, NULL);
     539           1 :         if (req == NULL) {
     540           0 :                 fprintf(stderr, "g_lock_lock send failed\n");
     541           0 :                 goto fail;
     542             :         }
     543           1 :         tevent_req_set_callback(req, lock4_done, &done);
     544             : 
     545           1 :         req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
     546           1 :         if (req == NULL) {
     547           0 :                 fprintf(stderr, "tevent_wakeup_send failed\n");
     548           0 :                 goto fail;
     549             :         }
     550           1 :         tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
     551             : 
     552           1 :         done = 0;
     553             : 
     554           4 :         while (done == 0) {
     555           3 :                 int tevent_ret = tevent_loop_once(ev);
     556           3 :                 if (tevent_ret != 0) {
     557           0 :                         perror("tevent_loop_once failed");
     558           0 :                         goto fail;
     559             :                 }
     560             :         }
     561             : 
     562             :         {
     563           1 :                 struct lock4_check_state state = {
     564           1 :                         .me = messaging_server_id(msg)
     565             :                 };
     566             : 
     567           1 :                 status = g_lock_dump(ctx, key, lock4_check, &state);
     568           1 :                 if (!NT_STATUS_IS_OK(status)) {
     569           0 :                         fprintf(stderr, "g_lock_dump failed: %s\n",
     570             :                                 nt_errstr(status));
     571           0 :                         goto fail;
     572             :                 }
     573           1 :                 if (!state.ok) {
     574           0 :                         fprintf(stderr, "lock4_check failed\n");
     575           0 :                         goto fail;
     576             :                 }
     577             :         }
     578             : 
     579           1 :         ret = true;
     580           1 : fail:
     581           1 :         TALLOC_FREE(ctx);
     582           1 :         TALLOC_FREE(msg);
     583           1 :         TALLOC_FREE(ev);
     584           0 :         return ret;
     585             : }
     586             : 
     587             : /*
     588             :  * Test a lock conflict: Contend with a READ lock
     589             :  */
     590             : 
     591           1 : bool run_g_lock4a(int dummy)
     592             : {
     593           1 :         struct tevent_context *ev = NULL;
     594           1 :         struct messaging_context *msg = NULL;
     595           1 :         struct g_lock_ctx *ctx = NULL;
     596           1 :         const char *lockname = "lock4a";
     597           1 :         TDB_DATA key = string_term_tdb_data(lockname);
     598           1 :         pid_t child;
     599           1 :         int ready_pipe[2];
     600           1 :         int exit_pipe[2];
     601           1 :         NTSTATUS status;
     602           1 :         bool ret = false;
     603           1 :         struct tevent_req *req;
     604           1 :         bool ok;
     605           1 :         int done;
     606             : 
     607           1 :         if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
     608           0 :                 perror("pipe failed");
     609           0 :                 return false;
     610             :         }
     611             : 
     612           1 :         child = fork();
     613             : 
     614           2 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
     615           2 :         if (!ok) {
     616           0 :                 goto fail;
     617             :         }
     618             : 
     619           2 :         if (child == -1) {
     620           0 :                 perror("fork failed");
     621           0 :                 return false;
     622             :         }
     623             : 
     624           2 :         if (child == 0) {
     625           1 :                 close(ready_pipe[0]);
     626           1 :                 close(exit_pipe[1]);
     627           1 :                 ok = lock4_child(
     628             :                         lockname, G_LOCK_READ, ready_pipe[1], exit_pipe[0]);
     629           1 :                 exit(ok ? 0 : 1);
     630             :         }
     631             : 
     632           1 :         close(ready_pipe[1]);
     633           1 :         close(exit_pipe[0]);
     634             : 
     635           1 :         if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
     636           0 :                 perror("read failed");
     637           0 :                 return false;
     638             :         }
     639             : 
     640           1 :         if (!ok) {
     641           0 :                 fprintf(stderr, "child returned error\n");
     642           0 :                 return false;
     643             :         }
     644             : 
     645           2 :         status = g_lock_lock(ctx, key, G_LOCK_WRITE,
     646           1 :                              (struct timeval) { .tv_usec = 1 },
     647             :                              NULL, NULL);
     648           1 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
     649           0 :                 fprintf(stderr, "g_lock_lock returned %s\n",
     650             :                         nt_errstr(status));
     651           0 :                 goto fail;
     652             :         }
     653             : 
     654           2 :         status = g_lock_lock(ctx, key, G_LOCK_READ,
     655           1 :                              (struct timeval) { .tv_usec = 1 },
     656             :                              NULL, NULL);
     657           1 :         if (!NT_STATUS_IS_OK(status)) {
     658           0 :                 fprintf(stderr, "g_lock_lock returned %s\n",
     659             :                         nt_errstr(status));
     660           0 :                 goto fail;
     661             :         }
     662             : 
     663           1 :         status = g_lock_unlock(ctx, key);
     664           1 :         if (!NT_STATUS_IS_OK(status)) {
     665           0 :                 fprintf(stderr,
     666             :                         "g_lock_unlock returned %s\n",
     667             :                         nt_errstr(status));
     668           0 :                 goto fail;
     669             :         }
     670             : 
     671           1 :         req = g_lock_lock_send(ev, ev, ctx, key, G_LOCK_WRITE, NULL, NULL);
     672           1 :         if (req == NULL) {
     673           0 :                 fprintf(stderr, "g_lock_lock send failed\n");
     674           0 :                 goto fail;
     675             :         }
     676           1 :         tevent_req_set_callback(req, lock4_done, &done);
     677             : 
     678           1 :         req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
     679           1 :         if (req == NULL) {
     680           0 :                 fprintf(stderr, "tevent_wakeup_send failed\n");
     681           0 :                 goto fail;
     682             :         }
     683           1 :         tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
     684             : 
     685           1 :         done = 0;
     686             : 
     687           5 :         while (done == 0) {
     688           4 :                 int tevent_ret = tevent_loop_once(ev);
     689           4 :                 if (tevent_ret != 0) {
     690           0 :                         perror("tevent_loop_once failed");
     691           0 :                         goto fail;
     692             :                 }
     693             :         }
     694             : 
     695             :         {
     696           1 :                 struct lock4_check_state state = {
     697           1 :                         .me = messaging_server_id(msg)
     698             :                 };
     699             : 
     700           1 :                 status = g_lock_dump(ctx, key, lock4_check, &state);
     701           1 :                 if (!NT_STATUS_IS_OK(status)) {
     702           0 :                         fprintf(stderr, "g_lock_dump failed: %s\n",
     703             :                                 nt_errstr(status));
     704           0 :                         goto fail;
     705             :                 }
     706           1 :                 if (!state.ok) {
     707           0 :                         fprintf(stderr, "lock4_check failed\n");
     708           0 :                         goto fail;
     709             :                 }
     710             :         }
     711             : 
     712           1 :         ret = true;
     713           1 : fail:
     714           1 :         TALLOC_FREE(ctx);
     715           1 :         TALLOC_FREE(msg);
     716           1 :         TALLOC_FREE(ev);
     717           0 :         return ret;
     718             : }
     719             : 
     720             : struct lock5_parser_state {
     721             :         size_t num_locks;
     722             : };
     723             : 
     724           5 : 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)
     730             : {
     731           5 :         struct lock5_parser_state *state = private_data;
     732           5 :         state->num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
     733           5 : }
     734             : 
     735             : /*
     736             :  * Test heuristic cleanup
     737             :  */
     738             : 
     739           1 : bool run_g_lock5(int dummy)
     740             : {
     741           1 :         struct tevent_context *ev = NULL;
     742           1 :         struct messaging_context *msg = NULL;
     743           1 :         struct g_lock_ctx *ctx = NULL;
     744           1 :         const char *lockname = "lock5";
     745           1 :         pid_t child;
     746           1 :         int exit_pipe[2], ready_pipe[2];
     747           1 :         NTSTATUS status;
     748           1 :         size_t i, nprocs;
     749           1 :         int ret;
     750           1 :         bool ok;
     751           1 :         ssize_t nread;
     752           1 :         char c;
     753             : 
     754           1 :         nprocs = 5;
     755             : 
     756           1 :         if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
     757           0 :                 perror("pipe failed");
     758           0 :                 return false;
     759             :         }
     760             : 
     761           1 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
     762           1 :         if (!ok) {
     763           0 :                 fprintf(stderr, "get_g_lock_ctx failed");
     764           0 :                 return false;
     765             :         }
     766             : 
     767           6 :         for (i=0; i<nprocs; i++) {
     768             : 
     769           5 :                 child = fork();
     770             : 
     771          10 :                 if (child == -1) {
     772           0 :                         perror("fork failed");
     773           0 :                         return false;
     774             :                 }
     775             : 
     776          10 :                 if (child == 0) {
     777           5 :                         TALLOC_FREE(ctx);
     778             : 
     779           5 :                         status = reinit_after_fork(msg, ev, false);
     780             : 
     781           5 :                         close(ready_pipe[0]);
     782           5 :                         close(exit_pipe[1]);
     783             : 
     784           5 :                         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
     785           5 :                         if (!ok) {
     786           0 :                                 fprintf(stderr, "get_g_lock_ctx failed");
     787           0 :                                 exit(1);
     788             :                         }
     789           5 :                         status = g_lock_lock(ctx,
     790             :                                              string_term_tdb_data(lockname),
     791             :                                              G_LOCK_READ,
     792           5 :                                              (struct timeval) { .tv_sec = 1 },
     793             :                                              NULL, NULL);
     794           5 :                         if (!NT_STATUS_IS_OK(status)) {
     795           0 :                                 fprintf(stderr,
     796             :                                         "child g_lock_lock failed %s\n",
     797             :                                         nt_errstr(status));
     798           0 :                                 exit(1);
     799             :                         }
     800           5 :                         close(ready_pipe[1]);
     801           5 :                         nread = sys_read(exit_pipe[0], &c, sizeof(c));
     802           5 :                         if (nread != 0) {
     803           0 :                                 fprintf(stderr, "sys_read returned %zu (%s)\n",
     804           0 :                                         nread, strerror(errno));
     805           0 :                                 exit(1);
     806             :                         }
     807           5 :                         exit(0);
     808             :                 }
     809             :         }
     810             : 
     811           1 :         close(ready_pipe[1]);
     812             : 
     813           1 :         nread = sys_read(ready_pipe[0], &c, sizeof(c));
     814           1 :         if (nread != 0) {
     815           0 :                 fprintf(stderr, "sys_read returned %zu (%s)\n",
     816           0 :                         nread, strerror(errno));
     817           0 :                 return false;
     818             :         }
     819             : 
     820           1 :         close(exit_pipe[1]);
     821             : 
     822           7 :         for (i=0; i<nprocs; i++) {
     823           5 :                 int child_status;
     824           5 :                 ret = waitpid(-1, &child_status, 0);
     825           5 :                 if (ret == -1) {
     826           0 :                         perror("waitpid failed");
     827           0 :                         return false;
     828             :                 }
     829             :         }
     830             : 
     831           6 :         for (i=0; i<nprocs; i++) {
     832           5 :                 struct lock5_parser_state state;
     833             : 
     834           5 :                 status = g_lock_dump(ctx, string_term_tdb_data(lockname),
     835             :                                      lock5_parser, &state);
     836           5 :                 if (!NT_STATUS_IS_OK(status)) {
     837           0 :                         fprintf(stderr, "g_lock_dump returned %s\n",
     838             :                                 nt_errstr(status));
     839           0 :                         return false;
     840             :                 }
     841             : 
     842           5 :                 if (state.num_locks != (nprocs - i)) {
     843           0 :                         fprintf(stderr, "nlocks=%zu, expected %zu\n",
     844             :                                 state.num_locks, (nprocs-i));
     845           0 :                         return false;
     846             :                 }
     847             : 
     848           5 :                 status = g_lock_lock(ctx, string_term_tdb_data(lockname),
     849             :                                      G_LOCK_READ,
     850           5 :                                      (struct timeval) { .tv_sec = 1 },
     851             :                                      NULL, NULL);
     852           5 :                 if (!NT_STATUS_IS_OK(status)) {
     853           0 :                         fprintf(stderr, "g_lock_lock failed %s\n",
     854             :                                 nt_errstr(status));
     855           0 :                         return false;
     856             :                 }
     857           5 :                 status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
     858           5 :                 if (!NT_STATUS_IS_OK(status)) {
     859           0 :                         fprintf(stderr, "g_lock_unlock failed %s\n",
     860             :                                 nt_errstr(status));
     861           0 :                         return false;
     862             :                 }
     863             :         }
     864             : 
     865             : 
     866           0 :         return true;
     867             : }
     868             : 
     869             : struct lock6_parser_state {
     870             :         size_t num_locks;
     871             : };
     872             : 
     873           1 : 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)
     879             : {
     880           1 :         struct lock6_parser_state *state = private_data;
     881           1 :         state->num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
     882           1 : }
     883             : 
     884             : /*
     885             :  * Test cleanup with contention and stale locks
     886             :  */
     887             : 
     888           1 : bool run_g_lock6(int dummy)
     889             : {
     890           1 :         struct tevent_context *ev = NULL;
     891           1 :         struct messaging_context *msg = NULL;
     892           1 :         struct g_lock_ctx *ctx = NULL;
     893           1 :         TDB_DATA lockname = string_term_tdb_data("lock6");
     894           1 :         pid_t child;
     895           1 :         int exit_pipe[2], ready_pipe[2];
     896           1 :         NTSTATUS status;
     897           1 :         size_t i, nprocs;
     898           1 :         int ret;
     899           1 :         bool ok;
     900           1 :         ssize_t nread;
     901           1 :         char c;
     902             : 
     903           1 :         if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
     904           0 :                 perror("pipe failed");
     905           0 :                 return false;
     906             :         }
     907             : 
     908           1 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
     909           1 :         if (!ok) {
     910           0 :                 fprintf(stderr, "get_g_lock_ctx failed");
     911           0 :                 return false;
     912             :         }
     913             : 
     914             :         /*
     915             :          * Wipe all stale locks -- in clustered mode there's no
     916             :          * CLEAR_IF_FIRST
     917             :          */
     918           2 :         status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
     919           1 :                              (struct timeval) { .tv_sec = 1 },
     920             :                              NULL, NULL);
     921           1 :         if (!NT_STATUS_IS_OK(status)) {
     922           0 :                 fprintf(stderr, "g_lock_lock failed: %s\n",
     923             :                         nt_errstr(status));
     924           0 :                 return false;
     925             :         }
     926           1 :         status = g_lock_unlock(ctx, lockname);
     927           1 :         if (!NT_STATUS_IS_OK(status)) {
     928           0 :                 fprintf(stderr, "g_lock_unlock failed: %s\n",
     929             :                         nt_errstr(status));
     930           0 :                 return false;
     931             :         }
     932             : 
     933           0 :         nprocs = 2;
     934           3 :         for (i=0; i<nprocs; i++) {
     935             : 
     936           2 :                 child = fork();
     937             : 
     938           4 :                 if (child == -1) {
     939           0 :                         perror("fork failed");
     940           0 :                         return false;
     941             :                 }
     942             : 
     943           4 :                 if (child == 0) {
     944           2 :                         TALLOC_FREE(ctx);
     945             : 
     946           2 :                         status = reinit_after_fork(msg, ev, false);
     947           2 :                         if (!NT_STATUS_IS_OK(status)) {
     948           0 :                                 fprintf(stderr, "reinit_after_fork failed: %s\n",
     949             :                                         nt_errstr(status));
     950           0 :                                 exit(1);
     951             :                         }
     952             : 
     953           2 :                         close(ready_pipe[0]);
     954           2 :                         close(exit_pipe[1]);
     955             : 
     956           2 :                         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
     957           2 :                         if (!ok) {
     958           0 :                                 fprintf(stderr, "get_g_lock_ctx failed");
     959           0 :                                 exit(1);
     960             :                         }
     961           4 :                         status = g_lock_lock(ctx,
     962             :                                              lockname,
     963             :                                              G_LOCK_READ,
     964           2 :                                              (struct timeval) { .tv_sec = 1 },
     965             :                                              NULL, NULL);
     966           2 :                         if (!NT_STATUS_IS_OK(status)) {
     967           0 :                                 fprintf(stderr,
     968             :                                         "child g_lock_lock failed %s\n",
     969             :                                         nt_errstr(status));
     970           0 :                                 exit(1);
     971             :                         }
     972           2 :                         if (i == 0) {
     973           1 :                                 exit(0);
     974             :                         }
     975           1 :                         close(ready_pipe[1]);
     976           1 :                         nread = sys_read(exit_pipe[0], &c, sizeof(c));
     977           1 :                         if (nread != 0) {
     978           0 :                                 fprintf(stderr, "sys_read returned %zu (%s)\n",
     979           0 :                                         nread, strerror(errno));
     980           0 :                                 exit(1);
     981             :                         }
     982           1 :                         exit(0);
     983             :                 }
     984             :         }
     985             : 
     986           1 :         close(ready_pipe[1]);
     987             : 
     988           1 :         nread = sys_read(ready_pipe[0], &c, sizeof(c));
     989           1 :         if (nread != 0) {
     990           0 :                 fprintf(stderr, "sys_read returned %zd (%s)\n",
     991           0 :                         nread, strerror(errno));
     992           0 :                 return false;
     993             :         }
     994             : 
     995             :         {
     996           1 :                 int child_status;
     997           1 :                 ret = waitpid(-1, &child_status, 0);
     998           1 :                 if (ret == -1) {
     999           0 :                         perror("waitpid failed");
    1000           0 :                         return false;
    1001             :                 }
    1002             :         }
    1003             : 
    1004             :         {
    1005           1 :                 struct lock6_parser_state state;
    1006             : 
    1007           1 :                 status = g_lock_dump(ctx, lockname, lock6_parser, &state);
    1008           1 :                 if (!NT_STATUS_IS_OK(status)) {
    1009           0 :                         fprintf(stderr, "g_lock_dump returned %s\n",
    1010             :                                 nt_errstr(status));
    1011           0 :                         return false;
    1012             :                 }
    1013             : 
    1014           1 :                 if (state.num_locks != nprocs) {
    1015           0 :                         fprintf(stderr, "nlocks=%zu, expected %zu\n",
    1016             :                                 state.num_locks, nprocs);
    1017           0 :                         return false;
    1018             :                 }
    1019             : 
    1020           2 :                 status = g_lock_lock(ctx,
    1021             :                                      lockname,
    1022             :                                      G_LOCK_WRITE,
    1023           1 :                                      (struct timeval) { .tv_sec = 1 },
    1024             :                                      NULL, NULL);
    1025           1 :                 if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
    1026           0 :                         fprintf(stderr, "g_lock_lock should have failed with %s - %s\n",
    1027           0 :                                 nt_errstr(NT_STATUS_IO_TIMEOUT),
    1028             :                                 nt_errstr(status));
    1029           0 :                         return false;
    1030             :                 }
    1031             : 
    1032           2 :                 status = g_lock_lock(ctx, lockname, G_LOCK_READ,
    1033           1 :                                      (struct timeval) { .tv_sec = 1 },
    1034             :                                      NULL, NULL);
    1035           1 :                 if (!NT_STATUS_IS_OK(status)) {
    1036           0 :                         fprintf(stderr, "g_lock_lock failed: %s\n",
    1037             :                                 nt_errstr(status));
    1038           0 :                         return false;
    1039             :                 }
    1040             :         }
    1041             : 
    1042           1 :         close(exit_pipe[1]);
    1043             : 
    1044             :         {
    1045           1 :                 int child_status;
    1046           1 :                 ret = waitpid(-1, &child_status, 0);
    1047           1 :                 if (ret == -1) {
    1048           0 :                         perror("waitpid failed");
    1049           0 :                         return false;
    1050             :                 }
    1051             :         }
    1052             : 
    1053           2 :         status = g_lock_lock(ctx, lockname, G_LOCK_UPGRADE,
    1054           1 :                              (struct timeval) { .tv_sec = 1 },
    1055             :                              NULL, NULL);
    1056           1 :         if (!NT_STATUS_IS_OK(status)) {
    1057           0 :                 fprintf(stderr, "g_lock_lock failed: %s\n",
    1058             :                         nt_errstr(status));
    1059           0 :                 return false;
    1060             :         }
    1061             : 
    1062           0 :         return true;
    1063             : }
    1064             : 
    1065             : /*
    1066             :  * Test upgrade deadlock
    1067             :  */
    1068             : 
    1069           1 : bool run_g_lock7(int dummy)
    1070             : {
    1071           1 :         struct tevent_context *ev = NULL;
    1072           1 :         struct messaging_context *msg = NULL;
    1073           1 :         struct g_lock_ctx *ctx = NULL;
    1074           1 :         const char *lockname = "lock7";
    1075           1 :         TDB_DATA key = string_term_tdb_data(lockname);
    1076           1 :         pid_t child;
    1077           1 :         int ready_pipe[2];
    1078           1 :         int down_pipe[2];
    1079           1 :         ssize_t n;
    1080           1 :         NTSTATUS status;
    1081           1 :         bool ret = false;
    1082           1 :         bool ok = true;
    1083             : 
    1084           1 :         if ((pipe(ready_pipe) != 0) || (pipe(down_pipe) != 0)) {
    1085           0 :                 perror("pipe failed");
    1086           0 :                 return false;
    1087             :         }
    1088             : 
    1089           1 :         child = fork();
    1090             : 
    1091           2 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
    1092           2 :         if (!ok) {
    1093           0 :                 goto fail;
    1094             :         }
    1095             : 
    1096           2 :         if (child == -1) {
    1097           0 :                 perror("fork failed");
    1098           0 :                 return false;
    1099             :         }
    1100             : 
    1101           2 :         if (child == 0) {
    1102           1 :                 struct tevent_req *req = NULL;
    1103             : 
    1104           1 :                 close(ready_pipe[0]);
    1105           1 :                 ready_pipe[0] = -1;
    1106           1 :                 close(down_pipe[1]);
    1107           1 :                 down_pipe[1] = -1;
    1108             : 
    1109           1 :                 status = reinit_after_fork(msg, ev, false);
    1110           1 :                 if (!NT_STATUS_IS_OK(status)) {
    1111           0 :                         fprintf(stderr,
    1112             :                                 "reinit_after_fork failed: %s\n",
    1113             :                                 nt_errstr(status));
    1114           0 :                         exit(1);
    1115             :                 }
    1116             : 
    1117           1 :                 printf("%d: locking READ\n", (int)getpid());
    1118             : 
    1119           2 :                 status = g_lock_lock(
    1120             :                         ctx,
    1121             :                         key,
    1122             :                         G_LOCK_READ,
    1123           1 :                         (struct timeval) { .tv_usec = 1 },
    1124             :                         NULL, NULL);
    1125           1 :                 if (!NT_STATUS_IS_OK(status)) {
    1126           0 :                         fprintf(stderr,
    1127             :                                 "g_lock_lock(READ) failed: %s\n",
    1128             :                                 nt_errstr(status));
    1129           0 :                         exit(1);
    1130             :                 }
    1131             : 
    1132           1 :                 ok = true;
    1133             : 
    1134           1 :                 n = sys_write(ready_pipe[1], &ok, sizeof(ok));
    1135           1 :                 if (n != sizeof(ok)) {
    1136           0 :                         fprintf(stderr,
    1137             :                                 "sys_write failed: %s\n",
    1138           0 :                                 strerror(errno));
    1139           0 :                         exit(1);
    1140             :                 }
    1141             : 
    1142           1 :                 n = sys_read(down_pipe[0], &ok, sizeof(ok));
    1143           1 :                 if (n != sizeof(ok)) {
    1144           0 :                         fprintf(stderr,
    1145             :                                 "sys_read failed: %s\n",
    1146           0 :                                 strerror(errno));
    1147           0 :                         exit(1);
    1148             :                 }
    1149             : 
    1150           1 :                 printf("%d: starting UPGRADE\n", (int)getpid());
    1151             : 
    1152           1 :                 req = g_lock_lock_send(
    1153             :                         msg,
    1154             :                         ev,
    1155             :                         ctx,
    1156             :                         key,
    1157             :                         G_LOCK_UPGRADE,
    1158             :                         NULL, NULL);
    1159           1 :                 if (req == NULL) {
    1160           0 :                         fprintf(stderr, "g_lock_lock_send(UPGRADE) failed\n");
    1161           0 :                         exit(1);
    1162             :                 }
    1163             : 
    1164           1 :                 n = sys_write(ready_pipe[1], &ok, sizeof(ok));
    1165           1 :                 if (n != sizeof(ok)) {
    1166           0 :                         fprintf(stderr,
    1167             :                                 "sys_write failed: %s\n",
    1168           0 :                                 strerror(errno));
    1169           0 :                         exit(1);
    1170             :                 }
    1171             : 
    1172           1 :                 exit(0);
    1173             :         }
    1174             : 
    1175           1 :         close(ready_pipe[1]);
    1176           1 :         close(down_pipe[0]);
    1177             : 
    1178           1 :         if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
    1179           0 :                 perror("read failed");
    1180           0 :                 return false;
    1181             :         }
    1182           1 :         if (!ok) {
    1183           0 :                 fprintf(stderr, "child returned error\n");
    1184           0 :                 return false;
    1185             :         }
    1186             : 
    1187           2 :         status = g_lock_lock(
    1188             :                 ctx,
    1189             :                 key,
    1190             :                 G_LOCK_READ,
    1191           1 :                 (struct timeval) { .tv_usec = 1 },
    1192             :                 NULL, NULL);
    1193           1 :         if (!NT_STATUS_IS_OK(status)) {
    1194           0 :                 fprintf(stderr,
    1195             :                         "g_lock_lock(READ) failed: %s\n",
    1196             :                         nt_errstr(status));
    1197           0 :                 goto fail;
    1198             :         }
    1199             : 
    1200           1 :         n = sys_write(down_pipe[1], &ok, sizeof(ok));
    1201           1 :         if (n != sizeof(ok)) {
    1202           0 :                 fprintf(stderr,
    1203             :                         "sys_write failed: %s\n",
    1204           0 :                         strerror(errno));
    1205           0 :                 goto fail;
    1206             :         }
    1207             : 
    1208           1 :         if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
    1209           0 :                 perror("read failed");
    1210           0 :                 goto fail;
    1211             :         }
    1212             : 
    1213           2 :         status = g_lock_lock(
    1214             :                 ctx,
    1215             :                 key,
    1216             :                 G_LOCK_UPGRADE,
    1217           1 :                 (struct timeval) { .tv_sec = 10 },
    1218             :                 NULL, NULL);
    1219           1 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_POSSIBLE_DEADLOCK)) {
    1220           0 :                 fprintf(stderr,
    1221             :                         "g_lock_lock returned %s\n",
    1222             :                         nt_errstr(status));
    1223           0 :                 goto fail;
    1224             :         }
    1225             : 
    1226           0 :         ret = true;
    1227           1 : fail:
    1228           1 :         TALLOC_FREE(ctx);
    1229           1 :         TALLOC_FREE(msg);
    1230           1 :         TALLOC_FREE(ev);
    1231           0 :         return ret;
    1232             : }
    1233             : 
    1234           1 : bool run_g_lock8(int dummy)
    1235             : {
    1236           1 :         struct tevent_context *ev = NULL;
    1237           1 :         struct messaging_context *msg = NULL;
    1238           1 :         struct g_lock_ctx *ctx = NULL;
    1239           1 :         struct tevent_req *req = NULL;
    1240           1 :         TDB_DATA lockname = string_term_tdb_data("lock8");
    1241           1 :         NTSTATUS status;
    1242           1 :         bool ok;
    1243             : 
    1244           1 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
    1245           1 :         if (!ok) {
    1246           0 :                 fprintf(stderr, "get_g_lock_ctx failed");
    1247           0 :                 return false;
    1248             :         }
    1249             : 
    1250           2 :         req = g_lock_watch_data_send(
    1251           1 :                 ev, ev, ctx, lockname, (struct server_id) { .pid = 0 });
    1252           1 :         if (req == NULL) {
    1253           0 :                 fprintf(stderr, "get_g_lock_ctx failed");
    1254           0 :                 return false;
    1255             :         }
    1256             : 
    1257           1 :         status = g_lock_lock(
    1258             :                 ctx,
    1259             :                 lockname,
    1260             :                 G_LOCK_WRITE,
    1261           1 :                 (struct timeval) { .tv_sec = 999 },
    1262             :                 NULL, NULL);
    1263           1 :         if (!NT_STATUS_IS_OK(status)) {
    1264           0 :                 fprintf(stderr,
    1265             :                         "g_lock_lock failed: %s\n",
    1266             :                         nt_errstr(status));
    1267           0 :                 return false;
    1268             :         }
    1269             : 
    1270           1 :         status = g_lock_write_data(
    1271           1 :                 ctx, lockname, lockname.dptr, lockname.dsize);
    1272           1 :         if (!NT_STATUS_IS_OK(status)) {
    1273           0 :                 fprintf(stderr,
    1274             :                         "g_lock_write_data failed: %s\n",
    1275             :                         nt_errstr(status));
    1276           0 :                 return false;
    1277             :         }
    1278             : 
    1279           1 :         status = g_lock_write_data(ctx, lockname, NULL, 0);
    1280           1 :         if (!NT_STATUS_IS_OK(status)) {
    1281           0 :                 fprintf(stderr,
    1282             :                         "g_lock_write_data failed: %s\n",
    1283             :                         nt_errstr(status));
    1284           0 :                 return false;
    1285             :         }
    1286             : 
    1287           1 :         status = g_lock_unlock(ctx, lockname);
    1288           1 :         if (!NT_STATUS_IS_OK(status)) {
    1289           0 :                 fprintf(stderr,
    1290             :                         "g_lock_unlock failed: %s\n",
    1291             :                         nt_errstr(status));
    1292           0 :                 return false;
    1293             :         }
    1294             : 
    1295           1 :         ok = tevent_req_poll_ntstatus(req, ev, &status);
    1296           1 :         if (!ok) {
    1297           0 :                 fprintf(stderr, "tevent_req_poll_ntstatus failed\n");
    1298           0 :                 return false;
    1299             :         }
    1300           1 :         if (!NT_STATUS_IS_OK(status)) {
    1301           0 :                 fprintf(stderr,
    1302             :                         "tevent_req_poll_ntstatus failed: %s\n",
    1303             :                         nt_errstr(status));
    1304           0 :                 return false;
    1305             :         }
    1306             : 
    1307           0 :         return true;
    1308             : }
    1309             : 
    1310             : extern int torture_numops;
    1311             : extern int torture_nprocs;
    1312             : 
    1313             : static struct timeval tp1, tp2;
    1314             : 
    1315           0 : static void start_timer(void)
    1316             : {
    1317           0 :         gettimeofday(&tp1,NULL);
    1318           0 : }
    1319             : 
    1320           0 : static double end_timer(void)
    1321             : {
    1322           0 :         gettimeofday(&tp2,NULL);
    1323           0 :         return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) -
    1324           0 :                 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
    1325             : }
    1326             : 
    1327             : /*
    1328             :  * g_lock ping_pong
    1329             :  */
    1330             : 
    1331           0 : bool run_g_lock_ping_pong(int dummy)
    1332             : {
    1333           0 :         struct tevent_context *ev = NULL;
    1334           0 :         struct messaging_context *msg = NULL;
    1335           0 :         struct g_lock_ctx *ctx = NULL;
    1336           0 :         fstring name;
    1337           0 :         NTSTATUS status;
    1338           0 :         int i = 0;
    1339           0 :         bool ret = false;
    1340           0 :         bool ok;
    1341           0 :         unsigned count = 0;
    1342             : 
    1343           0 :         torture_nprocs = MAX(2, torture_nprocs);
    1344             : 
    1345           0 :         ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
    1346           0 :         if (!ok) {
    1347           0 :                 goto fail;
    1348             :         }
    1349             : 
    1350           0 :         start_timer();
    1351             : 
    1352           0 :         snprintf(name, sizeof(name), "ping_pong_%d", i);
    1353             : 
    1354           0 :         status = g_lock_lock(ctx, string_term_tdb_data(name), G_LOCK_WRITE,
    1355           0 :                              (struct timeval) { .tv_sec = 60 },
    1356             :                              NULL, NULL);
    1357           0 :         if (!NT_STATUS_IS_OK(status)) {
    1358           0 :                 fprintf(stderr, "g_lock_lock failed: %s\n",
    1359             :                         nt_errstr(status));
    1360           0 :                 goto fail;
    1361             :         }
    1362             : 
    1363           0 :         for (i=0; i<torture_numops; i++) {
    1364             : 
    1365           0 :                 name[10] = '0' + ((i+1) % torture_nprocs);
    1366             : 
    1367           0 :                 status = g_lock_lock(ctx, string_term_tdb_data(name),
    1368             :                                      G_LOCK_WRITE,
    1369           0 :                                      (struct timeval) { .tv_sec = 60 },
    1370             :                                      NULL, NULL);
    1371           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1372           0 :                         fprintf(stderr, "g_lock_lock failed: %s\n",
    1373             :                                 nt_errstr(status));
    1374           0 :                         goto fail;
    1375             :                 }
    1376             : 
    1377           0 :                 name[10] = '0' + ((i) % torture_nprocs);
    1378             : 
    1379           0 :                 status = g_lock_unlock(ctx, string_term_tdb_data(name));
    1380           0 :                 if (!NT_STATUS_IS_OK(status)) {
    1381           0 :                         fprintf(stderr, "g_lock_unlock failed: %s\n",
    1382             :                                 nt_errstr(status));
    1383           0 :                         goto fail;
    1384             :                 }
    1385             : 
    1386           0 :                 count++;
    1387             : 
    1388           0 :                 if (end_timer() > 1.0) {
    1389           0 :                         printf("%8u locks/sec\r",
    1390           0 :                                (unsigned)(2*count/end_timer()));
    1391           0 :                         fflush(stdout);
    1392           0 :                         start_timer();
    1393           0 :                         count=0;
    1394             :                 }
    1395             :         }
    1396             : 
    1397           0 :         ret = true;
    1398           0 : fail:
    1399           0 :         TALLOC_FREE(ctx);
    1400           0 :         TALLOC_FREE(msg);
    1401           0 :         TALLOC_FREE(ev);
    1402           0 :         return ret;
    1403             : }

Generated by: LCOV version 1.14