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 "system/time.h"
26 #include "system/filesys.h"
27 #include "libcli/libcli.h"
28 #include "torture/util.h"
29 #include "lib/events/events.h"
30 #include "libcli/composite/composite.h"
31 #include "libcli/smb_composite/smb_composite.h"
32 #include "torture/raw/proto.h"
34 #define BASEDIR "\\testoffline"
36 static int nconnections
;
38 static int num_connected
;
39 static int test_failed
;
40 extern int torture_numops
;
41 extern int torture_entries
;
42 static bool test_finished
;
44 enum offline_op
{OP_LOADFILE
, OP_SAVEFILE
, OP_SETOFFLINE
, OP_GETOFFLINE
, OP_ENDOFLIST
};
46 static double latencies
[OP_ENDOFLIST
];
47 static double worst_latencies
[OP_ENDOFLIST
];
49 #define FILE_SIZE 8192
52 struct offline_state
{
53 struct torture_context
*tctx
;
54 struct tevent_context
*ev
;
55 struct smbcli_tree
*tree
;
62 uint32_t offline_count
;
63 uint32_t online_count
;
65 struct smb_composite_loadfile
*loadfile
;
66 struct smb_composite_savefile
*savefile
;
67 struct smbcli_request
*req
;
69 struct timeval tv_start
;
72 static void test_offline(struct offline_state
*state
);
75 static char *filename(TALLOC_CTX
*ctx
, int i
)
77 char *s
= talloc_asprintf(ctx
, BASEDIR
"\\file%u.dat", i
);
83 called when a loadfile completes
85 static void loadfile_callback(struct composite_context
*ctx
)
87 struct offline_state
*state
= ctx
->async
.private_data
;
91 status
= smb_composite_loadfile_recv(ctx
, state
->mem_ctx
);
92 if (!NT_STATUS_IS_OK(status
)) {
93 printf("Failed to read file '%s' - %s\n",
94 state
->loadfile
->in
.fname
, nt_errstr(status
));
99 /* check the data is correct */
100 if (state
->loadfile
->out
.size
!= FILE_SIZE
) {
101 printf("Wrong file size %u - expected %u\n",
102 state
->loadfile
->out
.size
, FILE_SIZE
);
107 for (i
=0;i
<FILE_SIZE
;i
++) {
108 if (state
->loadfile
->out
.data
[i
] != 1+(state
->fnumber
% 255)) {
109 printf("Bad data in file %u (got %u expected %u)\n",
111 state
->loadfile
->out
.data
[i
],
112 1+(state
->fnumber
% 255));
118 talloc_steal(state
->loadfile
, state
->loadfile
->out
.data
);
121 talloc_free(state
->loadfile
);
122 state
->loadfile
= NULL
;
124 if (!test_finished
) {
131 called when a savefile completes
133 static void savefile_callback(struct composite_context
*ctx
)
135 struct offline_state
*state
= ctx
->async
.private_data
;
138 status
= smb_composite_savefile_recv(ctx
);
139 if (!NT_STATUS_IS_OK(status
)) {
140 printf("Failed to save file '%s' - %s\n",
141 state
->savefile
->in
.fname
, nt_errstr(status
));
146 talloc_free(state
->savefile
);
147 state
->savefile
= NULL
;
149 if (!test_finished
) {
156 called when a setoffline completes
158 static void setoffline_callback(struct smbcli_request
*req
)
160 struct offline_state
*state
= req
->async
.private_data
;
163 status
= smbcli_request_simple_recv(req
);
164 if (!NT_STATUS_IS_OK(status
)) {
165 printf("Failed to set offline file '%s' - %s\n",
166 state
->fname
, nt_errstr(status
));
173 if (!test_finished
) {
180 called when a getoffline completes
182 static void getoffline_callback(struct smbcli_request
*req
)
184 struct offline_state
*state
= req
->async
.private_data
;
186 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 minimum 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 NT_STATUS_EQUAL(status
, NT_STATUS_CONNECTION_RESET
)) {
326 talloc_free(state
->tree
);
329 DEBUG(0,("lost connection\n"));
334 static void report_rate(struct tevent_context
*ev
, struct tevent_timer
*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 tevent_add_timer(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_data
= &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 tevent_add_timer(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 tevent_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 tevent_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
);