root/source4/torture/nbench/nbio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nb_set_createx_params
  2. nb_reestablish_locks
  3. nb_reopen_all_files
  4. nb_reconnect
  5. nbio_target_rate
  6. nbio_time_reset
  7. nbio_time_delay
  8. nbio_result
  9. nbio_latency
  10. nb_tick
  11. nb_alarm
  12. nbio_shmem
  13. find_lock
  14. find_ftable
  15. find_handle
  16. oplock_handler
  17. nb_setup
  18. check_status
  19. nb_unlink
  20. nb_do_createx
  21. nb_createx
  22. nb_writex
  23. nb_write
  24. nb_do_lockx
  25. nb_lockx
  26. nb_unlockx
  27. nb_readx
  28. nb_close
  29. nb_rmdir
  30. nb_mkdir
  31. nb_rename
  32. nb_qpathinfo
  33. nb_qfileinfo
  34. nb_sfileinfo
  35. nb_qfsinfo
  36. findfirst_callback
  37. nb_findfirst
  38. nb_flush
  39. nb_sleep
  40. nb_deltree
  41. nb_exit

   1 /*
   2   TODO: add splitting of writes for servers with signing
   3 */
   4 
   5 
   6 /* 
   7    Unix SMB/CIFS implementation.
   8    SMB torture tester
   9    Copyright (C) Andrew Tridgell 1997-1998
  10    
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 3 of the License, or
  14    (at your option) any later version.
  15    
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20    
  21    You should have received a copy of the GNU General Public License
  22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  23 */
  24 
  25 #include "includes.h"
  26 #include "system/time.h"
  27 #include "system/filesys.h"
  28 #include "../lib/util/dlinklist.h"
  29 #include "libcli/libcli.h"
  30 #include "libcli/raw/libcliraw.h"
  31 #include "torture/torture.h"
  32 #include "libcli/libcli.h"
  33 #include "torture/util.h"
  34 #include "torture/nbench/proto.h"
  35 
  36 extern int nbench_line_count;
  37 static int nbio_id = -1;
  38 static int nprocs;
  39 static bool bypass_io;
  40 static struct timeval tv_start, tv_end;
  41 static int warmup, timelimit;
  42 static int in_cleanup;
  43 
  44 struct lock_info {
  45         struct lock_info *next, *prev;
  46         off_t offset;
  47         int size;
  48 };
  49 
  50 struct createx_params {
  51         char *fname;
  52         uint_t create_options;
  53         uint_t create_disposition;
  54         int handle;
  55 };
  56 
  57 struct ftable {
  58         struct ftable *next, *prev;
  59         int fd;     /* the fd that we got back from the server */
  60         int handle; /* the handle in the load file */
  61         struct createx_params cp;
  62         struct lock_info *locks;
  63 };
  64 
  65 static struct ftable *ftable;
  66 
  67 static struct {
  68         double bytes, warmup_bytes;
  69         int line;
  70         int done;
  71         bool connected;
  72         double max_latency;
  73         struct timeval starttime;
  74 } *children;
  75 
  76 static bool nb_do_createx(struct ftable *f,
  77                           const char *fname,
  78                           uint_t create_options,
  79                           uint_t create_disposition,
  80                           int handle,
  81                           NTSTATUS status,
  82                           bool retry);
  83 
  84 static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status);
  85 
  86 static void nb_set_createx_params(struct ftable *f,
     /* [<][>][^][v][top][bottom][index][help] */
  87                                   const char *fname,
  88                                   uint_t create_options,
  89                                   uint_t create_disposition,
  90                                   int handle)
  91 {
  92         struct createx_params *cp = &f->cp;
  93 
  94         if (fname != NULL) {
  95                 cp->fname = talloc_strdup(f, fname);
  96                 if (cp->fname == NULL) {
  97                         perror("nb_set_createx_params: strdup");
  98                         nb_exit(1);
  99                 }
 100         } else {
 101                 cp->fname = NULL;
 102         }
 103 
 104         cp->create_options = create_options;
 105         cp->create_disposition = create_disposition;
 106         cp->handle = handle;
 107 }
 108 
 109 static bool nb_reestablish_locks(struct ftable *f)
     /* [<][>][^][v][top][bottom][index][help] */
 110 {
 111         struct lock_info *linfo = f->locks;
 112 
 113         while (linfo != NULL) {
 114                 DEBUG(1,("nb_reestablish_locks: lock for file %d at %lu\n",
 115                          f->handle, (unsigned long) linfo->offset));
 116 
 117                 if (!nb_do_lockx(true, f->handle, linfo->offset, linfo->size, NT_STATUS_OK)) {
 118                         printf("nb_reestablish_locks: failed to get lock for file %s at %lu\n",
 119                                f->cp.fname, (unsigned long) linfo->offset);
 120                         return false;
 121                 }
 122 
 123                 linfo = linfo->next;
 124         }
 125 
 126         return true;
 127 }
 128 
 129 static bool nb_reopen_all_files(void)
     /* [<][>][^][v][top][bottom][index][help] */
 130 {
 131         struct ftable *f = ftable;
 132 
 133         while (f != NULL) {
 134                 DEBUG(1,("-- nb_reopen_all_files: opening %s (handle %d)\n",
 135                          f->cp.fname, f->cp.handle));
 136 
 137                 if (!nb_do_createx(f,
 138                                    f->cp.fname,
 139                                    f->cp.create_options,
 140                                    f->cp.create_disposition,
 141                                    f->cp.handle,
 142                                    NT_STATUS_OK,
 143                                    true))
 144                 {
 145                         printf("-- nb_reopen_all_files: failed to open file %s\n", f->cp.fname);
 146                         return false;
 147                 }
 148 
 149                 if (!nb_reestablish_locks(f)) {
 150                         printf("--nb_reopen_all_files: failed to reestablish locks\n");
 151                         return false;
 152                 }
 153 
 154                 f = f->next;
 155         }
 156 
 157         return true;
 158 }
 159 
 160 bool nb_reconnect(struct smbcli_state **cli, struct torture_context *tctx, int client)
     /* [<][>][^][v][top][bottom][index][help] */
 161 {
 162         children[client].connected = false;
 163 
 164         if (*cli != NULL) {
 165                 talloc_free(*cli);
 166         }
 167 
 168         if (!torture_open_connection(cli, tctx, client)) {
 169                 printf("nb_reconnect: failed to connect\n");
 170                 *cli = NULL;
 171                 return false;
 172         }
 173 
 174         nb_setup(*cli, client);
 175 
 176         if (!nb_reopen_all_files()) {
 177                 printf("nb_reconnect: failed to reopen files in client %d\n", client);
 178                 return false;
 179         }
 180 
 181         return true;
 182 }
 183 
 184 void nbio_target_rate(double rate)
     /* [<][>][^][v][top][bottom][index][help] */
 185 {
 186         static double last_bytes;
 187         static struct timeval last_time;
 188         double tdelay;
 189 
 190         if (last_bytes == 0) {
 191                 last_bytes = children[nbio_id].bytes;
 192                 last_time = timeval_current();
 193                 return;
 194         }
 195 
 196         tdelay = (children[nbio_id].bytes - last_bytes)/(1.0e6*rate) - timeval_elapsed(&last_time);
 197         if (tdelay > 0) {
 198                 msleep(tdelay*1000);
 199         } else {
 200                 children[nbio_id].max_latency = MAX(children[nbio_id].max_latency, -tdelay);
 201         }
 202 
 203         last_time = timeval_current();
 204         last_bytes = children[nbio_id].bytes;
 205 }
 206 
 207 void nbio_time_reset(void)
     /* [<][>][^][v][top][bottom][index][help] */
 208 {
 209         children[nbio_id].starttime = timeval_current();        
 210 }
 211 
 212 void nbio_time_delay(double targett)
     /* [<][>][^][v][top][bottom][index][help] */
 213 {
 214         double elapsed = timeval_elapsed(&children[nbio_id].starttime);
 215         if (targett > elapsed) {
 216                 msleep(1000*(targett - elapsed));
 217         } else if (elapsed - targett > children[nbio_id].max_latency) {
 218                 children[nbio_id].max_latency = MAX(elapsed - targett, children[nbio_id].max_latency);
 219         }
 220 }
 221 
 222 double nbio_result(void)
     /* [<][>][^][v][top][bottom][index][help] */
 223 {
 224         int i;
 225         double total = 0;
 226         for (i=0;i<nprocs;i++) {
 227                 total += children[i].bytes - children[i].warmup_bytes;
 228         }
 229         return 1.0e-6 * total / timeval_elapsed2(&tv_start, &tv_end);
 230 }
 231 
 232 double nbio_latency(void)
     /* [<][>][^][v][top][bottom][index][help] */
 233 {
 234         int i;
 235         double max_latency = 0;
 236         for (i=0;i<nprocs;i++) {
 237                 if (children[i].max_latency > max_latency) {
 238                         max_latency = children[i].max_latency;
 239                         children[i].max_latency = 0;
 240                 }
 241         }
 242         return max_latency;
 243 }
 244 
 245 bool nb_tick(void)
     /* [<][>][^][v][top][bottom][index][help] */
 246 {
 247         return children[nbio_id].done;
 248 }
 249 
 250 
 251 void nb_alarm(int sig)
     /* [<][>][^][v][top][bottom][index][help] */
 252 {
 253         int i;
 254         int lines=0;
 255         double t;
 256         int in_warmup = 0;
 257         int num_connected = 0;
 258 
 259         if (nbio_id != -1) return;
 260 
 261         for (i=0;i<nprocs;i++) {
 262                 if (children[i].connected) {
 263                         num_connected++;
 264                 }
 265                 if (children[i].bytes == 0) {
 266                         in_warmup = 1;
 267                 }
 268                 lines += children[i].line;
 269         }
 270 
 271         t = timeval_elapsed(&tv_start);
 272 
 273         if (!in_warmup && warmup>0 && t > warmup) {
 274                 tv_start = timeval_current();
 275                 warmup = 0;
 276                 for (i=0;i<nprocs;i++) {
 277                         children[i].warmup_bytes = children[i].bytes;
 278                 }
 279                 goto next;
 280         }
 281         if (t < warmup) {
 282                 in_warmup = 1;
 283         } else if (!in_warmup && !in_cleanup && t > timelimit) {
 284                 for (i=0;i<nprocs;i++) {
 285                         children[i].done = 1;
 286                 }
 287                 tv_end = timeval_current();
 288                 in_cleanup = 1;
 289         }
 290         if (t < 1) {
 291                 goto next;
 292         }
 293         if (!in_cleanup) {
 294                 tv_end = timeval_current();
 295         }
 296 
 297         if (in_warmup) {
 298                 printf("%4d  %8d  %.2f MB/sec  warmup %.0f sec   \n", 
 299                        num_connected, lines/nprocs, 
 300                        nbio_result(), t);
 301         } else if (in_cleanup) {
 302                 printf("%4d  %8d  %.2f MB/sec  cleanup %.0f sec   \n", 
 303                        num_connected, lines/nprocs, 
 304                        nbio_result(), t);
 305         } else {
 306                 printf("%4d  %8d  %.2f MB/sec  execute %.0f sec  latency %.2f msec \n", 
 307                        num_connected, lines/nprocs, 
 308                        nbio_result(), t, nbio_latency() * 1.0e3);
 309         }
 310 
 311         fflush(stdout);
 312 next:
 313         signal(SIGALRM, nb_alarm);
 314         alarm(1);       
 315 }
 316 
 317 void nbio_shmem(int n, int t_timelimit, int t_warmup)
     /* [<][>][^][v][top][bottom][index][help] */
 318 {
 319         nprocs = n;
 320         children = shm_setup(sizeof(*children) * nprocs);
 321         if (!children) {
 322                 printf("Failed to setup shared memory!\n");
 323                 nb_exit(1);
 324         }
 325         memset(children, 0, sizeof(*children) * nprocs);
 326         timelimit = t_timelimit;
 327         warmup = t_warmup;
 328         in_cleanup = 0;
 329         tv_start = timeval_current();
 330 }
 331 
 332 static struct lock_info* find_lock(struct lock_info *linfo, off_t offset, int size)
     /* [<][>][^][v][top][bottom][index][help] */
 333 {
 334         while (linfo != NULL) {
 335                 if (linfo->offset == offset &&
 336                     linfo->size == size)
 337                 {
 338                         return linfo;
 339                 }
 340 
 341                 linfo = linfo->next;
 342         }
 343 
 344         return NULL;
 345 }
 346 
 347 static struct ftable *find_ftable(int handle)
     /* [<][>][^][v][top][bottom][index][help] */
 348 {
 349         struct ftable *f;
 350 
 351         for (f=ftable;f;f=f->next) {
 352                 if (f->handle == handle) return f;
 353         }
 354         return NULL;
 355 }
 356 
 357 static int find_handle(int handle, struct ftable **f_ret)
     /* [<][>][^][v][top][bottom][index][help] */
 358 {
 359         struct ftable *f;
 360 
 361         if (f_ret != NULL)
 362                 *f_ret = NULL;
 363 
 364         children[nbio_id].line = nbench_line_count;
 365 
 366         f = find_ftable(handle);
 367         if (f) {
 368                 if (f_ret != NULL)
 369                         *f_ret = f;
 370                 return f->fd;
 371         }
 372         printf("(%d) ERROR: handle %d was not found\n", 
 373                nbench_line_count, handle);
 374         nb_exit(1);
 375 
 376         return -1;              /* Not reached */
 377 }
 378 
 379 
 380 
 381 static struct smbcli_state *c;
 382 
 383 /*
 384   a handler function for oplock break requests
 385 */
 386 static bool oplock_handler(struct smbcli_transport *transport, uint16_t tid, 
     /* [<][>][^][v][top][bottom][index][help] */
 387                            uint16_t fnum, uint8_t level, void *private_data)
 388 {
 389         struct smbcli_tree *tree = (struct smbcli_tree *)private_data;
 390         return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
 391 }
 392 
 393 void nb_setup(struct smbcli_state *cli, int id)
     /* [<][>][^][v][top][bottom][index][help] */
 394 {
 395         nbio_id = id;
 396         c = cli;
 397         if (bypass_io)
 398                 printf("skipping I/O\n");
 399 
 400         if (cli) {
 401                 smbcli_oplock_handler(cli->transport, oplock_handler, cli->tree);
 402         }
 403 
 404         children[id].connected = true;
 405 }
 406 
 407 
 408 static bool check_status(const char *op, NTSTATUS status, NTSTATUS ret)
     /* [<][>][^][v][top][bottom][index][help] */
 409 {
 410         if ((NT_STATUS_EQUAL(ret, NT_STATUS_END_OF_FILE) ||
 411              NT_STATUS_EQUAL(ret, NT_STATUS_NET_WRITE_FAULT) ||
 412              NT_STATUS_EQUAL(ret, NT_STATUS_CONNECTION_RESET)) 
 413                 && !NT_STATUS_EQUAL (status, ret))
 414         {
 415                 return false;
 416         }
 417 
 418         if (!NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(ret)) {
 419                 printf("[%d] Error: %s should have failed with %s\n", 
 420                        nbench_line_count, op, nt_errstr(status));
 421                 nb_exit(1);
 422         }
 423 
 424         if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ret)) {
 425                 printf("[%d] Error: %s should have succeeded - %s\n", 
 426                        nbench_line_count, op, nt_errstr(ret));
 427                 nb_exit(1);
 428         }
 429 
 430         if (!NT_STATUS_EQUAL(status, ret)) {
 431                 printf("[%d] Warning: got status %s but expected %s\n",
 432                        nbench_line_count, nt_errstr(ret), nt_errstr(status));
 433         }
 434 
 435         return true;
 436 }
 437 
 438 
 439 bool nb_unlink(const char *fname, int attr, NTSTATUS status, bool retry)
     /* [<][>][^][v][top][bottom][index][help] */
 440 {
 441         union smb_unlink io;
 442         NTSTATUS ret;
 443 
 444         io.unlink.in.pattern = fname;
 445 
 446         io.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
 447         if (strchr(fname, '*') == 0) {
 448                 io.unlink.in.attrib |= FILE_ATTRIBUTE_DIRECTORY;
 449         }
 450 
 451         ret = smb_raw_unlink(c->tree, &io);
 452 
 453         if (!retry)
 454                 return check_status("Unlink", status, ret);
 455 
 456         return true;
 457 }
 458 
 459 static bool nb_do_createx(struct ftable *f,
     /* [<][>][^][v][top][bottom][index][help] */
 460                           const char *fname,
 461                           uint_t create_options,
 462                           uint_t create_disposition,
 463                           int handle,
 464                           NTSTATUS status,
 465                           bool retry)
 466 {
 467         union smb_open io;      
 468         uint32_t desired_access;
 469         NTSTATUS ret;
 470         TALLOC_CTX *mem_ctx;
 471         uint_t flags = 0;
 472 
 473         mem_ctx = talloc_init("raw_open");
 474 
 475         if (create_options & NTCREATEX_OPTIONS_DIRECTORY) {
 476                 desired_access = SEC_FILE_READ_DATA;
 477         } else {
 478                 desired_access = 
 479                         SEC_FILE_READ_DATA | 
 480                         SEC_FILE_WRITE_DATA |
 481                         SEC_FILE_READ_ATTRIBUTE |
 482                         SEC_FILE_WRITE_ATTRIBUTE;
 483                 flags = NTCREATEX_FLAGS_EXTENDED |
 484                         NTCREATEX_FLAGS_REQUEST_OPLOCK | 
 485                         NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK;
 486         }
 487 
 488         io.ntcreatex.level = RAW_OPEN_NTCREATEX;
 489         io.ntcreatex.in.flags = flags;
 490         io.ntcreatex.in.root_fid = 0;
 491         io.ntcreatex.in.access_mask = desired_access;
 492         io.ntcreatex.in.file_attr = 0;
 493         io.ntcreatex.in.alloc_size = 0;
 494         io.ntcreatex.in.share_access = NTCREATEX_SHARE_ACCESS_READ|NTCREATEX_SHARE_ACCESS_WRITE;
 495         io.ntcreatex.in.open_disposition = create_disposition;
 496         io.ntcreatex.in.create_options = create_options;
 497         io.ntcreatex.in.impersonation = 0;
 498         io.ntcreatex.in.security_flags = 0;
 499         io.ntcreatex.in.fname = fname;
 500 
 501         if (retry) {
 502                 /* Reopening after a disconnect. */
 503                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
 504         } else
 505         if (f != NULL &&
 506             f->cp.create_disposition == NTCREATEX_DISP_CREATE &&
 507             NT_STATUS_IS_OK(status))
 508         {
 509                 /* Reopening after nb_createx() error. */
 510                 io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN_IF;
 511         }
 512 
 513         ret = smb_raw_open(c->tree, mem_ctx, &io);
 514 
 515         talloc_free(mem_ctx);
 516 
 517         if (!check_status("NTCreateX", status, ret))
 518                 return false;
 519 
 520         if (!NT_STATUS_IS_OK(ret))
 521                 return true;
 522 
 523         if (f == NULL) {
 524                 f = talloc (NULL, struct ftable);
 525                 f->locks = NULL;
 526                 nb_set_createx_params(f, fname, create_options, create_disposition, handle);
 527                 DLIST_ADD_END(ftable, f, struct ftable *);
 528         }
 529 
 530         f->handle = handle;
 531         f->fd = io.ntcreatex.out.file.fnum;
 532 
 533         return true;
 534 }
 535 
 536 bool nb_createx(const char *fname, 
     /* [<][>][^][v][top][bottom][index][help] */
 537                uint_t create_options, uint_t create_disposition, int handle,
 538                NTSTATUS status)
 539 {
 540         return nb_do_createx(NULL, fname, create_options, create_disposition, handle, status, false);
 541 }
 542 
 543 bool nb_writex(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 544 {
 545         union smb_write io;
 546         int i;
 547         NTSTATUS ret;
 548         uint8_t *buf;
 549 
 550         i = find_handle(handle, NULL);
 551 
 552         if (bypass_io)
 553                 return true;
 554 
 555         buf = malloc(size);
 556         memset(buf, 0xab, size);
 557 
 558         io.writex.level = RAW_WRITE_WRITEX;
 559         io.writex.in.file.fnum = i;
 560         io.writex.in.wmode = 0;
 561         io.writex.in.remaining = 0;
 562         io.writex.in.offset = offset;
 563         io.writex.in.count = size;
 564         io.writex.in.data = buf;
 565 
 566         ret = smb_raw_write(c->tree, &io);
 567 
 568         free(buf);
 569 
 570         if (!check_status("WriteX", status, ret))
 571                 return false;
 572 
 573         if (NT_STATUS_IS_OK(ret) && io.writex.out.nwritten != ret_size) {
 574                 printf("[%d] Warning: WriteX got count %d expected %d\n", 
 575                        nbench_line_count,
 576                        io.writex.out.nwritten, ret_size);
 577         }       
 578 
 579         children[nbio_id].bytes += ret_size;
 580 
 581         return true;
 582 }
 583 
 584 bool nb_write(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 585 {
 586         union smb_write io;
 587         int i;
 588         NTSTATUS ret;
 589         uint8_t *buf;
 590 
 591         i = find_handle(handle, NULL);
 592 
 593         if (bypass_io)
 594                 return true;
 595 
 596         buf = malloc(size);
 597 
 598         memset(buf, 0x12, size);
 599 
 600         io.write.level = RAW_WRITE_WRITE;
 601         io.write.in.file.fnum = i;
 602         io.write.in.remaining = 0;
 603         io.write.in.offset = offset;
 604         io.write.in.count = size;
 605         io.write.in.data = buf;
 606 
 607         ret = smb_raw_write(c->tree, &io);
 608 
 609         free(buf);
 610 
 611         if (!check_status("Write", status, ret))
 612                 return false;
 613 
 614         if (NT_STATUS_IS_OK(ret) && io.write.out.nwritten != ret_size) {
 615                 printf("[%d] Warning: Write got count %d expected %d\n", 
 616                        nbench_line_count,
 617                        io.write.out.nwritten, ret_size);
 618         }       
 619 
 620         children[nbio_id].bytes += ret_size;
 621 
 622         return true;
 623 }
 624 
 625 static bool nb_do_lockx(bool relock, int handle, off_t offset, int size, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 626 {
 627         union smb_lock io;
 628         int i;
 629         NTSTATUS ret;
 630         struct smb_lock_entry lck;
 631         struct ftable *f;
 632 
 633         i = find_handle(handle, &f);
 634 
 635         lck.pid = getpid();
 636         lck.offset = offset;
 637         lck.count = size;
 638 
 639         io.lockx.level = RAW_LOCK_LOCKX;
 640         io.lockx.in.file.fnum = i;
 641         io.lockx.in.mode = 0;
 642         io.lockx.in.timeout = 0;
 643         io.lockx.in.ulock_cnt = 0;
 644         io.lockx.in.lock_cnt = 1;
 645         io.lockx.in.locks = &lck;
 646 
 647         ret = smb_raw_lock(c->tree, &io);
 648 
 649         if (!check_status("LockX", status, ret))
 650                 return false;
 651 
 652         if (f != NULL &&
 653             !relock)
 654         {
 655                 struct lock_info *linfo;
 656                 linfo = talloc (f, struct lock_info);
 657                 linfo->offset = offset;
 658                 linfo->size = size;
 659                 DLIST_ADD_END(f->locks, linfo, struct lock_info *);
 660         }
 661 
 662         return true;
 663 }
 664 
 665 bool nb_lockx(int handle, off_t offset, int size, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 666 {
 667         return nb_do_lockx(false, handle, offset, size, status);
 668 }
 669 
 670 bool nb_unlockx(int handle, uint_t offset, int size, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 671 {
 672         union smb_lock io;
 673         int i;
 674         NTSTATUS ret;
 675         struct smb_lock_entry lck;
 676         struct ftable *f;
 677 
 678         i = find_handle(handle, &f);
 679 
 680         lck.pid = getpid();
 681         lck.offset = offset;
 682         lck.count = size;
 683 
 684         io.lockx.level = RAW_LOCK_LOCKX;
 685         io.lockx.in.file.fnum = i;
 686         io.lockx.in.mode = 0;
 687         io.lockx.in.timeout = 0;
 688         io.lockx.in.ulock_cnt = 1;
 689         io.lockx.in.lock_cnt = 0;
 690         io.lockx.in.locks = &lck;
 691 
 692         ret = smb_raw_lock(c->tree, &io);
 693 
 694         if (!check_status("UnlockX", status, ret))
 695                 return false;
 696 
 697         if (f != NULL) {
 698                 struct lock_info *linfo;
 699                 linfo = find_lock(f->locks, offset, size);
 700                 if (linfo != NULL)
 701                         DLIST_REMOVE(f->locks, linfo);
 702                 else
 703                         printf("nb_unlockx: unknown lock (%d)\n", handle);
 704         }
 705 
 706         return true;
 707 }
 708 
 709 bool nb_readx(int handle, off_t offset, int size, int ret_size, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 710 {
 711         union smb_read io;
 712         int i;
 713         NTSTATUS ret;
 714         uint8_t *buf;
 715 
 716         i = find_handle(handle, NULL);
 717 
 718         if (bypass_io)
 719                 return true;
 720 
 721         buf = malloc(size);
 722 
 723         io.readx.level = RAW_READ_READX;
 724         io.readx.in.file.fnum = i;
 725         io.readx.in.offset    = offset;
 726         io.readx.in.mincnt    = size;
 727         io.readx.in.maxcnt    = size;
 728         io.readx.in.remaining = 0;
 729         io.readx.in.read_for_execute = false;
 730         io.readx.out.data     = buf;
 731 
 732         ret = smb_raw_read(c->tree, &io);
 733 
 734         free(buf);
 735 
 736         if (!check_status("ReadX", status, ret))
 737                 return false;
 738 
 739         if (NT_STATUS_IS_OK(ret) && io.readx.out.nread != ret_size) {
 740                 printf("[%d] ERROR: ReadX got count %d expected %d\n", 
 741                        nbench_line_count,
 742                        io.readx.out.nread, ret_size);
 743                 nb_exit(1);
 744         }       
 745 
 746         children[nbio_id].bytes += ret_size;
 747 
 748         return true;
 749 }
 750 
 751 bool nb_close(int handle, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 752 {
 753         NTSTATUS ret;
 754         union smb_close io;
 755         int i;
 756 
 757         i = find_handle(handle, NULL);
 758 
 759         io.close.level = RAW_CLOSE_CLOSE;
 760         io.close.in.file.fnum = i;
 761         io.close.in.write_time = 0;
 762 
 763         ret = smb_raw_close(c->tree, &io);
 764 
 765         if (!check_status("Close", status, ret))
 766                 return false;
 767 
 768         if (NT_STATUS_IS_OK(ret)) {
 769                 struct ftable *f = find_ftable(handle);
 770                 DLIST_REMOVE(ftable, f);
 771                 talloc_free(f);
 772         }
 773 
 774         return true;
 775 }
 776 
 777 bool nb_rmdir(const char *dname, NTSTATUS status, bool retry)
     /* [<][>][^][v][top][bottom][index][help] */
 778 {
 779         NTSTATUS ret;
 780         struct smb_rmdir io;
 781 
 782         io.in.path = dname;
 783 
 784         ret = smb_raw_rmdir(c->tree, &io);
 785 
 786         if (!retry)
 787                 return check_status("Rmdir", status, ret);
 788 
 789         return true;
 790 }
 791 
 792 bool nb_mkdir(const char *dname, NTSTATUS status, bool retry)
     /* [<][>][^][v][top][bottom][index][help] */
 793 {
 794         union smb_mkdir io;
 795 
 796         io.mkdir.level = RAW_MKDIR_MKDIR;
 797         io.mkdir.in.path = dname;
 798 
 799         /* NOTE! no error checking. Used for base fileset creation */
 800         smb_raw_mkdir(c->tree, &io);
 801 
 802         return true;
 803 }
 804 
 805 bool nb_rename(const char *o, const char *n, NTSTATUS status, bool retry)
     /* [<][>][^][v][top][bottom][index][help] */
 806 {
 807         NTSTATUS ret;
 808         union smb_rename io;
 809 
 810         io.generic.level = RAW_RENAME_RENAME;
 811         io.rename.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
 812         io.rename.in.pattern1 = o;
 813         io.rename.in.pattern2 = n;
 814 
 815         ret = smb_raw_rename(c->tree, &io);
 816 
 817         if (!retry)
 818                 return check_status("Rename", status, ret);
 819 
 820         return true;
 821 }
 822 
 823 
 824 bool nb_qpathinfo(const char *fname, int level, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 825 {
 826         union smb_fileinfo io;
 827         TALLOC_CTX *mem_ctx;
 828         NTSTATUS ret;
 829 
 830         mem_ctx = talloc_init("nb_qpathinfo");
 831 
 832         io.generic.level = level;
 833         io.generic.in.file.path = fname;
 834 
 835         ret = smb_raw_pathinfo(c->tree, mem_ctx, &io);
 836 
 837         talloc_free(mem_ctx);
 838 
 839         return check_status("Pathinfo", status, ret);
 840 }
 841 
 842 
 843 bool nb_qfileinfo(int fnum, int level, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 844 {
 845         union smb_fileinfo io;
 846         TALLOC_CTX *mem_ctx;
 847         NTSTATUS ret;
 848         int i;
 849 
 850         i = find_handle(fnum, NULL);
 851 
 852         mem_ctx = talloc_init("nb_qfileinfo");
 853 
 854         io.generic.level = level;
 855         io.generic.in.file.fnum = i;
 856 
 857         ret = smb_raw_fileinfo(c->tree, mem_ctx, &io);
 858 
 859         talloc_free(mem_ctx);
 860 
 861         return check_status("Fileinfo", status, ret);
 862 }
 863 
 864 bool nb_sfileinfo(int fnum, int level, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 865 {
 866         union smb_setfileinfo io;
 867         NTSTATUS ret;
 868         int i;
 869 
 870         if (level != RAW_SFILEINFO_BASIC_INFORMATION) {
 871                 printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count, level);
 872                 return true;
 873         }
 874 
 875         ZERO_STRUCT(io);
 876 
 877         i = find_handle(fnum, NULL);
 878 
 879         io.generic.level = level;
 880         io.generic.in.file.fnum = i;
 881         unix_to_nt_time(&io.basic_info.in.create_time, time(NULL));
 882         unix_to_nt_time(&io.basic_info.in.access_time, 0);
 883         unix_to_nt_time(&io.basic_info.in.write_time, 0);
 884         unix_to_nt_time(&io.basic_info.in.change_time, 0);
 885         io.basic_info.in.attrib = 0;
 886 
 887         ret = smb_raw_setfileinfo(c->tree, &io);
 888 
 889         return check_status("Setfileinfo", status, ret);
 890 }
 891 
 892 bool nb_qfsinfo(int level, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 893 {
 894         union smb_fsinfo io;
 895         TALLOC_CTX *mem_ctx;
 896         NTSTATUS ret;
 897 
 898         mem_ctx = talloc_init("smbcli_dskattr");
 899 
 900         io.generic.level = level;
 901         ret = smb_raw_fsinfo(c->tree, mem_ctx, &io);
 902 
 903         talloc_free(mem_ctx);
 904         
 905         return check_status("Fsinfo", status, ret);     
 906 }
 907 
 908 /* callback function used for trans2 search */
 909 static bool findfirst_callback(void *private_data, const union smb_search_data *file)
     /* [<][>][^][v][top][bottom][index][help] */
 910 {
 911         return true;
 912 }
 913 
 914 bool nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 915 {
 916         union smb_search_first io;
 917         TALLOC_CTX *mem_ctx;
 918         NTSTATUS ret;
 919 
 920         mem_ctx = talloc_init("smbcli_dskattr");
 921 
 922         io.t2ffirst.level = RAW_SEARCH_TRANS2;
 923         io.t2ffirst.data_level = level;
 924         io.t2ffirst.in.max_count = maxcnt;
 925         io.t2ffirst.in.search_attrib = FILE_ATTRIBUTE_DIRECTORY;
 926         io.t2ffirst.in.pattern = mask;
 927         io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
 928         io.t2ffirst.in.storage_type = 0;
 929                         
 930         ret = smb_raw_search_first(c->tree, mem_ctx, &io, NULL, findfirst_callback);
 931 
 932         talloc_free(mem_ctx);
 933 
 934         if (!check_status("Search", status, ret))
 935                 return false;
 936 
 937         if (NT_STATUS_IS_OK(ret) && io.t2ffirst.out.count != count) {
 938                 printf("[%d] Warning: got count %d expected %d\n", 
 939                        nbench_line_count,
 940                        io.t2ffirst.out.count, count);
 941         }
 942 
 943         return true;
 944 }
 945 
 946 bool nb_flush(int fnum, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 947 {
 948         union smb_flush io;
 949         NTSTATUS ret;
 950         int i;
 951         i = find_handle(fnum, NULL);
 952 
 953         io.flush.level          = RAW_FLUSH_FLUSH;
 954         io.flush.in.file.fnum   = i;
 955 
 956         ret = smb_raw_flush(c->tree, &io);
 957 
 958         return check_status("Flush", status, ret);
 959 }
 960 
 961 void nb_sleep(int usec, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 962 {
 963         usleep(usec);
 964 }
 965 
 966 bool nb_deltree(const char *dname, bool retry)
     /* [<][>][^][v][top][bottom][index][help] */
 967 {
 968         int total_deleted;
 969 
 970         smb_raw_exit(c->session);
 971 
 972         while (ftable) {
 973                 struct ftable *f = ftable;
 974                 DLIST_REMOVE(ftable, f);
 975                 talloc_free (f);
 976         }
 977 
 978         total_deleted = smbcli_deltree(c->tree, dname);
 979 
 980         if (total_deleted == -1) {
 981                 printf("Failed to cleanup tree %s - exiting\n", dname);
 982                 nb_exit(1);
 983         }
 984 
 985         smbcli_rmdir(c->tree, dname);
 986 
 987         return true;
 988 }
 989 
 990 
 991 void nb_exit(int status)
     /* [<][>][^][v][top][bottom][index][help] */
 992 {
 993         children[nbio_id].connected = false;
 994         printf("[%d] client %d exiting with status %d\n",
 995                nbench_line_count, nbio_id, status);
 996         exit(status);
 997 }

/* [<][>][^][v][top][bottom][index][help] */