root/source4/torture/raw/offline.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. filename
  2. loadfile_callback
  3. savefile_callback
  4. setoffline_callback
  5. getoffline_callback
  6. test_offline
  7. echo_completion
  8. report_rate
  9. torture_test_offline

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    Copyright (C) Andrew Tridgell 2008
   5    
   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.
  10    
  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.
  15    
  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/>.
  18 */
  19 
  20 /*
  21   test offline files
  22  */
  23 
  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"
  36 
  37 #define BASEDIR "\\testoffline"
  38 
  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;
  46 
  47 enum offline_op {OP_LOADFILE, OP_SAVEFILE, OP_SETOFFLINE, OP_GETOFFLINE, OP_ENDOFLIST};
  48 
  49 static double latencies[OP_ENDOFLIST];
  50 static double worst_latencies[OP_ENDOFLIST];
  51 
  52 #define FILE_SIZE 8192
  53 
  54 
  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;
  73 };
  74 
  75 static void test_offline(struct offline_state *state);
  76 
  77 
  78 static char *filename(TALLOC_CTX *ctx, int i)
     /* [<][>][^][v][top][bottom][index][help] */
  79 {
  80         char *s = talloc_asprintf(ctx, BASEDIR "\\file%u.dat", i);
  81         return s;
  82 }
  83 
  84 
  85 /*
  86   called when a loadfile completes
  87  */
  88 static void loadfile_callback(struct composite_context *ctx) 
     /* [<][>][^][v][top][bottom][index][help] */
  89 {
  90         struct offline_state *state = ctx->async.private_data;
  91         NTSTATUS status;
  92         int i;
  93 
  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++;
  99         }
 100 
 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;
 107         }
 108 
 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;
 117                 }
 118         }
 119         
 120         talloc_steal(state->loadfile, state->loadfile->out.data);
 121 
 122         state->count++;
 123         talloc_free(state->loadfile);
 124         state->loadfile = NULL;
 125 
 126         if (!test_finished) {
 127                 test_offline(state);
 128         }
 129 }
 130 
 131 
 132 /*
 133   called when a savefile completes
 134  */
 135 static void savefile_callback(struct composite_context *ctx) 
     /* [<][>][^][v][top][bottom][index][help] */
 136 {
 137         struct offline_state *state = ctx->async.private_data;
 138         NTSTATUS status;
 139 
 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++;
 145         }
 146 
 147         state->count++;
 148         talloc_free(state->savefile);
 149         state->savefile = NULL;
 150 
 151         if (!test_finished) {
 152                 test_offline(state);
 153         }
 154 }
 155 
 156 
 157 /*
 158   called when a setoffline completes
 159  */
 160 static void setoffline_callback(struct smbcli_request *req) 
     /* [<][>][^][v][top][bottom][index][help] */
 161 {
 162         struct offline_state *state = req->async.private_data;
 163         NTSTATUS status;
 164 
 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++;
 170         }
 171 
 172         state->req = NULL;
 173         state->count++;
 174 
 175         if (!test_finished) {
 176                 test_offline(state);
 177         }
 178 }
 179 
 180 
 181 /*
 182   called when a getoffline completes
 183  */
 184 static void getoffline_callback(struct smbcli_request *req) 
     /* [<][>][^][v][top][bottom][index][help] */
 185 {
 186         struct offline_state *state = req->async.private_data;
 187         NTSTATUS status;
 188         union smb_fileinfo io;
 189 
 190         io.getattr.level = RAW_FILEINFO_GETATTR;
 191         
 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++;
 197         }
 198 
 199         if (io.getattr.out.attrib & FILE_ATTRIBUTE_OFFLINE) {
 200                 state->offline_count++;
 201         } else {
 202                 state->online_count++;
 203         }
 204 
 205         state->req = NULL;
 206         state->count++;
 207 
 208         if (!test_finished) {
 209                 test_offline(state);
 210         }
 211 }
 212 
 213 
 214 /*
 215   send the next offline file fetch request
 216 */
 217 static void test_offline(struct offline_state *state)
     /* [<][>][^][v][top][bottom][index][help] */
 218 {
 219         struct composite_context *ctx;
 220         double lat;
 221 
 222         lat = timeval_elapsed(&state->tv_start);
 223         if (latencies[state->op] < lat) {
 224                 latencies[state->op] = lat;
 225         }
 226 
 227         state->op = (enum offline_op) (random() % OP_ENDOFLIST);
 228         
 229         state->fnumber = random() % torture_numops;
 230         talloc_free(state->fname);
 231         state->fname = filename(state->mem_ctx, state->fnumber);
 232 
 233         state->tv_start = timeval_current();
 234 
 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;
 239         
 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;
 244                 }
 245 
 246                 talloc_steal(state->loadfile, ctx);
 247 
 248                 ctx->async.fn = loadfile_callback;
 249                 ctx->async.private_data = state;
 250                 break;
 251 
 252         case OP_SAVEFILE:
 253                 state->savefile = talloc_zero(state->mem_ctx, struct smb_composite_savefile);
 254 
 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);
 259         
 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;
 264                 }
 265 
 266                 talloc_steal(state->savefile, ctx);
 267 
 268                 ctx->async.fn = savefile_callback;
 269                 ctx->async.private_data = state;
 270                 break;
 271 
 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;
 281 
 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;
 286                 }
 287                 
 288                 state->req->async.fn = setoffline_callback;
 289                 state->req->async.private_data = state;
 290                 break;
 291         }
 292 
 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;
 298 
 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;
 303                 }
 304                 
 305                 state->req->async.fn = getoffline_callback;
 306                 state->req->async.private_data = state;
 307                 break;
 308         }
 309 
 310         default:
 311                 printf("bad operation??\n");
 312                 break;
 313         }
 314 }
 315 
 316 
 317 
 318 
 319 static void echo_completion(struct smbcli_request *req)
     /* [<][>][^][v][top][bottom][index][help] */
 320 {
 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++;
 330         }
 331 }
 332 
 333 static void report_rate(struct tevent_context *ev, struct tevent_timer *te, 
     /* [<][>][^][v][top][bottom][index][help] */
 334                         struct timeval t, void *private_data)
 335 {
 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);
 344                 }
 345                 state[i].lastcount = state[i].count;            
 346                 total_online += state[i].online_count;
 347                 total_offline += state[i].offline_count;
 348         }
 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);
 361 
 362         for (i=0;i<OP_ENDOFLIST;i++) {
 363                 if (latencies[i] > worst_latencies[i]) {
 364                         worst_latencies[i] = latencies[i];
 365                 }
 366                 latencies[i] = 0;
 367         }
 368 
 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;
 374 
 375                 if (!state[i].tree) {
 376                         continue;
 377                 }
 378 
 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;
 385         }
 386 }
 387 
 388 /* 
 389    test offline file handling
 390 */
 391 bool torture_test_offline(struct torture_context *torture)
     /* [<][>][^][v][top][bottom][index][help] */
 392 {
 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);
 402 
 403         nconnections = torture_setting_int(torture, "nprocs", 4);
 404         numstates = nconnections * torture_entries;
 405 
 406         state = talloc_zero_array(mem_ctx, struct offline_state, numstates);
 407 
 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;
 415                 }
 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;
 420         }
 421 
 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;
 429         }
 430 
 431         num_connected = i;
 432 
 433         if (!torture_setup_dir(cli, BASEDIR)) {
 434                 goto failed;
 435         }
 436 
 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;
 444 
 445                 memset(buf, 1+(i % 255), sizeof(buf));
 446 
 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;
 451                 }
 452 
 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;
 456                 }
 457 
 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;
 462                 }
 463 
 464                 talloc_free(fname);
 465         }
 466 
 467         /* start the async ops */
 468         for (i=0;i<numstates;i++) {
 469                 state[i].tv_start = timeval_current();
 470                 test_offline(&state[i]);
 471         }
 472 
 473         tv = timeval_current(); 
 474 
 475         if (progress) {
 476                 event_add_timed(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state);
 477         }
 478 
 479         printf("Running for %d seconds\n", timelimit);
 480         while (timeval_elapsed(&tv) < timelimit) {
 481                 event_loop_once(torture->ev);
 482 
 483                 if (test_failed) {
 484                         DEBUG(0,("test failed\n"));
 485                         goto failed;
 486                 }
 487         }
 488 
 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);
 496                 }
 497         }       
 498 
 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]);
 504 
 505         smbcli_deltree(state[0].tree, BASEDIR);
 506         talloc_free(mem_ctx);
 507         printf("\n");
 508         return ret;
 509 
 510 failed:
 511         talloc_free(mem_ctx);
 512         return false;
 513 }

/* [<][>][^][v][top][bottom][index][help] */