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] != state->fnumber % 256) {
112 printf("Bad data in file %u\n", state->fnumber);
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;
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;
186 union smb_fileinfo io;
188 io.getattr.level = RAW_FILEINFO_GETATTR;
190 status = smb_raw_pathinfo_recv(req, state->mem_ctx, &io);
191 if (!NT_STATUS_IS_OK(status)) {
192 printf("Failed to get offline file '%s' - %s\n",
193 state->fname, nt_errstr(status));
197 if (io.getattr.out.attrib & FILE_ATTRIBUTE_OFFLINE) {
198 state->offline_count++;
200 state->online_count++;
206 if (!test_finished) {
213 send the next offline file fetch request
215 static void test_offline(struct offline_state *state)
217 struct composite_context *ctx;
220 lat = timeval_elapsed(&state->tv_start);
221 if (latencies[state->op] < lat) {
222 latencies[state->op] = lat;
225 state->op = (enum offline_op) (random() % OP_ENDOFLIST);
227 state->fnumber = random() % torture_numops;
228 talloc_free(state->fname);
229 state->fname = filename(state->mem_ctx, state->fnumber);
231 state->tv_start = timeval_current();
235 state->loadfile = talloc_zero(state->mem_ctx, struct smb_composite_loadfile);
236 state->loadfile->in.fname = state->fname;
238 ctx = smb_composite_loadfile_send(state->tree, state->loadfile);
240 printf("Failed to setup loadfile for %s\n", state->fname);
244 talloc_steal(state->loadfile, ctx);
246 ctx->async.fn = loadfile_callback;
247 ctx->async.private_data = state;
251 state->savefile = talloc_zero(state->mem_ctx, struct smb_composite_savefile);
253 state->savefile->in.fname = state->fname;
254 state->savefile->in.data = talloc_size(state->savefile, FILE_SIZE);
255 state->savefile->in.size = FILE_SIZE;
256 memset(state->savefile->in.data, state->fnumber, FILE_SIZE);
258 ctx = smb_composite_savefile_send(state->tree, state->savefile);
260 printf("Failed to setup savefile for %s\n", state->fname);
264 talloc_steal(state->savefile, ctx);
266 ctx->async.fn = savefile_callback;
267 ctx->async.private_data = state;
270 case OP_SETOFFLINE: {
271 union smb_setfileinfo io;
273 io.setattr.level = RAW_SFILEINFO_SETATTR;
274 io.setattr.in.attrib = FILE_ATTRIBUTE_OFFLINE;
275 io.setattr.in.file.path = state->fname;
276 /* make the file 1 hour old, to get past mininum age restrictions
278 io.setattr.in.write_time = time(NULL) - 60*60;
280 state->req = smb_raw_setpathinfo_send(state->tree, &io);
281 if (state->req == NULL) {
282 printf("Failed to setup setoffline for %s\n", state->fname);
286 state->req->async.fn = setoffline_callback;
287 state->req->async.private = state;
291 case OP_GETOFFLINE: {
292 union smb_fileinfo io;
294 io.getattr.level = RAW_FILEINFO_GETATTR;
295 io.getattr.in.file.path = state->fname;
297 state->req = smb_raw_pathinfo_send(state->tree, &io);
298 if (state->req == NULL) {
299 printf("Failed to setup getoffline for %s\n", state->fname);
303 state->req->async.fn = getoffline_callback;
304 state->req->async.private = state;
309 printf("bad operation??\n");
317 static void echo_completion(struct smbcli_request *req)
319 struct offline_state *state = (struct offline_state *)req->async.private;
320 NTSTATUS status = smbcli_request_simple_recv(req);
321 if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
322 NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT)) {
323 talloc_free(state->tree);
326 DEBUG(0,("lost connection\n"));
331 static void report_rate(struct event_context *ev, struct timed_event *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 get_lat=%.1f save_lat=%.1f load_lat=%.1f\r",
348 total, total_offline, total_online,
349 latencies[OP_SETOFFLINE],
350 latencies[OP_GETOFFLINE],
351 latencies[OP_SAVEFILE],
352 latencies[OP_LOADFILE]);
354 event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state);
356 for (i=0;i<OP_ENDOFLIST;i++) {
357 if (latencies[i] > worst_latencies[i]) {
358 worst_latencies[i] = latencies[i];
363 /* send an echo on each interface to ensure it stays alive - this helps
365 for (i=0;i<numstates;i++) {
367 struct smbcli_request *req;
369 if (!state[i].tree) {
373 p.in.repeat_count = 1;
376 req = smb_raw_echo_send(state[i].tree->session->transport, &p);
377 req->async.private = &state[i];
378 req->async.fn = echo_completion;
383 test offline file handling
385 bool torture_test_offline(struct torture_context *torture)
388 TALLOC_CTX *mem_ctx = talloc_new(torture);
390 int timelimit = torture_setting_int(torture, "timelimit", 10);
392 struct offline_state *state;
393 struct smbcli_state *cli;
395 progress = torture_setting_bool(torture, "progress", true);
397 nconnections = torture_setting_int(torture, "nprocs", 4);
398 numstates = nconnections * torture_entries;
400 state = talloc_zero_array(mem_ctx, struct offline_state, numstates);
402 printf("Opening %d connections with %d simultaneous operations and %u files\n", nconnections, numstates, torture_numops);
403 for (i=0;i<nconnections;i++) {
404 state[i].tctx = torture;
405 state[i].mem_ctx = talloc_new(state);
406 state[i].ev = torture->ev;
407 if (!torture_open_connection_ev(&cli, i, torture, torture->ev)) {
410 state[i].tree = cli->tree;
412 /* allow more time for offline files */
413 state[i].tree->session->transport->options.request_timeout = 200;
416 /* the others are repeats on the earlier connections */
417 for (i=nconnections;i<numstates;i++) {
418 state[i].tctx = torture;
419 state[i].mem_ctx = talloc_new(state);
420 state[i].ev = torture->ev;
421 state[i].tree = state[i % nconnections].tree;
427 if (!torture_setup_dir(cli, BASEDIR)) {
431 /* pre-create files */
432 printf("Pre-creating %u files ....\n", torture_numops);
433 for (i=0;i<torture_numops;i++) {
435 char *fname = filename(mem_ctx, i);
439 memset(buf, i % 256, sizeof(buf));
441 fnum = smbcli_open(state[0].tree, fname, O_RDWR|O_CREAT, DENY_NONE);
443 printf("Failed to open %s on connection %d\n", fname, i);
447 if (smbcli_write(state[0].tree, fnum, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
448 printf("Failed to write file of size %u\n", FILE_SIZE);
452 status = smbcli_close(state[0].tree, fnum);
453 if (!NT_STATUS_IS_OK(status)) {
454 printf("Close failed - %s\n", nt_errstr(status));
461 /* start the async ops */
462 for (i=0;i<numstates;i++) {
463 state[i].tv_start = timeval_current();
464 test_offline(&state[i]);
467 tv = timeval_current();
470 event_add_timed(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state);
473 printf("Running for %d seconds\n", timelimit);
474 while (timeval_elapsed(&tv) < timelimit) {
475 event_loop_once(torture->ev);
478 DEBUG(0,("test failed\n"));
483 printf("\nWaiting for completion\n");
484 test_finished = true;
485 for (i=0;i<numstates;i++) {
486 while (state[i].loadfile ||
489 event_loop_once(torture->ev);
493 printf("worst latencies: set_lat=%.1f get_lat=%.1f save_lat=%.1f load_lat=%.1f\n",
494 worst_latencies[OP_SETOFFLINE],
495 worst_latencies[OP_GETOFFLINE],
496 worst_latencies[OP_SAVEFILE],
497 worst_latencies[OP_LOADFILE]);
499 smbcli_deltree(state[0].tree, BASEDIR);
500 talloc_free(mem_ctx);
505 talloc_free(mem_ctx);