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 0 : 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 0 : *ev = global_event_context();
37 0 : if (*ev == NULL) {
38 0 : fprintf(stderr, "tevent_context_init failed\n");
39 0 : return false;
40 : }
41 0 : *msg = global_messaging_context();
42 0 : if (*msg == NULL) {
43 0 : fprintf(stderr, "messaging_init failed\n");
44 0 : TALLOC_FREE(*ev);
45 0 : return false;
46 : }
47 0 : *ctx = g_lock_ctx_init(*ev, *msg);
48 0 : 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 0 : bool run_g_lock1(int dummy)
59 : {
60 0 : struct tevent_context *ev = NULL;
61 0 : struct messaging_context *msg = NULL;
62 0 : struct g_lock_ctx *ctx = NULL;
63 0 : const char *lockname = "lock1";
64 : NTSTATUS status;
65 0 : bool ret = false;
66 : bool ok;
67 :
68 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
69 0 : if (!ok) {
70 0 : goto fail;
71 : }
72 :
73 0 : status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
74 0 : (struct timeval) { .tv_sec = 1 });
75 0 : 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 0 : status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
82 0 : (struct timeval) { .tv_sec = 1 });
83 0 : 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 0 : status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
90 0 : 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 0 : status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
97 0 : 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 0 : fail:
105 0 : TALLOC_FREE(ctx);
106 0 : TALLOC_FREE(msg);
107 0 : TALLOC_FREE(ev);
108 0 : return ret;
109 : }
110 :
111 : struct lock2_parser_state {
112 : uint8_t *rdata;
113 : bool ok;
114 : };
115 :
116 0 : static void lock2_parser(struct server_id exclusive,
117 : size_t num_shared,
118 : const struct server_id *shared,
119 : const uint8_t *data,
120 : size_t datalen,
121 : void *private_data)
122 : {
123 0 : struct lock2_parser_state *state = private_data;
124 :
125 0 : if (datalen != sizeof(uint8_t)) {
126 0 : return;
127 : }
128 0 : *state->rdata = *data;
129 0 : state->ok = true;
130 : }
131 :
132 : /*
133 : * Test g_lock_write_data
134 : */
135 :
136 0 : bool run_g_lock2(int dummy)
137 : {
138 0 : struct tevent_context *ev = NULL;
139 0 : struct messaging_context *msg = NULL;
140 0 : struct g_lock_ctx *ctx = NULL;
141 0 : const char *lockname = "lock2";
142 0 : uint8_t data = 42;
143 : uint8_t rdata;
144 0 : struct lock2_parser_state state = { .rdata = &rdata };
145 : NTSTATUS status;
146 0 : bool ret = false;
147 : bool ok;
148 :
149 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
150 0 : if (!ok) {
151 0 : goto fail;
152 : }
153 :
154 0 : status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
155 : &data, sizeof(data));
156 0 : 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 0 : status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_WRITE,
163 0 : (struct timeval) { .tv_sec = 1 });
164 0 : 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 0 : status = g_lock_write_data(ctx, string_term_tdb_data(lockname),
171 : &data, sizeof(data));
172 0 : 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 0 : status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
179 0 : 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 0 : status = g_lock_dump(ctx, string_term_tdb_data(lockname),
186 : lock2_parser, &state);
187 0 : 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 0 : if (!state.ok) {
194 0 : fprintf(stderr, "Could not parse data\n");
195 0 : goto fail;
196 : }
197 0 : 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 0 : fail:
205 0 : TALLOC_FREE(ctx);
206 0 : TALLOC_FREE(msg);
207 0 : TALLOC_FREE(ev);
208 0 : 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 0 : static void lock3_parser(struct server_id exclusive,
218 : size_t num_shared,
219 : const struct server_id *shared,
220 : const uint8_t *data,
221 : size_t datalen,
222 : void *private_data)
223 : {
224 0 : struct lock3_parser_state *state = private_data;
225 0 : size_t num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
226 : const struct server_id *pid;
227 :
228 0 : if (datalen != 0) {
229 0 : fprintf(stderr, "datalen=%zu\n", datalen);
230 0 : return;
231 : }
232 0 : if (num_locks != 1) {
233 0 : fprintf(stderr, "num_locks=%zu\n", num_locks);
234 0 : return;
235 : }
236 :
237 0 : if (state->lock_type == G_LOCK_WRITE) {
238 0 : if (exclusive.pid == 0) {
239 0 : fprintf(stderr, "Found READ, expected WRITE\n");
240 0 : return;
241 : }
242 : } else {
243 0 : if (exclusive.pid != 0) {
244 0 : fprintf(stderr, "Found WRITE, expected READ\n");
245 0 : return;
246 : }
247 : }
248 :
249 0 : pid = (exclusive.pid != 0) ? &exclusive : &shared[0];
250 :
251 0 : 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 0 : state->ok = true;
260 : }
261 :
262 : /*
263 : * Test lock upgrade/downgrade
264 : */
265 :
266 0 : bool run_g_lock3(int dummy)
267 : {
268 0 : struct tevent_context *ev = NULL;
269 0 : struct messaging_context *msg = NULL;
270 0 : struct g_lock_ctx *ctx = NULL;
271 0 : const char *lockname = "lock3";
272 : struct lock3_parser_state state;
273 : NTSTATUS status;
274 0 : bool ret = false;
275 : bool ok;
276 :
277 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
278 0 : if (!ok) {
279 0 : goto fail;
280 : }
281 :
282 0 : state.self = messaging_server_id(msg);
283 :
284 0 : status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_READ,
285 0 : (struct timeval) { .tv_sec = 1 });
286 0 : 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 0 : state.lock_type = G_LOCK_READ;
293 0 : state.ok = false;
294 :
295 0 : status = g_lock_dump(ctx, string_term_tdb_data(lockname),
296 : lock3_parser, &state);
297 0 : 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 0 : if (!state.ok) {
303 0 : goto fail;
304 : }
305 :
306 0 : status = g_lock_lock(ctx, string_term_tdb_data(lockname), G_LOCK_UPGRADE,
307 0 : (struct timeval) { .tv_sec = 1 });
308 0 : 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 0 : state.lock_type = G_LOCK_WRITE;
315 0 : state.ok = false;
316 :
317 0 : status = g_lock_dump(ctx, string_term_tdb_data(lockname),
318 : lock3_parser, &state);
319 0 : 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 0 : if (!state.ok) {
325 0 : goto fail;
326 : }
327 :
328 :
329 0 : ret = true;
330 0 : fail:
331 0 : TALLOC_FREE(ctx);
332 0 : TALLOC_FREE(msg);
333 0 : TALLOC_FREE(ev);
334 0 : return ret;
335 : }
336 :
337 0 : static bool lock4_child(const char *lockname,
338 : enum g_lock_type lock_type,
339 : int ready_pipe,
340 : int exit_pipe)
341 : {
342 0 : struct tevent_context *ev = NULL;
343 0 : struct messaging_context *msg = NULL;
344 0 : struct g_lock_ctx *ctx = NULL;
345 : NTSTATUS status;
346 : ssize_t n;
347 : bool ok;
348 :
349 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
350 0 : if (!ok) {
351 0 : return false;
352 : }
353 :
354 0 : status = g_lock_lock(
355 : ctx,
356 : string_term_tdb_data(lockname),
357 : lock_type,
358 0 : (struct timeval) { .tv_sec = 1 });
359 0 : 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 0 : n = sys_write(ready_pipe, &ok, sizeof(ok));
366 0 : if (n != sizeof(ok)) {
367 0 : fprintf(stderr, "child: write failed\n");
368 0 : return false;
369 : }
370 :
371 0 : if (ok) {
372 0 : n = sys_read(exit_pipe, &ok, sizeof(ok));
373 0 : 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 0 : static void lock4_done(struct tevent_req *subreq)
383 : {
384 0 : int *done = tevent_req_callback_data_void(subreq);
385 : NTSTATUS status;
386 :
387 0 : status = g_lock_lock_recv(subreq);
388 0 : TALLOC_FREE(subreq);
389 0 : 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 0 : *done = 1;
396 : }
397 :
398 0 : static void lock4_waited(struct tevent_req *subreq)
399 : {
400 0 : int *exit_pipe = tevent_req_callback_data_void(subreq);
401 : pid_t child;
402 : int status;
403 : bool ok;
404 :
405 0 : printf("waited\n");
406 :
407 0 : ok = tevent_wakeup_recv(subreq);
408 0 : TALLOC_FREE(subreq);
409 0 : if (!ok) {
410 0 : fprintf(stderr, "tevent_wakeup_recv failed\n");
411 : }
412 0 : close(*exit_pipe);
413 :
414 0 : child = wait(&status);
415 :
416 0 : printf("child %d exited with %d\n", (int)child, status);
417 0 : }
418 :
419 : struct lock4_check_state {
420 : struct server_id me;
421 : bool ok;
422 : };
423 :
424 0 : static void lock4_check(struct server_id exclusive,
425 : size_t num_shared,
426 : const struct server_id *shared,
427 : const uint8_t *data,
428 : size_t datalen,
429 : void *private_data)
430 : {
431 0 : struct lock4_check_state *state = private_data;
432 0 : size_t num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
433 :
434 0 : if (num_locks != 1) {
435 0 : fprintf(stderr, "num_locks=%zu\n", num_locks);
436 0 : return;
437 : }
438 :
439 0 : if (exclusive.pid == 0) {
440 0 : fprintf(stderr, "Wrong lock type, not WRITE\n");
441 0 : return;
442 : }
443 :
444 0 : 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 0 : state->ok = true;
453 : }
454 :
455 : /*
456 : * Test a lock conflict: Contend with a WRITE lock
457 : */
458 :
459 0 : bool run_g_lock4(int dummy)
460 : {
461 0 : struct tevent_context *ev = NULL;
462 0 : struct messaging_context *msg = NULL;
463 0 : struct g_lock_ctx *ctx = NULL;
464 0 : const char *lockname = "lock4";
465 0 : 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 0 : bool ret = false;
471 : struct tevent_req *req;
472 : bool ok;
473 : int done;
474 :
475 0 : if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
476 0 : perror("pipe failed");
477 0 : return false;
478 : }
479 :
480 0 : child = fork();
481 :
482 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
483 0 : if (!ok) {
484 0 : goto fail;
485 : }
486 :
487 0 : if (child == -1) {
488 0 : perror("fork failed");
489 0 : return false;
490 : }
491 :
492 0 : if (child == 0) {
493 0 : close(ready_pipe[0]);
494 0 : close(exit_pipe[1]);
495 0 : ok = lock4_child(
496 : lockname, G_LOCK_WRITE, ready_pipe[1], exit_pipe[0]);
497 0 : exit(ok ? 0 : 1);
498 : }
499 :
500 0 : close(ready_pipe[1]);
501 0 : close(exit_pipe[0]);
502 :
503 0 : if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
504 0 : perror("read failed");
505 0 : return false;
506 : }
507 :
508 0 : if (!ok) {
509 0 : fprintf(stderr, "child returned error\n");
510 0 : return false;
511 : }
512 :
513 0 : status = g_lock_lock(
514 0 : ctx, key, G_LOCK_WRITE, (struct timeval) { .tv_usec = 1 });
515 0 : 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 0 : status = g_lock_lock(
522 0 : ctx, key, G_LOCK_READ, (struct timeval) { .tv_usec = 1 });
523 0 : 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 0 : req = g_lock_lock_send(ev, ev, ctx, key, G_LOCK_WRITE);
530 0 : if (req == NULL) {
531 0 : fprintf(stderr, "g_lock_lock send failed\n");
532 0 : goto fail;
533 : }
534 0 : tevent_req_set_callback(req, lock4_done, &done);
535 :
536 0 : req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
537 0 : if (req == NULL) {
538 0 : fprintf(stderr, "tevent_wakeup_send failed\n");
539 0 : goto fail;
540 : }
541 0 : tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
542 :
543 0 : done = 0;
544 :
545 0 : while (done == 0) {
546 0 : int tevent_ret = tevent_loop_once(ev);
547 0 : if (tevent_ret != 0) {
548 0 : perror("tevent_loop_once failed");
549 0 : goto fail;
550 : }
551 : }
552 :
553 : {
554 0 : struct lock4_check_state state = {
555 0 : .me = messaging_server_id(msg)
556 : };
557 :
558 0 : status = g_lock_dump(ctx, key, lock4_check, &state);
559 0 : 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 0 : if (!state.ok) {
565 0 : fprintf(stderr, "lock4_check failed\n");
566 0 : goto fail;
567 : }
568 : }
569 :
570 0 : ret = true;
571 0 : fail:
572 0 : TALLOC_FREE(ctx);
573 0 : TALLOC_FREE(msg);
574 0 : TALLOC_FREE(ev);
575 0 : return ret;
576 : }
577 :
578 : /*
579 : * Test a lock conflict: Contend with a READ lock
580 : */
581 :
582 0 : bool run_g_lock4a(int dummy)
583 : {
584 0 : struct tevent_context *ev = NULL;
585 0 : struct messaging_context *msg = NULL;
586 0 : struct g_lock_ctx *ctx = NULL;
587 0 : const char *lockname = "lock4a";
588 0 : 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 0 : bool ret = false;
594 : struct tevent_req *req;
595 : bool ok;
596 : int done;
597 :
598 0 : if ((pipe(ready_pipe) != 0) || (pipe(exit_pipe) != 0)) {
599 0 : perror("pipe failed");
600 0 : return false;
601 : }
602 :
603 0 : child = fork();
604 :
605 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
606 0 : if (!ok) {
607 0 : goto fail;
608 : }
609 :
610 0 : if (child == -1) {
611 0 : perror("fork failed");
612 0 : return false;
613 : }
614 :
615 0 : if (child == 0) {
616 0 : close(ready_pipe[0]);
617 0 : close(exit_pipe[1]);
618 0 : ok = lock4_child(
619 : lockname, G_LOCK_READ, ready_pipe[1], exit_pipe[0]);
620 0 : exit(ok ? 0 : 1);
621 : }
622 :
623 0 : close(ready_pipe[1]);
624 0 : close(exit_pipe[0]);
625 :
626 0 : if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
627 0 : perror("read failed");
628 0 : return false;
629 : }
630 :
631 0 : if (!ok) {
632 0 : fprintf(stderr, "child returned error\n");
633 0 : return false;
634 : }
635 :
636 0 : status = g_lock_lock(
637 0 : ctx, key, G_LOCK_WRITE, (struct timeval) { .tv_usec = 1 });
638 0 : 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 0 : status = g_lock_lock(
645 0 : ctx, key, G_LOCK_READ, (struct timeval) { .tv_usec = 1 });
646 0 : 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 0 : status = g_lock_unlock(ctx, key);
653 0 : 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 0 : req = g_lock_lock_send(ev, ev, ctx, key, G_LOCK_WRITE);
661 0 : if (req == NULL) {
662 0 : fprintf(stderr, "g_lock_lock send failed\n");
663 0 : goto fail;
664 : }
665 0 : tevent_req_set_callback(req, lock4_done, &done);
666 :
667 0 : req = tevent_wakeup_send(ev, ev, timeval_current_ofs(1, 0));
668 0 : if (req == NULL) {
669 0 : fprintf(stderr, "tevent_wakeup_send failed\n");
670 0 : goto fail;
671 : }
672 0 : tevent_req_set_callback(req, lock4_waited, &exit_pipe[1]);
673 :
674 0 : done = 0;
675 :
676 0 : while (done == 0) {
677 0 : int tevent_ret = tevent_loop_once(ev);
678 0 : if (tevent_ret != 0) {
679 0 : perror("tevent_loop_once failed");
680 0 : goto fail;
681 : }
682 : }
683 :
684 : {
685 0 : struct lock4_check_state state = {
686 0 : .me = messaging_server_id(msg)
687 : };
688 :
689 0 : status = g_lock_dump(ctx, key, lock4_check, &state);
690 0 : 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 0 : if (!state.ok) {
696 0 : fprintf(stderr, "lock4_check failed\n");
697 0 : goto fail;
698 : }
699 : }
700 :
701 0 : ret = true;
702 0 : fail:
703 0 : TALLOC_FREE(ctx);
704 0 : TALLOC_FREE(msg);
705 0 : TALLOC_FREE(ev);
706 0 : return ret;
707 : }
708 :
709 : struct lock5_parser_state {
710 : size_t num_locks;
711 : };
712 :
713 0 : static void lock5_parser(struct server_id exclusive,
714 : size_t num_shared,
715 : const struct server_id *shared,
716 : const uint8_t *data,
717 : size_t datalen,
718 : void *private_data)
719 : {
720 0 : struct lock5_parser_state *state = private_data;
721 0 : state->num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
722 0 : }
723 :
724 : /*
725 : * Test heuristic cleanup
726 : */
727 :
728 0 : bool run_g_lock5(int dummy)
729 : {
730 0 : struct tevent_context *ev = NULL;
731 0 : struct messaging_context *msg = NULL;
732 0 : struct g_lock_ctx *ctx = NULL;
733 0 : 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 0 : nprocs = 5;
744 :
745 0 : if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
746 0 : perror("pipe failed");
747 0 : return false;
748 : }
749 :
750 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
751 0 : if (!ok) {
752 0 : fprintf(stderr, "get_g_lock_ctx failed");
753 0 : return false;
754 : }
755 :
756 0 : for (i=0; i<nprocs; i++) {
757 :
758 0 : child = fork();
759 :
760 0 : if (child == -1) {
761 0 : perror("fork failed");
762 0 : return false;
763 : }
764 :
765 0 : if (child == 0) {
766 0 : TALLOC_FREE(ctx);
767 :
768 0 : status = reinit_after_fork(msg, ev, false, "");
769 :
770 0 : close(ready_pipe[0]);
771 0 : close(exit_pipe[1]);
772 :
773 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
774 0 : if (!ok) {
775 0 : fprintf(stderr, "get_g_lock_ctx failed");
776 0 : exit(1);
777 : }
778 0 : status = g_lock_lock(ctx,
779 : string_term_tdb_data(lockname),
780 : G_LOCK_READ,
781 0 : (struct timeval) { .tv_sec = 1 });
782 0 : 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 0 : close(ready_pipe[1]);
789 0 : nread = sys_read(exit_pipe[0], &c, sizeof(c));
790 0 : if (nread != 0) {
791 0 : fprintf(stderr, "sys_read returned %zu (%s)\n",
792 0 : nread, strerror(errno));
793 0 : exit(1);
794 : }
795 0 : exit(0);
796 : }
797 : }
798 :
799 0 : close(ready_pipe[1]);
800 :
801 0 : nread = sys_read(ready_pipe[0], &c, sizeof(c));
802 0 : 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 0 : close(exit_pipe[1]);
809 :
810 0 : for (i=0; i<nprocs; i++) {
811 : int child_status;
812 0 : ret = waitpid(-1, &child_status, 0);
813 0 : if (ret == -1) {
814 0 : perror("waitpid failed");
815 0 : return false;
816 : }
817 : }
818 :
819 0 : for (i=0; i<nprocs; i++) {
820 : struct lock5_parser_state state;
821 :
822 0 : status = g_lock_dump(ctx, string_term_tdb_data(lockname),
823 : lock5_parser, &state);
824 0 : 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 0 : 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 0 : status = g_lock_lock(ctx, string_term_tdb_data(lockname),
837 : G_LOCK_READ,
838 0 : (struct timeval) { .tv_sec = 1 });
839 0 : 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 0 : status = g_lock_unlock(ctx, string_term_tdb_data(lockname));
845 0 : 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 0 : static void lock6_parser(struct server_id exclusive,
861 : size_t num_shared,
862 : const struct server_id *shared,
863 : const uint8_t *data,
864 : size_t datalen,
865 : void *private_data)
866 : {
867 0 : struct lock6_parser_state *state = private_data;
868 0 : state->num_locks = num_shared + ((exclusive.pid != 0) ? 1 : 0);
869 0 : }
870 :
871 : /*
872 : * Test cleanup with contention and stale locks
873 : */
874 :
875 0 : bool run_g_lock6(int dummy)
876 : {
877 0 : struct tevent_context *ev = NULL;
878 0 : struct messaging_context *msg = NULL;
879 0 : struct g_lock_ctx *ctx = NULL;
880 0 : 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 0 : if ((pipe(exit_pipe) != 0) || (pipe(ready_pipe) != 0)) {
891 0 : perror("pipe failed");
892 0 : return false;
893 : }
894 :
895 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
896 0 : 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 0 : status = g_lock_lock(ctx, lockname, G_LOCK_WRITE,
906 0 : (struct timeval) { .tv_sec = 1 });
907 0 : 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 0 : status = g_lock_unlock(ctx, lockname);
913 0 : 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 0 : for (i=0; i<nprocs; i++) {
921 :
922 0 : child = fork();
923 :
924 0 : if (child == -1) {
925 0 : perror("fork failed");
926 0 : return false;
927 : }
928 :
929 0 : if (child == 0) {
930 0 : TALLOC_FREE(ctx);
931 :
932 0 : status = reinit_after_fork(msg, ev, false, "");
933 0 : 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 0 : close(ready_pipe[0]);
940 0 : close(exit_pipe[1]);
941 :
942 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
943 0 : if (!ok) {
944 0 : fprintf(stderr, "get_g_lock_ctx failed");
945 0 : exit(1);
946 : }
947 0 : status = g_lock_lock(ctx,
948 : lockname,
949 : G_LOCK_READ,
950 0 : (struct timeval) { .tv_sec = 1 });
951 0 : 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 0 : if (i == 0) {
958 0 : exit(0);
959 : }
960 0 : close(ready_pipe[1]);
961 0 : nread = sys_read(exit_pipe[0], &c, sizeof(c));
962 0 : if (nread != 0) {
963 0 : fprintf(stderr, "sys_read returned %zu (%s)\n",
964 0 : nread, strerror(errno));
965 0 : exit(1);
966 : }
967 0 : exit(0);
968 : }
969 : }
970 :
971 0 : close(ready_pipe[1]);
972 :
973 0 : nread = sys_read(ready_pipe[0], &c, sizeof(c));
974 0 : 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 0 : ret = waitpid(-1, &child_status, 0);
983 0 : if (ret == -1) {
984 0 : perror("waitpid failed");
985 0 : return false;
986 : }
987 : }
988 :
989 : {
990 : struct lock6_parser_state state;
991 :
992 0 : status = g_lock_dump(ctx, lockname, lock6_parser, &state);
993 0 : 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 0 : 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 0 : status = g_lock_lock(ctx,
1006 : lockname,
1007 : G_LOCK_WRITE,
1008 0 : (struct timeval) { .tv_sec = 1 });
1009 0 : 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 0 : status = g_lock_lock(ctx, lockname, G_LOCK_READ,
1017 0 : (struct timeval) { .tv_sec = 1 });
1018 0 : 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 0 : close(exit_pipe[1]);
1026 :
1027 : {
1028 : int child_status;
1029 0 : ret = waitpid(-1, &child_status, 0);
1030 0 : if (ret == -1) {
1031 0 : perror("waitpid failed");
1032 0 : return false;
1033 : }
1034 : }
1035 :
1036 0 : status = g_lock_lock(ctx, lockname, G_LOCK_UPGRADE,
1037 0 : (struct timeval) { .tv_sec = 1 });
1038 0 : 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 0 : bool run_g_lock7(int dummy)
1052 : {
1053 0 : struct tevent_context *ev = NULL;
1054 0 : struct messaging_context *msg = NULL;
1055 0 : struct g_lock_ctx *ctx = NULL;
1056 0 : const char *lockname = "lock7";
1057 0 : 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 0 : bool ret = false;
1064 0 : bool ok = true;
1065 :
1066 0 : if ((pipe(ready_pipe) != 0) || (pipe(down_pipe) != 0)) {
1067 0 : perror("pipe failed");
1068 0 : return false;
1069 : }
1070 :
1071 0 : child = fork();
1072 :
1073 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
1074 0 : if (!ok) {
1075 0 : goto fail;
1076 : }
1077 :
1078 0 : if (child == -1) {
1079 0 : perror("fork failed");
1080 0 : return false;
1081 : }
1082 :
1083 0 : if (child == 0) {
1084 0 : struct tevent_req *req = NULL;
1085 :
1086 0 : close(ready_pipe[0]);
1087 0 : ready_pipe[0] = -1;
1088 0 : close(down_pipe[1]);
1089 0 : down_pipe[1] = -1;
1090 :
1091 0 : status = reinit_after_fork(msg, ev, false, "");
1092 0 : 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 0 : printf("%d: locking READ\n", (int)getpid());
1100 :
1101 0 : status = g_lock_lock(
1102 : ctx,
1103 : key,
1104 : G_LOCK_READ,
1105 0 : (struct timeval) { .tv_usec = 1 });
1106 0 : 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 0 : ok = true;
1114 :
1115 0 : n = sys_write(ready_pipe[1], &ok, sizeof(ok));
1116 0 : 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 0 : n = sys_read(down_pipe[0], &ok, sizeof(ok));
1124 0 : 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 0 : printf("%d: starting UPGRADE\n", (int)getpid());
1132 :
1133 0 : req = g_lock_lock_send(
1134 : msg,
1135 : ev,
1136 : ctx,
1137 : key,
1138 : G_LOCK_UPGRADE);
1139 0 : if (req == NULL) {
1140 0 : fprintf(stderr, "g_lock_lock_send(UPGRADE) failed\n");
1141 0 : exit(1);
1142 : }
1143 :
1144 0 : n = sys_write(ready_pipe[1], &ok, sizeof(ok));
1145 0 : 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 0 : exit(0);
1153 : }
1154 :
1155 0 : close(ready_pipe[1]);
1156 0 : close(down_pipe[0]);
1157 :
1158 0 : if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
1159 0 : perror("read failed");
1160 0 : return false;
1161 : }
1162 0 : if (!ok) {
1163 0 : fprintf(stderr, "child returned error\n");
1164 0 : return false;
1165 : }
1166 :
1167 0 : status = g_lock_lock(
1168 : ctx,
1169 : key,
1170 : G_LOCK_READ,
1171 0 : (struct timeval) { .tv_usec = 1 });
1172 0 : 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 0 : n = sys_write(down_pipe[1], &ok, sizeof(ok));
1180 0 : 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 0 : if (sys_read(ready_pipe[0], &ok, sizeof(ok)) != sizeof(ok)) {
1188 0 : perror("read failed");
1189 0 : goto fail;
1190 : }
1191 :
1192 0 : status = g_lock_lock(
1193 : ctx,
1194 : key,
1195 : G_LOCK_UPGRADE,
1196 0 : (struct timeval) { .tv_sec = 10 });
1197 0 : 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 0 : fail:
1206 0 : TALLOC_FREE(ctx);
1207 0 : TALLOC_FREE(msg);
1208 0 : TALLOC_FREE(ev);
1209 0 : return ret;
1210 : }
1211 :
1212 0 : bool run_g_lock8(int dummy)
1213 : {
1214 0 : struct tevent_context *ev = NULL;
1215 0 : struct messaging_context *msg = NULL;
1216 0 : struct g_lock_ctx *ctx = NULL;
1217 0 : struct tevent_req *req = NULL;
1218 0 : TDB_DATA lockname = string_term_tdb_data("lock8");
1219 : NTSTATUS status;
1220 : bool ok;
1221 :
1222 0 : ok = get_g_lock_ctx(talloc_tos(), &ev, &msg, &ctx);
1223 0 : if (!ok) {
1224 0 : fprintf(stderr, "get_g_lock_ctx failed");
1225 0 : return false;
1226 : }
1227 :
1228 0 : req = g_lock_watch_data_send(
1229 0 : ev, ev, ctx, lockname, (struct server_id) { .pid = 0 });
1230 0 : if (req == NULL) {
1231 0 : fprintf(stderr, "get_g_lock_ctx failed");
1232 0 : return false;
1233 : }
1234 :
1235 0 : status = g_lock_lock(
1236 : ctx,
1237 : lockname,
1238 : G_LOCK_WRITE,
1239 0 : (struct timeval) { .tv_sec = 999 });
1240 0 : 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 0 : status = g_lock_write_data(
1248 0 : ctx, lockname, lockname.dptr, lockname.dsize);
1249 0 : 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 0 : status = g_lock_write_data(ctx, lockname, NULL, 0);
1257 0 : 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 0 : status = g_lock_unlock(ctx, lockname);
1265 0 : 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 0 : ok = tevent_req_poll_ntstatus(req, ev, &status);
1273 0 : if (!ok) {
1274 0 : fprintf(stderr, "tevent_req_poll_ntstatus failed\n");
1275 0 : return false;
1276 : }
1277 0 : 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 : }
|