s3:winbindd: s/struct event_context/struct tevent_context
[Samba/gebeck_regimport.git] / source4 / torture / raw / offline.c
blob85b1235ff6daf609bb06bfbbc27839d08462511e
1 /*
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/>.
21 test offline files
24 #include "includes.h"
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;
37 static int numstates;
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;
56 TALLOC_CTX *mem_ctx;
57 int client;
58 int fnum;
59 uint32_t count;
60 uint32_t lastcount;
61 uint32_t fnumber;
62 uint32_t offline_count;
63 uint32_t online_count;
64 char *fname;
65 struct smb_composite_loadfile *loadfile;
66 struct smb_composite_savefile *savefile;
67 struct smbcli_request *req;
68 enum offline_op op;
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);
78 return s;
83 called when a loadfile completes
85 static void loadfile_callback(struct composite_context *ctx)
87 struct offline_state *state = ctx->async.private_data;
88 NTSTATUS status;
89 int i;
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));
95 test_failed++;
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);
102 test_failed++;
103 return;
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",
109 state->fnumber,
110 state->loadfile->out.data[i],
111 1+(state->fnumber % 255));
112 test_failed++;
113 return;
117 talloc_steal(state->loadfile, state->loadfile->out.data);
119 state->count++;
120 talloc_free(state->loadfile);
121 state->loadfile = NULL;
123 if (!test_finished) {
124 test_offline(state);
130 called when a savefile completes
132 static void savefile_callback(struct composite_context *ctx)
134 struct offline_state *state = ctx->async.private_data;
135 NTSTATUS status;
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));
141 test_failed++;
144 state->count++;
145 talloc_free(state->savefile);
146 state->savefile = NULL;
148 if (!test_finished) {
149 test_offline(state);
155 called when a setoffline completes
157 static void setoffline_callback(struct smbcli_request *req)
159 struct offline_state *state = req->async.private_data;
160 NTSTATUS status;
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));
166 test_failed++;
169 state->req = NULL;
170 state->count++;
172 if (!test_finished) {
173 test_offline(state);
179 called when a getoffline completes
181 static void getoffline_callback(struct smbcli_request *req)
183 struct offline_state *state = req->async.private_data;
184 NTSTATUS status;
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));
193 test_failed++;
196 if (io.getattr.out.attrib & FILE_ATTRIBUTE_OFFLINE) {
197 state->offline_count++;
198 } else {
199 state->online_count++;
202 state->req = NULL;
203 state->count++;
205 if (!test_finished) {
206 test_offline(state);
212 send the next offline file fetch request
214 static void test_offline(struct offline_state *state)
216 struct composite_context *ctx;
217 double lat;
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();
232 switch (state->op) {
233 case OP_LOADFILE:
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);
238 if (ctx == NULL) {
239 printf("Failed to setup loadfile for %s\n", state->fname);
240 test_failed = true;
243 talloc_steal(state->loadfile, ctx);
245 ctx->async.fn = loadfile_callback;
246 ctx->async.private_data = state;
247 break;
249 case OP_SAVEFILE:
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);
258 if (ctx == NULL) {
259 printf("Failed to setup savefile for %s\n", state->fname);
260 test_failed = true;
263 talloc_steal(state->savefile, ctx);
265 ctx->async.fn = savefile_callback;
266 ctx->async.private_data = state;
267 break;
269 case OP_SETOFFLINE: {
270 union smb_setfileinfo io;
271 ZERO_STRUCT(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
276 for HSM systems */
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);
282 test_failed = true;
285 state->req->async.fn = setoffline_callback;
286 state->req->async.private_data = state;
287 break;
290 case OP_GETOFFLINE: {
291 union smb_fileinfo io;
292 ZERO_STRUCT(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);
299 test_failed = true;
302 state->req->async.fn = getoffline_callback;
303 state->req->async.private_data = state;
304 break;
307 default:
308 printf("bad operation??\n");
309 break;
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);
324 state->tree = NULL;
325 num_connected--;
326 DEBUG(0,("lost connection\n"));
327 test_failed++;
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);
336 int i;
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]);
357 fflush(stdout);
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];
364 latencies[i] = 0;
367 /* send an echo on each interface to ensure it stays alive - this helps
368 with IP takeover */
369 for (i=0;i<numstates;i++) {
370 struct smb_echo p;
371 struct smbcli_request *req;
373 if (!state[i].tree) {
374 continue;
377 p.in.repeat_count = 1;
378 p.in.size = 0;
379 p.in.data = NULL;
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)
391 bool ret = true;
392 TALLOC_CTX *mem_ctx = talloc_new(torture);
393 int i;
394 int timelimit = torture_setting_int(torture, "timelimit", 10);
395 struct timeval tv;
396 struct offline_state *state;
397 struct smbcli_state *cli;
398 bool progress;
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)) {
412 return false;
414 state[i].tree = cli->tree;
415 state[i].client = i;
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;
426 state[i].client = i;
429 num_connected = i;
431 if (!torture_setup_dir(cli, BASEDIR)) {
432 goto failed;
435 /* pre-create files */
436 printf("Pre-creating %u files ....\n", torture_numops);
437 for (i=0;i<torture_numops;i++) {
438 int fnum;
439 char *fname = filename(mem_ctx, i);
440 char buf[FILE_SIZE];
441 NTSTATUS status;
443 memset(buf, 1+(i % 255), sizeof(buf));
445 fnum = smbcli_open(state[0].tree, fname, O_RDWR|O_CREAT, DENY_NONE);
446 if (fnum == -1) {
447 printf("Failed to open %s on connection %d\n", fname, i);
448 goto failed;
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);
453 goto failed;
456 status = smbcli_close(state[0].tree, fnum);
457 if (!NT_STATUS_IS_OK(status)) {
458 printf("Close failed - %s\n", nt_errstr(status));
459 goto failed;
462 talloc_free(fname);
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();
473 if (progress) {
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);
481 if (test_failed) {
482 DEBUG(0,("test failed\n"));
483 goto failed;
487 printf("\nWaiting for completion\n");
488 test_finished = true;
489 for (i=0;i<numstates;i++) {
490 while (state[i].loadfile ||
491 state[i].savefile ||
492 state[i].req) {
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);
505 printf("\n");
506 return ret;
508 failed:
509 talloc_free(mem_ctx);
510 return false;