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