This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "lib/cmdline/popt_common.h"
#include "libcli/composite/composite.h"
#include "libcli/smb_composite/smb_composite.h"
-
-#define CHECK_STATUS(status, correct) do { \
- if (!NT_STATUS_EQUAL(status, correct)) { \
- printf("(%s) Incorrect status %s - should be %s\n", \
- __location__, nt_errstr(status), nt_errstr(correct)); \
- goto failed; \
- }} while (0)
+#include "param/param.h"
#define BASEDIR "\\benchlock"
#define FNAME BASEDIR "\\lock.dat"
static int nprocs;
static int lock_failed;
+static int num_connected;
+
+enum lock_stage {LOCK_INITIAL, LOCK_LOCK, LOCK_UNLOCK};
struct benchlock_state {
struct event_context *ev;
TALLOC_CTX *mem_ctx;
int client_num;
int fnum;
- int offset;
+ enum lock_stage stage;
+ int lock_offset;
+ int unlock_offset;
int count;
- union smb_lock io;
- struct smb_lock_entry lock[2];
+ int lastcount;
struct smbcli_request *req;
struct smb_composite_connect reconnect;
+ struct timed_event *te;
/* these are used for reconnections */
int dest_port;
*/
static void lock_send(struct benchlock_state *state)
{
- state->io.lockx.in.file.fnum = state->fnum;
- state->io.lockx.in.ulock_cnt = 1;
- state->lock[0].pid = state->tree->session->pid;
- state->lock[1].pid = state->tree->session->pid;
- state->lock[0].offset = state->offset;
- state->lock[1].offset = (state->offset+1)%nprocs;
- state->req = smb_raw_lock_send(state->tree, &state->io);
+ union smb_lock io;
+ struct smb_lock_entry lock;
+
+ switch (state->stage) {
+ case LOCK_INITIAL:
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ state->lock_offset = 0;
+ state->unlock_offset = 0;
+ lock.offset = state->lock_offset;
+ break;
+ case LOCK_LOCK:
+ io.lockx.in.ulock_cnt = 0;
+ io.lockx.in.lock_cnt = 1;
+ state->lock_offset = (state->lock_offset+1)%(nprocs+1);
+ lock.offset = state->lock_offset;
+ break;
+ case LOCK_UNLOCK:
+ io.lockx.in.ulock_cnt = 1;
+ io.lockx.in.lock_cnt = 0;
+ lock.offset = state->unlock_offset;
+ state->unlock_offset = (state->unlock_offset+1)%(nprocs+1);
+ break;
+ }
+
+ lock.count = 1;
+ lock.pid = state->tree->session->pid;
+
+ io.lockx.level = RAW_LOCK_LOCKX;
+ io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
+ io.lockx.in.timeout = 100000;
+ io.lockx.in.locks = &lock;
+ io.lockx.in.file.fnum = state->fnum;
+
+ state->req = smb_raw_lock_send(state->tree, &io);
if (state->req == NULL) {
DEBUG(0,("Failed to setup lock\n"));
lock_failed++;
}
state->req->async.private = state;
state->req->async.fn = lock_completion;
- state->offset = (state->offset+1)%nprocs;
}
-static void reopen_connection(struct benchlock_state *state);
+static void reopen_connection(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *private_data);
static void reopen_file(struct event_context *ev, struct timed_event *te,
exit(1);
}
- /* reestablish one lock, preparing for the async lock loop */
- state->lock[0].offset = state->offset;
- state->io.lockx.in.ulock_cnt = 0;
- state->io.lockx.in.file.fnum = state->fnum;
- state->req = smb_raw_lock_send(state->tree, &state->io);
- if (state->req == NULL) {
- DEBUG(0,("Failed to setup lock\n"));
- lock_failed++;
- }
- state->req->async.private = state;
- state->req->async.fn = lock_completion;
- state->offset = (state->offset+1)%nprocs;
+ num_connected++;
+
+ DEBUG(0,("reconnect to %s finished (%u connected)\n", state->dest_host,
+ num_connected));
+
+ state->stage = LOCK_INITIAL;
+ lock_send(state);
}
/*
status = smb_composite_connect_recv(ctx, state->mem_ctx);
if (!NT_STATUS_IS_OK(status)) {
- reopen_connection(state);
+ talloc_free(state->te);
+ state->te = event_add_timed(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
return;
}
/*
- reopen dead connections
+ reopen a connection
*/
-static void reopen_connection(struct benchlock_state *state)
+static void reopen_connection(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *private_data)
{
+ struct benchlock_state *state = (struct benchlock_state *)private_data;
struct composite_context *ctx;
struct smb_composite_connect *io = &state->reconnect;
char *host, *share;
+ state->te = NULL;
+
if (!torture_get_conn_index(state->client_num, state->mem_ctx, &host, &share)) {
DEBUG(0,("Can't find host/share for reconnect?!\n"));
exit(1);
io->in.fallback_to_anonymous = False;
io->in.workgroup = lp_workgroup();
- DEBUG(0,("reopening connection to //%s/%s\n", host, share));
-
/* kill off the remnants of the old connection */
talloc_free(state->tree);
state->tree = NULL;
NTSTATUS status = smbcli_request_simple_recv(req);
state->req = NULL;
if (!NT_STATUS_IS_OK(status)) {
- if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {
- reopen_connection(state);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT)) {
+ talloc_free(state->tree);
+ state->tree = NULL;
+ num_connected--;
+ DEBUG(0,("reopening connection to %s\n", state->dest_host));
+ talloc_free(state->te);
+ state->te = event_add_timed(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
} else {
DEBUG(0,("Lock failed - %s\n", nt_errstr(status)));
lock_failed++;
}
- } else {
- state->count++;
- lock_send(state);
+ return;
+ }
+
+ switch (state->stage) {
+ case LOCK_INITIAL:
+ state->stage = LOCK_LOCK;
+ break;
+ case LOCK_LOCK:
+ state->stage = LOCK_UNLOCK;
+ break;
+ case LOCK_UNLOCK:
+ state->stage = LOCK_LOCK;
+ break;
+ }
+
+ state->count++;
+ lock_send(state);
+}
+
+
+static void echo_completion(struct smbcli_request *req)
+{
+ struct benchlock_state *state = (struct benchlock_state *)req->async.private;
+ NTSTATUS status = smbcli_request_simple_recv(req);
+ if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT)) {
+ talloc_free(state->tree);
+ state->tree = NULL;
+ num_connected--;
+ DEBUG(0,("reopening connection to %s\n", state->dest_host));
+ talloc_free(state->te);
+ state->te = event_add_timed(state->ev, state->mem_ctx,
+ timeval_current_ofs(1,0),
+ reopen_connection, state);
+ }
+}
+
+static void report_rate(struct event_context *ev, struct timed_event *te,
+ struct timeval t, void *private_data)
+{
+ struct benchlock_state *state = talloc_get_type(private_data,
+ struct benchlock_state);
+ int i;
+ for (i=0;i<nprocs;i++) {
+ printf("%5u ", (unsigned)(state[i].count - state[i].lastcount));
+ state[i].lastcount = state[i].count;
+ }
+ printf("\r");
+ fflush(stdout);
+ event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state);
+
+ /* send an echo on each interface to ensure it stays alive - this helps
+ with IP takeover */
+ for (i=0;i<nprocs;i++) {
+ struct smb_echo p;
+ struct smbcli_request *req;
+
+ if (!state[i].tree) {
+ continue;
+ }
+
+ p.in.repeat_count = 1;
+ p.in.size = 0;
+ p.in.data = NULL;
+ req = smb_raw_echo_send(state[i].tree->session->transport, &p);
+ req->async.private = &state[i];
+ req->async.fn = echo_completion;
}
}
struct timeval tv;
struct event_context *ev = event_context_find(mem_ctx);
struct benchlock_state *state;
- int total = 0, loops=0, minops=0;
- NTSTATUS status;
+ int total = 0, minops=0;
struct smbcli_state *cli;
-
- nprocs = lp_parm_int(-1, "torture", "nprocs", 4);
+ bool progress;
+
+ progress = torture_setting_bool(torture, "progress", true);
+
+ nprocs = lp_parm_int(NULL, "torture", "nprocs", 4);
state = talloc_zero_array(mem_ctx, struct benchlock_state, nprocs);
cli->tree->device);
}
+ num_connected = i;
+
if (!torture_setup_dir(cli, BASEDIR)) {
goto failed;
}
goto failed;
}
- state[i].io.lockx.level = RAW_LOCK_LOCKX;
- state[i].io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
- state[i].io.lockx.in.timeout = 100000;
- state[i].io.lockx.in.ulock_cnt = 0;
- state[i].io.lockx.in.lock_cnt = 1;
- state[i].lock[0].count = 1;
- state[i].lock[1].count = 1;
- state[i].io.lockx.in.locks = &state[i].lock[0];
-
- state[i].offset = i;
- state[i].io.lockx.in.file.fnum = state[i].fnum;
- state[i].lock[0].offset = state[i].offset;
- state[i].lock[0].pid = state[i].tree->session->pid;
- status = smb_raw_lock(state[i].tree, &state[i].io);
- CHECK_STATUS(status, NT_STATUS_OK);
- }
-
- for (i=0;i<nprocs;i++) {
+ state[i].stage = LOCK_INITIAL;
lock_send(&state[i]);
}
tv = timeval_current();
+ if (progress) {
+ event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state);
+ }
+
printf("Running for %d seconds\n", timelimit);
while (timeval_elapsed(&tv) < timelimit) {
event_loop_once(ev);
DEBUG(0,("locking failed\n"));
goto failed;
}
-
- if (loops++ % 10 != 0) continue;
-
- total = 0;
- for (i=0;i<nprocs;i++) {
- total += state[i].count;
- }
- if (torture_setting_bool(torture, "progress", true)) {
- printf("%.2f ops/second (remaining=%u)\r",
- total/timeval_elapsed(&tv),
- (unsigned)(timelimit - timeval_elapsed(&tv)));
- fflush(stdout);
- }
}
printf("%.2f ops/second\n", total/timeval_elapsed(&tv));
smbcli_deltree(state[0].tree, BASEDIR);
talloc_free(mem_ctx);
+ printf("\n");
return ret;
failed:
talloc_free(mem_ctx);
- return False;
+ return false;
}