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
));
98 /* check the data is correct */
99 if (state
->loadfile
->out
.size
!= FILE_SIZE
) {
100 printf("Wrong file size %u - expected %u\n",
101 state
->loadfile
->out
.size
, FILE_SIZE
);
106 for (i
=0;i
<FILE_SIZE
;i
++) {
107 if (state
->loadfile
->out
.data
[i
] != 1+(state
->fnumber
% 255)) {
108 printf("Bad data in file %u (got %u expected %u)\n",
110 state
->loadfile
->out
.data
[i
],
111 1+(state
->fnumber
% 255));
117 talloc_steal(state
->loadfile
, state
->loadfile
->out
.data
);
120 talloc_free(state
->loadfile
);
121 state
->loadfile
= NULL
;
123 if (!test_finished
) {
130 called when a savefile completes
132 static void savefile_callback(struct composite_context
*ctx
)
134 struct offline_state
*state
= ctx
->async
.private_data
;
137 status
= smb_composite_savefile_recv(ctx
);
138 if (!NT_STATUS_IS_OK(status
)) {
139 printf("Failed to save file '%s' - %s\n",
140 state
->savefile
->in
.fname
, nt_errstr(status
));
145 talloc_free(state
->savefile
);
146 state
->savefile
= NULL
;
148 if (!test_finished
) {
155 called when a setoffline completes
157 static void setoffline_callback(struct smbcli_request
*req
)
159 struct offline_state
*state
= req
->async
.private_data
;
162 status
= smbcli_request_simple_recv(req
);
163 if (!NT_STATUS_IS_OK(status
)) {
164 printf("Failed to set offline file '%s' - %s\n",
165 state
->fname
, nt_errstr(status
));
172 if (!test_finished
) {
179 called when a getoffline completes
181 static void getoffline_callback(struct smbcli_request
*req
)
183 struct offline_state
*state
= req
->async
.private_data
;
185 union smb_fileinfo io
;
187 io
.getattr
.level
= RAW_FILEINFO_GETATTR
;
189 status
= smb_raw_pathinfo_recv(req
, state
->mem_ctx
, &io
);
190 if (!NT_STATUS_IS_OK(status
)) {
191 printf("Failed to get offline file '%s' - %s\n",
192 state
->fname
, nt_errstr(status
));
196 if (io
.getattr
.out
.attrib
& FILE_ATTRIBUTE_OFFLINE
) {
197 state
->offline_count
++;
199 state
->online_count
++;
205 if (!test_finished
) {
212 send the next offline file fetch request
214 static void test_offline(struct offline_state
*state
)
216 struct composite_context
*ctx
;
219 lat
= timeval_elapsed(&state
->tv_start
);
220 if (latencies
[state
->op
] < lat
) {
221 latencies
[state
->op
] = lat
;
224 state
->op
= (enum offline_op
) (random() % OP_ENDOFLIST
);
226 state
->fnumber
= random() % torture_numops
;
227 talloc_free(state
->fname
);
228 state
->fname
= filename(state
->mem_ctx
, state
->fnumber
);
230 state
->tv_start
= timeval_current();
234 state
->loadfile
= talloc_zero(state
->mem_ctx
, struct smb_composite_loadfile
);
235 state
->loadfile
->in
.fname
= state
->fname
;
237 ctx
= smb_composite_loadfile_send(state
->tree
, state
->loadfile
);
239 printf("Failed to setup loadfile for %s\n", state
->fname
);
243 talloc_steal(state
->loadfile
, ctx
);
245 ctx
->async
.fn
= loadfile_callback
;
246 ctx
->async
.private_data
= state
;
250 state
->savefile
= talloc_zero(state
->mem_ctx
, struct smb_composite_savefile
);
252 state
->savefile
->in
.fname
= state
->fname
;
253 state
->savefile
->in
.data
= talloc_size(state
->savefile
, FILE_SIZE
);
254 state
->savefile
->in
.size
= FILE_SIZE
;
255 memset(state
->savefile
->in
.data
, 1+(state
->fnumber
%255), FILE_SIZE
);
257 ctx
= smb_composite_savefile_send(state
->tree
, state
->savefile
);
259 printf("Failed to setup savefile for %s\n", state
->fname
);
263 talloc_steal(state
->savefile
, ctx
);
265 ctx
->async
.fn
= savefile_callback
;
266 ctx
->async
.private_data
= state
;
269 case OP_SETOFFLINE
: {
270 union smb_setfileinfo io
;
272 io
.setattr
.level
= RAW_SFILEINFO_SETATTR
;
273 io
.setattr
.in
.attrib
= FILE_ATTRIBUTE_OFFLINE
;
274 io
.setattr
.in
.file
.path
= state
->fname
;
275 /* make the file 1 hour old, to get past mininum age restrictions
277 io
.setattr
.in
.write_time
= time(NULL
) - 60*60;
279 state
->req
= smb_raw_setpathinfo_send(state
->tree
, &io
);
280 if (state
->req
== NULL
) {
281 printf("Failed to setup setoffline for %s\n", state
->fname
);
285 state
->req
->async
.fn
= setoffline_callback
;
286 state
->req
->async
.private_data
= state
;
290 case OP_GETOFFLINE
: {
291 union smb_fileinfo io
;
293 io
.getattr
.level
= RAW_FILEINFO_GETATTR
;
294 io
.getattr
.in
.file
.path
= state
->fname
;
296 state
->req
= smb_raw_pathinfo_send(state
->tree
, &io
);
297 if (state
->req
== NULL
) {
298 printf("Failed to setup getoffline for %s\n", state
->fname
);
302 state
->req
->async
.fn
= getoffline_callback
;
303 state
->req
->async
.private_data
= state
;
308 printf("bad operation??\n");
316 static void echo_completion(struct smbcli_request
*req
)
318 struct offline_state
*state
= (struct offline_state
*)req
->async
.private_data
;
319 NTSTATUS status
= smbcli_request_simple_recv(req
);
320 if (NT_STATUS_EQUAL(status
, NT_STATUS_END_OF_FILE
) ||
321 NT_STATUS_EQUAL(status
, NT_STATUS_LOCAL_DISCONNECT
) ||
322 NT_STATUS_EQUAL(status
, NT_STATUS_CONNECTION_RESET
)) {
323 talloc_free(state
->tree
);
326 DEBUG(0,("lost connection\n"));
331 static void report_rate(struct tevent_context
*ev
, struct tevent_timer
*te
,
332 struct timeval t
, void *private_data
)
334 struct offline_state
*state
= talloc_get_type(private_data
,
335 struct offline_state
);
337 uint32_t total
=0, total_offline
=0, total_online
=0;
338 for (i
=0;i
<numstates
;i
++) {
339 total
+= state
[i
].count
- state
[i
].lastcount
;
340 if (timeval_elapsed(&state
[i
].tv_start
) > latencies
[state
[i
].op
]) {
341 latencies
[state
[i
].op
] = timeval_elapsed(&state
[i
].tv_start
);
343 state
[i
].lastcount
= state
[i
].count
;
344 total_online
+= state
[i
].online_count
;
345 total_offline
+= state
[i
].offline_count
;
347 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",
348 total
, total_offline
, total_online
,
349 latencies
[OP_SETOFFLINE
],
350 worst_latencies
[OP_SETOFFLINE
],
351 latencies
[OP_GETOFFLINE
],
352 worst_latencies
[OP_GETOFFLINE
],
353 latencies
[OP_SAVEFILE
],
354 worst_latencies
[OP_SAVEFILE
],
355 latencies
[OP_LOADFILE
],
356 worst_latencies
[OP_LOADFILE
]);
358 tevent_add_timer(ev
, state
, timeval_current_ofs(1, 0), report_rate
, state
);
360 for (i
=0;i
<OP_ENDOFLIST
;i
++) {
361 if (latencies
[i
] > worst_latencies
[i
]) {
362 worst_latencies
[i
] = latencies
[i
];
367 /* send an echo on each interface to ensure it stays alive - this helps
369 for (i
=0;i
<numstates
;i
++) {
371 struct smbcli_request
*req
;
373 if (!state
[i
].tree
) {
377 p
.in
.repeat_count
= 1;
380 req
= smb_raw_echo_send(state
[i
].tree
->session
->transport
, &p
);
381 req
->async
.private_data
= &state
[i
];
382 req
->async
.fn
= echo_completion
;
387 test offline file handling
389 bool torture_test_offline(struct torture_context
*torture
)
392 TALLOC_CTX
*mem_ctx
= talloc_new(torture
);
394 int timelimit
= torture_setting_int(torture
, "timelimit", 10);
396 struct offline_state
*state
;
397 struct smbcli_state
*cli
;
399 progress
= torture_setting_bool(torture
, "progress", true);
401 nconnections
= torture_setting_int(torture
, "nprocs", 4);
402 numstates
= nconnections
* torture_entries
;
404 state
= talloc_zero_array(mem_ctx
, struct offline_state
, numstates
);
406 printf("Opening %d connections with %d simultaneous operations and %u files\n", nconnections
, numstates
, torture_numops
);
407 for (i
=0;i
<nconnections
;i
++) {
408 state
[i
].tctx
= torture
;
409 state
[i
].mem_ctx
= talloc_new(state
);
410 state
[i
].ev
= torture
->ev
;
411 if (!torture_open_connection_ev(&cli
, i
, torture
, torture
->ev
)) {
414 state
[i
].tree
= cli
->tree
;
416 /* allow more time for offline files */
417 state
[i
].tree
->session
->transport
->options
.request_timeout
= 200;
420 /* the others are repeats on the earlier connections */
421 for (i
=nconnections
;i
<numstates
;i
++) {
422 state
[i
].tctx
= torture
;
423 state
[i
].mem_ctx
= talloc_new(state
);
424 state
[i
].ev
= torture
->ev
;
425 state
[i
].tree
= state
[i
% nconnections
].tree
;
431 if (!torture_setup_dir(cli
, BASEDIR
)) {
435 /* pre-create files */
436 printf("Pre-creating %u files ....\n", torture_numops
);
437 for (i
=0;i
<torture_numops
;i
++) {
439 char *fname
= filename(mem_ctx
, i
);
443 memset(buf
, 1+(i
% 255), sizeof(buf
));
445 fnum
= smbcli_open(state
[0].tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
447 printf("Failed to open %s on connection %d\n", fname
, i
);
451 if (smbcli_write(state
[0].tree
, fnum
, 0, buf
, 0, sizeof(buf
)) != sizeof(buf
)) {
452 printf("Failed to write file of size %u\n", FILE_SIZE
);
456 status
= smbcli_close(state
[0].tree
, fnum
);
457 if (!NT_STATUS_IS_OK(status
)) {
458 printf("Close failed - %s\n", nt_errstr(status
));
465 /* start the async ops */
466 for (i
=0;i
<numstates
;i
++) {
467 state
[i
].tv_start
= timeval_current();
468 test_offline(&state
[i
]);
471 tv
= timeval_current();
474 tevent_add_timer(torture
->ev
, state
, timeval_current_ofs(1, 0), report_rate
, state
);
477 printf("Running for %d seconds\n", timelimit
);
478 while (timeval_elapsed(&tv
) < timelimit
) {
479 tevent_loop_once(torture
->ev
);
482 DEBUG(0,("test failed\n"));
487 printf("\nWaiting for completion\n");
488 test_finished
= true;
489 for (i
=0;i
<numstates
;i
++) {
490 while (state
[i
].loadfile
||
493 tevent_loop_once(torture
->ev
);
497 printf("worst latencies: set_lat=%.1f get_lat=%.1f save_lat=%.1f load_lat=%.1f\n",
498 worst_latencies
[OP_SETOFFLINE
],
499 worst_latencies
[OP_GETOFFLINE
],
500 worst_latencies
[OP_SAVEFILE
],
501 worst_latencies
[OP_LOADFILE
]);
503 smbcli_deltree(state
[0].tree
, BASEDIR
);
504 talloc_free(mem_ctx
);
509 talloc_free(mem_ctx
);