r17255: fixed BENCH-NBENCH for new smb_raw_find_first() syntax
[abartlet/samba.git/.git] / source4 / torture / nbench / nbio.c
1 #define NBDEBUG 0
2
3 /* 
4    Unix SMB/CIFS implementation.
5    SMB torture tester
6    Copyright (C) Andrew Tridgell 1997-1998
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
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"
32
33 #define MAX_FILES 100
34
35 extern int nbench_line_count;
36 static int nbio_id = -1;
37 static int nprocs;
38 static BOOL bypass_io;
39 static struct timeval tv_start, tv_end;
40 static int warmup, timelimit;
41 static int in_cleanup;
42
43 struct ftable {
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 */
47 };
48
49 static struct ftable *ftable;
50
51 static struct {
52         double bytes, warmup_bytes;
53         int line;
54         int done;
55 } *children;
56
57 double nbio_result(void)
58 {
59         int i;
60         double total = 0;
61         for (i=0;i<nprocs;i++) {
62                 total += children[i].bytes - children[i].warmup_bytes;
63         }
64         return 1.0e-6 * total / timeval_elapsed2(&tv_start, &tv_end);
65 }
66
67 BOOL nb_tick(void)
68 {
69         return children[nbio_id].done;
70 }
71
72
73 void nb_alarm(int sig)
74 {
75         int i;
76         int lines=0;
77         double t;
78         int in_warmup = 0;
79
80         if (nbio_id != -1) return;
81
82         for (i=0;i<nprocs;i++) {
83                 if (children[i].bytes == 0) {
84                         in_warmup = 1;
85                 }
86                 lines += children[i].line;
87         }
88
89         t = timeval_elapsed(&tv_start);
90
91         if (!in_warmup && warmup>0 && t > warmup) {
92                 tv_start = timeval_current();
93                 warmup = 0;
94                 for (i=0;i<nprocs;i++) {
95                         children[i].warmup_bytes = children[i].bytes;
96                 }
97                 goto next;
98         }
99         if (t < warmup) {
100                 in_warmup = 1;
101         } else if (!in_warmup && !in_cleanup && t > timelimit) {
102                 for (i=0;i<nprocs;i++) {
103                         children[i].done = 1;
104                 }
105                 tv_end = timeval_current();
106                 in_cleanup = 1;
107         }
108         if (t < 1) {
109                 goto next;
110         }
111         if (!in_cleanup) {
112                 tv_end = timeval_current();
113         }
114
115         if (in_warmup) {
116                 printf("%4d  %8d  %.2f MB/sec  warmup %.0f sec   \n", 
117                        nprocs, lines/nprocs, 
118                        nbio_result(), t);
119         } else if (in_cleanup) {
120                 printf("%4d  %8d  %.2f MB/sec  cleanup %.0f sec   \n", 
121                        nprocs, lines/nprocs, 
122                        nbio_result(), t);
123         } else {
124                 printf("%4d  %8d  %.2f MB/sec  execute %.0f sec   \n", 
125                        nprocs, lines/nprocs, 
126                        nbio_result(), t);
127         }
128
129         fflush(stdout);
130 next:
131         signal(SIGALRM, nb_alarm);
132         alarm(1);       
133 }
134
135 void nbio_shmem(int n, int t_timelimit, int t_warmup)
136 {
137         nprocs = n;
138         children = shm_setup(sizeof(*children) * nprocs);
139         if (!children) {
140                 printf("Failed to setup shared memory!\n");
141                 exit(1);
142         }
143         memset(children, 0, sizeof(*children) * nprocs);
144         timelimit = t_timelimit;
145         warmup = t_warmup;
146         in_cleanup = 0;
147         tv_start = timeval_current();
148 }
149
150 static struct ftable *find_ftable(int handle)
151 {
152         struct ftable *f;
153
154         for (f=ftable;f;f=f->next) {
155                 if (f->handle == handle) return f;
156         }
157         return NULL;
158 }
159
160 static int find_handle(int handle)
161 {
162         struct ftable *f;
163
164         children[nbio_id].line = nbench_line_count;
165
166         f = find_ftable(handle);
167         if (f) {
168                 return f->fd;
169         }
170         printf("(%d) ERROR: handle %d was not found\n", 
171                nbench_line_count, handle);
172         exit(1);
173
174         return -1;              /* Not reached */
175 }
176
177
178
179 static struct smbcli_state *c;
180
181 /*
182   a handler function for oplock break requests
183 */
184 static BOOL oplock_handler(struct smbcli_transport *transport, uint16_t tid, 
185                            uint16_t fnum, uint8_t level, void *private)
186 {
187         struct smbcli_tree *tree = private;
188         return smbcli_oplock_ack(tree, fnum, OPLOCK_BREAK_TO_NONE);
189 }
190
191 void nb_setup(struct smbcli_state *cli, int id)
192 {
193         nbio_id = id;
194         c = cli;
195         if (bypass_io)
196                 printf("skipping I/O\n");
197
198         if (cli) {
199                 smbcli_oplock_handler(cli->transport, oplock_handler, cli->tree);
200         }
201 }
202
203
204 static void check_status(const char *op, NTSTATUS status, NTSTATUS ret)
205 {
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));
209                 exit(1);
210         }
211
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));
215                 exit(1);
216         }
217
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));
221         }
222 }
223
224
225 void nb_unlink(const char *fname, int attr, NTSTATUS status)
226 {
227         union smb_unlink io;
228         NTSTATUS ret;
229
230         io.unlink.in.pattern = fname;
231
232         io.unlink.in.attrib = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
233         if (strchr(fname, '*') == 0) {
234                 io.unlink.in.attrib |= FILE_ATTRIBUTE_DIRECTORY;
235         }
236
237         ret = smb_raw_unlink(c->tree, &io);
238
239         check_status("Unlink", status, ret);
240 }
241
242
243 void nb_createx(const char *fname, 
244                 uint_t create_options, uint_t create_disposition, int handle,
245                 NTSTATUS status)
246 {
247         union smb_open io;      
248         uint32_t desired_access;
249         NTSTATUS ret;
250         TALLOC_CTX *mem_ctx;
251         uint_t flags = 0;
252         struct ftable *f;
253
254         mem_ctx = talloc_init("raw_open");
255
256         if (create_options & NTCREATEX_OPTIONS_DIRECTORY) {
257                 desired_access = SEC_FILE_READ_DATA;
258         } else {
259                 desired_access = 
260                         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;
267         }
268
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;
281
282         ret = smb_raw_open(c->tree, mem_ctx, &io);
283
284         talloc_free(mem_ctx);
285
286         check_status("NTCreateX", status, ret);
287
288         if (!NT_STATUS_IS_OK(ret)) return;
289
290         f = malloc_p(struct ftable);
291         f->handle = handle;
292         f->fd = io.ntcreatex.out.file.fnum;
293
294         DLIST_ADD_END(ftable, f, struct ftable *);
295 }
296
297 void nb_writex(int handle, int offset, int size, int ret_size, NTSTATUS status)
298 {
299         union smb_write io;
300         int i;
301         NTSTATUS ret;
302         uint8_t *buf;
303
304         i = find_handle(handle);
305
306         if (bypass_io) return;
307
308         buf = malloc(size);
309         memset(buf, 0xab, size);
310
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;
318
319         ret = smb_raw_write(c->tree, &io);
320
321         free(buf);
322
323         check_status("WriteX", status, ret);
324
325         if (NT_STATUS_IS_OK(ret) && io.writex.out.nwritten != ret_size) {
326                 printf("[%d] Warning: WriteX got count %d expected %d\n", 
327                        nbench_line_count,
328                        io.writex.out.nwritten, ret_size);
329         }       
330
331         children[nbio_id].bytes += ret_size;
332 }
333
334 void nb_write(int handle, int offset, int size, int ret_size, NTSTATUS status)
335 {
336         union smb_write io;
337         int i;
338         NTSTATUS ret;
339         uint8_t *buf;
340
341         i = find_handle(handle);
342
343         if (bypass_io) return;
344
345         buf = malloc(size);
346
347         memset(buf, 0x12, size);
348
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;
355
356         ret = smb_raw_write(c->tree, &io);
357
358         free(buf);
359
360         check_status("Write", status, ret);
361
362         if (NT_STATUS_IS_OK(ret) && io.write.out.nwritten != ret_size) {
363                 printf("[%d] Warning: Write got count %d expected %d\n", 
364                        nbench_line_count,
365                        io.write.out.nwritten, ret_size);
366         }       
367
368         children[nbio_id].bytes += ret_size;
369 }
370
371
372 void nb_lockx(int handle, uint_t offset, int size, NTSTATUS status)
373 {
374         union smb_lock io;
375         int i;
376         NTSTATUS ret;
377         struct smb_lock_entry lck;
378
379         i = find_handle(handle);
380
381         lck.pid = getpid();
382         lck.offset = offset;
383         lck.count = size;
384
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;
392
393         ret = smb_raw_lock(c->tree, &io);
394
395         check_status("LockX", status, ret);
396 }
397
398 void nb_unlockx(int handle, uint_t offset, int size, NTSTATUS status)
399 {
400         union smb_lock io;
401         int i;
402         NTSTATUS ret;
403         struct smb_lock_entry lck;
404
405         i = find_handle(handle);
406
407         lck.pid = getpid();
408         lck.offset = offset;
409         lck.count = size;
410
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;
418
419         ret = smb_raw_lock(c->tree, &io);
420
421         check_status("UnlockX", status, ret);
422 }
423
424 void nb_readx(int handle, int offset, int size, int ret_size, NTSTATUS status)
425 {
426         union smb_read io;
427         int i;
428         NTSTATUS ret;
429         uint8_t *buf;
430
431         i = find_handle(handle);
432
433         if (bypass_io) return;
434
435         buf = malloc(size);
436
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;
445                 
446         ret = smb_raw_read(c->tree, &io);
447
448         free(buf);
449
450         check_status("ReadX", status, ret);
451
452         if (NT_STATUS_IS_OK(ret) && io.readx.out.nread != ret_size) {
453                 printf("[%d] ERROR: ReadX got count %d expected %d\n", 
454                        nbench_line_count,
455                        io.readx.out.nread, ret_size);
456                 exit(1);
457         }       
458
459         children[nbio_id].bytes += ret_size;
460 }
461
462 void nb_close(int handle, NTSTATUS status)
463 {
464         NTSTATUS ret;
465         union smb_close io;
466         int i;
467
468         i = find_handle(handle);
469
470         io.close.level = RAW_CLOSE_CLOSE;
471         io.close.in.file.fnum = i;
472         io.close.in.write_time = 0;
473
474         ret = smb_raw_close(c->tree, &io);
475
476         check_status("Close", status, ret);
477
478         if (NT_STATUS_IS_OK(ret)) {
479                 struct ftable *f = find_ftable(handle);
480                 DLIST_REMOVE(ftable, f);
481                 free(f);
482         }
483 }
484
485 void nb_rmdir(const char *dname, NTSTATUS status)
486 {
487         NTSTATUS ret;
488         struct smb_rmdir io;
489
490         io.in.path = dname;
491
492         ret = smb_raw_rmdir(c->tree, &io);
493
494         check_status("Rmdir", status, ret);
495 }
496
497 void nb_mkdir(const char *dname, NTSTATUS status)
498 {
499         union smb_mkdir io;
500
501         io.mkdir.level = RAW_MKDIR_MKDIR;
502         io.mkdir.in.path = dname;
503
504         /* NOTE! no error checking. Used for base fileset creation */
505         smb_raw_mkdir(c->tree, &io);
506 }
507
508 void nb_rename(const char *old, const char *new, NTSTATUS status)
509 {
510         NTSTATUS ret;
511         union smb_rename io;
512
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;
517
518         ret = smb_raw_rename(c->tree, &io);
519
520         check_status("Rename", status, ret);
521 }
522
523
524 void nb_qpathinfo(const char *fname, int level, NTSTATUS status)
525 {
526         union smb_fileinfo io;
527         TALLOC_CTX *mem_ctx;
528         NTSTATUS ret;
529
530         mem_ctx = talloc_init("nb_qpathinfo");
531
532         io.generic.level = level;
533         io.generic.in.file.path = fname;
534
535         ret = smb_raw_pathinfo(c->tree, mem_ctx, &io);
536
537         talloc_free(mem_ctx);
538
539         check_status("Pathinfo", status, ret);
540 }
541
542
543 void nb_qfileinfo(int fnum, int level, NTSTATUS status)
544 {
545         union smb_fileinfo io;
546         TALLOC_CTX *mem_ctx;
547         NTSTATUS ret;
548         int i;
549
550         i = find_handle(fnum);
551
552         mem_ctx = talloc_init("nb_qfileinfo");
553
554         io.generic.level = level;
555         io.generic.in.file.fnum = i;
556
557         ret = smb_raw_fileinfo(c->tree, mem_ctx, &io);
558
559         talloc_free(mem_ctx);
560
561         check_status("Fileinfo", status, ret);
562 }
563
564 void nb_sfileinfo(int fnum, int level, NTSTATUS status)
565 {
566         union smb_setfileinfo io;
567         NTSTATUS ret;
568         int i;
569
570         if (level != RAW_SFILEINFO_BASIC_INFORMATION) {
571                 printf("[%d] Warning: setfileinfo level %d not handled\n", nbench_line_count, level);
572                 return;
573         }
574
575         ZERO_STRUCT(io);
576
577         i = find_handle(fnum);
578
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;
586
587         ret = smb_raw_setfileinfo(c->tree, &io);
588
589         check_status("Setfileinfo", status, ret);
590 }
591
592 void nb_qfsinfo(int level, NTSTATUS status)
593 {
594         union smb_fsinfo io;
595         TALLOC_CTX *mem_ctx;
596         NTSTATUS ret;
597
598         mem_ctx = talloc_init("smbcli_dskattr");
599
600         io.generic.level = level;
601         ret = smb_raw_fsinfo(c->tree, mem_ctx, &io);
602
603         talloc_free(mem_ctx);
604         
605         check_status("Fsinfo", status, ret);    
606 }
607
608 /* callback function used for trans2 search */
609 static BOOL findfirst_callback(void *private, union smb_search_data *file)
610 {
611         return True;
612 }
613
614 void nb_findfirst(const char *mask, int level, int maxcnt, int count, NTSTATUS status)
615 {
616         union smb_search_first io;
617         TALLOC_CTX *mem_ctx;
618         NTSTATUS ret;
619
620         mem_ctx = talloc_init("smbcli_dskattr");
621
622         io.t2ffirst.level = RAW_SEARCH_TRANS2;
623         io.t2ffirst.data_level = level;
624         io.t2ffirst.in.max_count = maxcnt;
625         io.t2ffirst.in.search_attrib = FILE_ATTRIBUTE_DIRECTORY;
626         io.t2ffirst.in.pattern = mask;
627         io.t2ffirst.in.flags = FLAG_TRANS2_FIND_CLOSE;
628         io.t2ffirst.in.storage_type = 0;
629                         
630         ret = smb_raw_search_first(c->tree, mem_ctx, &io, NULL, findfirst_callback);
631
632         talloc_free(mem_ctx);
633
634         check_status("Search", status, ret);
635
636         if (NT_STATUS_IS_OK(ret) && io.t2ffirst.out.count != count) {
637                 printf("[%d] Warning: got count %d expected %d\n", 
638                        nbench_line_count,
639                        io.t2ffirst.out.count, count);
640         }
641 }
642
643 void nb_flush(int fnum, NTSTATUS status)
644 {
645         union smb_flush io;
646         NTSTATUS ret;
647         int i;
648         i = find_handle(fnum);
649
650         io.flush.level          = RAW_FLUSH_FLUSH;
651         io.flush.in.file.fnum   = i;
652
653         ret = smb_raw_flush(c->tree, &io);
654
655         check_status("Flush", status, ret);
656 }
657
658 void nb_sleep(int usec, NTSTATUS status)
659 {
660         usleep(usec);
661 }
662
663 void nb_deltree(const char *dname)
664 {
665         int total_deleted;
666
667         smb_raw_exit(c->session);
668
669         while (ftable) {
670                 struct ftable *f = ftable;
671                 DLIST_REMOVE(ftable, f);
672                 free(f);
673         }
674
675         total_deleted = smbcli_deltree(c->tree, dname);
676
677         if (total_deleted == -1) {
678                 printf("Failed to cleanup tree %s - exiting\n", dname);
679                 exit(1);
680         }
681
682         smbcli_rmdir(c->tree, dname);
683 }
684