r26238: Add a loadparm context parameter to torture_context, remove more uses of...
[gd/samba-autobuild/.git] / source4 / torture / raw / pingpong.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    ping pong test
5
6    Copyright (C) Ronnie Sahlberg 2007
7
8    Significantly based on and borrowed from lockbench.c by
9    Copyright (C) Andrew Tridgell 2006
10    
11    This program is free software; you can redistribute it and/or modify
12    it under the terms of the GNU General Public License as published by
13    the Free Software Foundation; either version 3 of the License, or
14    (at your option) any later version.
15    
16    This program is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19    GNU General Public License for more details.
20    
21    You should have received a copy of the GNU General Public License
22    along with this program.  If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 /*
26    filename is specified by
27          --option=torture:filename=...
28
29    number of locks is specified by
30          --option=torture:num_locks=...
31
32    locktimeout is specified in ms by
33          --option=torture:locktimeout=...
34
35        default is 100 seconds
36        if set to 0 pingpong will instead loop trying the lock operation
37        over and over until it completes.
38
39    reading from the file can be enabled with
40          --option=torture:read=true
41
42    writing to the file can be enabled with
43          --option=torture:write=true
44
45 */
46 #include "includes.h"
47 #include "torture/torture.h"
48 #include "libcli/raw/libcliraw.h"
49 #include "system/time.h"
50 #include "system/filesys.h"
51 #include "libcli/libcli.h"
52 #include "torture/util.h"
53 #include "param/param.h"
54
55 static void lock_byte(struct smbcli_state *cli, int fd, int offset, int lock_timeout)
56 {
57         union smb_lock io;
58         struct smb_lock_entry lock;
59         NTSTATUS status;
60
61 try_again:
62         ZERO_STRUCT(lock);
63         io.lockx.in.ulock_cnt = 0;
64         io.lockx.in.lock_cnt = 1;
65
66         lock.count = 1;
67         lock.offset = offset;
68         lock.pid = cli->tree->session->pid;
69         io.lockx.level = RAW_LOCK_LOCKX;
70         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
71         io.lockx.in.timeout = lock_timeout;
72         io.lockx.in.locks = &lock;
73         io.lockx.in.file.fnum = fd;
74
75         status = smb_raw_lock(cli->tree, &io);
76
77         /* If we dont use timeouts and we got file lock conflict
78            just try the lock again.
79         */
80         if (lock_timeout==0) {
81                 if ( (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status))
82                    ||(NT_STATUS_EQUAL(NT_STATUS_LOCK_NOT_GRANTED, status)) ) {
83                         goto try_again;
84                 }
85         }
86
87         if (!NT_STATUS_IS_OK(status)) {
88                 DEBUG(0,("Lock failed\n"));
89                 exit(1);
90         }
91 }
92
93 static void unlock_byte(struct smbcli_state *cli, int fd, int offset)
94 {
95         union smb_lock io;
96         struct smb_lock_entry lock;
97         NTSTATUS status;
98
99         ZERO_STRUCT(lock);
100         io.lockx.in.ulock_cnt = 1;
101         io.lockx.in.lock_cnt = 0;
102
103         lock.count = 1;
104         lock.offset = offset;
105         lock.pid = cli->tree->session->pid;
106         io.lockx.level = RAW_LOCK_LOCKX;
107         io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
108         io.lockx.in.timeout = 100000;
109         io.lockx.in.locks = &lock;
110         io.lockx.in.file.fnum = fd;
111
112         status = smb_raw_lock(cli->tree, &io);
113
114         if (!NT_STATUS_IS_OK(status)) {
115                 DEBUG(0,("Unlock failed\n"));
116                 exit(1);
117         }
118 }
119
120 static void write_byte(struct smbcli_state *cli, int fd, uint8_t c, int offset)
121 {
122         union smb_write io;
123         NTSTATUS status;
124
125         io.generic.level = RAW_WRITE_WRITEX;
126         io.writex.in.file.fnum = fd;
127         io.writex.in.offset = offset;
128         io.writex.in.wmode = 0;
129         io.writex.in.remaining = 0;
130         io.writex.in.count = 1;
131         io.writex.in.data = &c;
132
133         status = smb_raw_write(cli->tree, &io);
134         if (!NT_STATUS_IS_OK(status)) {
135                 printf("write failed\n");
136                 exit(1);
137         }
138 }       
139
140 static void read_byte(struct smbcli_state *cli, int fd, uint8_t *c, int offset)
141 {
142         union smb_read io;
143         NTSTATUS status;
144
145         io.generic.level = RAW_READ_READX;
146         io.readx.in.file.fnum = fd;
147         io.readx.in.mincnt = 1;
148         io.readx.in.maxcnt = 1;
149         io.readx.in.offset = offset;
150         io.readx.in.remaining = 0;
151         io.readx.in.read_for_execute = false;
152         io.readx.out.data = c;
153
154         status = smb_raw_read(cli->tree, &io);
155         if (!NT_STATUS_IS_OK(status)) {
156                 printf("read failed\n");
157                 exit(1);
158         }
159 }       
160
161
162 static struct timeval tp1, tp2;
163
164 static void start_timer(void)
165 {
166         gettimeofday(&tp1, NULL);
167 }
168
169 static double end_timer(void)
170 {
171         gettimeofday(&tp2, NULL);
172         return (tp2.tv_sec + (tp2.tv_usec*1.0e-6)) - 
173                 (tp1.tv_sec + (tp1.tv_usec*1.0e-6));
174 }
175
176 /* 
177    ping pong
178 */
179 bool torture_ping_pong(struct torture_context *torture)
180 {
181         const char *fn;
182         int num_locks;
183         TALLOC_CTX *mem_ctx = talloc_new(torture);
184         static bool do_reads;
185         static bool do_writes;
186         int lock_timeout;
187         int fd;
188         struct smbcli_state *cli;
189         int i;
190         uint8_t incr=0, last_incr=0;
191         uint8_t *val;
192         int count, loops;
193
194         fn = torture_setting_string(torture, "filename", NULL);
195         if (fn == NULL) {
196                 DEBUG(0,("You must specify the filename using --option=torture:filename=...\n"));
197                 return false;
198         }
199
200         num_locks = torture_setting_int(torture, "num_locks", -1);
201         if (num_locks == -1) {
202                 DEBUG(0,("You must specify num_locks using --option=torture:num_locks=...\n"));
203                 return false;
204         }
205
206         do_reads     = torture_setting_bool(torture, "read", false);
207         do_writes    = torture_setting_bool(torture, "write", false);
208         lock_timeout =  torture_setting_int(torture, "lock_timeout", 100000);
209
210         if (!torture_open_connection(&cli, 0)) {
211                 DEBUG(0,("Could not open connection\n"));
212                 return false;
213         }
214
215         fd = smbcli_open(cli->tree, fn, O_RDWR|O_CREAT, DENY_NONE);
216         if (fd == -1) {
217                 printf("Failed to open %s\n", fn);
218                 exit(1);
219         }
220
221         write_byte(cli, fd, 0, num_locks);
222         lock_byte(cli, fd, 0, lock_timeout);
223
224
225         start_timer();
226         val = talloc_zero_array(mem_ctx, uint8_t, num_locks);
227         i = 0;
228         count = 0;
229         loops = 0;
230         while (1) {
231                 lock_byte(cli, fd, (i+1)%num_locks, lock_timeout);
232
233                 if (do_reads) {
234                         uint8_t c;
235                         read_byte(cli, fd, &c, i);
236                         incr   = c-val[i];
237                         val[i] = c;                     
238                 }
239
240                 if (do_writes) {
241                         uint8_t c = val[i] + 1;
242                         write_byte(cli, fd, c, i);
243                 }
244
245                 unlock_byte(cli, fd, i);
246
247                 i = (i+1)%num_locks;
248                 count++;
249                 if (loops>num_locks && incr!=last_incr) {
250                         last_incr = incr;
251                         printf("data increment = %u\n", incr);
252                         fflush(stdout);
253                 }
254                 if (end_timer() > 1.0) {
255                         printf("%8u locks/sec\r", 
256                                (unsigned)(2*count/end_timer()));
257                         fflush(stdout);
258                         start_timer();
259                         count=0;
260                 }
261                 loops++;
262         }
263
264         talloc_free(mem_ctx);
265         return true;
266 }
267