diff options
author | Volker Lendecke <vl@samba.org> | 2009-10-12 17:29:45 +0200 |
---|---|---|
committer | Volker Lendecke <vl@samba.org> | 2009-10-13 20:34:25 +0200 |
commit | 94d5417d10a9baa281a19b86d157fb856430dd13 (patch) | |
tree | 0d292ff438ca8ce369d0587ba418f426d342bfdd | |
parent | 1302526a74fe71b4cb56ff3c0ce26d6c5b71d360 (diff) | |
download | samba-94d5417d10a9baa281a19b86d157fb856430dd13.tar.gz samba-94d5417d10a9baa281a19b86d157fb856430dd13.tar.bz2 samba-94d5417d10a9baa281a19b86d157fb856430dd13.zip |
s3:torture: Add a notify-bench test
This is a test that creates and deletes files in a directory as fast as the
network allows it. At the same time, it opens a filechangenotify. This test is
done to just torture handling a single directory together with the notify
infrastructure.
-rw-r--r-- | source3/libsmb/clifile.c | 4 | ||||
-rw-r--r-- | source3/torture/torture.c | 403 |
2 files changed, 407 insertions, 0 deletions
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 9cab3f675e..5eb8bd471b 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -5028,6 +5028,10 @@ NTSTATUS cli_posix_rmdir(struct cli_state *cli, const char *fname) return status; } +/**************************************************************************** + filechangenotify +****************************************************************************/ + struct cli_notify_state { uint8_t setup[8]; uint32_t num_changes; diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 9e1ac7648e..e9d03eace8 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -5271,6 +5271,408 @@ static bool run_chain2(int dummy) return True; } + +struct torture_createdel_state { + struct tevent_context *ev; + struct cli_state *cli; +}; + +static void torture_createdel_created(struct tevent_req *subreq); +static void torture_createdel_closed(struct tevent_req *subreq); + +static struct tevent_req *torture_createdel_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *name) +{ + struct tevent_req *req, *subreq; + struct torture_createdel_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct torture_createdel_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + + subreq = cli_ntcreate_send( + state, ev, cli, name, 0, + FILE_READ_DATA|FILE_WRITE_DATA|DELETE_ACCESS, + FILE_ATTRIBUTE_NORMAL, + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, + FILE_OPEN_IF, FILE_DELETE_ON_CLOSE, 0); + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, torture_createdel_created, req); + return req; +} + +static void torture_createdel_created(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct torture_createdel_state *state = tevent_req_data( + req, struct torture_createdel_state); + NTSTATUS status; + uint16_t fnum; + + status = cli_ntcreate_recv(subreq, &fnum); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("cli_ntcreate_recv returned %s\n", + nt_errstr(status))); + tevent_req_nterror(req, status); + return; + } + + subreq = cli_close_send(state, state->ev, state->cli, fnum); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, torture_createdel_closed, req); +} + +static void torture_createdel_closed(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = cli_close_recv(subreq); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("cli_close_recv returned %s\n", nt_errstr(status))); + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +static NTSTATUS torture_createdel_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +struct torture_createdels_state { + struct tevent_context *ev; + struct cli_state *cli; + const char *base_name; + int sent; + int received; + int num_files; + struct tevent_req **reqs; +}; + +static void torture_createdels_done(struct tevent_req *subreq); + +static struct tevent_req *torture_createdels_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + const char *base_name, + int num_parallel, + int num_files) +{ + struct tevent_req *req; + struct torture_createdels_state *state; + int i; + + req = tevent_req_create(mem_ctx, &state, + struct torture_createdels_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + state->base_name = talloc_strdup(state, base_name); + if (tevent_req_nomem(state->base_name, req)) { + return tevent_req_post(req, ev); + } + state->num_files = MAX(num_parallel, num_files); + state->sent = 0; + state->received = 0; + + state->reqs = talloc_array(state, struct tevent_req *, num_parallel); + if (tevent_req_nomem(state->reqs, req)) { + return tevent_req_post(req, ev); + } + + for (i=0; i<num_parallel; i++) { + char *name; + + name = talloc_asprintf(state, "%s%8.8d", state->base_name, + state->sent); + if (tevent_req_nomem(name, req)) { + return tevent_req_post(req, ev); + } + state->reqs[i] = torture_createdel_send( + state->reqs, state->ev, state->cli, name); + if (tevent_req_nomem(state->reqs[i], req)) { + return tevent_req_post(req, ev); + } + name = talloc_move(state->reqs[i], &name); + tevent_req_set_callback(state->reqs[i], + torture_createdels_done, req); + state->sent += 1; + } + return req; +} + +static void torture_createdels_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct torture_createdels_state *state = tevent_req_data( + req, struct torture_createdels_state); + size_t num_parallel = talloc_array_length(state->reqs); + NTSTATUS status; + char *name; + int i; + + status = torture_createdel_recv(subreq); + if (!NT_STATUS_IS_OK(status)){ + DEBUG(10, ("torture_createdel_recv returned %s\n", + nt_errstr(status))); + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; + } + + for (i=0; i<num_parallel; i++) { + if (subreq == state->reqs[i]) { + break; + } + } + if (i == num_parallel) { + DEBUG(10, ("received something we did not send\n")); + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + TALLOC_FREE(state->reqs[i]); + + if (state->sent >= state->num_files) { + tevent_req_done(req); + return; + } + + name = talloc_asprintf(state, "%s%8.8d", state->base_name, + state->sent); + if (tevent_req_nomem(name, req)) { + return; + } + state->reqs[i] = torture_createdel_send(state->reqs, state->ev, + state->cli, name); + if (tevent_req_nomem(state->reqs[i], req)) { + return; + } + name = talloc_move(state->reqs[i], &name); + tevent_req_set_callback(state->reqs[i], torture_createdels_done, req); + state->sent += 1; +} + +static NTSTATUS torture_createdels_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); +} + +struct swallow_notify_state { + struct tevent_context *ev; + struct cli_state *cli; + uint16_t fnum; + uint32_t completion_filter; + bool recursive; + bool (*fn)(uint32_t action, const char *name, void *priv); + void *priv; +}; + +static void swallow_notify_done(struct tevent_req *subreq); + +static struct tevent_req *swallow_notify_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint32_t completion_filter, + bool recursive, + bool (*fn)(uint32_t action, + const char *name, + void *priv), + void *priv) +{ + struct tevent_req *req, *subreq; + struct swallow_notify_state *state; + + req = tevent_req_create(mem_ctx, &state, + struct swallow_notify_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + state->fnum = fnum; + state->completion_filter = completion_filter; + state->recursive = recursive; + state->fn = fn; + state->priv = priv; + + subreq = cli_notify_send(state, state->ev, state->cli, state->fnum, + 0xffff, state->completion_filter, + state->recursive); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, swallow_notify_done, req); + return req; +} + +static void swallow_notify_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct swallow_notify_state *state = tevent_req_data( + req, struct swallow_notify_state); + NTSTATUS status; + uint32_t i, num_changes; + struct notify_change *changes; + + status = cli_notify_recv(subreq, state, &num_changes, &changes); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("cli_notify_recv returned %s\n", + nt_errstr(status))); + tevent_req_nterror(req, status); + return; + } + + for (i=0; i<num_changes; i++) { + state->fn(changes[i].action, changes[i].name, state->priv); + } + TALLOC_FREE(changes); + + subreq = cli_notify_send(state, state->ev, state->cli, state->fnum, + 0xffff, state->completion_filter, + state->recursive); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, swallow_notify_done, req); +} + +static bool print_notifies(uint32_t action, const char *name, void *priv) +{ + if (DEBUGLEVEL > 5) { + d_printf("%d %s\n", (int)action, name); + } + return true; +} + +static void notify_bench_done(struct tevent_req *req) +{ + int *num_finished = (int *)tevent_req_callback_data_void(req); + *num_finished += 1; +} + +static bool run_notify_bench(int dummy) +{ + const char *dname = "\\notify-bench"; + struct tevent_context *ev; + NTSTATUS status; + uint16_t dnum; + struct tevent_req *req1, *req2; + int i, num_unc_names; + int num_finished = 0; + + printf("starting notify-bench test\n"); + + if (use_multishare_conn) { + char **unc_list; + unc_list = file_lines_load(multishare_conn_fname, + &num_unc_names, 0, NULL); + if (!unc_list || num_unc_names <= 0) { + d_printf("Failed to load unc names list from '%s'\n", + multishare_conn_fname); + return false; + } + TALLOC_FREE(unc_list); + } else { + num_unc_names = 1; + } + + ev = tevent_context_init(talloc_tos()); + if (ev == NULL) { + d_printf("tevent_context_init failed\n"); + return false; + } + + for (i=0; i<num_unc_names; i++) { + struct cli_state *cli; + char *base_fname; + + base_fname = talloc_asprintf(talloc_tos(), "%s\\file%3.3d.", + dname, i); + if (base_fname == NULL) { + return false; + } + + if (!torture_open_connection(&cli, i)) { + return false; + } + + status = cli_ntcreate(cli, dname, 0, + MAXIMUM_ALLOWED_ACCESS, + 0, FILE_SHARE_READ|FILE_SHARE_WRITE| + FILE_SHARE_DELETE, + FILE_OPEN_IF, FILE_DIRECTORY_FILE, 0, + &dnum); + + if (!NT_STATUS_IS_OK(status)) { + d_printf("Could not create %s: %s\n", dname, + nt_errstr(status)); + return false; + } + + req1 = swallow_notify_send(talloc_tos(), ev, cli, dnum, + FILE_NOTIFY_CHANGE_FILE_NAME | + FILE_NOTIFY_CHANGE_DIR_NAME | + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_LAST_WRITE, + false, print_notifies, NULL); + if (req1 == NULL) { + d_printf("Could not create notify request\n"); + return false; + } + + req2 = torture_createdels_send(talloc_tos(), ev, cli, + base_fname, 10, torture_numops); + if (req2 == NULL) { + d_printf("Could not create createdels request\n"); + return false; + } + TALLOC_FREE(base_fname); + + tevent_req_set_callback(req2, notify_bench_done, + &num_finished); + } + + while (num_finished < num_unc_names) { + int ret; + ret = tevent_loop_once(ev); + if (ret != 0) { + d_printf("tevent_loop_once failed\n"); + return false; + } + } + + if (!tevent_req_poll(req2, ev)) { + d_printf("tevent_req_poll failed\n"); + } + + status = torture_createdels_recv(req2); + d_printf("torture_createdels_recv returned %s\n", nt_errstr(status)); + + return true; +} + static bool run_mangle1(int dummy) { struct cli_state *cli; @@ -6579,6 +6981,7 @@ static struct { { "GETADDRINFO", run_getaddrinfo_send, 0}, { "TLDAP", run_tldap }, { "STREAMERROR", run_streamerror }, + { "NOTIFY-BENCH", run_notify_bench }, { "LOCAL-SUBSTITUTE", run_local_substitute, 0}, { "LOCAL-GENCACHE", run_local_gencache, 0}, { "LOCAL-TALLOC-DICT", run_local_talloc_dict, 0}, |