2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2008
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "torture/torture.h"
26 #include "libcli/raw/libcliraw.h"
27 #include "system/time.h"
28 #include "system/filesys.h"
29 #include "libcli/libcli.h"
30 #include "torture/util.h"
31 #include "lib/events/events.h"
32 #include "lib/cmdline/popt_common.h"
33 #include "libcli/composite/composite.h"
34 #include "libcli/smb_composite/smb_composite.h"
35 #include "libcli/resolve/resolve.h"
36 #include "param/param.h"
38 #define BASEDIR "\\testoffline"
40 static int nconnections
;
42 static int num_connected
;
43 static int test_failed
;
44 extern int torture_numops
;
45 extern int torture_entries
;
46 static bool test_finished
;
48 enum offline_op
{OP_LOADFILE
, OP_SAVEFILE
, OP_SETOFFLINE
, OP_GETOFFLINE
, OP_ENDOFLIST
};
50 static double latencies
[OP_ENDOFLIST
];
51 static double worst_latencies
[OP_ENDOFLIST
];
53 #define FILE_SIZE 8192
56 struct offline_state
{
57 struct torture_context
*tctx
;
58 struct event_context
*ev
;
59 struct smbcli_tree
*tree
;
66 uint32_t offline_count
;
67 uint32_t online_count
;
69 struct smb_composite_loadfile
*loadfile
;
70 struct smb_composite_savefile
*savefile
;
71 struct smbcli_request
*req
;
73 struct timeval tv_start
;
76 static void test_offline(struct offline_state
*state
);
79 static char *filename(TALLOC_CTX
*ctx
, int i
)
81 char *s
= talloc_asprintf(ctx
, BASEDIR
"\\file%u.dat", i
);
87 called when a loadfile completes
89 static void loadfile_callback(struct composite_context
*ctx
)
91 struct offline_state
*state
= ctx
->async
.private_data
;
95 status
= smb_composite_loadfile_recv(ctx
, state
->mem_ctx
);
96 if (!NT_STATUS_IS_OK(status
)) {
97 printf("Failed to read file '%s' - %s\n",
98 state
->loadfile
->in
.fname
, nt_errstr(status
));
102 /* check the data is correct */
103 if (state
->loadfile
->out
.size
!= FILE_SIZE
) {
104 printf("Wrong file size %u - expected %u\n",
105 state
->loadfile
->out
.size
, FILE_SIZE
);
110 for (i
=0;i
<FILE_SIZE
;i
++) {
111 if (state
->loadfile
->out
.data
[i
] != 1+(state
->fnumber
% 255)) {
112 printf("Bad data in file %u (got %u expected %u)\n",
114 state
->loadfile
->out
.data
[i
],
115 1+(state
->fnumber
% 255));
121 talloc_steal(state
->loadfile
, state
->loadfile
->out
.data
);
124 talloc_free(state
->loadfile
);
125 state
->loadfile
= NULL
;
127 if (!test_finished
) {
134 called when a savefile completes
136 static void savefile_callback(struct composite_context
*ctx
)
138 struct offline_state
*state
= ctx
->async
.private_data
;
141 status
= smb_composite_savefile_recv(ctx
);
142 if (!NT_STATUS_IS_OK(status
)) {
143 printf("Failed to save file '%s' - %s\n",
144 state
->savefile
->in
.fname
, nt_errstr(status
));
149 talloc_free(state
->savefile
);
150 state
->savefile
= NULL
;
152 if (!test_finished
) {
159 called when a setoffline completes
161 static void setoffline_callback(struct smbcli_request
*req
)
163 struct offline_state
*state
= req
->async
.private;
166 status
= smbcli_request_simple_recv(req
);
167 if (!NT_STATUS_IS_OK(status
)) {
168 printf("Failed to set offline file '%s' - %s\n",
169 state
->fname
, nt_errstr(status
));
176 if (!test_finished
) {
183 called when a getoffline completes
185 static void getoffline_callback(struct smbcli_request
*req
)
187 struct offline_state
*state
= req
->async
.private;
189 union smb_fileinfo io
;
191 io
.getattr
.level
= RAW_FILEINFO_GETATTR
;
193 status
= smb_raw_pathinfo_recv(req
, state
->mem_ctx
, &io
);
194 if (!NT_STATUS_IS_OK(status
)) {
195 printf("Failed to get offline file '%s' - %s\n",
196 state
->fname
, nt_errstr(status
));
200 if (io
.getattr
.out
.attrib
& FILE_ATTRIBUTE_OFFLINE
) {
201 state
->offline_count
++;
203 state
->online_count
++;
209 if (!test_finished
) {
216 send the next offline file fetch request
218 static void test_offline(struct offline_state
*state
)
220 struct composite_context
*ctx
;
223 lat
= timeval_elapsed(&state
->tv_start
);
224 if (latencies
[state
->op
] < lat
) {
225 latencies
[state
->op
] = lat
;
228 state
->op
= (enum offline_op
) (random() % OP_ENDOFLIST
);
230 state
->fnumber
= random() % torture_numops
;
231 talloc_free(state
->fname
);
232 state
->fname
= filename(state
->mem_ctx
, state
->fnumber
);
234 state
->tv_start
= timeval_current();
238 state
->loadfile
= talloc_zero(state
->mem_ctx
, struct smb_composite_loadfile
);
239 state
->loadfile
->in
.fname
= state
->fname
;
241 ctx
= smb_composite_loadfile_send(state
->tree
, state
->loadfile
);
243 printf("Failed to setup loadfile for %s\n", state
->fname
);
247 talloc_steal(state
->loadfile
, ctx
);
249 ctx
->async
.fn
= loadfile_callback
;
250 ctx
->async
.private_data
= state
;
254 state
->savefile
= talloc_zero(state
->mem_ctx
, struct smb_composite_savefile
);
256 state
->savefile
->in
.fname
= state
->fname
;
257 state
->savefile
->in
.data
= talloc_size(state
->savefile
, FILE_SIZE
);
258 state
->savefile
->in
.size
= FILE_SIZE
;
259 memset(state
->savefile
->in
.data
, state
->fnumber
, FILE_SIZE
);
261 ctx
= smb_composite_savefile_send(state
->tree
, state
->savefile
);
263 printf("Failed to setup savefile for %s\n", state
->fname
);
267 talloc_steal(state
->savefile
, ctx
);
269 ctx
->async
.fn
= savefile_callback
;
270 ctx
->async
.private_data
= state
;
273 case OP_SETOFFLINE
: {
274 union smb_setfileinfo io
;
276 io
.setattr
.level
= RAW_SFILEINFO_SETATTR
;
277 io
.setattr
.in
.attrib
= FILE_ATTRIBUTE_OFFLINE
;
278 io
.setattr
.in
.file
.path
= state
->fname
;
279 /* make the file 1 hour old, to get past mininum age restrictions
281 io
.setattr
.in
.write_time
= time(NULL
) - 60*60;
283 state
->req
= smb_raw_setpathinfo_send(state
->tree
, &io
);
284 if (state
->req
== NULL
) {
285 printf("Failed to setup setoffline for %s\n", state
->fname
);
289 state
->req
->async
.fn
= setoffline_callback
;
290 state
->req
->async
.private = state
;
294 case OP_GETOFFLINE
: {
295 union smb_fileinfo io
;
297 io
.getattr
.level
= RAW_FILEINFO_GETATTR
;
298 io
.getattr
.in
.file
.path
= state
->fname
;
300 state
->req
= smb_raw_pathinfo_send(state
->tree
, &io
);
301 if (state
->req
== NULL
) {
302 printf("Failed to setup getoffline for %s\n", state
->fname
);
306 state
->req
->async
.fn
= getoffline_callback
;
307 state
->req
->async
.private = state
;
312 printf("bad operation??\n");
320 static void echo_completion(struct smbcli_request
*req
)
322 struct offline_state
*state
= (struct offline_state
*)req
->async
.private;
323 NTSTATUS status
= smbcli_request_simple_recv(req
);
324 if (NT_STATUS_EQUAL(status
, NT_STATUS_END_OF_FILE
) ||
325 NT_STATUS_EQUAL(status
, NT_STATUS_LOCAL_DISCONNECT
)) {
326 talloc_free(state
->tree
);
329 DEBUG(0,("lost connection\n"));
334 static void report_rate(struct event_context
*ev
, struct timed_event
*te
,
335 struct timeval t
, void *private_data
)
337 struct offline_state
*state
= talloc_get_type(private_data
,
338 struct offline_state
);
340 uint32_t total
=0, total_offline
=0, total_online
=0;
341 for (i
=0;i
<numstates
;i
++) {
342 total
+= state
[i
].count
- state
[i
].lastcount
;
343 if (timeval_elapsed(&state
[i
].tv_start
) > latencies
[state
[i
].op
]) {
344 latencies
[state
[i
].op
] = timeval_elapsed(&state
[i
].tv_start
);
346 state
[i
].lastcount
= state
[i
].count
;
347 total_online
+= state
[i
].online_count
;
348 total_offline
+= state
[i
].offline_count
;
350 printf("ops/s=%4u offline=%5u online=%4u set_lat=%.1f/%.1f get_lat=%.1f/%.1f save_lat=%.1f/%.1f load_lat=%.1f/%.1f\n",
351 total
, total_offline
, total_online
,
352 latencies
[OP_SETOFFLINE
],
353 worst_latencies
[OP_SETOFFLINE
],
354 latencies
[OP_GETOFFLINE
],
355 worst_latencies
[OP_GETOFFLINE
],
356 latencies
[OP_SAVEFILE
],
357 worst_latencies
[OP_SAVEFILE
],
358 latencies
[OP_LOADFILE
],
359 worst_latencies
[OP_LOADFILE
]);
361 event_add_timed(ev
, state
, timeval_current_ofs(1, 0), report_rate
, state
);
363 for (i
=0;i
<OP_ENDOFLIST
;i
++) {
364 if (latencies
[i
] > worst_latencies
[i
]) {
365 worst_latencies
[i
] = latencies
[i
];
370 /* send an echo on each interface to ensure it stays alive - this helps
372 for (i
=0;i
<numstates
;i
++) {
374 struct smbcli_request
*req
;
376 if (!state
[i
].tree
) {
380 p
.in
.repeat_count
= 1;
383 req
= smb_raw_echo_send(state
[i
].tree
->session
->transport
, &p
);
384 req
->async
.private = &state
[i
];
385 req
->async
.fn
= echo_completion
;
390 test offline file handling
392 bool torture_test_offline(struct torture_context
*torture
)
395 TALLOC_CTX
*mem_ctx
= talloc_new(torture
);
397 int timelimit
= torture_setting_int(torture
, "timelimit", 10);
399 struct offline_state
*state
;
400 struct smbcli_state
*cli
;
402 progress
= torture_setting_bool(torture
, "progress", true);
404 nconnections
= torture_setting_int(torture
, "nprocs", 4);
405 numstates
= nconnections
* torture_entries
;
407 state
= talloc_zero_array(mem_ctx
, struct offline_state
, numstates
);
409 printf("Opening %d connections with %d simultaneous operations and %u files\n", nconnections
, numstates
, torture_numops
);
410 for (i
=0;i
<nconnections
;i
++) {
411 state
[i
].tctx
= torture
;
412 state
[i
].mem_ctx
= talloc_new(state
);
413 state
[i
].ev
= torture
->ev
;
414 if (!torture_open_connection_ev(&cli
, i
, torture
, torture
->ev
)) {
417 state
[i
].tree
= cli
->tree
;
419 /* allow more time for offline files */
420 state
[i
].tree
->session
->transport
->options
.request_timeout
= 200;
423 /* the others are repeats on the earlier connections */
424 for (i
=nconnections
;i
<numstates
;i
++) {
425 state
[i
].tctx
= torture
;
426 state
[i
].mem_ctx
= talloc_new(state
);
427 state
[i
].ev
= torture
->ev
;
428 state
[i
].tree
= state
[i
% nconnections
].tree
;
434 if (!torture_setup_dir(cli
, BASEDIR
)) {
438 /* pre-create files */
439 printf("Pre-creating %u files ....\n", torture_numops
);
440 for (i
=0;i
<torture_numops
;i
++) {
442 char *fname
= filename(mem_ctx
, i
);
446 memset(buf
, 1+(i
% 255), sizeof(buf
));
448 fnum
= smbcli_open(state
[0].tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
450 printf("Failed to open %s on connection %d\n", fname
, i
);
454 if (smbcli_write(state
[0].tree
, fnum
, 0, buf
, 0, sizeof(buf
)) != sizeof(buf
)) {
455 printf("Failed to write file of size %u\n", FILE_SIZE
);
459 status
= smbcli_close(state
[0].tree
, fnum
);
460 if (!NT_STATUS_IS_OK(status
)) {
461 printf("Close failed - %s\n", nt_errstr(status
));
468 /* start the async ops */
469 for (i
=0;i
<numstates
;i
++) {
470 state
[i
].tv_start
= timeval_current();
471 test_offline(&state
[i
]);
474 tv
= timeval_current();
477 event_add_timed(torture
->ev
, state
, timeval_current_ofs(1, 0), report_rate
, state
);
480 printf("Running for %d seconds\n", timelimit
);
481 while (timeval_elapsed(&tv
) < timelimit
) {
482 event_loop_once(torture
->ev
);
485 DEBUG(0,("test failed\n"));
490 printf("\nWaiting for completion\n");
491 test_finished
= true;
492 for (i
=0;i
<numstates
;i
++) {
493 while (state
[i
].loadfile
||
496 event_loop_once(torture
->ev
);
500 printf("worst latencies: set_lat=%.1f get_lat=%.1f save_lat=%.1f load_lat=%.1f\n",
501 worst_latencies
[OP_SETOFFLINE
],
502 worst_latencies
[OP_GETOFFLINE
],
503 worst_latencies
[OP_SAVEFILE
],
504 worst_latencies
[OP_LOADFILE
]);
506 smbcli_deltree(state
[0].tree
, BASEDIR
);
507 talloc_free(mem_ctx
);
512 talloc_free(mem_ctx
);