4 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 1997-1998
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "system/time.h"
25 #include "system/filesys.h"
26 #include "dlinklist.h"
27 #include "libcli/libcli.h"
28 #include "libcli/raw/libcliraw.h"
29 #include "torture/torture.h"
30 #include "libcli/libcli.h"
31 #include "torture/util.h"
35 extern int nbench_line_count
;
36 static int nbio_id
= -1;
38 static BOOL bypass_io
;
39 static struct timeval tv_start
, tv_end
;
40 static int warmup
, timelimit
;
41 static int in_cleanup
;
44 struct ftable
*next
, *prev
;
45 int fd
; /* the fd that we got back from the server */
46 int handle
; /* the handle in the load file */
49 static struct ftable
*ftable
;
52 double bytes
, warmup_bytes
;
57 double nbio_result(void)
61 for (i
=0;i
<nprocs
;i
++) {
62 total
+= children
[i
].bytes
- children
[i
].warmup_bytes
;
64 return 1.0e-6 * total
/ timeval_elapsed2(&tv_start
, &tv_end
);
69 return children
[nbio_id
].done
;
73 void nb_alarm(int sig
)
80 if (nbio_id
!= -1) return;
82 for (i
=0;i
<nprocs
;i
++) {
83 if (children
[i
].bytes
== 0) {
86 lines
+= children
[i
].line
;
89 t
= timeval_elapsed(&tv_start
);
91 if (!in_warmup
&& warmup
>0 && t
> warmup
) {
92 tv_start
= timeval_current();
94 for (i
=0;i
<nprocs
;i
++) {
95 children
[i
].warmup_bytes
= children
[i
].bytes
;
101 } else if (!in_warmup
&& !in_cleanup
&& t
> timelimit
) {
102 for (i
=0;i
<nprocs
;i
++) {
103 children
[i
].done
= 1;
105 tv_end
= timeval_current();
112 tv_end
= timeval_current();
116 printf("%4d %8d %.2f MB/sec warmup %.0f sec \n",
117 nprocs
, lines
/nprocs
,
119 } else if (in_cleanup
) {
120 printf("%4d %8d %.2f MB/sec cleanup %.0f sec \n",
121 nprocs
, lines
/nprocs
,
124 printf("%4d %8d %.2f MB/sec execute %.0f sec \n",
125 nprocs
, lines
/nprocs
,
131 signal(SIGALRM
, nb_alarm
);
135 void nbio_shmem(int n
, int t_timelimit
, int t_warmup
)
138 children
= shm_setup(sizeof(*children
) * nprocs
);
140 printf("Failed to setup shared memory!\n");
143 memset(children
, 0, sizeof(*children
) * nprocs
);
144 timelimit
= t_timelimit
;
147 tv_start
= timeval_current();
150 static struct ftable
*find_ftable(int handle
)
154 for (f
=ftable
;f
;f
=f
->next
) {
155 if (f
->handle
== handle
) return f
;
160 static int find_handle(int handle
)
164 children
[nbio_id
].line
= nbench_line_count
;
166 f
= find_ftable(handle
);
170 printf("(%d) ERROR: handle %d was not found\n",
171 nbench_line_count
, handle
);
174 return -1; /* Not reached */
179 static struct smbcli_state
*c
;
182 a handler function for oplock break requests
184 static BOOL
oplock_handler(struct smbcli_transport
*transport
, uint16_t tid
,
185 uint16_t fnum
, uint8_t level
, void *private)
187 struct smbcli_tree
*tree
= private;
188 return smbcli_oplock_ack(tree
, fnum
, OPLOCK_BREAK_TO_NONE
);
191 void nb_setup(struct smbcli_state
*cli
, int id
)
196 printf("skipping I/O\n");
199 smbcli_oplock_handler(cli
->transport
, oplock_handler
, cli
->tree
);
204 static void check_status(const char *op
, NTSTATUS status
, NTSTATUS ret
)
206 if (!NT_STATUS_IS_OK(status
) && NT_STATUS_IS_OK(ret
)) {
207 printf("[%d] Error: %s should have failed with %s\n",
208 nbench_line_count
, op
, nt_errstr(status
));
212 if (NT_STATUS_IS_OK(status
) && !NT_STATUS_IS_OK(ret
)) {
213 printf("[%d] Error: %s should have succeeded - %s\n",
214 nbench_line_count
, op
, nt_errstr(ret
));
218 if (!NT_STATUS_EQUAL(status
, ret
)) {
219 printf("[%d] Warning: got status %s but expected %s\n",
220 nbench_line_count
, nt_errstr(ret
), nt_errstr(status
));
225 void nb_unlink(const char *fname
, int attr
, NTSTATUS status
)
230 io
.unlink
.in
.pattern
= fname
;
232 io
.unlink
.in
.attrib
= FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
;
233 if (strchr(fname
, '*') == 0) {
234 io
.unlink
.in
.attrib
|= FILE_ATTRIBUTE_DIRECTORY
;
237 ret
= smb_raw_unlink(c
->tree
, &io
);
239 check_status("Unlink", status
, ret
);
243 void nb_createx(const char *fname
,
244 uint_t create_options
, uint_t create_disposition
, int handle
,
248 uint32_t desired_access
;
254 mem_ctx
= talloc_init("raw_open");
256 if (create_options
& NTCREATEX_OPTIONS_DIRECTORY
) {
257 desired_access
= SEC_FILE_READ_DATA
;
261 SEC_FILE_WRITE_DATA
|
262 SEC_FILE_READ_ATTRIBUTE
|
263 SEC_FILE_WRITE_ATTRIBUTE
;
264 flags
= NTCREATEX_FLAGS_EXTENDED
|
265 NTCREATEX_FLAGS_REQUEST_OPLOCK
|
266 NTCREATEX_FLAGS_REQUEST_BATCH_OPLOCK
;
269 io
.ntcreatex
.level
= RAW_OPEN_NTCREATEX
;
270 io
.ntcreatex
.in
.flags
= flags
;
271 io
.ntcreatex
.in
.root_fid
= 0;
272 io
.ntcreatex
.in
.access_mask
= desired_access
;
273 io
.ntcreatex
.in
.file_attr
= 0;
274 io
.ntcreatex
.in
.alloc_size
= 0;
275 io
.ntcreatex
.in
.share_access
= NTCREATEX_SHARE_ACCESS_READ
|NTCREATEX_SHARE_ACCESS_WRITE
;
276 io
.ntcreatex
.in
.open_disposition
= create_disposition
;
277 io
.ntcreatex
.in
.create_options
= create_options
;
278 io
.ntcreatex
.in
.impersonation
= 0;
279 io
.ntcreatex
.in
.security_flags
= 0;
280 io
.ntcreatex
.in
.fname
= fname
;
282 ret
= smb_raw_open(c
->tree
, mem_ctx
, &io
);
284 talloc_free(mem_ctx
);
286 check_status("NTCreateX", status
, ret
);
288 if (!NT_STATUS_IS_OK(ret
)) return;
290 f
= malloc_p(struct ftable
);
292 f
->fd
= io
.ntcreatex
.out
.file
.fnum
;
294 DLIST_ADD_END(ftable
, f
, struct ftable
*);
297 void nb_writex(int handle
, int offset
, int size
, int ret_size
, NTSTATUS status
)
304 i
= find_handle(handle
);
306 if (bypass_io
) return;
309 memset(buf
, 0xab, size
);
311 io
.writex
.level
= RAW_WRITE_WRITEX
;
312 io
.writex
.in
.file
.fnum
= i
;
313 io
.writex
.in
.wmode
= 0;
314 io
.writex
.in
.remaining
= 0;
315 io
.writex
.in
.offset
= offset
;
316 io
.writex
.in
.count
= size
;
317 io
.writex
.in
.data
= buf
;
319 ret
= smb_raw_write(c
->tree
, &io
);
323 check_status("WriteX", status
, ret
);
325 if (NT_STATUS_IS_OK(ret
) && io
.writex
.out
.nwritten
!= ret_size
) {
326 printf("[%d] Warning: WriteX got count %d expected %d\n",
328 io
.writex
.out
.nwritten
, ret_size
);
331 children
[nbio_id
].bytes
+= ret_size
;
334 void nb_write(int handle
, int offset
, int size
, int ret_size
, NTSTATUS status
)
341 i
= find_handle(handle
);
343 if (bypass_io
) return;
347 memset(buf
, 0x12, size
);
349 io
.write
.level
= RAW_WRITE_WRITE
;
350 io
.write
.in
.file
.fnum
= i
;
351 io
.write
.in
.remaining
= 0;
352 io
.write
.in
.offset
= offset
;
353 io
.write
.in
.count
= size
;
354 io
.write
.in
.data
= buf
;
356 ret
= smb_raw_write(c
->tree
, &io
);
360 check_status("Write", status
, ret
);
362 if (NT_STATUS_IS_OK(ret
) && io
.write
.out
.nwritten
!= ret_size
) {
363 printf("[%d] Warning: Write got count %d expected %d\n",
365 io
.write
.out
.nwritten
, ret_size
);
368 children
[nbio_id
].bytes
+= ret_size
;
372 void nb_lockx(int handle
, uint_t offset
, int size
, NTSTATUS status
)
377 struct smb_lock_entry lck
;
379 i
= find_handle(handle
);
385 io
.lockx
.level
= RAW_LOCK_LOCKX
;
386 io
.lockx
.in
.file
.fnum
= i
;
387 io
.lockx
.in
.mode
= 0;
388 io
.lockx
.in
.timeout
= 0;
389 io
.lockx
.in
.ulock_cnt
= 0;
390 io
.lockx
.in
.lock_cnt
= 1;
391 io
.lockx
.in
.locks
= &lck
;
393 ret
= smb_raw_lock(c
->tree
, &io
);
395 check_status("LockX", status
, ret
);
398 void nb_unlockx(int handle
, uint_t offset
, int size
, NTSTATUS status
)
403 struct smb_lock_entry lck
;
405 i
= find_handle(handle
);
411 io
.lockx
.level
= RAW_LOCK_LOCKX
;
412 io
.lockx
.in
.file
.fnum
= i
;
413 io
.lockx
.in
.mode
= 0;
414 io
.lockx
.in
.timeout
= 0;
415 io
.lockx
.in
.ulock_cnt
= 1;
416 io
.lockx
.in
.lock_cnt
= 0;
417 io
.lockx
.in
.locks
= &lck
;
419 ret
= smb_raw_lock(c
->tree
, &io
);
421 check_status("UnlockX", status
, ret
);
424 void nb_readx(int handle
, int offset
, int size
, int ret_size
, NTSTATUS status
)
431 i
= find_handle(handle
);
433 if (bypass_io
) return;
437 io
.readx
.level
= RAW_READ_READX
;
438 io
.readx
.in
.file
.fnum
= i
;
439 io
.readx
.in
.offset
= offset
;
440 io
.readx
.in
.mincnt
= size
;
441 io
.readx
.in
.maxcnt
= size
;
442 io
.readx
.in
.remaining
= 0;
443 io
.readx
.in
.read_for_execute
= False
;
444 io
.readx
.out
.data
= buf
;
446 ret
= smb_raw_read(c
->tree
, &io
);
450 check_status("ReadX", status
, ret
);
452 if (NT_STATUS_IS_OK(ret
) && io
.readx
.out
.nread
!= ret_size
) {
453 printf("[%d] ERROR: ReadX got count %d expected %d\n",
455 io
.readx
.out
.nread
, ret_size
);
459 children
[nbio_id
].bytes
+= ret_size
;
462 void nb_close(int handle
, NTSTATUS status
)
468 i
= find_handle(handle
);
470 io
.close
.level
= RAW_CLOSE_CLOSE
;
471 io
.close
.in
.file
.fnum
= i
;
472 io
.close
.in
.write_time
= 0;
474 ret
= smb_raw_close(c
->tree
, &io
);
476 check_status("Close", status
, ret
);
478 if (NT_STATUS_IS_OK(ret
)) {
479 struct ftable
*f
= find_ftable(handle
);
480 DLIST_REMOVE(ftable
, f
);
485 void nb_rmdir(const char *dname
, NTSTATUS status
)
492 ret
= smb_raw_rmdir(c
->tree
, &io
);
494 check_status("Rmdir", status
, ret
);
497 void nb_mkdir(const char *dname
, NTSTATUS status
)
501 io
.mkdir
.level
= RAW_MKDIR_MKDIR
;
502 io
.mkdir
.in
.path
= dname
;
504 /* NOTE! no error checking. Used for base fileset creation */
505 smb_raw_mkdir(c
->tree
, &io
);
508 void nb_rename(const char *old
, const char *new, NTSTATUS status
)
513 io
.generic
.level
= RAW_RENAME_RENAME
;
514 io
.rename
.in
.attrib
= FILE_ATTRIBUTE_SYSTEM
| FILE_ATTRIBUTE_HIDDEN
| FILE_ATTRIBUTE_DIRECTORY
;
515 io
.rename
.in
.pattern1
= old
;
516 io
.rename
.in
.pattern2
= new;
518 ret
= smb_raw_rename(c
->tree
, &io
);
520 check_status("Rename", status
, ret
);
524 void nb_qpathinfo(const char *fname
, int level
, NTSTATUS status
)
526 union smb_fileinfo io
;
530 mem_ctx
= talloc_init("nb_qpathinfo");
532 io
.generic
.level
= level
;
533 io
.generic
.in
.file
.path
= fname
;
535 ret
= smb_raw_pathinfo(c
->tree
, mem_ctx
, &io
);
537 talloc_free(mem_ctx
);
539 check_status("Pathinfo", status
, ret
);
543 void nb_qfileinfo(int fnum
, int level
, NTSTATUS status
)
545 union smb_fileinfo io
;
550 i
= find_handle(fnum
);
552 mem_ctx
= talloc_init("nb_qfileinfo");
554 io
.generic
.level
= level
;
555 io
.generic
.in
.file
.fnum
= i
;
557 ret
= smb_raw_fileinfo(c
->tree
, mem_ctx
, &io
);
559 talloc_free(mem_ctx
);
561 check_status("Fileinfo", status
, ret
);
564 void nb_sfileinfo(int fnum
, int level
, NTSTATUS status
)
566 union smb_setfileinfo io
;
570 if (level
!= RAW_SFILEINFO_BASIC_INFORMATION
) {
571 printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count
, level
);
577 i
= find_handle(fnum
);
579 io
.generic
.level
= level
;
580 io
.generic
.in
.file
.fnum
= i
;
581 unix_to_nt_time(&io
.basic_info
.in
.create_time
, time(NULL
));
582 unix_to_nt_time(&io
.basic_info
.in
.access_time
, 0);
583 unix_to_nt_time(&io
.basic_info
.in
.write_time
, 0);
584 unix_to_nt_time(&io
.basic_info
.in
.change_time
, 0);
585 io
.basic_info
.in
.attrib
= 0;
587 ret
= smb_raw_setfileinfo(c
->tree
, &io
);
589 check_status("Setfileinfo", status
, ret
);
592 void nb_qfsinfo(int level
, NTSTATUS status
)
598 mem_ctx
= talloc_init("smbcli_dskattr");
600 io
.generic
.level
= level
;
601 ret
= smb_raw_fsinfo(c
->tree
, mem_ctx
, &io
);
603 talloc_free(mem_ctx
);
605 check_status("Fsinfo", status
, ret
);
608 /* callback function used for trans2 search */
609 static BOOL
findfirst_callback(void *private, union smb_search_data
*file
)
614 void nb_findfirst(const char *mask
, int level
, int maxcnt
, int count
, NTSTATUS status
)
616 union smb_search_first io
;
620 mem_ctx
= talloc_init("smbcli_dskattr");
622 io
.t2ffirst
.level
= level
;
623 io
.t2ffirst
.in
.max_count
= maxcnt
;
624 io
.t2ffirst
.in
.search_attrib
= FILE_ATTRIBUTE_DIRECTORY
;
625 io
.t2ffirst
.in
.pattern
= mask
;
626 io
.t2ffirst
.in
.flags
= FLAG_TRANS2_FIND_CLOSE
;
627 io
.t2ffirst
.in
.storage_type
= 0;
629 ret
= smb_raw_search_first(c
->tree
, mem_ctx
, &io
, NULL
, findfirst_callback
);
631 talloc_free(mem_ctx
);
633 check_status("Search", status
, ret
);
635 if (NT_STATUS_IS_OK(ret
) && io
.t2ffirst
.out
.count
!= count
) {
636 printf("[%d] Warning: got count %d expected %d\n",
638 io
.t2ffirst
.out
.count
, count
);
642 void nb_flush(int fnum
, NTSTATUS status
)
647 i
= find_handle(fnum
);
649 io
.flush
.in
.file
.fnum
= i
;
651 ret
= smb_raw_flush(c
->tree
, &io
);
653 check_status("Flush", status
, ret
);
656 void nb_sleep(int usec
, NTSTATUS status
)
661 void nb_deltree(const char *dname
)
665 smb_raw_exit(c
->session
);
668 struct ftable
*f
= ftable
;
669 DLIST_REMOVE(ftable
, f
);
673 total_deleted
= smbcli_deltree(c
->tree
, dname
);
675 if (total_deleted
== -1) {
676 printf("Failed to cleanup tree %s - exiting\n", dname
);
680 smbcli_rmdir(c
->tree
, dname
);