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