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