2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2007
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "torture/torture.h"
25 #include "libcli/raw/libcliraw.h"
26 #include "system/time.h"
27 #include "system/filesys.h"
28 #include "libcli/libcli.h"
29 #include "torture/util.h"
30 #include "lib/events/events.h"
31 #include "lib/cmdline/popt_common.h"
32 #include "libcli/composite/composite.h"
33 #include "libcli/smb_composite/smb_composite.h"
35 #define BASEDIR "\\benchopen"
38 static int open_failed;
39 static int open_retries;
41 static int num_connected;
43 struct benchopen_state {
45 struct event_context *ev;
46 struct smbcli_state *cli;
47 struct smbcli_tree *tree;
53 BOOL waiting_open, waiting_close;
54 union smb_open open_parms;
55 union smb_close close_parms;
56 struct smbcli_request *req_open;
57 struct smbcli_request *req_close;
58 struct smb_composite_connect reconnect;
60 /* these are used for reconnections */
62 const char *dest_host;
63 const char *called_name;
64 const char *service_type;
67 static void next_open(struct benchopen_state *state);
68 static void reopen_connection(struct event_context *ev, struct timed_event *te,
69 struct timeval t, void *private_data);
73 complete an async reconnect
75 static void reopen_connection_complete(struct composite_context *ctx)
77 struct benchopen_state *state = (struct benchopen_state *)ctx->async.private_data;
79 struct smb_composite_connect *io = &state->reconnect;
81 status = smb_composite_connect_recv(ctx, state->mem_ctx);
82 if (!NT_STATUS_IS_OK(status)) {
83 event_add_timed(state->ev, state->mem_ctx,
84 timeval_current_ofs(1,0),
85 reopen_connection, state);
89 state->tree = io->out.tree;
93 DEBUG(0,("reconnect to %s finished (%u connected)\n", state->dest_host,
104 static void reopen_connection(struct event_context *ev, struct timed_event *te,
105 struct timeval t, void *private_data)
107 struct benchopen_state *state = (struct benchopen_state *)private_data;
108 struct composite_context *ctx;
109 struct smb_composite_connect *io = &state->reconnect;
112 if (!torture_get_conn_index(state->client_num, state->mem_ctx, &host, &share)) {
113 DEBUG(0,("Can't find host/share for reconnect?!\n"));
117 io->in.dest_host = state->dest_host;
118 io->in.port = state->dest_port;
119 io->in.called_name = state->called_name;
120 io->in.service = share;
121 io->in.service_type = state->service_type;
122 io->in.credentials = cmdline_credentials;
123 io->in.fallback_to_anonymous = False;
124 io->in.workgroup = lp_workgroup();
126 /* kill off the remnants of the old connection */
127 talloc_free(state->tree);
130 state->waiting_open = False;
131 state->waiting_close = False;
133 ctx = smb_composite_connect_send(io, state->mem_ctx, state->ev);
135 DEBUG(0,("Failed to setup async reconnect\n"));
139 ctx->async.fn = reopen_connection_complete;
140 ctx->async.private_data = state;
143 static void open_completed(struct smbcli_request *req);
144 static void close_completed(struct smbcli_request *req);
147 static void next_open(struct benchopen_state *state)
151 state->file_num = (state->file_num+1) % (nprocs+1);
152 state->open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
153 state->open_parms.ntcreatex.in.flags = 0;
154 state->open_parms.ntcreatex.in.root_fid = 0;
155 state->open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
156 state->open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
157 state->open_parms.ntcreatex.in.alloc_size = 0;
158 state->open_parms.ntcreatex.in.share_access = 0;
159 state->open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
160 state->open_parms.ntcreatex.in.create_options = 0;
161 state->open_parms.ntcreatex.in.impersonation = 0;
162 state->open_parms.ntcreatex.in.security_flags = 0;
163 state->open_parms.ntcreatex.in.fname = fnames[state->file_num];
165 state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
166 state->req_open->async.fn = open_completed;
167 state->req_open->async.private = state;
168 state->waiting_open = True;
170 if (state->fnum == -1) {
174 state->close_parms.close.level = RAW_CLOSE_CLOSE;
175 state->close_parms.close.in.file.fnum = state->fnum;
176 state->close_parms.close.in.write_time = 0;
178 state->req_close = smb_raw_close_send(state->tree, &state->close_parms);
179 state->req_close->async.fn = close_completed;
180 state->req_close->async.private = state;
181 state->waiting_close = True;
185 called when a open completes
187 static void open_completed(struct smbcli_request *req)
189 struct benchopen_state *state = (struct benchopen_state *)req->async.private;
190 TALLOC_CTX *tmp_ctx = talloc_new(state->mem_ctx);
193 status = smb_raw_open_recv(req, tmp_ctx, &state->open_parms);
195 talloc_free(tmp_ctx);
197 state->req_open = NULL;
199 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
200 NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT)) {
201 talloc_free(state->tree);
202 talloc_free(state->cli);
206 DEBUG(0,("reopening connection to %s\n", state->dest_host));
207 event_add_timed(state->ev, state->mem_ctx,
208 timeval_current_ofs(1,0),
209 reopen_connection, state);
213 if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
215 state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
216 state->req_open->async.fn = open_completed;
217 state->req_open->async.private = state;
221 if (!NT_STATUS_IS_OK(status)) {
223 DEBUG(0,("open failed - %s\n", nt_errstr(status)));
227 state->fnum = state->open_parms.ntcreatex.out.file.fnum;
228 state->waiting_open = False;
230 if (!state->waiting_close) {
236 called when a close completes
238 static void close_completed(struct smbcli_request *req)
240 struct benchopen_state *state = (struct benchopen_state *)req->async.private;
241 NTSTATUS status = smbcli_request_simple_recv(req);
243 state->req_close = NULL;
245 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
246 NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT)) {
247 talloc_free(state->tree);
248 talloc_free(state->cli);
252 DEBUG(0,("reopening connection to %s\n", state->dest_host));
253 event_add_timed(state->ev, state->mem_ctx,
254 timeval_current_ofs(1,0),
255 reopen_connection, state);
259 if (!NT_STATUS_IS_OK(status)) {
261 DEBUG(0,("close failed - %s\n", nt_errstr(status)));
265 state->waiting_close = False;
267 if (!state->waiting_open) {
273 static void report_rate(struct event_context *ev, struct timed_event *te,
274 struct timeval t, void *private_data)
276 struct benchopen_state *state = talloc_get_type(private_data,
277 struct benchopen_state);
279 for (i=0;i<nprocs;i++) {
280 printf("%5u ", (unsigned)(state[i].count - state[i].lastcount));
281 state[i].lastcount = state[i].count;
285 event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state);
291 BOOL torture_bench_open(struct torture_context *torture)
294 TALLOC_CTX *mem_ctx = talloc_new(torture);
296 int timelimit = torture_setting_int(torture, "timelimit", 10);
298 struct event_context *ev = event_context_find(mem_ctx);
299 struct benchopen_state *state;
300 int total = 0, minops=0;
303 progress = torture_setting_bool(torture, "progress", true);
305 nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
307 state = talloc_zero_array(mem_ctx, struct benchopen_state, nprocs);
309 printf("Opening %d connections\n", nprocs);
310 for (i=0;i<nprocs;i++) {
311 state[i].mem_ctx = talloc_new(state);
312 state[i].client_num = i;
314 if (!torture_open_connection_ev(&state[i].cli, i, ev)) {
317 talloc_steal(mem_ctx, state);
318 state[i].tree = state[i].cli->tree;
319 state[i].dest_host = talloc_strdup(state[i].mem_ctx,
320 state[i].cli->tree->session->transport->socket->hostname);
321 state[i].dest_port = state[i].cli->tree->session->transport->socket->port;
322 state[i].called_name = talloc_strdup(state[i].mem_ctx,
323 state[i].cli->tree->session->transport->called.name);
324 state[i].service_type = talloc_strdup(state[i].mem_ctx,
325 state[i].cli->tree->device);
330 if (!torture_setup_dir(state[0].cli, BASEDIR)) {
334 fnames = talloc_array(mem_ctx, char *, nprocs+1);
335 for (i=0;i<nprocs+1;i++) {
336 fnames[i] = talloc_asprintf(fnames, "%s\\file%d.dat", BASEDIR, i);
339 for (i=0;i<nprocs;i++) {
341 state[i].file_num = i;
342 next_open(&state[i]);
345 tv = timeval_current();
348 event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state);
351 printf("Running for %d seconds\n", timelimit);
352 while (timeval_elapsed(&tv) < timelimit) {
356 DEBUG(0,("open failed\n"));
361 printf("%.2f ops/second (%d retries)\n",
362 total/timeval_elapsed(&tv), open_retries);
363 minops = state[0].count;
364 for (i=0;i<nprocs;i++) {
365 printf("[%d] %u ops\n", i, state[i].count);
366 if (state[i].count < minops) minops = state[i].count;
368 if (minops < 0.5*total/nprocs) {
369 printf("Failed: unbalanced open\n");
373 for (i=0;i<nprocs;i++) {
374 talloc_free(state[i].req_open);
375 talloc_free(state[i].req_close);
376 smb_raw_exit(state[i].tree->session);
379 smbcli_deltree(state[0].tree, BASEDIR);
380 talloc_free(mem_ctx);
384 talloc_free(mem_ctx);