LCOV - code coverage report
Current view: top level - source3/torture - test_g_lock.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 418 712 58.7 %
Date: 2021-09-23 10:06:22 Functions: 18 22 81.8 %

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

Generated by: LCOV version 1.13