s3-torture: Don't leak memory.
[Samba/vl.git] / source3 / torture / test_notify.c
blobe1755ad20c72c29d593c3b1c4c459e2b53edf628
1 /*
2 Unix SMB/CIFS implementation.
3 Scalability test for notifies
4 Copyright (C) Volker Lendecke 2012
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.
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.
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/>.
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"
27 extern int torture_nprocs, torture_numops;
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;
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);
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)
51 struct tevent_req *req, *subreq;
52 struct wait_for_one_notify_state *state;
54 req = tevent_req_create(mem_ctx, &state,
55 struct wait_for_one_notify_state);
56 if (req == NULL) {
57 return NULL;
59 state->ev = ev;
60 state->cli = cli;
61 state->filter = filter;
62 state->recursive = recursive;
63 state->num_notifies = num_notifies;
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);
73 tevent_req_set_callback(subreq, wait_for_one_notify_opened, req);
74 return req;
77 static void wait_for_one_notify_opened(struct tevent_req *subreq)
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;
85 status = cli_ntcreate_recv(subreq, &state->dnum);
86 TALLOC_FREE(subreq);
87 if (tevent_req_nterror(req, status)) {
88 return;
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;
95 tevent_req_set_callback(subreq, wait_for_one_notify_done, req);
98 * To make sure the notify received at the server, we do another no-op
99 * that is replied to.
101 subreq = cli_chkpath_send(state, state->ev, state->cli, "\\");
102 if (tevent_req_nomem(subreq, req)) {
103 return;
105 tevent_req_set_callback(subreq, wait_for_one_notify_chkpath_done, req);
108 static void wait_for_one_notify_chkpath_done(struct tevent_req *subreq)
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;
116 status = cli_chkpath_recv(subreq);
117 TALLOC_FREE(subreq);
118 if (tevent_req_nterror(req, status)) {
119 return;
121 *state->num_notifies += 1;
124 static void wait_for_one_notify_done(struct tevent_req *subreq)
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;
134 status = cli_notify_recv(subreq, state, &num_changes, &changes);
135 TALLOC_FREE(subreq);
136 if (tevent_req_nterror(req, status)) {
137 return;
139 subreq = cli_close_send(state, state->ev, state->cli, state->dnum);
140 if (tevent_req_nomem(subreq, req)) {
141 return;
143 tevent_req_set_callback(subreq, wait_for_one_notify_closed, req);
146 static void wait_for_one_notify_closed(struct tevent_req *subreq)
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;
154 status = cli_close_recv(subreq);
155 TALLOC_FREE(subreq);
156 if (tevent_req_nterror(req, status)) {
157 return;
159 *state->num_notifies -= 1;
160 tevent_req_done(req);
163 static NTSTATUS wait_for_one_notify_recv(struct tevent_req *req)
165 return tevent_req_simple_recv_ntstatus(req);
168 static void notify_bench2_done(struct tevent_req *req);
170 bool run_notify_bench2(int dummy)
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;
179 if (!torture_open_connection(&cli, 0)) {
180 return false;
183 printf("starting notify bench 2 test\n");
185 cli_rmdir(cli, "\\notify.dir\\subdir");
186 cli_rmdir(cli, "\\notify.dir");
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;
194 clis = talloc_array(talloc_tos(), struct cli_state *, torture_nprocs);
195 if (clis == NULL) {
196 printf("talloc failed\n");
197 return false;
200 ev = samba_tevent_context_init(talloc_tos());
201 if (ev == NULL) {
202 printf("tevent_context_create failed\n");
203 return false;
206 for (i=0; i<torture_nprocs; i++) {
207 int j;
208 if (!torture_open_connection(&clis[i], i)) {
209 return false;
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;
222 tevent_req_set_callback(req, notify_bench2_done, NULL);
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;
236 cli_mkdir(cli, "\\notify.dir\\subdir");
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;
248 return true;
251 static void notify_bench2_done(struct tevent_req *req)
253 NTSTATUS status;
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));
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.
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;
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);
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)
303 struct tevent_req *req, *subreq;
304 struct notify_bench3_state *state;
306 req = tevent_req_create(mem_ctx, &state, struct notify_bench3_state);
307 if (req == NULL) {
308 return NULL;
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;
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);
325 tevent_req_set_callback(subreq, notify_bench3_mkdir1_done, req);
326 return req;
329 static void notify_bench3_mkdir1_done(struct tevent_req *subreq)
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;
337 status = cli_ntcreate_recv(subreq, &state->dnum);
338 TALLOC_FREE(subreq);
339 if (tevent_req_nterror(req, status)) {
340 return;
342 subreq = tevent_barrier_wait_send(state, state->ev, state->small);
343 if (tevent_req_nomem(subreq, req)) {
344 return;
346 tevent_req_set_callback(subreq, notify_bench3_before_notify, req);
349 static void notify_bench3_before_notify(struct tevent_req *subreq)
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;
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;
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;
368 tevent_req_set_callback(subreq, notify_bench3_notify_done, req);
371 * To make sure the notify received at the server, we do another no-op
372 * that is replied to.
374 subreq = cli_chkpath_send(state, state->ev, state->cli, "\\");
375 if (tevent_req_nomem(subreq, req)) {
376 return;
378 tevent_req_set_callback(subreq, notify_bench3_chkpath_done, req);
381 static void notify_bench3_notify_done(struct tevent_req *subreq)
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;
391 status = cli_notify_recv(subreq, state, &num_changes, &changes);
392 TALLOC_FREE(subreq);
393 if (tevent_req_nterror(req, status)) {
394 return;
396 subreq = tevent_barrier_wait_send(state, state->ev, state->large);
397 if (tevent_req_nomem(subreq, req)) {
398 return;
400 tevent_req_set_callback(subreq, notify_bench3_notifies_done, req);
403 static void notify_bench3_notifies_done(struct tevent_req *subreq)
405 struct tevent_req *req = tevent_req_callback_data(
406 subreq, struct tevent_req);
407 int ret;
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;
417 static void notify_bench3_chkpath_done(struct tevent_req *subreq)
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;
425 status = cli_chkpath_recv(subreq);
426 TALLOC_FREE(subreq);
427 if (tevent_req_nterror(req, status)) {
428 return;
430 if (state->subdir_path == NULL) {
431 return;
433 subreq = tevent_barrier_wait_send(state, state->ev, state->small);
434 if (tevent_req_nomem(subreq, req)) {
435 return;
437 tevent_req_set_callback(subreq, notify_bench3_before_mkdir2, req);
440 static void notify_bench3_before_mkdir2(struct tevent_req *subreq)
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;
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;
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;
463 tevent_req_set_callback(subreq, notify_bench3_mksubdir_done, req);
466 static void notify_bench3_mksubdir_done(struct tevent_req *subreq)
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;
474 status = cli_ntcreate_recv(subreq, &state->subdir_dnum);
475 TALLOC_FREE(subreq);
476 if (tevent_req_nterror(req, status)) {
477 return;
479 subreq = tevent_barrier_wait_send(state, state->ev, state->large);
480 if (tevent_req_nomem(subreq, req)) {
481 return;
483 tevent_req_set_callback(subreq, notify_bench3_before_close_subdir,
484 req);
487 static void notify_bench3_before_close_subdir(struct tevent_req *subreq)
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;
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;
501 subreq = cli_close_send(state, state->ev, state->cli,
502 state->subdir_dnum);
503 if (tevent_req_nomem(subreq, req)) {
504 return;
506 tevent_req_set_callback(subreq, notify_bench3_close_subdir_done, req);
509 static void notify_bench3_close_subdir_done(struct tevent_req *subreq)
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;
517 status = cli_close_recv(subreq);
518 TALLOC_FREE(subreq);
519 if (tevent_req_nterror(req, status)) {
520 return;
522 subreq = cli_rmdir_send(state, state->ev, state->cli,
523 state->subdir_path);
524 if (tevent_req_nomem(subreq, req)) {
525 return;
527 tevent_req_set_callback(subreq, notify_bench3_deleted_subdir, req);
530 static void notify_bench3_deleted_subdir(struct tevent_req *subreq)
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;
538 status = cli_rmdir_recv(subreq);
539 TALLOC_FREE(subreq);
540 if (tevent_req_nterror(req, status)) {
541 return;
543 subreq = tevent_barrier_wait_send(state, state->ev, state->small);
544 if (tevent_req_nomem(subreq, req)) {
545 return;
547 tevent_req_set_callback(subreq, notify_bench3_deleted_subdirs, req);
550 static void notify_bench3_deleted_subdirs(struct tevent_req *subreq)
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;
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;
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;
569 tevent_req_set_callback(subreq, notify_bench3_del_on_close_set, req);
572 static void notify_bench3_del_on_close_set(struct tevent_req *subreq)
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;
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;
586 tevent_req_set_callback(subreq, notify_bench3_closed, req);
589 static void notify_bench3_closed(struct tevent_req *subreq)
591 struct tevent_req *req = tevent_req_callback_data(
592 subreq, struct tevent_req);
593 NTSTATUS status;
595 status = cli_close_recv(subreq);
596 TALLOC_FREE(subreq);
597 if (tevent_req_nterror(req, status)) {
598 return;
600 tevent_req_done(req);
603 static NTSTATUS notify_bench3_recv(struct tevent_req *req)
605 return tevent_req_simple_recv_ntstatus(req);
608 static void notify_bench3_done(struct tevent_req *req)
610 unsigned *num_done = (unsigned *)tevent_req_callback_data_void(req);
611 NTSTATUS status;
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));
618 *num_done += 1;
621 static void notify_bench3_barrier_cb(void *private_data)
623 struct timeval *ts = (struct timeval *)private_data;
624 struct timeval now;
626 GetTimeOfDay(&now);
627 printf("barrier triggered: %f\n", timeval_elapsed2(ts, &now));
628 GetTimeOfDay(ts);
631 bool run_notify_bench3(int dummy)
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;
641 clis = talloc_array(talloc_tos(), struct cli_state *, torture_nprocs);
642 if (clis == NULL) {
643 printf("talloc failed\n");
644 return false;
647 GetTimeOfDay(&ts);
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;
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;
663 ev = samba_tevent_context_init(talloc_tos());
664 if (ev == NULL) {
665 printf("tevent_context_create failed\n");
666 return false;
669 for (i=0; i<torture_nprocs; i++) {
670 if (!torture_open_connection(&clis[i], i)) {
671 return false;
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;
681 dirname = talloc_asprintf(
682 talloc_tos(), "\\dir%.8d", idx);
683 if (dirname == NULL) {
684 return false;
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;
694 req = notify_bench3_send(
695 talloc_tos(), ev, clis[i], dirname,
696 subdirname, small, large);
697 if (req == NULL) {
698 return false;
700 tevent_req_set_callback(req, notify_bench3_done,
701 &num_done);
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;
715 GetTimeOfDay(&now);
716 printf("turndow: %f\n", timeval_elapsed2(&ts, &now));
717 TALLOC_FREE(small);
718 TALLOC_FREE(large);
719 return true;