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