Line data Source code
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 "system/time.h"
48 : #include "system/filesys.h"
49 : #include "libcli/libcli.h"
50 : #include "torture/util.h"
51 : #include "torture/raw/proto.h"
52 :
53 0 : static void lock_byte(struct smbcli_state *cli, int fd, int offset, int lock_timeout)
54 : {
55 0 : union smb_lock io;
56 0 : struct smb_lock_entry lock;
57 0 : NTSTATUS status;
58 :
59 0 : try_again:
60 0 : ZERO_STRUCT(lock);
61 0 : io.lockx.in.ulock_cnt = 0;
62 0 : io.lockx.in.lock_cnt = 1;
63 :
64 0 : lock.count = 1;
65 0 : lock.offset = offset;
66 0 : lock.pid = cli->tree->session->pid;
67 0 : io.lockx.level = RAW_LOCK_LOCKX;
68 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
69 0 : io.lockx.in.timeout = lock_timeout;
70 0 : io.lockx.in.locks = &lock;
71 0 : io.lockx.in.file.fnum = fd;
72 :
73 0 : status = smb_raw_lock(cli->tree, &io);
74 :
75 : /* If we don't use timeouts and we got file lock conflict
76 : just try the lock again.
77 : */
78 0 : if (lock_timeout==0) {
79 0 : if ( (NT_STATUS_EQUAL(NT_STATUS_FILE_LOCK_CONFLICT, status))
80 0 : ||(NT_STATUS_EQUAL(NT_STATUS_LOCK_NOT_GRANTED, status)) ) {
81 0 : goto try_again;
82 : }
83 : }
84 :
85 0 : if (!NT_STATUS_IS_OK(status)) {
86 0 : DEBUG(0,("Lock failed\n"));
87 0 : exit(1);
88 : }
89 0 : }
90 :
91 0 : static void unlock_byte(struct smbcli_state *cli, int fd, int offset)
92 : {
93 0 : union smb_lock io;
94 0 : struct smb_lock_entry lock;
95 0 : NTSTATUS status;
96 :
97 0 : ZERO_STRUCT(lock);
98 0 : io.lockx.in.ulock_cnt = 1;
99 0 : io.lockx.in.lock_cnt = 0;
100 :
101 0 : lock.count = 1;
102 0 : lock.offset = offset;
103 0 : lock.pid = cli->tree->session->pid;
104 0 : io.lockx.level = RAW_LOCK_LOCKX;
105 0 : io.lockx.in.mode = LOCKING_ANDX_LARGE_FILES;
106 0 : io.lockx.in.timeout = 100000;
107 0 : io.lockx.in.locks = &lock;
108 0 : io.lockx.in.file.fnum = fd;
109 :
110 0 : status = smb_raw_lock(cli->tree, &io);
111 :
112 0 : if (!NT_STATUS_IS_OK(status)) {
113 0 : DEBUG(0,("Unlock failed\n"));
114 0 : exit(1);
115 : }
116 0 : }
117 :
118 0 : static void write_byte(struct smbcli_state *cli, int fd, uint8_t c, int offset)
119 : {
120 0 : union smb_write io;
121 0 : NTSTATUS status;
122 :
123 0 : io.generic.level = RAW_WRITE_WRITEX;
124 0 : io.writex.in.file.fnum = fd;
125 0 : io.writex.in.offset = offset;
126 0 : io.writex.in.wmode = 0;
127 0 : io.writex.in.remaining = 0;
128 0 : io.writex.in.count = 1;
129 0 : io.writex.in.data = &c;
130 :
131 0 : status = smb_raw_write(cli->tree, &io);
132 0 : if (!NT_STATUS_IS_OK(status)) {
133 0 : printf("write failed\n");
134 0 : exit(1);
135 : }
136 0 : }
137 :
138 0 : static void read_byte(struct smbcli_state *cli, int fd, uint8_t *c, int offset)
139 : {
140 0 : union smb_read io;
141 0 : NTSTATUS status;
142 :
143 0 : io.generic.level = RAW_READ_READX;
144 0 : io.readx.in.file.fnum = fd;
145 0 : io.readx.in.mincnt = 1;
146 0 : io.readx.in.maxcnt = 1;
147 0 : io.readx.in.offset = offset;
148 0 : io.readx.in.remaining = 0;
149 0 : io.readx.in.read_for_execute = false;
150 0 : io.readx.out.data = c;
151 :
152 0 : status = smb_raw_read(cli->tree, &io);
153 0 : if (!NT_STATUS_IS_OK(status)) {
154 0 : printf("read failed\n");
155 0 : exit(1);
156 : }
157 0 : }
158 :
159 : /*
160 : ping pong
161 : */
162 0 : bool torture_ping_pong(struct torture_context *torture)
163 : {
164 0 : const char *fn;
165 0 : int num_locks;
166 0 : TALLOC_CTX *mem_ctx = talloc_new(torture);
167 0 : static bool do_reads;
168 0 : static bool do_writes;
169 0 : int lock_timeout;
170 0 : int fd;
171 0 : struct smbcli_state *cli;
172 0 : int i;
173 0 : uint8_t incr=0, last_incr=0;
174 0 : uint8_t *val;
175 0 : int count, loops;
176 0 : struct timeval start;
177 :
178 0 : fn = torture_setting_string(torture, "filename", NULL);
179 0 : if (fn == NULL) {
180 0 : DEBUG(0,("You must specify the filename using --option=torture:filename=...\n"));
181 0 : return false;
182 : }
183 :
184 0 : num_locks = torture_setting_int(torture, "num_locks", -1);
185 0 : if (num_locks == -1) {
186 0 : DEBUG(0,("You must specify num_locks using --option=torture:num_locks=...\n"));
187 0 : return false;
188 : }
189 :
190 0 : do_reads = torture_setting_bool(torture, "read", false);
191 0 : do_writes = torture_setting_bool(torture, "write", false);
192 0 : lock_timeout = torture_setting_int(torture, "lock_timeout", 100000);
193 :
194 0 : if (!torture_open_connection(&cli, torture, 0)) {
195 0 : DEBUG(0,("Could not open connection\n"));
196 0 : return false;
197 : }
198 :
199 0 : fd = smbcli_open(cli->tree, fn, O_RDWR|O_CREAT, DENY_NONE);
200 0 : if (fd == -1) {
201 0 : printf("Failed to open %s\n", fn);
202 0 : exit(1);
203 : }
204 :
205 0 : write_byte(cli, fd, 0, num_locks);
206 0 : lock_byte(cli, fd, 0, lock_timeout);
207 :
208 :
209 0 : start = timeval_current();
210 0 : val = talloc_zero_array(mem_ctx, uint8_t, num_locks);
211 0 : i = 0;
212 0 : count = 0;
213 0 : loops = 0;
214 0 : while (1) {
215 0 : lock_byte(cli, fd, (i+1)%num_locks, lock_timeout);
216 :
217 0 : if (do_reads) {
218 0 : uint8_t c;
219 0 : read_byte(cli, fd, &c, i);
220 0 : incr = c-val[i];
221 0 : val[i] = c;
222 : }
223 :
224 0 : if (do_writes) {
225 0 : uint8_t c = val[i] + 1;
226 0 : write_byte(cli, fd, c, i);
227 : }
228 :
229 0 : unlock_byte(cli, fd, i);
230 :
231 0 : i = (i+1)%num_locks;
232 0 : count++;
233 0 : if (loops>num_locks && incr!=last_incr) {
234 0 : last_incr = incr;
235 0 : printf("data increment = %u\n", incr);
236 0 : fflush(stdout);
237 : }
238 0 : if (timeval_elapsed(&start) > 1.0) {
239 0 : printf("%8u locks/sec\r",
240 0 : (unsigned)(2*count/timeval_elapsed(&start)));
241 0 : fflush(stdout);
242 0 : start = timeval_current();
243 0 : count=0;
244 : }
245 0 : loops++;
246 : }
247 : }
248 :
|