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"
37 #define BASEDIR "\\testoffline"
39 static int nconnections
;
41 static int num_connected
;
42 static int test_failed
;
43 extern int torture_numops
;
44 extern int torture_entries
;
45 static bool test_finished
;
47 enum offline_op
{OP_LOADFILE
, OP_SAVEFILE
, OP_SETOFFLINE
, OP_GETOFFLINE
, OP_ENDOFLIST
};
49 static double latencies
[OP_ENDOFLIST
];
50 static double worst_latencies
[OP_ENDOFLIST
];
52 #define FILE_SIZE 8192
55 struct offline_state
{
56 struct torture_context
*tctx
;
57 struct tevent_context
*ev
;
58 struct smbcli_tree
*tree
;
65 uint32_t offline_count
;
66 uint32_t online_count
;
68 struct smb_composite_loadfile
*loadfile
;
69 struct smb_composite_savefile
*savefile
;
70 struct smbcli_request
*req
;
72 struct timeval tv_start
;
75 static void test_offline(struct offline_state
*state
);
78 static char *filename(TALLOC_CTX
*ctx
, int i
)
80 char *s
= talloc_asprintf(ctx
, BASEDIR
"\\file%u.dat", i
);
86 called when a loadfile completes
88 static void loadfile_callback(struct composite_context
*ctx
)
90 struct offline_state
*state
= ctx
->async
.private_data
;
94 status
= smb_composite_loadfile_recv(ctx
, state
->mem_ctx
);
95 if (!NT_STATUS_IS_OK(status
)) {
96 printf("Failed to read file '%s' - %s\n",
97 state
->loadfile
->in
.fname
, nt_errstr(status
));
101 /* check the data is correct */
102 if (state
->loadfile
->out
.size
!= FILE_SIZE
) {
103 printf("Wrong file size %u - expected %u\n",
104 state
->loadfile
->out
.size
, FILE_SIZE
);
109 for (i
=0;i
<FILE_SIZE
;i
++) {
110 if (state
->loadfile
->out
.data
[i
] != 1+(state
->fnumber
% 255)) {
111 printf("Bad data in file %u (got %u expected %u)\n",
113 state
->loadfile
->out
.data
[i
],
114 1+(state
->fnumber
% 255));
120 talloc_steal(state
->loadfile
, state
->loadfile
->out
.data
);
123 talloc_free(state
->loadfile
);
124 state
->loadfile
= NULL
;
126 if (!test_finished
) {
133 called when a savefile completes
135 static void savefile_callback(struct composite_context
*ctx
)
137 struct offline_state
*state
= ctx
->async
.private_data
;
140 status
= smb_composite_savefile_recv(ctx
);
141 if (!NT_STATUS_IS_OK(status
)) {
142 printf("Failed to save file '%s' - %s\n",
143 state
->savefile
->in
.fname
, nt_errstr(status
));
148 talloc_free(state
->savefile
);
149 state
->savefile
= NULL
;
151 if (!test_finished
) {
158 called when a setoffline completes
160 static void setoffline_callback(struct smbcli_request
*req
)
162 struct offline_state
*state
= req
->async
.private_data
;
165 status
= smbcli_request_simple_recv(req
);
166 if (!NT_STATUS_IS_OK(status
)) {
167 printf("Failed to set offline file '%s' - %s\n",
168 state
->fname
, nt_errstr(status
));
175 if (!test_finished
) {
182 called when a getoffline completes
184 static void getoffline_callback(struct smbcli_request
*req
)
186 struct offline_state
*state
= req
->async
.private_data
;
188 union smb_fileinfo io
;
190 io
.getattr
.level
= RAW_FILEINFO_GETATTR
;
192 status
= smb_raw_pathinfo_recv(req
, state
->mem_ctx
, &io
);
193 if (!NT_STATUS_IS_OK(status
)) {
194 printf("Failed to get offline file '%s' - %s\n",
195 state
->fname
, nt_errstr(status
));
199 if (io
.getattr
.out
.attrib
& FILE_ATTRIBUTE_OFFLINE
) {
200 state
->offline_count
++;
202 state
->online_count
++;
208 if (!test_finished
) {
215 send the next offline file fetch request
217 static void test_offline(struct offline_state
*state
)
219 struct composite_context
*ctx
;
222 lat
= timeval_elapsed(&state
->tv_start
);
223 if (latencies
[state
->op
] < lat
) {
224 latencies
[state
->op
] = lat
;
227 state
->op
= (enum offline_op
) (random() % OP_ENDOFLIST
);
229 state
->fnumber
= random() % torture_numops
;
230 talloc_free(state
->fname
);
231 state
->fname
= filename(state
->mem_ctx
, state
->fnumber
);
233 state
->tv_start
= timeval_current();
237 state
->loadfile
= talloc_zero(state
->mem_ctx
, struct smb_composite_loadfile
);
238 state
->loadfile
->in
.fname
= state
->fname
;
240 ctx
= smb_composite_loadfile_send(state
->tree
, state
->loadfile
);
242 printf("Failed to setup loadfile for %s\n", state
->fname
);
246 talloc_steal(state
->loadfile
, ctx
);
248 ctx
->async
.fn
= loadfile_callback
;
249 ctx
->async
.private_data
= state
;
253 state
->savefile
= talloc_zero(state
->mem_ctx
, struct smb_composite_savefile
);
255 state
->savefile
->in
.fname
= state
->fname
;
256 state
->savefile
->in
.data
= talloc_size(state
->savefile
, FILE_SIZE
);
257 state
->savefile
->in
.size
= FILE_SIZE
;
258 memset(state
->savefile
->in
.data
, 1+(state
->fnumber
%255), FILE_SIZE
);
260 ctx
= smb_composite_savefile_send(state
->tree
, state
->savefile
);
262 printf("Failed to setup savefile for %s\n", state
->fname
);
266 talloc_steal(state
->savefile
, ctx
);
268 ctx
->async
.fn
= savefile_callback
;
269 ctx
->async
.private_data
= state
;
272 case OP_SETOFFLINE
: {
273 union smb_setfileinfo io
;
275 io
.setattr
.level
= RAW_SFILEINFO_SETATTR
;
276 io
.setattr
.in
.attrib
= FILE_ATTRIBUTE_OFFLINE
;
277 io
.setattr
.in
.file
.path
= state
->fname
;
278 /* make the file 1 hour old, to get past mininum age restrictions
280 io
.setattr
.in
.write_time
= time(NULL
) - 60*60;
282 state
->req
= smb_raw_setpathinfo_send(state
->tree
, &io
);
283 if (state
->req
== NULL
) {
284 printf("Failed to setup setoffline for %s\n", state
->fname
);
288 state
->req
->async
.fn
= setoffline_callback
;
289 state
->req
->async
.private_data
= state
;
293 case OP_GETOFFLINE
: {
294 union smb_fileinfo io
;
296 io
.getattr
.level
= RAW_FILEINFO_GETATTR
;
297 io
.getattr
.in
.file
.path
= state
->fname
;
299 state
->req
= smb_raw_pathinfo_send(state
->tree
, &io
);
300 if (state
->req
== NULL
) {
301 printf("Failed to setup getoffline for %s\n", state
->fname
);
305 state
->req
->async
.fn
= getoffline_callback
;
306 state
->req
->async
.private_data
= state
;
311 printf("bad operation??\n");
319 static void echo_completion(struct smbcli_request
*req
)
321 struct offline_state
*state
= (struct offline_state
*)req
->async
.private_data
;
322 NTSTATUS status
= smbcli_request_simple_recv(req
);
323 if (NT_STATUS_EQUAL(status
, NT_STATUS_END_OF_FILE
) ||
324 NT_STATUS_EQUAL(status
, NT_STATUS_LOCAL_DISCONNECT
)) {
325 talloc_free(state
->tree
);
328 DEBUG(0,("lost connection\n"));
333 static void report_rate(struct tevent_context
*ev
, struct tevent_timer
*te
,
334 struct timeval t
, void *private_data
)
336 struct offline_state
*state
= talloc_get_type(private_data
,
337 struct offline_state
);
339 uint32_t total
=0, total_offline
=0, total_online
=0;
340 for (i
=0;i
<numstates
;i
++) {
341 total
+= state
[i
].count
- state
[i
].lastcount
;
342 if (timeval_elapsed(&state
[i
].tv_start
) > latencies
[state
[i
].op
]) {
343 latencies
[state
[i
].op
] = timeval_elapsed(&state
[i
].tv_start
);
345 state
[i
].lastcount
= state
[i
].count
;
346 total_online
+= state
[i
].online_count
;
347 total_offline
+= state
[i
].offline_count
;
349 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",
350 total
, total_offline
, total_online
,
351 latencies
[OP_SETOFFLINE
],
352 worst_latencies
[OP_SETOFFLINE
],
353 latencies
[OP_GETOFFLINE
],
354 worst_latencies
[OP_GETOFFLINE
],
355 latencies
[OP_SAVEFILE
],
356 worst_latencies
[OP_SAVEFILE
],
357 latencies
[OP_LOADFILE
],
358 worst_latencies
[OP_LOADFILE
]);
360 event_add_timed(ev
, state
, timeval_current_ofs(1, 0), report_rate
, state
);
362 for (i
=0;i
<OP_ENDOFLIST
;i
++) {
363 if (latencies
[i
] > worst_latencies
[i
]) {
364 worst_latencies
[i
] = latencies
[i
];
369 /* send an echo on each interface to ensure it stays alive - this helps
371 for (i
=0;i
<numstates
;i
++) {
373 struct smbcli_request
*req
;
375 if (!state
[i
].tree
) {
379 p
.in
.repeat_count
= 1;
382 req
= smb_raw_echo_send(state
[i
].tree
->session
->transport
, &p
);
383 req
->async
.private_data
= &state
[i
];
384 req
->async
.fn
= echo_completion
;
389 test offline file handling
391 bool torture_test_offline(struct torture_context
*torture
)
394 TALLOC_CTX
*mem_ctx
= talloc_new(torture
);
396 int timelimit
= torture_setting_int(torture
, "timelimit", 10);
398 struct offline_state
*state
;
399 struct smbcli_state
*cli
;
401 progress
= torture_setting_bool(torture
, "progress", true);
403 nconnections
= torture_setting_int(torture
, "nprocs", 4);
404 numstates
= nconnections
* torture_entries
;
406 state
= talloc_zero_array(mem_ctx
, struct offline_state
, numstates
);
408 printf("Opening %d connections with %d simultaneous operations and %u files\n", nconnections
, numstates
, torture_numops
);
409 for (i
=0;i
<nconnections
;i
++) {
410 state
[i
].tctx
= torture
;
411 state
[i
].mem_ctx
= talloc_new(state
);
412 state
[i
].ev
= torture
->ev
;
413 if (!torture_open_connection_ev(&cli
, i
, torture
, torture
->ev
)) {
416 state
[i
].tree
= cli
->tree
;
418 /* allow more time for offline files */
419 state
[i
].tree
->session
->transport
->options
.request_timeout
= 200;
422 /* the others are repeats on the earlier connections */
423 for (i
=nconnections
;i
<numstates
;i
++) {
424 state
[i
].tctx
= torture
;
425 state
[i
].mem_ctx
= talloc_new(state
);
426 state
[i
].ev
= torture
->ev
;
427 state
[i
].tree
= state
[i
% nconnections
].tree
;
433 if (!torture_setup_dir(cli
, BASEDIR
)) {
437 /* pre-create files */
438 printf("Pre-creating %u files ....\n", torture_numops
);
439 for (i
=0;i
<torture_numops
;i
++) {
441 char *fname
= filename(mem_ctx
, i
);
445 memset(buf
, 1+(i
% 255), sizeof(buf
));
447 fnum
= smbcli_open(state
[0].tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
449 printf("Failed to open %s on connection %d\n", fname
, i
);
453 if (smbcli_write(state
[0].tree
, fnum
, 0, buf
, 0, sizeof(buf
)) != sizeof(buf
)) {
454 printf("Failed to write file of size %u\n", FILE_SIZE
);
458 status
= smbcli_close(state
[0].tree
, fnum
);
459 if (!NT_STATUS_IS_OK(status
)) {
460 printf("Close failed - %s\n", nt_errstr(status
));
467 /* start the async ops */
468 for (i
=0;i
<numstates
;i
++) {
469 state
[i
].tv_start
= timeval_current();
470 test_offline(&state
[i
]);
473 tv
= timeval_current();
476 event_add_timed(torture
->ev
, state
, timeval_current_ofs(1, 0), report_rate
, state
);
479 printf("Running for %d seconds\n", timelimit
);
480 while (timeval_elapsed(&tv
) < timelimit
) {
481 event_loop_once(torture
->ev
);
484 DEBUG(0,("test failed\n"));
489 printf("\nWaiting for completion\n");
490 test_finished
= true;
491 for (i
=0;i
<numstates
;i
++) {
492 while (state
[i
].loadfile
||
495 event_loop_once(torture
->ev
);
499 printf("worst latencies: set_lat=%.1f get_lat=%.1f save_lat=%.1f load_lat=%.1f\n",
500 worst_latencies
[OP_SETOFFLINE
],
501 worst_latencies
[OP_GETOFFLINE
],
502 worst_latencies
[OP_SAVEFILE
],
503 worst_latencies
[OP_LOADFILE
]);
505 smbcli_deltree(state
[0].tree
, BASEDIR
);
506 talloc_free(mem_ctx
);
511 talloc_free(mem_ctx
);