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