greatly improved NBENCH netbench simulator
authorAndrew Tridgell <tridge@samba.org>
Tue, 9 Mar 2004 02:13:13 +0000 (02:13 +0000)
committerAndrew Tridgell <tridge@samba.org>
Tue, 9 Mar 2004 02:13:13 +0000 (02:13 +0000)
 - more accurate request simulation using Samba4 raw client library
 - now checks for correct status on all requests
 - timelimit based benchmarking, default of 600 seconds
(This used to be commit a46c009c0459658784d7d7b3b0502dc20958043a)

source4/Makefile.in
source4/torture/config.m4
source4/torture/nbench/nbench.c [new file with mode: 0644]
source4/torture/nbench/nbio.c [new file with mode: 0644]
source4/torture/nbio.c [deleted file]
source4/torture/torture.c

index b362b0c18d085faf7f8f60420e49c228bde4da92..e240afb7666a9c112c00a4a4964bc639459d7005 100644 (file)
@@ -141,6 +141,8 @@ TORTURE_RAW_OBJS = @TORTURE_RAW_OBJS@
 
 TORTURE_RPC_OBJS = @TORTURE_RPC_OBJS@
 
+TORTURE_NBENCH_OBJS = @TORTURE_NBENCH_OBJS@
+
 TORTURE_OBJS = @TORTURE_OBJS@
 TORTURE_LIBS = @TORTURE_LIBS@
 
index 0d6e375bcaed7d153a6cd71fa0eeb6ce82df4ab6..f7ad78611c07fb4753b51cffbb9558dfce0a48c4 100755 (executable)
@@ -16,9 +16,12 @@ SMB_SUBSYSTEM(TORTURE_RPC,[],
                torture/rpc/scanner.o torture/rpc/autoidl.o torture/rpc/netlogon.o],
                torture/rpc/torture_rpc_public_proto.h)
 
+SMB_SUBSYSTEM(TORTURE_NBENCH,[],
+               [torture/nbench/nbio.o torture/nbench/nbench.o])
+
 SMB_SUBSYSTEM(TORTURE,[],
-               [torture/torture.o torture/torture_util.o torture/nbio.o torture/scanner.o \
+               [torture/torture.o torture/torture_util.o torture/scanner.o \
                torture/utable.o torture/denytest.o torture/mangle_test.o \
                torture/aliases.o libcli/raw/clirewrite.o \$(TORTURE_RAW_OBJS) \
-               \$(TORTURE_RPC_OBJS)],
+               \$(TORTURE_RPC_OBJS) \$(TORTURE_NBENCH_OBJS)],
                torture/torture_public_proto.h)
diff --git a/source4/torture/nbench/nbench.c b/source4/torture/nbench/nbench.c
new file mode 100644 (file)
index 0000000..6b0e78e
--- /dev/null
@@ -0,0 +1,192 @@
+/* 
+   Unix SMB/CIFS implementation.
+   SMB torture tester - NBENCH test
+   Copyright (C) Andrew Tridgell 1997-2004
+   
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.
+*/
+
+#include "includes.h"
+
+int nbench_line_count = 0;
+static int timelimit = 300;
+static const char *loadfile;
+
+#define ival(s) strtol(s, NULL, 0)
+
+/* run a test that simulates an approximate netbench client load */
+static BOOL run_netbench(struct cli_state *cli, int client)
+{
+       int i;
+       pstring line;
+       char *cname;
+       FILE *f;
+       fstring params[20];
+       const char *p;
+       BOOL correct = True;
+
+       nb_setup(cli, client);
+
+       asprintf(&cname, "client%d", client);
+
+       f = fopen(loadfile, "r");
+
+       if (!f) {
+               perror(loadfile);
+               return False;
+       }
+
+again:
+       while (fgets(line, sizeof(line)-1, f)) {
+               NTSTATUS status;
+
+               if (end_timer() >= timelimit) {
+                       goto done;
+               }
+
+               nbench_line_count++;
+
+               line[strlen(line)-1] = 0;
+
+               all_string_sub(line,"client1", cname, sizeof(line));
+               
+               p = line;
+               for (i=0; 
+                    i<19 && next_token(&p, params[i], " ", sizeof(fstring));
+                    i++) ;
+
+               params[i][0] = 0;
+
+               if (i < 2 || params[0][0] == '#') continue;
+
+               if (!strncmp(params[0],"SMB", 3)) {
+                       printf("ERROR: You are using a dbench 1 load file\n");
+                       exit(1);
+               }
+
+               if (strncmp(params[i-1], "NT_STATUS_", 10) != 0) {
+                       printf("Badly formed status at line %d\n", nbench_line_count);
+                       continue;
+               }
+
+               status = nt_status_string_to_code(params[i-1]);
+
+               DEBUG(9,("run_netbench(%d): %s %s\n", client, params[0], params[1]));
+
+               if (!strcmp(params[0],"NTCreateX")) {
+                       nb_createx(params[1], ival(params[2]), ival(params[3]), 
+                                  ival(params[4]), status);
+               } else if (!strcmp(params[0],"Close")) {
+                       nb_close(ival(params[1]), status);
+               } else if (!strcmp(params[0],"Rename")) {
+                       nb_rename(params[1], params[2], status);
+               } else if (!strcmp(params[0],"Unlink")) {
+                       nb_unlink(params[1], ival(params[2]), status);
+               } else if (!strcmp(params[0],"Deltree")) {
+                       nb_deltree(params[1]);
+               } else if (!strcmp(params[0],"Rmdir")) {
+                       nb_rmdir(params[1], status);
+               } else if (!strcmp(params[0],"QUERY_PATH_INFORMATION")) {
+                       nb_qpathinfo(params[1], ival(params[2]), status);
+               } else if (!strcmp(params[0],"QUERY_FILE_INFORMATION")) {
+                       nb_qfileinfo(ival(params[1]), ival(params[2]), status);
+               } else if (!strcmp(params[0],"QUERY_FS_INFORMATION")) {
+                       nb_qfsinfo(ival(params[1]), status);
+               } else if (!strcmp(params[0],"SET_FILE_INFORMATION")) {
+                       nb_sfileinfo(ival(params[1]), ival(params[2]), status);
+               } else if (!strcmp(params[0],"FIND_FIRST")) {
+                       nb_findfirst(params[1], ival(params[2]), 
+                                    ival(params[3]), ival(params[4]), status);
+               } else if (!strcmp(params[0],"WriteX")) {
+                       nb_writex(ival(params[1]), 
+                                 ival(params[2]), ival(params[3]), ival(params[4]),
+                                 status);
+               } else if (!strcmp(params[0],"Write")) {
+                       nb_write(ival(params[1]), 
+                                ival(params[2]), ival(params[3]), ival(params[4]),
+                                status);
+               } else if (!strcmp(params[0],"LockX")) {
+                       nb_lockx(ival(params[1]), 
+                                ival(params[2]), ival(params[3]), status);
+               } else if (!strcmp(params[0],"UnlockX")) {
+                       nb_unlockx(ival(params[1]), 
+                                ival(params[2]), ival(params[3]), status);
+               } else if (!strcmp(params[0],"ReadX")) {
+                       nb_readx(ival(params[1]), 
+                                ival(params[2]), ival(params[3]), ival(params[4]),
+                                status);
+               } else if (!strcmp(params[0],"Flush")) {
+                       nb_flush(ival(params[1]), status);
+               } else {
+                       printf("[%d] Unknown operation %s\n", nbench_line_count, params[0]);
+               }
+       }
+
+       rewind(f);
+       goto again;
+
+done:
+       fclose(f);
+       nb_cleanup(cname);
+
+       if (!torture_close_connection(cli)) {
+               correct = False;
+       }
+       
+       return correct;
+}
+
+
+/* run a test that simulates an approximate netbench client load */
+BOOL torture_nbench(int dummy)
+{
+       double t;
+       BOOL correct = True;
+       extern int torture_nprocs;
+       struct cli_state *cli;
+       char *p;
+
+       p = lp_parm_string(-1, "torture", "timelimit");
+       if (p && *p) {
+               timelimit = atoi(p);
+       }
+
+       loadfile =  lp_parm_string(-1, "torture", "loadfile");
+       if (!loadfile || !*loadfile) {
+               loadfile = "client.txt";
+       }
+
+       if (!torture_open_connection(&cli)) {
+               return False;
+       }
+
+       nb_setup(cli, -1);
+       nb_deltree("\\clients");
+
+       nbio_shmem(torture_nprocs);
+
+       printf("Running for %d seconds with load '%s'\n", timelimit, loadfile);
+
+       signal(SIGALRM, SIGNAL_CAST nb_alarm);
+       alarm(1);
+       t = torture_create_procs(run_netbench, &correct);
+       alarm(0);
+
+       printf("\nThroughput %g MB/sec\n", 
+              1.0e-6 * nbio_total() / t);
+       return correct;
+}
+
+
diff --git a/source4/torture/nbench/nbio.c b/source4/torture/nbench/nbio.c
new file mode 100644 (file)
index 0000000..819383b
--- /dev/null
@@ -0,0 +1,579 @@
+#define NBDEBUG 0
+
+/* 
+   Unix SMB/CIFS implementation.
+   SMB torture tester
+   Copyright (C) Andrew Tridgell 1997-1998
+   
+   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
+   (at your option) any later version.
+   
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   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.
+*/
+
+#include "includes.h"
+
+#define MAX_FILES 1000
+
+extern int nbench_line_count;
+static int nbio_id;
+static int nprocs;
+static BOOL bypass_io;
+
+static struct {
+       int fd;
+       int handle;
+} ftable[MAX_FILES];
+
+static struct {
+       double bytes_in, bytes_out;
+       int line;
+       int done;
+} *children;
+
+double nbio_total(void)
+{
+       int i;
+       double total = 0;
+       for (i=0;i<nprocs;i++) {
+               total += children[i].bytes_out + children[i].bytes_in;
+       }
+       return total;
+}
+
+void nb_alarm(void)
+{
+       int i;
+       int lines=0, num_clients=0;
+       double t;
+
+       if (nbio_id != -1) return;
+
+       for (i=0;i<nprocs;i++) {
+               lines += children[i].line;
+               if (!children[i].done) num_clients++;
+       }
+
+       t = end_timer();
+
+       printf("%4d  %8d  %.2f MB/sec  t=%.0f    \r", 
+              num_clients, lines/nprocs, 
+              1.0e-6 * nbio_total() / t, 
+              t);
+
+       signal(SIGALRM, nb_alarm);
+       alarm(1);       
+}
+
+void nbio_shmem(int n)
+{
+       nprocs = n;
+       children = shm_setup(sizeof(*children) * nprocs);
+       if (!children) {
+               printf("Failed to setup shared memory!\n");
+               exit(1);
+       }
+}
+
+static int find_handle(int handle)
+{
+       int i;
+       children[nbio_id].line = nbench_line_count;
+       for (i=0;i<MAX_FILES;i++) {
+               if (ftable[i].handle == handle) return i;
+       }
+       printf("(%d) ERROR: handle %d was not found\n", 
+              nbench_line_count, handle);
+       exit(1);
+
+       return -1;              /* Not reached */
+}
+
+
+static struct cli_state *c;
+
+void nb_setup(struct cli_state *cli, int id)
+{
+       nbio_id = id;
+       c = cli;
+       start_timer();
+       if (children) {
+               children[nbio_id].done = 0;
+       }
+       if (bypass_io)
+               printf("skipping I/O\n");
+}
+
+
+static void check_status(const char *op, NTSTATUS status, NTSTATUS ret)
+{
+       if (!NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(ret)) {
+               printf("[%d] Error: %s should have failed with %s\n", 
+                      nbench_line_count, op, nt_errstr(status));
+               exit(1);
+       }
+
+       if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ret)) {
+               printf("[%d] Error: %s should have succeeded - %s\n", 
+                      nbench_line_count, op, nt_errstr(ret));
+               exit(1);
+       }
+
+       if (!NT_STATUS_EQUAL(status, ret)) {
+               printf("[%d] Warning: got status %s but expected %s\n",
+                      nbench_line_count, nt_errstr(ret), nt_errstr(status));
+       }
+}
+
+
+void nb_unlink(const char *fname, int attr, NTSTATUS status)
+{
+       struct smb_unlink io;
+       NTSTATUS ret;
+
+       io.in.pattern = fname;
+
+       io.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+       if (strchr(fname, '*') == 0) {
+               io.in.attrib |= FILE_ATTRIBUTE_DIRECTORY;
+       }
+
+       ret = smb_raw_unlink(c->tree, &io);
+
+       check_status("Unlink", status, ret);
+}
+
+
+void nb_createx(const char *fname, 
+               unsigned create_options, unsigned create_disposition, int handle,
+               NTSTATUS status)
+{
+       union smb_open io;      
+       int i;
+       uint32 desired_access;
+       NTSTATUS ret;
+       TALLOC_CTX *mem_ctx;
+
+       mem_ctx = talloc_init("raw_open");
+
+       if (create_options & NTCREATEX_OPTIONS_DIRECTORY) {
+               desired_access = SA_RIGHT_FILE_READ_DATA;
+       } else {
+               desired_access = 
+                       SA_RIGHT_FILE_READ_DATA | 
+                       SA_RIGHT_FILE_WRITE_DATA |
+                       SA_RIGHT_FILE_READ_ATTRIBUTES |
+                       SA_RIGHT_FILE_WRITE_ATTRIBUTES;
+       }
+
+       io.ntcreatex.level = RAW_OPEN_NTCREATEX;
+       io.ntcreatex.in.flags = 0;
+       io.ntcreatex.in.root_fid = 0;
+       io.ntcreatex.in.access_mask = desired_access;
+       io.ntcreatex.in.file_attr = 0;
+       io.ntcreatex.in.alloc_size = 0;
+       io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE;
+       io.ntcreatex.in.open_disposition = create_disposition;
+       io.ntcreatex.in.create_options = create_options;
+       io.ntcreatex.in.impersonation = 0;
+       io.ntcreatex.in.security_flags = 0;
+       io.ntcreatex.in.fname = fname;
+
+       ret = smb_raw_open(c->tree, mem_ctx, &io);
+
+       talloc_destroy(mem_ctx);
+
+       check_status("NTCreateX", status, ret);
+
+       if (!NT_STATUS_IS_OK(ret)) return;
+
+       for (i=0;i<MAX_FILES;i++) {
+               if (ftable[i].handle == 0) break;
+       }
+       if (i == MAX_FILES) {
+               printf("(%d) file table full for %s\n", nbench_line_count, 
+                      fname);
+               exit(1);
+       }
+       ftable[i].handle = handle;
+       ftable[i].fd = io.ntcreatex.out.fnum;
+}
+
+void nb_writex(int handle, int offset, int size, int ret_size, NTSTATUS status)
+{
+       union smb_write io;
+       int i;
+       NTSTATUS ret;
+       char *buf;
+
+       i = find_handle(handle);
+
+       if (bypass_io) return;
+
+       buf = malloc(size);
+       memset(buf, 0xab, size);
+
+       io.writex.level = RAW_WRITE_WRITEX;
+       io.writex.in.fnum = ftable[i].fd;
+       io.writex.in.wmode = 0;
+       io.writex.in.remaining = 0;
+       io.writex.in.offset = offset;
+       io.writex.in.count = size;
+       io.writex.in.data = buf;
+
+       ret = smb_raw_write(c->tree, &io);
+
+       free(buf);
+
+       check_status("WriteX", status, ret);
+
+       if (io.writex.out.nwritten != ret_size) {
+               printf("[%d] Warning: WriteX got count %d expected %d\n", 
+                      nbench_line_count,
+                      io.writex.out.nwritten, ret_size);
+       }       
+
+       children[nbio_id].bytes_out += ret_size;
+}
+
+
+void nb_write(int handle, int offset, int size, int ret_size, NTSTATUS status)
+{
+       union smb_write io;
+       int i;
+       NTSTATUS ret;
+       char *buf;
+
+       i = find_handle(handle);
+
+       if (bypass_io) return;
+
+       buf = malloc(size);
+
+       memset(buf, 0x12, size);
+
+       io.write.level = RAW_WRITE_WRITE;
+       io.write.in.fnum = ftable[i].fd;
+       io.write.in.remaining = 0;
+       io.write.in.offset = offset;
+       io.write.in.count = size;
+       io.write.in.data = buf;
+
+       ret = smb_raw_write(c->tree, &io);
+
+       free(buf);
+
+       check_status("Write", status, ret);
+
+       if (io.write.out.nwritten != ret_size) {
+               printf("[%d] Warning: Write got count %d expected %d\n", 
+                      nbench_line_count,
+                      io.write.out.nwritten, ret_size);
+       }       
+
+       children[nbio_id].bytes_out += ret_size;
+}
+
+
+void nb_lockx(int handle, unsigned offset, int size, NTSTATUS status)
+{
+       union smb_lock io;
+       int i;
+       NTSTATUS ret;
+       struct smb_lock_entry lck;
+
+       i = find_handle(handle);
+
+       lck.pid = getpid();
+       lck.offset = offset;
+       lck.count = size;
+
+       io.lockx.level = RAW_LOCK_LOCKX;
+       io.lockx.in.fnum = ftable[i].fd;
+       io.lockx.in.mode = 0;
+       io.lockx.in.timeout = 0;
+       io.lockx.in.ulock_cnt = 0;
+       io.lockx.in.lock_cnt = 1;
+       io.lockx.in.locks = &lck;
+
+       ret = smb_raw_lock(c->tree, &io);
+
+       check_status("LockX", status, ret);
+}
+
+void nb_unlockx(int handle, unsigned offset, int size, NTSTATUS status)
+{
+       union smb_lock io;
+       int i;
+       NTSTATUS ret;
+       struct smb_lock_entry lck;
+
+       i = find_handle(handle);
+
+       lck.pid = getpid();
+       lck.offset = offset;
+       lck.count = size;
+
+       io.lockx.level = RAW_LOCK_LOCKX;
+       io.lockx.in.fnum = ftable[i].fd;
+       io.lockx.in.mode = 0;
+       io.lockx.in.timeout = 0;
+       io.lockx.in.ulock_cnt = 1;
+       io.lockx.in.lock_cnt = 0;
+       io.lockx.in.locks = &lck;
+
+       ret = smb_raw_lock(c->tree, &io);
+
+       check_status("UnlockX", status, ret);
+}
+
+void nb_readx(int handle, int offset, int size, int ret_size, NTSTATUS status)
+{
+       union smb_read io;
+       int i;
+       NTSTATUS ret;
+       char *buf;
+
+       i = find_handle(handle);
+
+       if (bypass_io) return;
+
+       buf = malloc(size);
+
+       io.readx.level = RAW_READ_READX;
+       io.readx.in.fnum = ftable[i].fd;
+       io.readx.in.offset    = offset;
+       io.readx.in.mincnt    = size;
+       io.readx.in.maxcnt    = size;
+       io.readx.in.remaining = 0;
+       io.readx.out.data     = buf;
+               
+       ret = smb_raw_read(c->tree, &io);
+
+       free(buf);
+
+       check_status("ReadX", status, ret);
+
+       if (io.readx.out.nread != ret_size) {
+               printf("[%d] Warning: ReadX got count %d expected %d\n", 
+                      nbench_line_count,
+                      io.readx.out.nread, ret_size);
+       }       
+
+       children[nbio_id].bytes_in += ret_size;
+}
+
+void nb_close(int handle, NTSTATUS status)
+{
+       int i;
+       NTSTATUS ret;
+       union smb_close io;
+       
+       i = find_handle(handle);
+
+       io.close.level = RAW_CLOSE_CLOSE;
+       io.close.in.fnum = ftable[i].fd;
+       io.close.in.write_time = 0;
+
+       ret = smb_raw_close(c->tree, &io);
+
+       check_status("Close", status, ret);
+
+       if (NT_STATUS_IS_OK(ret)) {
+               ftable[i].handle = 0;
+       }
+}
+
+void nb_rmdir(const char *dname, NTSTATUS status)
+{
+       NTSTATUS ret;
+       struct smb_rmdir io;
+
+       io.in.path = dname;
+
+       ret = smb_raw_rmdir(c->tree, &io);
+
+       check_status("Rmdir", status, ret);
+}
+
+void nb_rename(const char *old, const char *new, NTSTATUS status)
+{
+       NTSTATUS ret;
+       union smb_rename io;
+
+       io.generic.level = RAW_RENAME_RENAME;
+       io.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
+       io.rename.in.pattern1 = old;
+       io.rename.in.pattern2 = new;
+
+       ret = smb_raw_rename(c->tree, &io);
+
+       check_status("Rename", status, ret);
+}
+
+
+void nb_qpathinfo(const char *fname, int level, NTSTATUS status)
+{
+       union smb_fileinfo io;
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS ret;
+
+       mem_ctx = talloc_init("nb_qpathinfo");
+
+       io.generic.level = level;
+       io.generic.in.fname = fname;
+
+       ret = smb_raw_pathinfo(c->tree, mem_ctx, &io);
+
+       talloc_destroy(mem_ctx);
+
+       check_status("Pathinfo", status, ret);
+}
+
+
+void nb_qfileinfo(int fnum, int level, NTSTATUS status)
+{
+       union smb_fileinfo io;
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS ret;
+       int i;
+
+       i = find_handle(fnum);
+
+       mem_ctx = talloc_init("nb_qfileinfo");
+
+       io.generic.level = level;
+       io.generic.in.fnum = ftable[i].fd;
+
+       ret = smb_raw_fileinfo(c->tree, mem_ctx, &io);
+
+       talloc_destroy(mem_ctx);
+
+       check_status("Fileinfo", status, ret);
+}
+
+void nb_sfileinfo(int fnum, int level, NTSTATUS status)
+{
+       union smb_setfileinfo io;
+       NTSTATUS ret;
+       int i;
+
+       if (level != RAW_SFILEINFO_BASIC_INFORMATION) {
+               printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count, level);
+               return;
+       }
+
+       ZERO_STRUCT(io);
+
+       i = find_handle(fnum);
+
+       io.generic.level = level;
+       io.generic.file.fnum = ftable[i].fd;
+       unix_to_nt_time(&io.basic_info.in.create_time, time(NULL));
+       unix_to_nt_time(&io.basic_info.in.access_time, 0);
+       unix_to_nt_time(&io.basic_info.in.write_time, 0);
+       unix_to_nt_time(&io.basic_info.in.change_time, 0);
+       io.basic_info.in.attrib = 0;
+
+       ret = smb_raw_setfileinfo(c->tree, &io);
+
+       check_status("Setfileinfo", status, ret);
+}
+
+void nb_qfsinfo(int level, NTSTATUS status)
+{
+       union smb_fsinfo io;
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS ret;
+
+       mem_ctx = talloc_init("cli_dskattr");
+
+       io.generic.level = level;
+       ret = smb_raw_fsinfo(c->tree, mem_ctx, &io);
+
+       talloc_destroy(mem_ctx);
+       
+       check_status("Fsinfo", status, ret);    
+}
+
+/* callback function used for trans2 search */
+static BOOL findfirst_callback(void *private, union smb_search_data *file)
+{
+       return True;
+}
+
+void nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status)
+{
+       union smb_search_first io;
+       TALLOC_CTX *mem_ctx;
+       NTSTATUS ret;
+
+       mem_ctx = talloc_init("cli_dskattr");
+
+       io.t2ffirst.level = level;
+       io.t2ffirst.in.max_count = maxcnt;
+       io.t2ffirst.in.search_attrib = FILE_ATTRIBUTE_DIRECTORY;
+       io.t2ffirst.in.pattern = mask;
+       io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
+       io.t2ffirst.in.storage_type = 0;
+                       
+       ret = smb_raw_search_first(c->tree, mem_ctx, &io, NULL, findfirst_callback);
+
+       talloc_destroy(mem_ctx);
+
+       check_status("Search", status, ret);
+
+       if (io.t2ffirst.out.count != count) {
+               printf("[%d] Warning: got count %d expected %d\n", 
+                      nbench_line_count,
+                      io.t2ffirst.out.count, count);
+       }
+}
+
+void nb_flush(int fnum, NTSTATUS status)
+{
+       struct smb_flush io;
+       NTSTATUS ret;
+       int i;
+       i = find_handle(fnum);
+
+       io.in.fnum = ftable[i].fd;
+
+       ret = smb_raw_flush(c->tree, &io);
+
+       check_status("Flush", status, ret);
+}
+
+void nb_deltree(const char *dname)
+{
+       int total_deleted;
+
+       total_deleted = cli_deltree(c->tree, dname);
+
+       if (total_deleted == -1) {
+               printf("Failed to cleanup tree %s - exiting\n", dname);
+               exit(1);
+       }
+
+       cli_rmdir(c->tree, dname);
+}
+
+void nb_cleanup(const char *cname)
+{
+       char *dname = NULL;
+       smb_raw_exit(c->session);
+       asprintf(&dname, "\\clients\\%s", cname);
+       nb_deltree(dname);
+       free(dname);
+       cli_rmdir(c->tree, "clients");
+       children[nbio_id].done = 1;
+}
diff --git a/source4/torture/nbio.c b/source4/torture/nbio.c
deleted file mode 100644 (file)
index 65584b1..0000000
+++ /dev/null
@@ -1,287 +0,0 @@
-#define NBDEBUG 0
-
-/* 
-   Unix SMB/CIFS implementation.
-   SMB torture tester
-   Copyright (C) Andrew Tridgell 1997-1998
-   
-   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
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   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.
-*/
-
-#include "includes.h"
-
-#define MAX_FILES 1000
-
-static char buf[70000];
-extern int line_count;
-extern int nbio_id;
-static int nprocs;
-static BOOL bypass_io;
-
-static struct {
-       int fd;
-       int handle;
-} ftable[MAX_FILES];
-
-static struct {
-       double bytes_in, bytes_out;
-       int line;
-       int done;
-} *children;
-
-double nbio_total(void)
-{
-       int i;
-       double total = 0;
-       for (i=0;i<nprocs;i++) {
-               total += children[i].bytes_out + children[i].bytes_in;
-       }
-       return total;
-}
-
-void nb_alarm(void)
-{
-       int i;
-       int lines=0, num_clients=0;
-       if (nbio_id != -1) return;
-
-       for (i=0;i<nprocs;i++) {
-               lines += children[i].line;
-               if (!children[i].done) num_clients++;
-       }
-
-       printf("%4d  %8d  %.2f MB/sec\r", num_clients, lines/nprocs, 1.0e-6 * nbio_total() / end_timer());
-
-       signal(SIGALRM, nb_alarm);
-       alarm(1);       
-}
-
-void nbio_shmem(int n)
-{
-       nprocs = n;
-       children = shm_setup(sizeof(*children) * nprocs);
-       if (!children) {
-               printf("Failed to setup shared memory!\n");
-               exit(1);
-       }
-}
-
-static int find_handle(int handle)
-{
-       int i;
-       children[nbio_id].line = line_count;
-       for (i=0;i<MAX_FILES;i++) {
-               if (ftable[i].handle == handle) return i;
-       }
-       printf("(%d) ERROR: handle %d was not found\n", 
-              line_count, handle);
-       exit(1);
-
-       return -1;              /* Not reached */
-}
-
-
-static struct cli_state *c;
-
-static void sigsegv(int sig)
-{
-       char line[200];
-       printf("segv at line %d\n", line_count);
-       slprintf(line, sizeof(line), "/usr/X11R6/bin/xterm -e gdb /proc/%d/exe %d", 
-               (int)getpid(), (int)getpid());
-       system(line);
-       exit(1);
-}
-
-void nb_setup(struct cli_state *cli)
-{
-       signal(SIGSEGV, sigsegv);
-       c = cli;
-       start_timer();
-       children[nbio_id].done = 0;
-       if (bypass_io)
-               printf("skipping I/O\n");
-}
-
-
-void nb_unlink(const char *fname)
-{
-       if (NT_STATUS_IS_ERR(cli_unlink(c->tree, fname))) {
-#if NBDEBUG
-               printf("(%d) unlink %s failed (%s)\n", 
-                      line_count, fname, cli_errstr(c));
-#endif
-       }
-}
-
-
-void nb_createx(const char *fname, 
-               unsigned create_options, unsigned create_disposition, int handle)
-{
-       int fd, i;
-       uint32 desired_access;
-
-       if (create_options & NTCREATEX_OPTIONS_DIRECTORY) {
-               desired_access = SA_RIGHT_FILE_READ_DATA;
-       } else {
-               desired_access = SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_WRITE_DATA;
-       }
-
-       fd = cli_nt_create_full(c->tree, fname, 0, 
-                               desired_access,
-                               0x0,
-                               NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE, 
-                               create_disposition, 
-                               create_options, 0);
-       if (fd == -1 && handle != -1) {
-               printf("ERROR: cli_nt_create_full failed for %s - %s\n",
-                      fname, cli_errstr(c->tree));
-               exit(1);
-       }
-       if (fd != -1 && handle == -1) {
-               printf("ERROR: cli_nt_create_full succeeded for %s\n", fname);
-               exit(1);
-       }
-       if (fd == -1) return;
-
-       for (i=0;i<MAX_FILES;i++) {
-               if (ftable[i].handle == 0) break;
-       }
-       if (i == MAX_FILES) {
-               printf("(%d) file table full for %s\n", line_count, 
-                      fname);
-               exit(1);
-       }
-       ftable[i].handle = handle;
-       ftable[i].fd = fd;
-}
-
-void nb_writex(int handle, int offset, int size, int ret_size)
-{
-       int i;
-
-       if (buf[0] == 0) memset(buf, 1, sizeof(buf));
-
-       i = find_handle(handle);
-       if (!bypass_io && cli_write(c->tree, ftable[i].fd, 0, buf, offset, size) != ret_size) {
-               printf("(%d) ERROR: write failed on handle %d, fd %d \
-errno %d (%s)\n", line_count, handle, ftable[i].fd, errno, strerror(errno));
-               exit(1);
-       }
-
-       children[nbio_id].bytes_out += ret_size;
-}
-
-void nb_readx(int handle, int offset, int size, int ret_size)
-{
-       int i, ret;
-
-       i = find_handle(handle);
-       if (!bypass_io && (ret=cli_read(c->tree, ftable[i].fd, buf, offset, size)) != ret_size) {
-               printf("(%d) ERROR: read failed on handle %d ofs=%d size=%d res=%d fd %d errno %d (%s)\n",
-                       line_count, handle, offset, size, ret, ftable[i].fd, errno, strerror(errno));
-               exit(1);
-       }
-       children[nbio_id].bytes_in += ret_size;
-}
-
-void nb_close(int handle)
-{
-       int i;
-       i = find_handle(handle);
-       if (NT_STATUS_IS_ERR(cli_close(c->tree, ftable[i].fd))) {
-               printf("(%d) close failed on handle %d\n", line_count, handle);
-               exit(1);
-       }
-       ftable[i].handle = 0;
-}
-
-void nb_rmdir(const char *fname)
-{
-       if (NT_STATUS_IS_ERR(cli_rmdir(c->tree, fname))) {
-               printf("ERROR: rmdir %s failed (%s)\n", 
-                      fname, cli_errstr(c->tree));
-               exit(1);
-       }
-}
-
-void nb_rename(const char *old, const char *new)
-{
-       if (NT_STATUS_IS_ERR(cli_rename(c->tree, old, new))) {
-               printf("ERROR: rename %s %s failed (%s)\n", 
-                      old, new, cli_errstr(c->tree));
-               exit(1);
-       }
-}
-
-
-void nb_qpathinfo(const char *fname)
-{
-       cli_qpathinfo(c->tree, fname, NULL, NULL, NULL, NULL, NULL);
-}
-
-void nb_qfileinfo(int fnum)
-{
-       int i;
-       i = find_handle(fnum);
-       cli_qfileinfo(c->tree, ftable[i].fd, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
-}
-
-void nb_qfsinfo(int level)
-{
-       int bsize, total, avail;
-       /* this is not the right call - we need cli_qfsinfo() */
-       cli_dskattr(c->tree, &bsize, &total, &avail);
-}
-
-static void find_fn(file_info *finfo, const char *name, void *state)
-{
-       /* noop */
-}
-
-void nb_findfirst(const char *mask)
-{
-       cli_list(c->tree, mask, 0, find_fn, NULL);
-}
-
-void nb_flush(int fnum)
-{
-       struct smb_flush io;
-       int i;
-       i = find_handle(fnum);
-       io.in.fnum = ftable[i].fd;
-       smb_raw_flush(c->tree, &io);
-}
-
-void nb_deltree(const char *dname)
-{
-       int total_deleted;
-
-       total_deleted = cli_deltree(c->tree, dname);
-
-       if (total_deleted == -1) {
-               printf("Failed to cleanup tree %s - exiting\n", dname);
-               exit(1);
-       }
-
-       if (total_deleted > 0) printf("WARNING: Cleaned up %d files\n", total_deleted);
-}
-
-
-void nb_cleanup(void)
-{
-       cli_rmdir(c->tree, "clients");
-       children[nbio_id].done = 1;
-}
index a770e98c5fe8e566d096c8a4abd3e16af94c656a..bd804539c06f17fad51615f00076b2f53710a432 100644 (file)
@@ -20,7 +20,7 @@
 
 #include "includes.h"
 
-static int nprocs=4;
+int torture_nprocs=4;
 int torture_numops=100;
 int torture_entries=1000;
 int torture_failures=1;
@@ -28,13 +28,10 @@ static int procnum; /* records process count number when forking */
 static struct cli_state *current_cli;
 static BOOL use_oplocks;
 static BOOL use_level_II_oplocks;
-static const char *client_txt = "client_oplocks.txt";
 static BOOL use_kerberos;
 
 BOOL torture_showall = False;
 
-static double create_procs(BOOL (*fn)(int), BOOL *result);
-
 #define CHECK_MAX_FAILURES(label) do { if (++failures >= torture_failures) goto label; } while (0)
 
 static struct cli_state *open_nbt_connection(void)
@@ -298,13 +295,10 @@ static BOOL rw_torture(struct cli_state *c)
        return correct;
 }
 
-static BOOL run_torture(int dummy)
+static BOOL run_torture(struct cli_state *cli, int dummy)
 {
-       struct cli_state *cli;
         BOOL ret;
 
-       cli = current_cli;
-
        ret = rw_torture(cli);
        
        if (!torture_close_connection(cli)) {
@@ -525,13 +519,10 @@ static BOOL run_readwritetest(int dummy)
        return (test1 && test2);
 }
 
-static BOOL run_readwritemulti(int dummy)
+static BOOL run_readwritemulti(struct cli_state *cli, int dummy)
 {
-       struct cli_state *cli;
        BOOL test;
 
-       cli = current_cli;
-
        test = rw_torture3(cli, "\\multitest.txt");
 
        if (!torture_close_connection(cli)) {
@@ -542,128 +533,6 @@ static BOOL run_readwritemulti(int dummy)
 }
 
 
-int line_count = 0;
-int nbio_id;
-
-#define ival(s) strtol(s, NULL, 0)
-
-/* run a test that simulates an approximate netbench client load */
-static BOOL run_netbench(int client)
-{
-       struct cli_state *cli;
-       int i;
-       pstring line;
-       char *cname;
-       FILE *f;
-       const char *params[20];
-       BOOL correct = True;
-
-       cli = current_cli;
-
-       nbio_id = client;
-
-       nb_setup(cli);
-
-       asprintf(&cname, "client%d", client);
-
-       f = fopen(client_txt, "r");
-
-       if (!f) {
-               perror(client_txt);
-               return False;
-       }
-
-       while (fgets(line, sizeof(line)-1, f)) {
-               line_count++;
-
-               line[strlen(line)-1] = 0;
-
-               /* printf("[%d] %s\n", line_count, line); */
-
-               all_string_sub(line,"client1", cname, sizeof(line));
-               
-               /* parse the command parameters */
-               params[0] = strtok(line," ");
-               i = 0;
-               while (params[i]) params[++i] = strtok(NULL," ");
-
-               params[i] = "";
-
-               if (i < 2) continue;
-
-               if (!strncmp(params[0],"SMB", 3)) {
-                       printf("ERROR: You are using a dbench 1 load file\n");
-                       exit(1);
-               }
-               DEBUG(9,("run_netbench(%d): %s %s\n", client, params[0], params[1]));
-
-               if (!strcmp(params[0],"NTCreateX")) {
-                       nb_createx(params[1], ival(params[2]), ival(params[3]), 
-                                  ival(params[4]));
-               } else if (!strcmp(params[0],"Close")) {
-                       nb_close(ival(params[1]));
-               } else if (!strcmp(params[0],"Rename")) {
-                       nb_rename(params[1], params[2]);
-               } else if (!strcmp(params[0],"Unlink")) {
-                       nb_unlink(params[1]);
-               } else if (!strcmp(params[0],"Deltree")) {
-                       nb_deltree(params[1]);
-               } else if (!strcmp(params[0],"Rmdir")) {
-                       nb_rmdir(params[1]);
-               } else if (!strcmp(params[0],"QUERY_PATH_INFORMATION")) {
-                       nb_qpathinfo(params[1]);
-               } else if (!strcmp(params[0],"QUERY_FILE_INFORMATION")) {
-                       nb_qfileinfo(ival(params[1]));
-               } else if (!strcmp(params[0],"QUERY_FS_INFORMATION")) {
-                       nb_qfsinfo(ival(params[1]));
-               } else if (!strcmp(params[0],"FIND_FIRST")) {
-                       nb_findfirst(params[1]);
-               } else if (!strcmp(params[0],"WriteX")) {
-                       nb_writex(ival(params[1]), 
-                               ival(params[2]), ival(params[3]), ival(params[4]));
-               } else if (!strcmp(params[0],"ReadX")) {
-                       nb_readx(ival(params[1]), 
-                     ival(params[2]), ival(params[3]), ival(params[4]));
-               } else if (!strcmp(params[0],"Flush")) {
-                       nb_flush(ival(params[1]));
-               } else {
-                       printf("Unknown operation %s\n", params[0]);
-                       exit(1);
-               }
-       }
-       fclose(f);
-
-       nb_cleanup();
-
-       if (!torture_close_connection(cli)) {
-               correct = False;
-       }
-       
-       return correct;
-}
-
-
-/* run a test that simulates an approximate netbench client load */
-static BOOL run_nbench(int dummy)
-{
-       double t;
-       BOOL correct = True;
-
-       nbio_shmem(nprocs);
-
-       nbio_id = -1;
-
-       signal(SIGALRM, SIGNAL_CAST nb_alarm);
-       alarm(1);
-       t = create_procs(run_netbench, &correct);
-       alarm(0);
-
-       printf("\nThroughput %g MB/sec\n", 
-              1.0e-6 * nbio_total() / t);
-       return correct;
-}
-
-
 /*
   This test checks for two things:
 
@@ -1852,17 +1721,14 @@ static BOOL run_unlinktest(int dummy)
 /*
 test how many open files this server supports on the one socket
 */
-static BOOL run_maxfidtest(int dummy)
+static BOOL run_maxfidtest(struct cli_state *cli, int dummy)
 {
-       struct cli_state *cli;
        const char *template = "\\maxfid.%d.%d";
        char *fname;
        int fnums[0x11000], i;
        int retries=4;
        BOOL correct = True;
 
-       cli = current_cli;
-
        if (retries <= 0) {
                printf("failed to connect\n");
                return False;
@@ -3837,39 +3703,39 @@ static void sigcont(void)
 {
 }
 
-static double create_procs(BOOL (*fn)(int), BOOL *result)
+double torture_create_procs(BOOL (*fn)(struct cli_state *, int), BOOL *result)
 {
        int i, status;
        volatile pid_t *child_status;
        volatile BOOL *child_status_out;
        int synccount;
        int tries = 8;
-       double start_time_limit = 10 + (nprocs * 1.5);
+       double start_time_limit = 10 + (torture_nprocs * 1.5);
 
        synccount = 0;
 
        signal(SIGCONT, sigcont);
 
-       child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*nprocs);
+       child_status = (volatile pid_t *)shm_setup(sizeof(pid_t)*torture_nprocs);
        if (!child_status) {
                printf("Failed to setup shared memory\n");
                return -1;
        }
 
-       child_status_out = (volatile BOOL *)shm_setup(sizeof(BOOL)*nprocs);
+       child_status_out = (volatile BOOL *)shm_setup(sizeof(BOOL)*torture_nprocs);
        if (!child_status_out) {
                printf("Failed to setup result status shared memory\n");
                return -1;
        }
 
-       for (i = 0; i < nprocs; i++) {
+       for (i = 0; i < torture_nprocs; i++) {
                child_status[i] = 0;
                child_status_out[i] = True;
        }
 
        start_timer();
 
-       for (i=0;i<nprocs;i++) {
+       for (i=0;i<torture_nprocs;i++) {
                procnum = i;
                if (fork() == 0) {
                        char *myname;
@@ -3899,38 +3765,38 @@ static double create_procs(BOOL (*fn)(int), BOOL *result)
                                _exit(1);
                        }
 
-                       child_status_out[i] = fn(i);
+                       child_status_out[i] = fn(current_cli, i);
                        _exit(0);
                }
        }
 
        do {
                synccount = 0;
-               for (i=0;i<nprocs;i++) {
+               for (i=0;i<torture_nprocs;i++) {
                        if (child_status[i]) synccount++;
                }
-               if (synccount == nprocs) break;
+               if (synccount == torture_nprocs) break;
                msleep(100);
        } while (end_timer() < start_time_limit);
 
-       if (synccount != nprocs) {
-               printf("FAILED TO START %d CLIENTS (started %d)\n", nprocs, synccount);
+       if (synccount != torture_nprocs) {
+               printf("FAILED TO START %d CLIENTS (started %d)\n", torture_nprocs, synccount);
                *result = False;
                return end_timer();
        }
 
-       printf("Starting %d clients\n", nprocs);
+       printf("Starting %d clients\n", torture_nprocs);
 
        /* start the client load */
        start_timer();
-       for (i=0;i<nprocs;i++) {
+       for (i=0;i<torture_nprocs;i++) {
                child_status[i] = 0;
        }
        kill(0, SIGCONT);
 
-       printf("%d clients started\n", nprocs);
+       printf("%d clients started\n", torture_nprocs);
 
-       for (i=0;i<nprocs;i++) {
+       for (i=0;i<torture_nprocs;i++) {
                int ret;
                while ((ret=waitpid(0, &status, 0)) == -1 && errno == EINTR) /* noop */ ;
                if (ret == -1 || WEXITSTATUS(status) != 0) {
@@ -3940,7 +3806,7 @@ static double create_procs(BOOL (*fn)(int), BOOL *result)
 
        printf("\n");
        
-       for (i=0;i<nprocs;i++) {
+       for (i=0;i<torture_nprocs;i++) {
                if (!child_status_out[i]) {
                        *result = False;
                }
@@ -3969,7 +3835,7 @@ static struct {
        {"MAXFID", run_maxfidtest, FLAG_MULTIPROC},
        {"TORTURE",run_torture,    FLAG_MULTIPROC},
        {"NEGNOWAIT", run_negprot_nowait, 0},
-       {"NBENCH",  run_nbench, 0},
+       {"NBENCH",  torture_nbench, 0},
        {"DIR",  run_dirtest, 0},
        {"DIR1",  run_dirtest1, 0},
        {"DENY1",  torture_denytest1, 0},
@@ -4067,7 +3933,7 @@ static BOOL run_test(const char *name)
                        printf("Running %s\n", torture_ops[i].name);
                        if (torture_ops[i].flags & FLAG_MULTIPROC) {
                                BOOL result;
-                               t = create_procs(torture_ops[i].fn, &result);
+                               t = torture_create_procs(torture_ops[i].fn, &result);
                                if (!result) { 
                                        ret = False;
                                        printf("TEST %s FAILED!\n", torture_ops[i].name);
@@ -4130,6 +3996,7 @@ static void usage(void)
        printf("\t-m maximum protocol\n");
        printf("\t-L use oplocks\n");
        printf("\t-c CLIENT.TXT   specify client load file for NBENCH\n");
+       printf("\t-t timelimit    specify NBENCH time limit (seconds)\n");
        printf("\t-A showall\n");
        printf("\t-p port\n");
        printf("\t-s seed\n");
@@ -4211,7 +4078,7 @@ static void usage(void)
 
        srandom(time(NULL));
 
-       while ((opt = getopt(argc, argv, "p:hW:U:n:N:O:o:e:m:Ld:Ac:ks:f:s:")) != EOF) {
+       while ((opt = getopt(argc, argv, "p:hW:U:n:N:O:o:e:m:Ld:Ac:ks:f:s:t:")) != EOF) {
                switch (opt) {
                case 'p':
                        lp_set_cmdline("smb ports", optarg);
@@ -4236,7 +4103,7 @@ static void usage(void)
                        srandom(atoi(optarg));
                        break;
                case 'N':
-                       nprocs = atoi(optarg);
+                       torture_nprocs = atoi(optarg);
                        break;
                case 'o':
                        torture_numops = atoi(optarg);
@@ -4251,7 +4118,10 @@ static void usage(void)
                        torture_showall = True;
                        break;
                case 'c':
-                       client_txt = optarg;
+                       lp_set_cmdline("torture:loadfile", optarg);
+                       break;
+               case 't':
+                       lp_set_cmdline("torture:timelimit", optarg);
                        break;
                case 'k':
 #ifdef HAVE_KRB5