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 /source3 | |
| 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.
Diffstat (limited to 'source3')
| -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},  | 
