s3:torture:delete: untangle function call from result check
[kai/samba.git] / source3 / torture / test_notify.c
1 /*
2    Unix SMB/CIFS implementation.
3    Scalability test for notifies
4    Copyright (C) Volker Lendecke 2012
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 "libsmb/libsmb.h"
23 #include "lib/util/tevent_ntstatus.h"
24 #include "libcli/security/security.h"
25 #include "lib/tevent_barrier.h"
26
27 extern int torture_nprocs, torture_numops;
28
29 struct wait_for_one_notify_state {
30         struct tevent_context *ev;
31         struct cli_state *cli;
32         uint16_t dnum;
33         uint32_t filter;
34         bool recursive;
35         unsigned *num_notifies;
36 };
37
38 static void wait_for_one_notify_opened(struct tevent_req *subreq);
39 static void wait_for_one_notify_chkpath_done(struct tevent_req *subreq);
40 static void wait_for_one_notify_done(struct tevent_req *subreq);
41 static void wait_for_one_notify_closed(struct tevent_req *subreq);
42
43 static struct tevent_req *wait_for_one_notify_send(TALLOC_CTX *mem_ctx,
44                                                    struct tevent_context *ev,
45                                                    struct cli_state *cli,
46                                                    const char *path,
47                                                    uint32_t filter,
48                                                    bool recursive,
49                                                    unsigned *num_notifies)
50 {
51         struct tevent_req *req, *subreq;
52         struct wait_for_one_notify_state *state;
53
54         req = tevent_req_create(mem_ctx, &state,
55                                 struct wait_for_one_notify_state);
56         if (req == NULL) {
57                 return NULL;
58         }
59         state->ev = ev;
60         state->cli = cli;
61         state->filter = filter;
62         state->recursive = recursive;
63         state->num_notifies = num_notifies;
64
65         subreq = cli_ntcreate_send(
66                 state, state->ev, state->cli, path, 0,
67                 MAXIMUM_ALLOWED_ACCESS,
68                 0, FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
69                 FILE_OPEN, FILE_DIRECTORY_FILE, 0);
70         if (tevent_req_nomem(subreq, req)) {
71                 return tevent_req_post(req, ev);
72         }
73         tevent_req_set_callback(subreq, wait_for_one_notify_opened, req);
74         return req;
75 }
76
77 static void wait_for_one_notify_opened(struct tevent_req *subreq)
78 {
79         struct tevent_req *req = tevent_req_callback_data(
80                 subreq, struct tevent_req);
81         struct wait_for_one_notify_state *state = tevent_req_data(
82                 req, struct wait_for_one_notify_state);
83         NTSTATUS status;
84
85         status = cli_ntcreate_recv(subreq, &state->dnum);
86         TALLOC_FREE(subreq);
87         if (tevent_req_nterror(req, status)) {
88                 return;
89         }
90         subreq = cli_notify_send(state, state->ev, state->cli, state->dnum,
91                                  0xffff, state->filter, state->recursive);
92         if (tevent_req_nomem(subreq, req)) {
93                 return;
94         }
95         tevent_req_set_callback(subreq, wait_for_one_notify_done, req);
96
97         /*
98          * To make sure the notify received at the server, we do another no-op
99          * that is replied to.
100          */
101         subreq = cli_chkpath_send(state, state->ev, state->cli, "\\");
102         if (tevent_req_nomem(subreq, req)) {
103                 return;
104         }
105         tevent_req_set_callback(subreq, wait_for_one_notify_chkpath_done, req);
106 }
107
108 static void wait_for_one_notify_chkpath_done(struct tevent_req *subreq)
109 {
110         struct tevent_req *req = tevent_req_callback_data(
111                 subreq, struct tevent_req);
112         struct wait_for_one_notify_state *state = tevent_req_data(
113                 req, struct wait_for_one_notify_state);
114         NTSTATUS status;
115
116         status = cli_chkpath_recv(subreq);
117         TALLOC_FREE(subreq);
118         if (tevent_req_nterror(req, status)) {
119                 return;
120         }
121         *state->num_notifies += 1;
122 }
123
124 static void wait_for_one_notify_done(struct tevent_req *subreq)
125 {
126         struct tevent_req *req = tevent_req_callback_data(
127                 subreq, struct tevent_req);
128         struct wait_for_one_notify_state *state = tevent_req_data(
129                 req, struct wait_for_one_notify_state);
130         uint32_t num_changes;
131         struct notify_change *changes;
132         NTSTATUS status;
133
134         status = cli_notify_recv(subreq, state, &num_changes, &changes);
135         TALLOC_FREE(subreq);
136         if (tevent_req_nterror(req, status)) {
137                 return;
138         }
139         subreq = cli_close_send(state, state->ev, state->cli, state->dnum);
140         if (tevent_req_nomem(subreq, req)) {
141                 return;
142         }
143         tevent_req_set_callback(subreq, wait_for_one_notify_closed, req);
144 }
145
146 static void wait_for_one_notify_closed(struct tevent_req *subreq)
147 {
148         struct tevent_req *req = tevent_req_callback_data(
149                 subreq, struct tevent_req);
150         struct wait_for_one_notify_state *state = tevent_req_data(
151                 req, struct wait_for_one_notify_state);
152         NTSTATUS status;
153
154         status = cli_close_recv(subreq);
155         TALLOC_FREE(subreq);
156         if (tevent_req_nterror(req, status)) {
157                 return;
158         }
159         *state->num_notifies -= 1;
160         tevent_req_done(req);
161 }
162
163 static NTSTATUS wait_for_one_notify_recv(struct tevent_req *req)
164 {
165         return tevent_req_simple_recv_ntstatus(req);
166 }
167
168 static void notify_bench2_done(struct tevent_req *req);
169
170 bool run_notify_bench2(int dummy)
171 {
172         struct cli_state *cli;
173         struct cli_state **clis;
174         struct tevent_context *ev;
175         unsigned num_notifies = 0;
176         NTSTATUS status;
177         int i;
178
179         if (!torture_open_connection(&cli, 0)) {
180                 return false;
181         }
182
183         printf("starting notify bench 2 test\n");
184
185         cli_rmdir(cli, "\\notify.dir\\subdir");
186         cli_rmdir(cli, "\\notify.dir");
187
188         status = cli_mkdir(cli, "\\notify.dir");
189         if (!NT_STATUS_IS_OK(status)) {
190                 printf("mkdir failed : %s\n", nt_errstr(status));
191                 return false;
192         }
193
194         clis = talloc_array(talloc_tos(), struct cli_state *, torture_nprocs);
195         if (clis == NULL) {
196                 printf("talloc failed\n");
197                 return false;
198         }
199
200         ev = tevent_context_init(talloc_tos());
201         if (ev == NULL) {
202                 printf("tevent_context_create failed\n");
203                 return false;
204         }
205
206         for (i=0; i<torture_nprocs; i++) {
207                 int j;
208                 if (!torture_open_connection(&clis[i], i)) {
209                         return false;
210                 }
211
212                 for (j=0; j<torture_numops; j++) {
213                         struct tevent_req *req;
214                         req = wait_for_one_notify_send(
215                                 talloc_tos(), ev, clis[i], "\\notify.dir",
216                                 FILE_NOTIFY_CHANGE_ALL, true,
217                                 &num_notifies);
218                         if (req == NULL) {
219                                 printf("wait_for_one_notify_send failed\n");
220                                 return false;
221                         }
222                         tevent_req_set_callback(req, notify_bench2_done, NULL);
223                 }
224         }
225
226         while (num_notifies < torture_nprocs * torture_numops) {
227                 int ret;
228                 ret = tevent_loop_once(ev);
229                 if (ret != 0) {
230                         printf("tevent_loop_once failed: %s\n",
231                                strerror(errno));
232                         return false;
233                 }
234         }
235
236         cli_mkdir(cli, "\\notify.dir\\subdir");
237
238         while (num_notifies > 0) {
239                 int ret;
240                 ret = tevent_loop_once(ev);
241                 if (ret != 0) {
242                         printf("tevent_loop_once failed: %s\n",
243                                strerror(errno));
244                         return false;
245                 }
246         }
247
248         return true;
249 }
250
251 static void notify_bench2_done(struct tevent_req *req)
252 {
253         NTSTATUS status;
254
255         status = wait_for_one_notify_recv(req);
256         TALLOC_FREE(req);
257         if (!NT_STATUS_IS_OK(status)) {
258                 printf("wait_for_one_notify returned %s\n",
259                        nt_errstr(status));
260         }
261 }
262
263 /*
264  * This test creates a subdirectory. It then waits on a barrier before the
265  * notify is sent. Then it creates the notify. It then waits for another
266  * barrier, so that all of the notifies have gone through. It then creates
267  * another subdirectory, which will trigger notifications to be sent. When the
268  * notifies have been received, it waits once more before everything is
269  * cleaned up.
270  */
271
272 struct notify_bench3_state {
273         struct tevent_context *ev;
274         struct cli_state *cli;
275         const char *dir;
276         uint16_t dnum;
277         const char *subdir_path;
278         uint16_t subdir_dnum;
279         int wait_timeout;
280         struct tevent_barrier *small;
281         struct tevent_barrier *large;
282 };
283
284 static void notify_bench3_mkdir1_done(struct tevent_req *subreq);
285 static void notify_bench3_before_notify(struct tevent_req *subreq);
286 static void notify_bench3_chkpath_done(struct tevent_req *subreq);
287 static void notify_bench3_before_mkdir2(struct tevent_req *subreq);
288 static void notify_bench3_notify_done(struct tevent_req *subreq);
289 static void notify_bench3_notifies_done(struct tevent_req *subreq);
290 static void notify_bench3_mksubdir_done(struct tevent_req *subreq);
291 static void notify_bench3_before_close_subdir(struct tevent_req *subreq);
292 static void notify_bench3_close_subdir_done(struct tevent_req *subreq);
293 static void notify_bench3_deleted_subdir(struct tevent_req *subreq);
294 static void notify_bench3_deleted_subdirs(struct tevent_req *subreq);
295 static void notify_bench3_del_on_close_set(struct tevent_req *subreq);
296 static void notify_bench3_closed(struct tevent_req *subreq);
297
298 static struct tevent_req *notify_bench3_send(
299         TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
300         const char *dir, const char *subdir_path,
301         struct tevent_barrier *small, struct tevent_barrier *large)
302 {
303         struct tevent_req *req, *subreq;
304         struct notify_bench3_state *state;
305
306         req = tevent_req_create(mem_ctx, &state, struct notify_bench3_state);
307         if (req == NULL) {
308                 return NULL;
309         }
310         state->ev = ev;
311         state->cli = cli;
312         state->dir = dir;
313         state->subdir_path = subdir_path;
314         state->small = small;
315         state->large = large;
316
317         subreq = cli_ntcreate_send(
318                 state, state->ev, state->cli, state->dir, 0,
319                 MAXIMUM_ALLOWED_ACCESS, 0,
320                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
321                 FILE_OPEN_IF, FILE_DIRECTORY_FILE, 0);
322         if (tevent_req_nomem(subreq, req)) {
323                 return tevent_req_post(req, ev);
324         }
325         tevent_req_set_callback(subreq, notify_bench3_mkdir1_done, req);
326         return req;
327 }
328
329 static void notify_bench3_mkdir1_done(struct tevent_req *subreq)
330 {
331         struct tevent_req *req = tevent_req_callback_data(
332                 subreq, struct tevent_req);
333         struct notify_bench3_state *state = tevent_req_data(
334                 req, struct notify_bench3_state);
335         NTSTATUS status;
336
337         status = cli_ntcreate_recv(subreq, &state->dnum);
338         TALLOC_FREE(subreq);
339         if (tevent_req_nterror(req, status)) {
340                 return;
341         }
342         subreq = tevent_barrier_wait_send(state, state->ev, state->small);
343         if (tevent_req_nomem(subreq, req)) {
344                 return;
345         }
346         tevent_req_set_callback(subreq, notify_bench3_before_notify, req);
347 }
348
349 static void notify_bench3_before_notify(struct tevent_req *subreq)
350 {
351         struct tevent_req *req = tevent_req_callback_data(
352                 subreq, struct tevent_req);
353         struct notify_bench3_state *state = tevent_req_data(
354                 req, struct notify_bench3_state);
355         int ret;
356
357         ret = tevent_barrier_wait_recv(subreq);
358         TALLOC_FREE(subreq);
359         if (ret != 0) {
360                 tevent_req_nterror(req, map_nt_error_from_unix(ret));
361                 return;
362         }
363         subreq = cli_notify_send(state, state->ev, state->cli, state->dnum,
364                                  0xffff, FILE_NOTIFY_CHANGE_ALL, true);
365         if (tevent_req_nomem(subreq, req)) {
366                 return;
367         }
368         tevent_req_set_callback(subreq, notify_bench3_notify_done, req);
369
370         /*
371          * To make sure the notify received at the server, we do another no-op
372          * that is replied to.
373          */
374         subreq = cli_chkpath_send(state, state->ev, state->cli, "\\");
375         if (tevent_req_nomem(subreq, req)) {
376                 return;
377         }
378         tevent_req_set_callback(subreq, notify_bench3_chkpath_done, req);
379 }
380
381 static void notify_bench3_notify_done(struct tevent_req *subreq)
382 {
383         struct tevent_req *req = tevent_req_callback_data(
384                 subreq, struct tevent_req);
385         struct notify_bench3_state *state = tevent_req_data(
386                 req, struct notify_bench3_state);
387         uint32_t num_changes;
388         struct notify_change *changes;
389         NTSTATUS status;
390
391         status = cli_notify_recv(subreq, state, &num_changes, &changes);
392         TALLOC_FREE(subreq);
393         if (tevent_req_nterror(req, status)) {
394                 return;
395         }
396         subreq = tevent_barrier_wait_send(state, state->ev, state->large);
397         if (tevent_req_nomem(subreq, req)) {
398                 return;
399         }
400         tevent_req_set_callback(subreq, notify_bench3_notifies_done, req);
401 }
402
403 static void notify_bench3_notifies_done(struct tevent_req *subreq)
404 {
405         struct tevent_req *req = tevent_req_callback_data(
406                 subreq, struct tevent_req);
407         int ret;
408
409         ret = tevent_barrier_wait_recv(subreq);
410         TALLOC_FREE(subreq);
411         if (ret != 0) {
412                 tevent_req_nterror(req, map_nt_error_from_unix(ret));
413                 return;
414         }
415 }
416
417 static void notify_bench3_chkpath_done(struct tevent_req *subreq)
418 {
419         struct tevent_req *req = tevent_req_callback_data(
420                 subreq, struct tevent_req);
421         struct notify_bench3_state *state = tevent_req_data(
422                 req, struct notify_bench3_state);
423         NTSTATUS status;
424
425         status = cli_chkpath_recv(subreq);
426         TALLOC_FREE(subreq);
427         if (tevent_req_nterror(req, status)) {
428                 return;
429         }
430         if (state->subdir_path == NULL) {
431                 return;
432         }
433         subreq = tevent_barrier_wait_send(state, state->ev, state->small);
434         if (tevent_req_nomem(subreq, req)) {
435                 return;
436         }
437         tevent_req_set_callback(subreq, notify_bench3_before_mkdir2, req);
438 }
439
440 static void notify_bench3_before_mkdir2(struct tevent_req *subreq)
441 {
442         struct tevent_req *req = tevent_req_callback_data(
443                 subreq, struct tevent_req);
444         struct notify_bench3_state *state = tevent_req_data(
445                 req, struct notify_bench3_state);
446         int ret;
447
448         ret = tevent_barrier_wait_recv(subreq);
449         TALLOC_FREE(subreq);
450         if (ret != 0) {
451                 tevent_req_nterror(req, map_nt_error_from_unix(ret));
452                 return;
453         }
454         subreq =  cli_ntcreate_send(
455                 state, state->ev, state->cli, state->subdir_path, 0,
456                 MAXIMUM_ALLOWED_ACCESS, 0,
457                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
458                 FILE_CREATE,
459                 FILE_DIRECTORY_FILE, 0);
460         if (tevent_req_nomem(subreq, req)) {
461                 return;
462         }
463         tevent_req_set_callback(subreq, notify_bench3_mksubdir_done, req);
464 }
465
466 static void notify_bench3_mksubdir_done(struct tevent_req *subreq)
467 {
468         struct tevent_req *req = tevent_req_callback_data(
469                 subreq, struct tevent_req);
470         struct notify_bench3_state *state = tevent_req_data(
471                 req, struct notify_bench3_state);
472         NTSTATUS status;
473
474         status = cli_ntcreate_recv(subreq, &state->subdir_dnum);
475         TALLOC_FREE(subreq);
476         if (tevent_req_nterror(req, status)) {
477                 return;
478         }
479         subreq = tevent_barrier_wait_send(state, state->ev, state->large);
480         if (tevent_req_nomem(subreq, req)) {
481                 return;
482         }
483         tevent_req_set_callback(subreq, notify_bench3_before_close_subdir,
484                                 req);
485 }
486
487 static void notify_bench3_before_close_subdir(struct tevent_req *subreq)
488 {
489         struct tevent_req *req = tevent_req_callback_data(
490                 subreq, struct tevent_req);
491         struct notify_bench3_state *state = tevent_req_data(
492                 req, struct notify_bench3_state);
493         int ret;
494
495         ret = tevent_barrier_wait_recv(subreq);
496         TALLOC_FREE(subreq);
497         if (ret != 0) {
498                 tevent_req_nterror(req, map_nt_error_from_unix(ret));
499                 return;
500         }
501         subreq = cli_close_send(state, state->ev, state->cli,
502                                 state->subdir_dnum);
503         if (tevent_req_nomem(subreq, req)) {
504                 return;
505         }
506         tevent_req_set_callback(subreq, notify_bench3_close_subdir_done, req);
507 }
508
509 static void notify_bench3_close_subdir_done(struct tevent_req *subreq)
510 {
511         struct tevent_req *req = tevent_req_callback_data(
512                 subreq, struct tevent_req);
513         struct notify_bench3_state *state = tevent_req_data(
514                 req, struct notify_bench3_state);
515         NTSTATUS status;
516
517         status = cli_close_recv(subreq);
518         TALLOC_FREE(subreq);
519         if (tevent_req_nterror(req, status)) {
520                 return;
521         }
522         subreq = cli_rmdir_send(state, state->ev, state->cli,
523                                 state->subdir_path);
524         if (tevent_req_nomem(subreq, req)) {
525                 return;
526         }
527         tevent_req_set_callback(subreq, notify_bench3_deleted_subdir, req);
528 }
529
530 static void notify_bench3_deleted_subdir(struct tevent_req *subreq)
531 {
532         struct tevent_req *req = tevent_req_callback_data(
533                 subreq, struct tevent_req);
534         struct notify_bench3_state *state = tevent_req_data(
535                 req, struct notify_bench3_state);
536         NTSTATUS status;
537
538         status = cli_rmdir_recv(subreq);
539         TALLOC_FREE(subreq);
540         if (tevent_req_nterror(req, status)) {
541                 return;
542         }
543         subreq = tevent_barrier_wait_send(state, state->ev, state->small);
544         if (tevent_req_nomem(subreq, req)) {
545                 return;
546         }
547         tevent_req_set_callback(subreq, notify_bench3_deleted_subdirs, req);
548 }
549
550 static void notify_bench3_deleted_subdirs(struct tevent_req *subreq)
551 {
552         struct tevent_req *req = tevent_req_callback_data(
553                 subreq, struct tevent_req);
554         struct notify_bench3_state *state = tevent_req_data(
555                 req, struct notify_bench3_state);
556         int ret;
557
558         ret = tevent_barrier_wait_recv(subreq);
559         TALLOC_FREE(subreq);
560         if (ret != 0) {
561                 tevent_req_nterror(req, map_nt_error_from_unix(ret));
562                 return;
563         }
564         subreq = cli_nt_delete_on_close_send(state, state->ev, state->cli,
565                                              state->dnum, true);
566         if (tevent_req_nomem(subreq, req)) {
567                 return;
568         }
569         tevent_req_set_callback(subreq, notify_bench3_del_on_close_set, req);
570 }
571
572 static void notify_bench3_del_on_close_set(struct tevent_req *subreq)
573 {
574         struct tevent_req *req = tevent_req_callback_data(
575                 subreq, struct tevent_req);
576         struct notify_bench3_state *state = tevent_req_data(
577                 req, struct notify_bench3_state);
578         NTSTATUS status;
579
580         status = cli_nt_delete_on_close_recv(subreq);
581         TALLOC_FREE(subreq);
582         subreq = cli_close_send(state, state->ev, state->cli, state->dnum);
583         if (tevent_req_nomem(subreq, req)) {
584                 return;
585         }
586         tevent_req_set_callback(subreq, notify_bench3_closed, req);
587 }
588
589 static void notify_bench3_closed(struct tevent_req *subreq)
590 {
591         struct tevent_req *req = tevent_req_callback_data(
592                 subreq, struct tevent_req);
593         NTSTATUS status;
594
595         status = cli_close_recv(subreq);
596         TALLOC_FREE(subreq);
597         if (tevent_req_nterror(req, status)) {
598                 return;
599         }
600         tevent_req_done(req);
601 }
602
603 static NTSTATUS notify_bench3_recv(struct tevent_req *req)
604 {
605         return tevent_req_simple_recv_ntstatus(req);
606 }
607
608 static void notify_bench3_done(struct tevent_req *req)
609 {
610         unsigned *num_done = (unsigned *)tevent_req_callback_data_void(req);
611         NTSTATUS status;
612
613         status = notify_bench3_recv(req);
614         TALLOC_FREE(req);
615         if (!NT_STATUS_IS_OK(status)) {
616                 d_printf("notify_bench3 returned %s\n", nt_errstr(status));
617         }
618         *num_done += 1;
619 }
620
621 static void notify_bench3_barrier_cb(void *private_data)
622 {
623         struct timeval *ts = (struct timeval *)private_data;
624         struct timeval now;
625
626         GetTimeOfDay(&now);
627         printf("barrier triggered: %f\n", timeval_elapsed2(ts, &now));
628         GetTimeOfDay(ts);
629 }
630
631 bool run_notify_bench3(int dummy)
632 {
633         struct cli_state **clis;
634         struct tevent_context *ev;
635         struct tevent_barrier *small;
636         struct tevent_barrier *large;
637         unsigned i, j;
638         unsigned num_done = 0;
639         struct timeval ts, now;
640
641         clis = talloc_array(talloc_tos(), struct cli_state *, torture_nprocs);
642         if (clis == NULL) {
643                 printf("talloc failed\n");
644                 return false;
645         }
646
647         GetTimeOfDay(&ts);
648
649         small = tevent_barrier_init(
650                 talloc_tos(), torture_nprocs * torture_numops,
651                 notify_bench3_barrier_cb, &ts);
652         if (small == NULL) {
653                 return false;
654         }
655
656         large = tevent_barrier_init(
657                 talloc_tos(), 2 * torture_nprocs * torture_numops,
658                 notify_bench3_barrier_cb, &ts);
659         if (large == NULL) {
660                 return false;
661         }
662
663         ev = tevent_context_init(talloc_tos());
664         if (ev == NULL) {
665                 printf("tevent_context_create failed\n");
666                 return false;
667         }
668
669         for (i=0; i<torture_nprocs; i++) {
670                 if (!torture_open_connection(&clis[i], i)) {
671                         return false;
672                 }
673         }
674
675         for (i=0; i<torture_nprocs; i++) {
676                 for (j=0; j<torture_numops; j++) {
677                         int idx = i * torture_numops + j;
678                         struct tevent_req *req;
679                         char *dirname, *subdirname;
680
681                         dirname = talloc_asprintf(
682                                 talloc_tos(), "\\dir%.8d", idx);
683                         if (dirname == NULL) {
684                                 return false;
685                         }
686                         subdirname = talloc_asprintf(
687                                 talloc_tos(), "\\dir%.8d\\subdir",
688                                 (idx + torture_numops + 1) %
689                                 (torture_nprocs * torture_numops));
690                         if (subdirname == NULL) {
691                                 return false;
692                         }
693
694                         req = notify_bench3_send(
695                                 talloc_tos(), ev, clis[i], dirname,
696                                 subdirname, small, large);
697                         if (req == NULL) {
698                                 return false;
699                         }
700                         tevent_req_set_callback(req, notify_bench3_done,
701                                                 &num_done);
702                 }
703         }
704
705         while (num_done < torture_nprocs * torture_numops) {
706                 int ret;
707                 ret = tevent_loop_once(ev);
708                 if (ret != 0) {
709                         printf("tevent_loop_once failed: %s\n",
710                                strerror(errno));
711                         return false;
712                 }
713         }
714
715         GetTimeOfDay(&now);
716         printf("turndow: %f\n", timeval_elapsed2(&ts, &now));
717         TALLOC_FREE(small);
718         TALLOC_FREE(large);
719         return true;
720 }