s3: Fix bug #9085.
[Samba.git] / source4 / torture / raw / offline.c
blob5322f471a2b88642a9e3b07582775fb13e80bc28
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 "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"
37 #define BASEDIR "\\testoffline"
39 static int nconnections;
40 static int numstates;
41 static int num_connected;
42 static int test_failed;
43 extern int torture_numops;
44 extern int torture_entries;
45 static bool test_finished;
47 enum offline_op {OP_LOADFILE, OP_SAVEFILE, OP_SETOFFLINE, OP_GETOFFLINE, OP_ENDOFLIST};
49 static double latencies[OP_ENDOFLIST];
50 static double worst_latencies[OP_ENDOFLIST];
52 #define FILE_SIZE 8192
55 struct offline_state {
56 struct torture_context *tctx;
57 struct tevent_context *ev;
58 struct smbcli_tree *tree;
59 TALLOC_CTX *mem_ctx;
60 int client;
61 int fnum;
62 uint32_t count;
63 uint32_t lastcount;
64 uint32_t fnumber;
65 uint32_t offline_count;
66 uint32_t online_count;
67 char *fname;
68 struct smb_composite_loadfile *loadfile;
69 struct smb_composite_savefile *savefile;
70 struct smbcli_request *req;
71 enum offline_op op;
72 struct timeval tv_start;
75 static void test_offline(struct offline_state *state);
78 static char *filename(TALLOC_CTX *ctx, int i)
80 char *s = talloc_asprintf(ctx, BASEDIR "\\file%u.dat", i);
81 return s;
86 called when a loadfile completes
88 static void loadfile_callback(struct composite_context *ctx)
90 struct offline_state *state = ctx->async.private_data;
91 NTSTATUS status;
92 int i;
94 status = smb_composite_loadfile_recv(ctx, state->mem_ctx);
95 if (!NT_STATUS_IS_OK(status)) {
96 printf("Failed to read file '%s' - %s\n",
97 state->loadfile->in.fname, nt_errstr(status));
98 test_failed++;
101 /* check the data is correct */
102 if (state->loadfile->out.size != FILE_SIZE) {
103 printf("Wrong file size %u - expected %u\n",
104 state->loadfile->out.size, FILE_SIZE);
105 test_failed++;
106 return;
109 for (i=0;i<FILE_SIZE;i++) {
110 if (state->loadfile->out.data[i] != 1+(state->fnumber % 255)) {
111 printf("Bad data in file %u (got %u expected %u)\n",
112 state->fnumber,
113 state->loadfile->out.data[i],
114 1+(state->fnumber % 255));
115 test_failed++;
116 return;
120 talloc_steal(state->loadfile, state->loadfile->out.data);
122 state->count++;
123 talloc_free(state->loadfile);
124 state->loadfile = NULL;
126 if (!test_finished) {
127 test_offline(state);
133 called when a savefile completes
135 static void savefile_callback(struct composite_context *ctx)
137 struct offline_state *state = ctx->async.private_data;
138 NTSTATUS status;
140 status = smb_composite_savefile_recv(ctx);
141 if (!NT_STATUS_IS_OK(status)) {
142 printf("Failed to save file '%s' - %s\n",
143 state->savefile->in.fname, nt_errstr(status));
144 test_failed++;
147 state->count++;
148 talloc_free(state->savefile);
149 state->savefile = NULL;
151 if (!test_finished) {
152 test_offline(state);
158 called when a setoffline completes
160 static void setoffline_callback(struct smbcli_request *req)
162 struct offline_state *state = req->async.private_data;
163 NTSTATUS status;
165 status = smbcli_request_simple_recv(req);
166 if (!NT_STATUS_IS_OK(status)) {
167 printf("Failed to set offline file '%s' - %s\n",
168 state->fname, nt_errstr(status));
169 test_failed++;
172 state->req = NULL;
173 state->count++;
175 if (!test_finished) {
176 test_offline(state);
182 called when a getoffline completes
184 static void getoffline_callback(struct smbcli_request *req)
186 struct offline_state *state = req->async.private_data;
187 NTSTATUS status;
188 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));
196 test_failed++;
199 if (io.getattr.out.attrib & FILE_ATTRIBUTE_OFFLINE) {
200 state->offline_count++;
201 } else {
202 state->online_count++;
205 state->req = NULL;
206 state->count++;
208 if (!test_finished) {
209 test_offline(state);
215 send the next offline file fetch request
217 static void test_offline(struct offline_state *state)
219 struct composite_context *ctx;
220 double lat;
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();
235 switch (state->op) {
236 case OP_LOADFILE:
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);
241 if (ctx == NULL) {
242 printf("Failed to setup loadfile for %s\n", state->fname);
243 test_failed = true;
246 talloc_steal(state->loadfile, ctx);
248 ctx->async.fn = loadfile_callback;
249 ctx->async.private_data = state;
250 break;
252 case OP_SAVEFILE:
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);
261 if (ctx == NULL) {
262 printf("Failed to setup savefile for %s\n", state->fname);
263 test_failed = true;
266 talloc_steal(state->savefile, ctx);
268 ctx->async.fn = savefile_callback;
269 ctx->async.private_data = state;
270 break;
272 case OP_SETOFFLINE: {
273 union smb_setfileinfo io;
274 ZERO_STRUCT(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 mininum age restrictions
279 for HSM systems */
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);
285 test_failed = true;
288 state->req->async.fn = setoffline_callback;
289 state->req->async.private_data = state;
290 break;
293 case OP_GETOFFLINE: {
294 union smb_fileinfo io;
295 ZERO_STRUCT(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);
302 test_failed = true;
305 state->req->async.fn = getoffline_callback;
306 state->req->async.private_data = state;
307 break;
310 default:
311 printf("bad operation??\n");
312 break;
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 talloc_free(state->tree);
326 state->tree = NULL;
327 num_connected--;
328 DEBUG(0,("lost connection\n"));
329 test_failed++;
333 static void report_rate(struct tevent_context *ev, struct tevent_timer *te,
334 struct timeval t, void *private_data)
336 struct offline_state *state = talloc_get_type(private_data,
337 struct offline_state);
338 int i;
339 uint32_t total=0, total_offline=0, total_online=0;
340 for (i=0;i<numstates;i++) {
341 total += state[i].count - state[i].lastcount;
342 if (timeval_elapsed(&state[i].tv_start) > latencies[state[i].op]) {
343 latencies[state[i].op] = timeval_elapsed(&state[i].tv_start);
345 state[i].lastcount = state[i].count;
346 total_online += state[i].online_count;
347 total_offline += state[i].offline_count;
349 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",
350 total, total_offline, total_online,
351 latencies[OP_SETOFFLINE],
352 worst_latencies[OP_SETOFFLINE],
353 latencies[OP_GETOFFLINE],
354 worst_latencies[OP_GETOFFLINE],
355 latencies[OP_SAVEFILE],
356 worst_latencies[OP_SAVEFILE],
357 latencies[OP_LOADFILE],
358 worst_latencies[OP_LOADFILE]);
359 fflush(stdout);
360 event_add_timed(ev, state, timeval_current_ofs(1, 0), report_rate, state);
362 for (i=0;i<OP_ENDOFLIST;i++) {
363 if (latencies[i] > worst_latencies[i]) {
364 worst_latencies[i] = latencies[i];
366 latencies[i] = 0;
369 /* send an echo on each interface to ensure it stays alive - this helps
370 with IP takeover */
371 for (i=0;i<numstates;i++) {
372 struct smb_echo p;
373 struct smbcli_request *req;
375 if (!state[i].tree) {
376 continue;
379 p.in.repeat_count = 1;
380 p.in.size = 0;
381 p.in.data = NULL;
382 req = smb_raw_echo_send(state[i].tree->session->transport, &p);
383 req->async.private_data = &state[i];
384 req->async.fn = echo_completion;
389 test offline file handling
391 bool torture_test_offline(struct torture_context *torture)
393 bool ret = true;
394 TALLOC_CTX *mem_ctx = talloc_new(torture);
395 int i;
396 int timelimit = torture_setting_int(torture, "timelimit", 10);
397 struct timeval tv;
398 struct offline_state *state;
399 struct smbcli_state *cli;
400 bool progress;
401 progress = torture_setting_bool(torture, "progress", true);
403 nconnections = torture_setting_int(torture, "nprocs", 4);
404 numstates = nconnections * torture_entries;
406 state = talloc_zero_array(mem_ctx, struct offline_state, numstates);
408 printf("Opening %d connections with %d simultaneous operations and %u files\n", nconnections, numstates, torture_numops);
409 for (i=0;i<nconnections;i++) {
410 state[i].tctx = torture;
411 state[i].mem_ctx = talloc_new(state);
412 state[i].ev = torture->ev;
413 if (!torture_open_connection_ev(&cli, i, torture, torture->ev)) {
414 return false;
416 state[i].tree = cli->tree;
417 state[i].client = i;
418 /* allow more time for offline files */
419 state[i].tree->session->transport->options.request_timeout = 200;
422 /* the others are repeats on the earlier connections */
423 for (i=nconnections;i<numstates;i++) {
424 state[i].tctx = torture;
425 state[i].mem_ctx = talloc_new(state);
426 state[i].ev = torture->ev;
427 state[i].tree = state[i % nconnections].tree;
428 state[i].client = i;
431 num_connected = i;
433 if (!torture_setup_dir(cli, BASEDIR)) {
434 goto failed;
437 /* pre-create files */
438 printf("Pre-creating %u files ....\n", torture_numops);
439 for (i=0;i<torture_numops;i++) {
440 int fnum;
441 char *fname = filename(mem_ctx, i);
442 char buf[FILE_SIZE];
443 NTSTATUS status;
445 memset(buf, 1+(i % 255), sizeof(buf));
447 fnum = smbcli_open(state[0].tree, fname, O_RDWR|O_CREAT, DENY_NONE);
448 if (fnum == -1) {
449 printf("Failed to open %s on connection %d\n", fname, i);
450 goto failed;
453 if (smbcli_write(state[0].tree, fnum, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
454 printf("Failed to write file of size %u\n", FILE_SIZE);
455 goto failed;
458 status = smbcli_close(state[0].tree, fnum);
459 if (!NT_STATUS_IS_OK(status)) {
460 printf("Close failed - %s\n", nt_errstr(status));
461 goto failed;
464 talloc_free(fname);
467 /* start the async ops */
468 for (i=0;i<numstates;i++) {
469 state[i].tv_start = timeval_current();
470 test_offline(&state[i]);
473 tv = timeval_current();
475 if (progress) {
476 event_add_timed(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state);
479 printf("Running for %d seconds\n", timelimit);
480 while (timeval_elapsed(&tv) < timelimit) {
481 event_loop_once(torture->ev);
483 if (test_failed) {
484 DEBUG(0,("test failed\n"));
485 goto failed;
489 printf("\nWaiting for completion\n");
490 test_finished = true;
491 for (i=0;i<numstates;i++) {
492 while (state[i].loadfile ||
493 state[i].savefile ||
494 state[i].req) {
495 event_loop_once(torture->ev);
499 printf("worst latencies: set_lat=%.1f get_lat=%.1f save_lat=%.1f load_lat=%.1f\n",
500 worst_latencies[OP_SETOFFLINE],
501 worst_latencies[OP_GETOFFLINE],
502 worst_latencies[OP_SAVEFILE],
503 worst_latencies[OP_LOADFILE]);
505 smbcli_deltree(state[0].tree, BASEDIR);
506 talloc_free(mem_ctx);
507 printf("\n");
508 return ret;
510 failed:
511 talloc_free(mem_ctx);
512 return false;