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"
33 #define BASEDIR "\\testoffline"
35 static int nconnections
;
37 static int num_connected
;
38 static int test_failed
;
39 extern int torture_numops
;
40 extern int torture_entries
;
41 static bool test_finished
;
43 enum offline_op
{OP_LOADFILE
, OP_SAVEFILE
, OP_SETOFFLINE
, OP_GETOFFLINE
, OP_ENDOFLIST
};
45 static double latencies
[OP_ENDOFLIST
];
46 static double worst_latencies
[OP_ENDOFLIST
];
48 #define FILE_SIZE 8192
51 struct offline_state
{
52 struct torture_context
*tctx
;
53 struct tevent_context
*ev
;
54 struct smbcli_tree
*tree
;
61 uint32_t offline_count
;
62 uint32_t online_count
;
64 struct smb_composite_loadfile
*loadfile
;
65 struct smb_composite_savefile
*savefile
;
66 struct smbcli_request
*req
;
68 struct timeval tv_start
;
71 static void test_offline(struct offline_state
*state
);
74 static char *filename(TALLOC_CTX
*ctx
, int i
)
76 char *s
= talloc_asprintf(ctx
, BASEDIR
"\\file%u.dat", i
);
82 called when a loadfile completes
84 static void loadfile_callback(struct composite_context
*ctx
)
86 struct offline_state
*state
= ctx
->async
.private_data
;
90 status
= smb_composite_loadfile_recv(ctx
, state
->mem_ctx
);
91 if (!NT_STATUS_IS_OK(status
)) {
92 printf("Failed to read file '%s' - %s\n",
93 state
->loadfile
->in
.fname
, nt_errstr(status
));
97 /* check the data is correct */
98 if (state
->loadfile
->out
.size
!= FILE_SIZE
) {
99 printf("Wrong file size %u - expected %u\n",
100 state
->loadfile
->out
.size
, FILE_SIZE
);
105 for (i
=0;i
<FILE_SIZE
;i
++) {
106 if (state
->loadfile
->out
.data
[i
] != 1+(state
->fnumber
% 255)) {
107 printf("Bad data in file %u (got %u expected %u)\n",
109 state
->loadfile
->out
.data
[i
],
110 1+(state
->fnumber
% 255));
116 talloc_steal(state
->loadfile
, state
->loadfile
->out
.data
);
119 talloc_free(state
->loadfile
);
120 state
->loadfile
= NULL
;
122 if (!test_finished
) {
129 called when a savefile completes
131 static void savefile_callback(struct composite_context
*ctx
)
133 struct offline_state
*state
= ctx
->async
.private_data
;
136 status
= smb_composite_savefile_recv(ctx
);
137 if (!NT_STATUS_IS_OK(status
)) {
138 printf("Failed to save file '%s' - %s\n",
139 state
->savefile
->in
.fname
, nt_errstr(status
));
144 talloc_free(state
->savefile
);
145 state
->savefile
= NULL
;
147 if (!test_finished
) {
154 called when a setoffline completes
156 static void setoffline_callback(struct smbcli_request
*req
)
158 struct offline_state
*state
= req
->async
.private_data
;
161 status
= smbcli_request_simple_recv(req
);
162 if (!NT_STATUS_IS_OK(status
)) {
163 printf("Failed to set offline file '%s' - %s\n",
164 state
->fname
, nt_errstr(status
));
171 if (!test_finished
) {
178 called when a getoffline completes
180 static void getoffline_callback(struct smbcli_request
*req
)
182 struct offline_state
*state
= req
->async
.private_data
;
184 union smb_fileinfo io
;
186 io
.getattr
.level
= RAW_FILEINFO_GETATTR
;
188 status
= smb_raw_pathinfo_recv(req
, state
->mem_ctx
, &io
);
189 if (!NT_STATUS_IS_OK(status
)) {
190 printf("Failed to get offline file '%s' - %s\n",
191 state
->fname
, nt_errstr(status
));
195 if (io
.getattr
.out
.attrib
& FILE_ATTRIBUTE_OFFLINE
) {
196 state
->offline_count
++;
198 state
->online_count
++;
204 if (!test_finished
) {
211 send the next offline file fetch request
213 static void test_offline(struct offline_state
*state
)
215 struct composite_context
*ctx
;
218 lat
= timeval_elapsed(&state
->tv_start
);
219 if (latencies
[state
->op
] < lat
) {
220 latencies
[state
->op
] = lat
;
223 state
->op
= (enum offline_op
) (random() % OP_ENDOFLIST
);
225 state
->fnumber
= random() % torture_numops
;
226 talloc_free(state
->fname
);
227 state
->fname
= filename(state
->mem_ctx
, state
->fnumber
);
229 state
->tv_start
= timeval_current();
233 state
->loadfile
= talloc_zero(state
->mem_ctx
, struct smb_composite_loadfile
);
234 state
->loadfile
->in
.fname
= state
->fname
;
236 ctx
= smb_composite_loadfile_send(state
->tree
, state
->loadfile
);
238 printf("Failed to setup loadfile for %s\n", state
->fname
);
242 talloc_steal(state
->loadfile
, ctx
);
244 ctx
->async
.fn
= loadfile_callback
;
245 ctx
->async
.private_data
= state
;
249 state
->savefile
= talloc_zero(state
->mem_ctx
, struct smb_composite_savefile
);
251 state
->savefile
->in
.fname
= state
->fname
;
252 state
->savefile
->in
.data
= talloc_size(state
->savefile
, FILE_SIZE
);
253 state
->savefile
->in
.size
= FILE_SIZE
;
254 memset(state
->savefile
->in
.data
, 1+(state
->fnumber
%255), FILE_SIZE
);
256 ctx
= smb_composite_savefile_send(state
->tree
, state
->savefile
);
258 printf("Failed to setup savefile for %s\n", state
->fname
);
262 talloc_steal(state
->savefile
, ctx
);
264 ctx
->async
.fn
= savefile_callback
;
265 ctx
->async
.private_data
= state
;
268 case OP_SETOFFLINE
: {
269 union smb_setfileinfo io
;
271 io
.setattr
.level
= RAW_SFILEINFO_SETATTR
;
272 io
.setattr
.in
.attrib
= FILE_ATTRIBUTE_OFFLINE
;
273 io
.setattr
.in
.file
.path
= state
->fname
;
274 /* make the file 1 hour old, to get past mininum age restrictions
276 io
.setattr
.in
.write_time
= time(NULL
) - 60*60;
278 state
->req
= smb_raw_setpathinfo_send(state
->tree
, &io
);
279 if (state
->req
== NULL
) {
280 printf("Failed to setup setoffline for %s\n", state
->fname
);
284 state
->req
->async
.fn
= setoffline_callback
;
285 state
->req
->async
.private_data
= state
;
289 case OP_GETOFFLINE
: {
290 union smb_fileinfo io
;
292 io
.getattr
.level
= RAW_FILEINFO_GETATTR
;
293 io
.getattr
.in
.file
.path
= state
->fname
;
295 state
->req
= smb_raw_pathinfo_send(state
->tree
, &io
);
296 if (state
->req
== NULL
) {
297 printf("Failed to setup getoffline for %s\n", state
->fname
);
301 state
->req
->async
.fn
= getoffline_callback
;
302 state
->req
->async
.private_data
= state
;
307 printf("bad operation??\n");
315 static void echo_completion(struct smbcli_request
*req
)
317 struct offline_state
*state
= (struct offline_state
*)req
->async
.private_data
;
318 NTSTATUS status
= smbcli_request_simple_recv(req
);
319 if (NT_STATUS_EQUAL(status
, NT_STATUS_END_OF_FILE
) ||
320 NT_STATUS_EQUAL(status
, NT_STATUS_LOCAL_DISCONNECT
) ||
321 NT_STATUS_EQUAL(status
, NT_STATUS_CONNECTION_RESET
)) {
322 talloc_free(state
->tree
);
325 DEBUG(0,("lost connection\n"));
330 static void report_rate(struct tevent_context
*ev
, struct tevent_timer
*te
,
331 struct timeval t
, void *private_data
)
333 struct offline_state
*state
= talloc_get_type(private_data
,
334 struct offline_state
);
336 uint32_t total
=0, total_offline
=0, total_online
=0;
337 for (i
=0;i
<numstates
;i
++) {
338 total
+= state
[i
].count
- state
[i
].lastcount
;
339 if (timeval_elapsed(&state
[i
].tv_start
) > latencies
[state
[i
].op
]) {
340 latencies
[state
[i
].op
] = timeval_elapsed(&state
[i
].tv_start
);
342 state
[i
].lastcount
= state
[i
].count
;
343 total_online
+= state
[i
].online_count
;
344 total_offline
+= state
[i
].offline_count
;
346 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",
347 total
, total_offline
, total_online
,
348 latencies
[OP_SETOFFLINE
],
349 worst_latencies
[OP_SETOFFLINE
],
350 latencies
[OP_GETOFFLINE
],
351 worst_latencies
[OP_GETOFFLINE
],
352 latencies
[OP_SAVEFILE
],
353 worst_latencies
[OP_SAVEFILE
],
354 latencies
[OP_LOADFILE
],
355 worst_latencies
[OP_LOADFILE
]);
357 event_add_timed(ev
, state
, timeval_current_ofs(1, 0), report_rate
, state
);
359 for (i
=0;i
<OP_ENDOFLIST
;i
++) {
360 if (latencies
[i
] > worst_latencies
[i
]) {
361 worst_latencies
[i
] = latencies
[i
];
366 /* send an echo on each interface to ensure it stays alive - this helps
368 for (i
=0;i
<numstates
;i
++) {
370 struct smbcli_request
*req
;
372 if (!state
[i
].tree
) {
376 p
.in
.repeat_count
= 1;
379 req
= smb_raw_echo_send(state
[i
].tree
->session
->transport
, &p
);
380 req
->async
.private_data
= &state
[i
];
381 req
->async
.fn
= echo_completion
;
386 test offline file handling
388 bool torture_test_offline(struct torture_context
*torture
)
391 TALLOC_CTX
*mem_ctx
= talloc_new(torture
);
393 int timelimit
= torture_setting_int(torture
, "timelimit", 10);
395 struct offline_state
*state
;
396 struct smbcli_state
*cli
;
398 progress
= torture_setting_bool(torture
, "progress", true);
400 nconnections
= torture_setting_int(torture
, "nprocs", 4);
401 numstates
= nconnections
* torture_entries
;
403 state
= talloc_zero_array(mem_ctx
, struct offline_state
, numstates
);
405 printf("Opening %d connections with %d simultaneous operations and %u files\n", nconnections
, numstates
, torture_numops
);
406 for (i
=0;i
<nconnections
;i
++) {
407 state
[i
].tctx
= torture
;
408 state
[i
].mem_ctx
= talloc_new(state
);
409 state
[i
].ev
= torture
->ev
;
410 if (!torture_open_connection_ev(&cli
, i
, torture
, torture
->ev
)) {
413 state
[i
].tree
= cli
->tree
;
415 /* allow more time for offline files */
416 state
[i
].tree
->session
->transport
->options
.request_timeout
= 200;
419 /* the others are repeats on the earlier connections */
420 for (i
=nconnections
;i
<numstates
;i
++) {
421 state
[i
].tctx
= torture
;
422 state
[i
].mem_ctx
= talloc_new(state
);
423 state
[i
].ev
= torture
->ev
;
424 state
[i
].tree
= state
[i
% nconnections
].tree
;
430 if (!torture_setup_dir(cli
, BASEDIR
)) {
434 /* pre-create files */
435 printf("Pre-creating %u files ....\n", torture_numops
);
436 for (i
=0;i
<torture_numops
;i
++) {
438 char *fname
= filename(mem_ctx
, i
);
442 memset(buf
, 1+(i
% 255), sizeof(buf
));
444 fnum
= smbcli_open(state
[0].tree
, fname
, O_RDWR
|O_CREAT
, DENY_NONE
);
446 printf("Failed to open %s on connection %d\n", fname
, i
);
450 if (smbcli_write(state
[0].tree
, fnum
, 0, buf
, 0, sizeof(buf
)) != sizeof(buf
)) {
451 printf("Failed to write file of size %u\n", FILE_SIZE
);
455 status
= smbcli_close(state
[0].tree
, fnum
);
456 if (!NT_STATUS_IS_OK(status
)) {
457 printf("Close failed - %s\n", nt_errstr(status
));
464 /* start the async ops */
465 for (i
=0;i
<numstates
;i
++) {
466 state
[i
].tv_start
= timeval_current();
467 test_offline(&state
[i
]);
470 tv
= timeval_current();
473 event_add_timed(torture
->ev
, state
, timeval_current_ofs(1, 0), report_rate
, state
);
476 printf("Running for %d seconds\n", timelimit
);
477 while (timeval_elapsed(&tv
) < timelimit
) {
478 event_loop_once(torture
->ev
);
481 DEBUG(0,("test failed\n"));
486 printf("\nWaiting for completion\n");
487 test_finished
= true;
488 for (i
=0;i
<numstates
;i
++) {
489 while (state
[i
].loadfile
||
492 event_loop_once(torture
->ev
);
496 printf("worst latencies: set_lat=%.1f get_lat=%.1f save_lat=%.1f load_lat=%.1f\n",
497 worst_latencies
[OP_SETOFFLINE
],
498 worst_latencies
[OP_GETOFFLINE
],
499 worst_latencies
[OP_SAVEFILE
],
500 worst_latencies
[OP_LOADFILE
]);
502 smbcli_deltree(state
[0].tree
, BASEDIR
);
503 talloc_free(mem_ctx
);
508 talloc_free(mem_ctx
);