r25000: Fix some more C++ compatibility warnings.
[abartlet/samba.git/.git] / source4 / torture / nbench / nbio.c
index 1864c82fdcba9c2af2b54cd467981ad05dd06c60..e35b9d14ab8de24293d2450ec99e5e1381d6c4c7 100644 (file)
@@ -1,4 +1,7 @@
-#define NBDEBUG 0
+/*
+  TODO: add splitting of writes for servers with signing
+*/
+
 
 /* 
    Unix SMB/CIFS implementation.
@@ -7,7 +10,7 @@
    
    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 "system/time.h"
-#include "dlinklist.h"
-#include "librpc/gen_ndr/ndr_security.h"
-
-#define MAX_FILES 100
+#include "system/filesys.h"
+#include "lib/util/dlinklist.h"
+#include "libcli/libcli.h"
+#include "libcli/raw/libcliraw.h"
+#include "torture/torture.h"
+#include "libcli/libcli.h"
+#include "torture/util.h"
+#include "torture/nbench/proto.h"
 
 extern int nbench_line_count;
 static int nbio_id = -1;
@@ -35,10 +41,25 @@ static struct timeval tv_start, tv_end;
 static int warmup, timelimit;
 static int in_cleanup;
 
+struct lock_info {
+       struct lock_info *next, *prev;
+       off_t offset;
+       int size;
+};
+
+struct createx_params {
+       char *fname;
+       uint_t create_options;
+       uint_t create_disposition;
+       int handle;
+};
+
 struct ftable {
        struct ftable *next, *prev;
        int fd;     /* the fd that we got back from the server */
        int handle; /* the handle in the load file */
+       struct createx_params cp;
+       struct lock_info *locks;
 };
 
 static struct ftable *ftable;
@@ -47,8 +68,157 @@ static struct {
        double bytes, warmup_bytes;
        int line;
        int done;
+       bool connected;
+       double max_latency;
+       struct timeval starttime;
 } *children;
 
+static bool nb_do_createx(struct ftable *f,
+                         const char *fname,
+                         uint_t create_options,
+                         uint_t create_disposition,
+                         int handle,
+                         NTSTATUS status,
+                         bool retry);
+
+static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status);
+
+static void nb_set_createx_params(struct ftable *f,
+                                 const char *fname,
+                                 uint_t create_options,
+                                 uint_t create_disposition,
+                                 int handle)
+{
+       struct createx_params *cp = &f->cp;
+
+       if (fname != NULL) {
+               cp->fname = talloc_strdup(f, fname);
+               if (cp->fname == NULL) {
+                       perror("nb_set_createx_params: strdup");
+                       nb_exit(1);
+               }
+       } else {
+               cp->fname = NULL;
+       }
+
+       cp->create_options = create_options;
+       cp->create_disposition = create_disposition;
+       cp->handle = handle;
+}
+
+static bool nb_reestablish_locks(struct ftable *f)
+{
+       struct lock_info *linfo = f->locks;
+
+       while (linfo != NULL) {
+               DEBUG(1,("nb_reestablish_locks: lock for file %d at %lu\n",
+                        f->handle, (unsigned long) linfo->offset));
+
+               if (!nb_do_lockx(true, f->handle, linfo->offset, linfo->size, NT_STATUS_OK)) {
+                       printf("nb_reestablish_locks: failed to get lock for file %s at %lu\n",
+                              f->cp.fname, (unsigned long) linfo->offset);
+                       return False;
+               }
+
+               linfo = linfo->next;
+       }
+
+       return True;
+}
+
+static bool nb_reopen_all_files(void)
+{
+       struct ftable *f = ftable;
+
+       while (f != NULL) {
+               DEBUG(1,("-- nb_reopen_all_files: opening %s (handle %d)\n",
+                        f->cp.fname, f->cp.handle));
+
+               if (!nb_do_createx(f,
+                                  f->cp.fname,
+                                  f->cp.create_options,
+                                  f->cp.create_disposition,
+                                  f->cp.handle,
+                                  NT_STATUS_OK,
+                                  True))
+               {
+                       printf("-- nb_reopen_all_files: failed to open file %s\n", f->cp.fname);
+                       return False;
+               }
+
+               if (!nb_reestablish_locks(f)) {
+                       printf("--nb_reopen_all_files: failed to reestablish locks\n");
+                       return False;
+               }
+
+               f = f->next;
+       }
+
+       return True;
+}
+
+bool nb_reconnect(struct smbcli_state **cli, int client)
+{
+       children[client].connected = false;
+
+       if (*cli != NULL) {
+               talloc_free(*cli);
+       }
+
+       if (!torture_open_connection(cli, client)) {
+               printf("nb_reconnect: failed to connect\n");
+               *cli = NULL;
+               return False;
+       }
+
+       nb_setup(*cli, client);
+
+       if (!nb_reopen_all_files()) {
+               printf("nb_reconnect: failed to reopen files in client %d\n", client);
+               return False;
+       }
+
+       return True;
+}
+
+void nbio_target_rate(double rate)
+{
+       static double last_bytes;
+       static struct timeval last_time;
+       double tdelay;
+
+       if (last_bytes == 0) {
+               last_bytes = children[nbio_id].bytes;
+               last_time = timeval_current();
+               return;
+       }
+
+       tdelay = (children[nbio_id].bytes - last_bytes)/(1.0e6*rate) - timeval_elapsed(&last_time);
+       if (tdelay > 0) {
+               msleep(tdelay*1000);
+       } else {
+               children[nbio_id].max_latency = MAX(children[nbio_id].max_latency, -tdelay);
+       }
+
+       last_time = timeval_current();
+       last_bytes = children[nbio_id].bytes;
+}
+
+void nbio_time_reset(void)
+{
+       children[nbio_id].starttime = timeval_current();        
+}
+
+void nbio_time_delay(double targett)
+{
+       double elapsed = timeval_elapsed(&children[nbio_id].starttime);
+       if (targett > elapsed) {
+               msleep(1000*(targett - elapsed));
+       } else if (elapsed - targett > children[nbio_id].max_latency) {
+               children[nbio_id].max_latency = MAX(elapsed - targett, children[nbio_id].max_latency);
+       }
+}
+
 double nbio_result(void)
 {
        int i;
@@ -59,6 +229,19 @@ double nbio_result(void)
        return 1.0e-6 * total / timeval_elapsed2(&tv_start, &tv_end);
 }
 
+double nbio_latency(void)
+{
+       int i;
+       double max_latency = 0;
+       for (i=0;i<nprocs;i++) {
+               if (children[i].max_latency > max_latency) {
+                       max_latency = children[i].max_latency;
+                       children[i].max_latency = 0;
+               }
+       }
+       return max_latency;
+}
+
 BOOL nb_tick(void)
 {
        return children[nbio_id].done;
@@ -71,10 +254,14 @@ void nb_alarm(int sig)
        int lines=0;
        double t;
        int in_warmup = 0;
+       int num_connected = 0;
 
        if (nbio_id != -1) return;
 
        for (i=0;i<nprocs;i++) {
+               if (children[i].connected) {
+                       num_connected++;
+               }
                if (children[i].bytes == 0) {
                        in_warmup = 1;
                }
@@ -109,16 +296,16 @@ void nb_alarm(int sig)
 
        if (in_warmup) {
                printf("%4d  %8d  %.2f MB/sec  warmup %.0f sec   \n", 
-                      nprocs, lines/nprocs, 
+                      num_connected, lines/nprocs, 
                       nbio_result(), t);
        } else if (in_cleanup) {
                printf("%4d  %8d  %.2f MB/sec  cleanup %.0f sec   \n", 
-                      nprocs, lines/nprocs, 
+                      num_connected, lines/nprocs, 
                       nbio_result(), t);
        } else {
-               printf("%4d  %8d  %.2f MB/sec  execute %.0f sec   \n", 
-                      nprocs, lines/nprocs, 
-                      nbio_result(), t);
+               printf("%4d  %8d  %.2f MB/sec  execute %.0f sec  latency %.2f msec \n", 
+                      num_connected, lines/nprocs, 
+                      nbio_result(), t, nbio_latency() * 1.0e3);
        }
 
        fflush(stdout);
@@ -133,7 +320,7 @@ void nbio_shmem(int n, int t_timelimit, int t_warmup)
        children = shm_setup(sizeof(*children) * nprocs);
        if (!children) {
                printf("Failed to setup shared memory!\n");
-               exit(1);
+               nb_exit(1);
        }
        memset(children, 0, sizeof(*children) * nprocs);
        timelimit = t_timelimit;
@@ -142,6 +329,21 @@ void nbio_shmem(int n, int t_timelimit, int t_warmup)
        tv_start = timeval_current();
 }
 
+static struct lock_info* find_lock(struct lock_info *linfo, off_t offset, int size)
+{
+       while (linfo != NULL) {
+               if (linfo->offset == offset &&
+                   linfo->size == size)
+               {
+                       return linfo;
+               }
+
+               linfo = linfo->next;
+       }
+
+       return NULL;
+}
+
 static struct ftable *find_ftable(int handle)
 {
        struct ftable *f;
@@ -152,19 +354,24 @@ static struct ftable *find_ftable(int handle)
        return NULL;
 }
 
-static int find_handle(int handle)
+static int find_handle(int handle, struct ftable **f_ret)
 {
        struct ftable *f;
 
+       if (f_ret != NULL)
+               *f_ret = NULL;
+
        children[nbio_id].line = nbench_line_count;
 
        f = find_ftable(handle);
        if (f) {
+               if (f_ret != NULL)
+                       *f_ret = f;
                return f->fd;
        }
        printf("(%d) ERROR: handle %d was not found\n", 
               nbench_line_count, handle);
-       exit(1);
+       nb_exit(1);
 
        return -1;              /* Not reached */
 }
@@ -176,10 +383,11 @@ static struct smbcli_state *c;
 /*
   a handler function for oplock break requests
 */
-static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, uint16_t fnum, uint8_t level, void *private)
+static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, 
+                          uint16_t fnum, uint8_t level, void *private)
 {
-       struct smbcli_tree *tree = private;
-       return smbcli_oplock_ack(tree, fnum, level);
+       struct smbcli_tree *tree = (struct smbcli_tree *)private;
+       return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
 }
 
 void nb_setup(struct smbcli_state *cli, int id)
@@ -192,58 +400,75 @@ void nb_setup(struct smbcli_state *cli, int id)
        if (cli) {
                smbcli_oplock_handler(cli->transport, oplock_handler, cli->tree);
        }
+
+       children[id].connected = true;
 }
 
 
-static void check_status(const char *op, NTSTATUS status, NTSTATUS ret)
+static bool check_status(const char *op, NTSTATUS status, NTSTATUS ret)
 {
+       if ((NT_STATUS_EQUAL(ret, NT_STATUS_END_OF_FILE) ||
+            NT_STATUS_EQUAL(ret, NT_STATUS_NET_WRITE_FAULT) ||
+            NT_STATUS_EQUAL(ret, NT_STATUS_CONNECTION_RESET)) 
+               && !NT_STATUS_EQUAL (status, ret))
+       {
+               return False;
+       }
+
        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);
+               nb_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);
+               nb_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));
        }
+
+       return True;
 }
 
 
-void nb_unlink(const char *fname, int attr, NTSTATUS status)
+bool nb_unlink(const char *fname, int attr, NTSTATUS status, bool retry)
 {
-       struct smb_unlink io;
+       union smb_unlink io;
        NTSTATUS ret;
 
-       io.in.pattern = fname;
+       io.unlink.in.pattern = fname;
 
-       io.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+       io.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
        if (strchr(fname, '*') == 0) {
-               io.in.attrib |= FILE_ATTRIBUTE_DIRECTORY;
+               io.unlink.in.attrib |= FILE_ATTRIBUTE_DIRECTORY;
        }
 
        ret = smb_raw_unlink(c->tree, &io);
 
-       check_status("Unlink", status, ret);
-}
+       if (!retry)
+               return check_status("Unlink", status, ret);
 
+       return True;
+}
 
-void nb_createx(const char *fname, 
-               uint_t create_options, uint_t create_disposition, int handle,
-               NTSTATUS status)
+static bool nb_do_createx(struct ftable *f,
+                         const char *fname,
+                         uint_t create_options,
+                         uint_t create_disposition,
+                         int handle,
+                         NTSTATUS status,
+                         bool retry)
 {
        union smb_open io;      
        uint32_t desired_access;
        NTSTATUS ret;
        TALLOC_CTX *mem_ctx;
        uint_t flags = 0;
-       struct ftable *f;
 
        mem_ctx = talloc_init("raw_open");
 
@@ -273,37 +498,65 @@ void nb_createx(const char *fname,
        io.ntcreatex.in.security_flags = 0;
        io.ntcreatex.in.fname = fname;
 
+       if (retry) {
+               /* Reopening after a disconnect. */
+               io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       } else
+       if (f != NULL &&
+           f->cp.create_disposition == NTCREATEX_DISP_CREATE &&
+           NT_STATUS_IS_OK(status))
+       {
+               /* Reopening after nb_createx() error. */
+               io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
+       }
+
        ret = smb_raw_open(c->tree, mem_ctx, &io);
 
        talloc_free(mem_ctx);
 
-       check_status("NTCreateX", status, ret);
+       if (!check_status("NTCreateX", status, ret))
+               return False;
+
+       if (!NT_STATUS_IS_OK(ret))
+               return True;
 
-       if (!NT_STATUS_IS_OK(ret)) return;
+       if (f == NULL) {
+               f = talloc (NULL, struct ftable);
+               f->locks = NULL;
+               nb_set_createx_params(f, fname, create_options, create_disposition, handle);
+               DLIST_ADD_END(ftable, f, struct ftable *);
+       }
 
-       f = malloc_p(struct ftable);
        f->handle = handle;
-       f->fd = io.ntcreatex.out.fnum;
+       f->fd = io.ntcreatex.out.file.fnum;
 
-       DLIST_ADD_END(ftable, f, struct ftable *);
+       return True;
 }
 
-void nb_writex(int handle, int offset, int size, int ret_size, NTSTATUS status)
+bool nb_createx(const char *fname, 
+              uint_t create_options, uint_t create_disposition, int handle,
+              NTSTATUS status)
+{
+       return nb_do_createx(NULL, fname, create_options, create_disposition, handle, status, False);
+}
+
+bool nb_writex(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
 {
        union smb_write io;
        int i;
        NTSTATUS ret;
        uint8_t *buf;
 
-       i = find_handle(handle);
+       i = find_handle(handle, NULL);
 
-       if (bypass_io) return;
+       if (bypass_io)
+               return True;
 
        buf = malloc(size);
        memset(buf, 0xab, size);
 
        io.writex.level = RAW_WRITE_WRITEX;
-       io.writex.in.fnum = i;
+       io.writex.in.file.fnum = i;
        io.writex.in.wmode = 0;
        io.writex.in.remaining = 0;
        io.writex.in.offset = offset;
@@ -314,7 +567,8 @@ void nb_writex(int handle, int offset, int size, int ret_size, NTSTATUS status)
 
        free(buf);
 
-       check_status("WriteX", status, ret);
+       if (!check_status("WriteX", status, ret))
+               return False;
 
        if (NT_STATUS_IS_OK(ret) && io.writex.out.nwritten != ret_size) {
                printf("[%d] Warning: WriteX got count %d expected %d\n", 
@@ -323,25 +577,28 @@ void nb_writex(int handle, int offset, int size, int ret_size, NTSTATUS status)
        }       
 
        children[nbio_id].bytes += ret_size;
+
+       return True;
 }
 
-void nb_write(int handle, int offset, int size, int ret_size, NTSTATUS status)
+bool nb_write(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
 {
        union smb_write io;
        int i;
        NTSTATUS ret;
        uint8_t *buf;
 
-       i = find_handle(handle);
+       i = find_handle(handle, NULL);
 
-       if (bypass_io) return;
+       if (bypass_io)
+               return True;
 
        buf = malloc(size);
 
        memset(buf, 0x12, size);
 
        io.write.level = RAW_WRITE_WRITE;
-       io.write.in.fnum = i;
+       io.write.in.file.fnum = i;
        io.write.in.remaining = 0;
        io.write.in.offset = offset;
        io.write.in.count = size;
@@ -351,7 +608,8 @@ void nb_write(int handle, int offset, int size, int ret_size, NTSTATUS status)
 
        free(buf);
 
-       check_status("Write", status, ret);
+       if (!check_status("Write", status, ret))
+               return False;
 
        if (NT_STATUS_IS_OK(ret) && io.write.out.nwritten != ret_size) {
                printf("[%d] Warning: Write got count %d expected %d\n", 
@@ -360,24 +618,26 @@ void nb_write(int handle, int offset, int size, int ret_size, NTSTATUS status)
        }       
 
        children[nbio_id].bytes += ret_size;
-}
 
+       return True;
+}
 
-void nb_lockx(int handle, uint_t offset, int size, NTSTATUS status)
+static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status)
 {
        union smb_lock io;
        int i;
        NTSTATUS ret;
        struct smb_lock_entry lck;
+       struct ftable *f;
 
-       i = find_handle(handle);
+       i = find_handle(handle, &f);
 
        lck.pid = getpid();
        lck.offset = offset;
        lck.count = size;
 
        io.lockx.level = RAW_LOCK_LOCKX;
-       io.lockx.in.fnum = i;
+       io.lockx.in.file.fnum = i;
        io.lockx.in.mode = 0;
        io.lockx.in.timeout = 0;
        io.lockx.in.ulock_cnt = 0;
@@ -386,24 +646,43 @@ void nb_lockx(int handle, uint_t offset, int size, NTSTATUS status)
 
        ret = smb_raw_lock(c->tree, &io);
 
-       check_status("LockX", status, ret);
+       if (!check_status("LockX", status, ret))
+               return False;
+
+       if (f != NULL &&
+           !relock)
+       {
+               struct lock_info *linfo;
+               linfo = talloc (f, struct lock_info);
+               linfo->offset = offset;
+               linfo->size = size;
+               DLIST_ADD_END(f->locks, linfo, struct lock_info *);
+       }
+
+       return True;
+}
+
+bool nb_lockx(int handle, off_t offset, int size, NTSTATUS status)
+{
+       return nb_do_lockx(false, handle, offset, size, status);
 }
 
-void nb_unlockx(int handle, uint_t offset, int size, NTSTATUS status)
+bool nb_unlockx(int handle, uint_t offset, int size, NTSTATUS status)
 {
        union smb_lock io;
        int i;
        NTSTATUS ret;
        struct smb_lock_entry lck;
+       struct ftable *f;
 
-       i = find_handle(handle);
+       i = find_handle(handle, &f);
 
        lck.pid = getpid();
        lck.offset = offset;
        lck.count = size;
 
        io.lockx.level = RAW_LOCK_LOCKX;
-       io.lockx.in.fnum = i;
+       io.lockx.in.file.fnum = i;
        io.lockx.in.mode = 0;
        io.lockx.in.timeout = 0;
        io.lockx.in.ulock_cnt = 1;
@@ -412,70 +691,90 @@ void nb_unlockx(int handle, uint_t offset, int size, NTSTATUS status)
 
        ret = smb_raw_lock(c->tree, &io);
 
-       check_status("UnlockX", status, ret);
+       if (!check_status("UnlockX", status, ret))
+               return False;
+
+       if (f != NULL) {
+               struct lock_info *linfo;
+               linfo = find_lock(f->locks, offset, size);
+               if (linfo != NULL)
+                       DLIST_REMOVE(f->locks, linfo);
+               else
+                       printf("nb_unlockx: unknown lock (%d)\n", handle);
+       }
+
+       return True;
 }
 
-void nb_readx(int handle, int offset, int size, int ret_size, NTSTATUS status)
+bool nb_readx(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
 {
        union smb_read io;
        int i;
        NTSTATUS ret;
        uint8_t *buf;
 
-       i = find_handle(handle);
+       i = find_handle(handle, NULL);
 
-       if (bypass_io) return;
+       if (bypass_io)
+               return True;
 
        buf = malloc(size);
 
        io.readx.level = RAW_READ_READX;
-       io.readx.in.fnum = i;
+       io.readx.in.file.fnum = i;
        io.readx.in.offset    = offset;
        io.readx.in.mincnt    = size;
        io.readx.in.maxcnt    = size;
        io.readx.in.remaining = 0;
+       io.readx.in.read_for_execute = False;
        io.readx.out.data     = buf;
-               
+
        ret = smb_raw_read(c->tree, &io);
 
        free(buf);
 
-       check_status("ReadX", status, ret);
+       if (!check_status("ReadX", status, ret))
+               return False;
 
        if (NT_STATUS_IS_OK(ret) && io.readx.out.nread != ret_size) {
                printf("[%d] ERROR: ReadX got count %d expected %d\n", 
                       nbench_line_count,
                       io.readx.out.nread, ret_size);
-               exit(1);
+               nb_exit(1);
        }       
 
        children[nbio_id].bytes += ret_size;
+
+       return True;
 }
 
-void nb_close(int handle, NTSTATUS status)
+bool nb_close(int handle, NTSTATUS status)
 {
        NTSTATUS ret;
        union smb_close io;
        int i;
 
-       i = find_handle(handle);
+       i = find_handle(handle, NULL);
 
        io.close.level = RAW_CLOSE_CLOSE;
-       io.close.in.fnum = i;
+       io.close.in.file.fnum = i;
        io.close.in.write_time = 0;
 
        ret = smb_raw_close(c->tree, &io);
 
-       check_status("Close", status, ret);
+       if (!check_status("Close", status, ret))
+               return False;
 
        if (NT_STATUS_IS_OK(ret)) {
                struct ftable *f = find_ftable(handle);
                DLIST_REMOVE(ftable, f);
-               free(f);
+               talloc_free(f);
        }
+
+       return True;
 }
 
-void nb_rmdir(const char *dname, NTSTATUS status)
+bool nb_rmdir(const char *dname, NTSTATUS status, bool retry)
 {
        NTSTATUS ret;
        struct smb_rmdir io;
@@ -484,10 +783,13 @@ void nb_rmdir(const char *dname, NTSTATUS status)
 
        ret = smb_raw_rmdir(c->tree, &io);
 
-       check_status("Rmdir", status, ret);
+       if (!retry)
+               return check_status("Rmdir", status, ret);
+
+       return True;
 }
 
-void nb_mkdir(const char *dname, NTSTATUS status)
+bool nb_mkdir(const char *dname, NTSTATUS status, bool retry)
 {
        union smb_mkdir io;
 
@@ -496,9 +798,11 @@ void nb_mkdir(const char *dname, NTSTATUS status)
 
        /* NOTE! no error checking. Used for base fileset creation */
        smb_raw_mkdir(c->tree, &io);
+
+       return True;
 }
 
-void nb_rename(const char *old, const char *new, NTSTATUS status)
+bool nb_rename(const char *old, const char *new, NTSTATUS status, bool retry)
 {
        NTSTATUS ret;
        union smb_rename io;
@@ -510,11 +814,14 @@ void nb_rename(const char *old, const char *new, NTSTATUS status)
 
        ret = smb_raw_rename(c->tree, &io);
 
-       check_status("Rename", status, ret);
+       if (!retry)
+               return check_status("Rename", status, ret);
+
+       return True;
 }
 
 
-void nb_qpathinfo(const char *fname, int level, NTSTATUS status)
+bool nb_qpathinfo(const char *fname, int level, NTSTATUS status)
 {
        union smb_fileinfo io;
        TALLOC_CTX *mem_ctx;
@@ -523,38 +830,38 @@ void nb_qpathinfo(const char *fname, int level, NTSTATUS status)
        mem_ctx = talloc_init("nb_qpathinfo");
 
        io.generic.level = level;
-       io.generic.in.fname = fname;
+       io.generic.in.file.path = fname;
 
        ret = smb_raw_pathinfo(c->tree, mem_ctx, &io);
 
        talloc_free(mem_ctx);
 
-       check_status("Pathinfo", status, ret);
+       return check_status("Pathinfo", status, ret);
 }
 
 
-void nb_qfileinfo(int fnum, int level, NTSTATUS status)
+bool nb_qfileinfo(int fnum, int level, NTSTATUS status)
 {
        union smb_fileinfo io;
        TALLOC_CTX *mem_ctx;
        NTSTATUS ret;
        int i;
 
-       i = find_handle(fnum);
+       i = find_handle(fnum, NULL);
 
        mem_ctx = talloc_init("nb_qfileinfo");
 
        io.generic.level = level;
-       io.generic.in.fnum = i;
+       io.generic.in.file.fnum = i;
 
        ret = smb_raw_fileinfo(c->tree, mem_ctx, &io);
 
        talloc_free(mem_ctx);
 
-       check_status("Fileinfo", status, ret);
+       return check_status("Fileinfo", status, ret);
 }
 
-void nb_sfileinfo(int fnum, int level, NTSTATUS status)
+bool nb_sfileinfo(int fnum, int level, NTSTATUS status)
 {
        union smb_setfileinfo io;
        NTSTATUS ret;
@@ -562,15 +869,15 @@ void nb_sfileinfo(int fnum, int level, NTSTATUS status)
 
        if (level != RAW_SFILEINFO_BASIC_INFORMATION) {
                printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count, level);
-               return;
+               return True;
        }
 
        ZERO_STRUCT(io);
 
-       i = find_handle(fnum);
+       i = find_handle(fnum, NULL);
 
        io.generic.level = level;
-       io.generic.file.fnum = i;
+       io.generic.in.file.fnum = i;
        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);
@@ -579,10 +886,10 @@ void nb_sfileinfo(int fnum, int level, NTSTATUS status)
 
        ret = smb_raw_setfileinfo(c->tree, &io);
 
-       check_status("Setfileinfo", status, ret);
+       return check_status("Setfileinfo", status, ret);
 }
 
-void nb_qfsinfo(int level, NTSTATUS status)
+bool nb_qfsinfo(int level, NTSTATUS status)
 {
        union smb_fsinfo io;
        TALLOC_CTX *mem_ctx;
@@ -595,16 +902,16 @@ void nb_qfsinfo(int level, NTSTATUS status)
 
        talloc_free(mem_ctx);
        
-       check_status("Fsinfo", status, ret);    
+       return check_status("Fsinfo", status, ret);     
 }
 
 /* callback function used for trans2 search */
-static BOOL findfirst_callback(void *private, union smb_search_data *file)
+static BOOL findfirst_callback(void *private, const union smb_search_data *file)
 {
        return True;
 }
 
-void nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status)
+bool nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status)
 {
        union smb_search_first io;
        TALLOC_CTX *mem_ctx;
@@ -612,7 +919,8 @@ void nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS s
 
        mem_ctx = talloc_init("smbcli_dskattr");
 
-       io.t2ffirst.level = level;
+       io.t2ffirst.level = RAW_SEARCH_TRANS2;
+       io.t2ffirst.data_level = level;
        io.t2ffirst.in.max_count = maxcnt;
        io.t2ffirst.in.search_attrib = FILE_ATTRIBUTE_DIRECTORY;
        io.t2ffirst.in.pattern = mask;
@@ -623,36 +931,39 @@ void nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS s
 
        talloc_free(mem_ctx);
 
-       check_status("Search", status, ret);
+       if (!check_status("Search", status, ret))
+               return False;
 
        if (NT_STATUS_IS_OK(ret) && io.t2ffirst.out.count != count) {
                printf("[%d] Warning: got count %d expected %d\n", 
                       nbench_line_count,
                       io.t2ffirst.out.count, count);
        }
+
+       return True;
 }
 
-void nb_flush(int fnum, NTSTATUS status)
+bool nb_flush(int fnum, NTSTATUS status)
 {
-       struct smb_flush io;
+       union smb_flush io;
        NTSTATUS ret;
        int i;
-       i = find_handle(fnum);
+       i = find_handle(fnum, NULL);
 
-       io.in.fnum = i;
+       io.flush.level          = RAW_FLUSH_FLUSH;
+       io.flush.in.file.fnum   = i;
 
        ret = smb_raw_flush(c->tree, &io);
 
-       check_status("Flush", status, ret);
+       return check_status("Flush", status, ret);
 }
 
 void nb_sleep(int usec, NTSTATUS status)
 {
-       (void)status;
-       sys_usleep(usec);
+       usleep(usec);
 }
 
-void nb_deltree(const char *dname)
+bool nb_deltree(const char *dname, bool retry)
 {
        int total_deleted;
 
@@ -661,16 +972,26 @@ void nb_deltree(const char *dname)
        while (ftable) {
                struct ftable *f = ftable;
                DLIST_REMOVE(ftable, f);
-               free(f);
+               talloc_free (f);
        }
 
        total_deleted = smbcli_deltree(c->tree, dname);
 
        if (total_deleted == -1) {
                printf("Failed to cleanup tree %s - exiting\n", dname);
-               exit(1);
+               nb_exit(1);
        }
 
        smbcli_rmdir(c->tree, dname);
+
+       return True;
 }
 
+
+void nb_exit(int status)
+{
+       children[nbio_id].connected = false;
+       printf("[%d] client %d exiting with status %d\n",
+              nbench_line_count, nbio_id, status);
+       exit(status);
+}