LCOV - code coverage report
Current view: top level - source4/torture/raw - offline.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 0 262 0.0 %
Date: 2024-04-21 15:09:00 Functions: 0 9 0.0 %

          Line data    Source code
       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 "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"
      33             : 
      34             : #define BASEDIR "\\testoffline"
      35             : 
      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;
      43             : 
      44             : enum offline_op {OP_LOADFILE, OP_SAVEFILE, OP_SETOFFLINE, OP_GETOFFLINE, OP_ENDOFLIST};
      45             : 
      46             : static double latencies[OP_ENDOFLIST];
      47             : static double worst_latencies[OP_ENDOFLIST];
      48             : 
      49             : #define FILE_SIZE 8192
      50             : 
      51             : 
      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;
      70             : };
      71             : 
      72             : static void test_offline(struct offline_state *state);
      73             : 
      74             : 
      75           0 : static char *filename(TALLOC_CTX *ctx, int i)
      76             : {
      77           0 :         char *s = talloc_asprintf(ctx, BASEDIR "\\file%u.dat", i);
      78           0 :         return s;
      79             : }
      80             : 
      81             : 
      82             : /*
      83             :   called when a loadfile completes
      84             :  */
      85           0 : static void loadfile_callback(struct composite_context *ctx)
      86             : {
      87           0 :         struct offline_state *state = ctx->async.private_data;
      88           0 :         NTSTATUS status;
      89           0 :         int i;
      90             : 
      91           0 :         status = smb_composite_loadfile_recv(ctx, state->mem_ctx);
      92           0 :         if (!NT_STATUS_IS_OK(status)) {
      93           0 :                 printf("Failed to read file '%s' - %s\n",
      94           0 :                        state->loadfile->in.fname, nt_errstr(status));
      95           0 :                 test_failed++;
      96           0 :                 return;
      97             :         }
      98             : 
      99             :         /* check the data is correct */
     100           0 :         if (state->loadfile->out.size != FILE_SIZE) {
     101           0 :                 printf("Wrong file size %u - expected %u\n",
     102           0 :                        state->loadfile->out.size, FILE_SIZE);
     103           0 :                 test_failed++;
     104           0 :                 return;
     105             :         }
     106             : 
     107           0 :         for (i=0;i<FILE_SIZE;i++) {
     108           0 :                 if (state->loadfile->out.data[i] != 1+(state->fnumber % 255)) {
     109           0 :                         printf("Bad data in file %u (got %u expected %u)\n",
     110             :                                state->fnumber,
     111           0 :                                state->loadfile->out.data[i],
     112           0 :                                1+(state->fnumber % 255));
     113           0 :                         test_failed++;
     114           0 :                         return;
     115             :                 }
     116             :         }
     117             : 
     118           0 :         talloc_steal(state->loadfile, state->loadfile->out.data);
     119             : 
     120           0 :         state->count++;
     121           0 :         talloc_free(state->loadfile);
     122           0 :         state->loadfile = NULL;
     123             : 
     124           0 :         if (!test_finished) {
     125           0 :                 test_offline(state);
     126             :         }
     127             : }
     128             : 
     129             : 
     130             : /*
     131             :   called when a savefile completes
     132             :  */
     133           0 : static void savefile_callback(struct composite_context *ctx)
     134             : {
     135           0 :         struct offline_state *state = ctx->async.private_data;
     136           0 :         NTSTATUS status;
     137             : 
     138           0 :         status = smb_composite_savefile_recv(ctx);
     139           0 :         if (!NT_STATUS_IS_OK(status)) {
     140           0 :                 printf("Failed to save file '%s' - %s\n",
     141           0 :                        state->savefile->in.fname, nt_errstr(status));
     142           0 :                 test_failed++;
     143             :         }
     144             : 
     145           0 :         state->count++;
     146           0 :         talloc_free(state->savefile);
     147           0 :         state->savefile = NULL;
     148             : 
     149           0 :         if (!test_finished) {
     150           0 :                 test_offline(state);
     151             :         }
     152           0 : }
     153             : 
     154             : 
     155             : /*
     156             :   called when a setoffline completes
     157             :  */
     158           0 : static void setoffline_callback(struct smbcli_request *req)
     159             : {
     160           0 :         struct offline_state *state = req->async.private_data;
     161           0 :         NTSTATUS status;
     162             : 
     163           0 :         status = smbcli_request_simple_recv(req);
     164           0 :         if (!NT_STATUS_IS_OK(status)) {
     165           0 :                 printf("Failed to set offline file '%s' - %s\n",
     166             :                        state->fname, nt_errstr(status));
     167           0 :                 test_failed++;
     168             :         }
     169             : 
     170           0 :         state->req = NULL;
     171           0 :         state->count++;
     172             : 
     173           0 :         if (!test_finished) {
     174           0 :                 test_offline(state);
     175             :         }
     176           0 : }
     177             : 
     178             : 
     179             : /*
     180             :   called when a getoffline completes
     181             :  */
     182           0 : static void getoffline_callback(struct smbcli_request *req)
     183             : {
     184           0 :         struct offline_state *state = req->async.private_data;
     185           0 :         NTSTATUS status;
     186           0 :         union smb_fileinfo io;
     187             : 
     188           0 :         ZERO_STRUCT(io);
     189             : 
     190           0 :         io.getattr.level = RAW_FILEINFO_GETATTR;
     191             : 
     192           0 :         status = smb_raw_pathinfo_recv(req, state->mem_ctx, &io);
     193           0 :         if (!NT_STATUS_IS_OK(status)) {
     194           0 :                 printf("Failed to get offline file '%s' - %s\n",
     195             :                        state->fname, nt_errstr(status));
     196           0 :                 test_failed++;
     197             :         }
     198             : 
     199           0 :         if (io.getattr.out.attrib & FILE_ATTRIBUTE_OFFLINE) {
     200           0 :                 state->offline_count++;
     201             :         } else {
     202           0 :                 state->online_count++;
     203             :         }
     204             : 
     205           0 :         state->req = NULL;
     206           0 :         state->count++;
     207             : 
     208           0 :         if (!test_finished) {
     209           0 :                 test_offline(state);
     210             :         }
     211           0 : }
     212             : 
     213             : 
     214             : /*
     215             :   send the next offline file fetch request
     216             : */
     217           0 : static void test_offline(struct offline_state *state)
     218             : {
     219           0 :         struct composite_context *ctx;
     220           0 :         double lat;
     221             : 
     222           0 :         lat = timeval_elapsed(&state->tv_start);
     223           0 :         if (latencies[state->op] < lat) {
     224           0 :                 latencies[state->op] = lat;
     225             :         }
     226             : 
     227           0 :         state->op = (enum offline_op) (random() % OP_ENDOFLIST);
     228             : 
     229           0 :         state->fnumber = random() % torture_numops;
     230           0 :         talloc_free(state->fname);
     231           0 :         state->fname = filename(state->mem_ctx, state->fnumber);
     232             : 
     233           0 :         state->tv_start = timeval_current();
     234             : 
     235           0 :         switch (state->op) {
     236           0 :         case OP_LOADFILE:
     237           0 :                 state->loadfile = talloc_zero(state->mem_ctx, struct smb_composite_loadfile);
     238           0 :                 state->loadfile->in.fname = state->fname;
     239             : 
     240           0 :                 ctx = smb_composite_loadfile_send(state->tree, state->loadfile);
     241           0 :                 if (ctx == NULL) {
     242           0 :                         printf("Failed to setup loadfile for %s\n", state->fname);
     243           0 :                         test_failed = true;
     244             :                 }
     245             : 
     246           0 :                 talloc_steal(state->loadfile, ctx);
     247             : 
     248           0 :                 ctx->async.fn = loadfile_callback;
     249           0 :                 ctx->async.private_data = state;
     250           0 :                 break;
     251             : 
     252           0 :         case OP_SAVEFILE:
     253           0 :                 state->savefile = talloc_zero(state->mem_ctx, struct smb_composite_savefile);
     254             : 
     255           0 :                 state->savefile->in.fname = state->fname;
     256           0 :                 state->savefile->in.data  = talloc_size(state->savefile, FILE_SIZE);
     257           0 :                 state->savefile->in.size  = FILE_SIZE;
     258           0 :                 memset(state->savefile->in.data, 1+(state->fnumber%255), FILE_SIZE);
     259             : 
     260           0 :                 ctx = smb_composite_savefile_send(state->tree, state->savefile);
     261           0 :                 if (ctx == NULL) {
     262           0 :                         printf("Failed to setup savefile for %s\n", state->fname);
     263           0 :                         test_failed = true;
     264             :                 }
     265             : 
     266           0 :                 talloc_steal(state->savefile, ctx);
     267             : 
     268           0 :                 ctx->async.fn = savefile_callback;
     269           0 :                 ctx->async.private_data = state;
     270           0 :                 break;
     271             : 
     272           0 :         case OP_SETOFFLINE: {
     273           0 :                 union smb_setfileinfo io;
     274           0 :                 ZERO_STRUCT(io);
     275           0 :                 io.setattr.level = RAW_SFILEINFO_SETATTR;
     276           0 :                 io.setattr.in.attrib = FILE_ATTRIBUTE_OFFLINE;
     277           0 :                 io.setattr.in.file.path = state->fname;
     278             :                 /* make the file 1 hour old, to get past minimum age restrictions
     279             :                    for HSM systems */
     280           0 :                 io.setattr.in.write_time = time(NULL) - 60*60;
     281             : 
     282           0 :                 state->req = smb_raw_setpathinfo_send(state->tree, &io);
     283           0 :                 if (state->req == NULL) {
     284           0 :                         printf("Failed to setup setoffline for %s\n", state->fname);
     285           0 :                         test_failed = true;
     286             :                 }
     287             : 
     288           0 :                 state->req->async.fn = setoffline_callback;
     289           0 :                 state->req->async.private_data = state;
     290           0 :                 break;
     291             :         }
     292             : 
     293           0 :         case OP_GETOFFLINE: {
     294           0 :                 union smb_fileinfo io;
     295           0 :                 ZERO_STRUCT(io);
     296           0 :                 io.getattr.level = RAW_FILEINFO_GETATTR;
     297           0 :                 io.getattr.in.file.path = state->fname;
     298             : 
     299           0 :                 state->req = smb_raw_pathinfo_send(state->tree, &io);
     300           0 :                 if (state->req == NULL) {
     301           0 :                         printf("Failed to setup getoffline for %s\n", state->fname);
     302           0 :                         test_failed = true;
     303             :                 }
     304             : 
     305           0 :                 state->req->async.fn = getoffline_callback;
     306           0 :                 state->req->async.private_data = state;
     307           0 :                 break;
     308             :         }
     309             : 
     310           0 :         default:
     311           0 :                 printf("bad operation??\n");
     312           0 :                 break;
     313             :         }
     314           0 : }
     315             : 
     316             : 
     317             : 
     318             : 
     319           0 : static void echo_completion(struct smbcli_request *req)
     320             : {
     321           0 :         struct offline_state *state = (struct offline_state *)req->async.private_data;
     322           0 :         NTSTATUS status = smbcli_request_simple_recv(req);
     323           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
     324           0 :             NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
     325           0 :             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
     326           0 :                 talloc_free(state->tree);
     327           0 :                 state->tree = NULL;
     328           0 :                 num_connected--;
     329           0 :                 DEBUG(0,("lost connection\n"));
     330           0 :                 test_failed++;
     331             :         }
     332           0 : }
     333             : 
     334           0 : static void report_rate(struct tevent_context *ev, struct tevent_timer *te,
     335             :                         struct timeval t, void *private_data)
     336             : {
     337           0 :         struct offline_state *state = talloc_get_type(private_data,
     338             :                                                         struct offline_state);
     339           0 :         int i;
     340           0 :         uint32_t total=0, total_offline=0, total_online=0;
     341           0 :         for (i=0;i<numstates;i++) {
     342           0 :                 total += state[i].count - state[i].lastcount;
     343           0 :                 if (timeval_elapsed(&state[i].tv_start) > latencies[state[i].op]) {
     344           0 :                         latencies[state[i].op] = timeval_elapsed(&state[i].tv_start);
     345             :                 }
     346           0 :                 state[i].lastcount = state[i].count;
     347           0 :                 total_online += state[i].online_count;
     348           0 :                 total_offline += state[i].offline_count;
     349             :         }
     350           0 :         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",
     351             :                total, total_offline, total_online,
     352             :                latencies[OP_SETOFFLINE],
     353             :                worst_latencies[OP_SETOFFLINE],
     354             :                latencies[OP_GETOFFLINE],
     355             :                worst_latencies[OP_GETOFFLINE],
     356             :                latencies[OP_SAVEFILE],
     357             :                worst_latencies[OP_SAVEFILE],
     358             :                latencies[OP_LOADFILE],
     359             :                worst_latencies[OP_LOADFILE]);
     360           0 :         fflush(stdout);
     361           0 :         tevent_add_timer(ev, state, timeval_current_ofs(1, 0), report_rate, state);
     362             : 
     363           0 :         for (i=0;i<OP_ENDOFLIST;i++) {
     364           0 :                 if (latencies[i] > worst_latencies[i]) {
     365           0 :                         worst_latencies[i] = latencies[i];
     366             :                 }
     367           0 :                 latencies[i] = 0;
     368             :         }
     369             : 
     370             :         /* send an echo on each interface to ensure it stays alive - this helps
     371             :            with IP takeover */
     372           0 :         for (i=0;i<numstates;i++) {
     373           0 :                 struct smb_echo p;
     374           0 :                 struct smbcli_request *req;
     375             : 
     376           0 :                 if (!state[i].tree) {
     377           0 :                         continue;
     378             :                 }
     379             : 
     380           0 :                 p.in.repeat_count = 1;
     381           0 :                 p.in.size = 0;
     382           0 :                 p.in.data = NULL;
     383           0 :                 req = smb_raw_echo_send(state[i].tree->session->transport, &p);
     384           0 :                 req->async.private_data = &state[i];
     385           0 :                 req->async.fn      = echo_completion;
     386             :         }
     387           0 : }
     388             : 
     389             : /*
     390             :    test offline file handling
     391             : */
     392           0 : bool torture_test_offline(struct torture_context *torture)
     393             : {
     394           0 :         bool ret = true;
     395           0 :         TALLOC_CTX *mem_ctx = talloc_new(torture);
     396           0 :         int i;
     397           0 :         int timelimit = torture_setting_int(torture, "timelimit", 10);
     398           0 :         struct timeval tv;
     399           0 :         struct offline_state *state;
     400           0 :         struct smbcli_state *cli;
     401           0 :         bool progress;
     402           0 :         progress = torture_setting_bool(torture, "progress", true);
     403             : 
     404           0 :         nconnections = torture_setting_int(torture, "nprocs", 4);
     405           0 :         numstates = nconnections * torture_entries;
     406             : 
     407           0 :         state = talloc_zero_array(mem_ctx, struct offline_state, numstates);
     408             : 
     409           0 :         printf("Opening %d connections with %d simultaneous operations and %u files\n", nconnections, numstates, torture_numops);
     410           0 :         for (i=0;i<nconnections;i++) {
     411           0 :                 state[i].tctx = torture;
     412           0 :                 state[i].mem_ctx = talloc_new(state);
     413           0 :                 state[i].ev = torture->ev;
     414           0 :                 if (!torture_open_connection_ev(&cli, i, torture, torture->ev)) {
     415           0 :                         return false;
     416             :                 }
     417           0 :                 state[i].tree = cli->tree;
     418           0 :                 state[i].client = i;
     419             :                 /* allow more time for offline files */
     420           0 :                 state[i].tree->session->transport->options.request_timeout = 200;
     421             :         }
     422             : 
     423             :         /* the others are repeats on the earlier connections */
     424           0 :         for (i=nconnections;i<numstates;i++) {
     425           0 :                 state[i].tctx = torture;
     426           0 :                 state[i].mem_ctx = talloc_new(state);
     427           0 :                 state[i].ev = torture->ev;
     428           0 :                 state[i].tree = state[i % nconnections].tree;
     429           0 :                 state[i].client = i;
     430             :         }
     431             : 
     432           0 :         num_connected = i;
     433             : 
     434           0 :         if (!torture_setup_dir(cli, BASEDIR)) {
     435           0 :                 goto failed;
     436             :         }
     437             : 
     438             :         /* pre-create files */
     439           0 :         printf("Pre-creating %u files ....\n", torture_numops);
     440           0 :         for (i=0;i<torture_numops;i++) {
     441           0 :                 int fnum;
     442           0 :                 char *fname = filename(mem_ctx, i);
     443           0 :                 char buf[FILE_SIZE];
     444           0 :                 NTSTATUS status;
     445             : 
     446           0 :                 memset(buf, 1+(i % 255), sizeof(buf));
     447             : 
     448           0 :                 fnum = smbcli_open(state[0].tree, fname, O_RDWR|O_CREAT, DENY_NONE);
     449           0 :                 if (fnum == -1) {
     450           0 :                         printf("Failed to open %s on connection %d\n", fname, i);
     451           0 :                         goto failed;
     452             :                 }
     453             : 
     454           0 :                 if (smbcli_write(state[0].tree, fnum, 0, buf, 0, sizeof(buf)) != sizeof(buf)) {
     455           0 :                         printf("Failed to write file of size %u\n", FILE_SIZE);
     456           0 :                         goto failed;
     457             :                 }
     458             : 
     459           0 :                 status = smbcli_close(state[0].tree, fnum);
     460           0 :                 if (!NT_STATUS_IS_OK(status)) {
     461           0 :                         printf("Close failed - %s\n", nt_errstr(status));
     462           0 :                         goto failed;
     463             :                 }
     464             : 
     465           0 :                 talloc_free(fname);
     466             :         }
     467             : 
     468             :         /* start the async ops */
     469           0 :         for (i=0;i<numstates;i++) {
     470           0 :                 state[i].tv_start = timeval_current();
     471           0 :                 test_offline(&state[i]);
     472             :         }
     473             : 
     474           0 :         tv = timeval_current();
     475             : 
     476           0 :         if (progress) {
     477           0 :                 tevent_add_timer(torture->ev, state, timeval_current_ofs(1, 0), report_rate, state);
     478             :         }
     479             : 
     480           0 :         printf("Running for %d seconds\n", timelimit);
     481           0 :         while (timeval_elapsed(&tv) < timelimit) {
     482           0 :                 tevent_loop_once(torture->ev);
     483             : 
     484           0 :                 if (test_failed) {
     485           0 :                         DEBUG(0,("test failed\n"));
     486           0 :                         goto failed;
     487             :                 }
     488             :         }
     489             : 
     490           0 :         printf("\nWaiting for completion\n");
     491           0 :         test_finished = true;
     492           0 :         for (i=0;i<numstates;i++) {
     493           0 :                 while (state[i].loadfile ||
     494           0 :                        state[i].savefile ||
     495           0 :                        state[i].req) {
     496           0 :                         tevent_loop_once(torture->ev);
     497             :                 }
     498             :         }
     499             : 
     500           0 :         printf("worst latencies: set_lat=%.1f get_lat=%.1f save_lat=%.1f load_lat=%.1f\n",
     501             :                worst_latencies[OP_SETOFFLINE],
     502             :                worst_latencies[OP_GETOFFLINE],
     503             :                worst_latencies[OP_SAVEFILE],
     504             :                worst_latencies[OP_LOADFILE]);
     505             : 
     506           0 :         smbcli_deltree(state[0].tree, BASEDIR);
     507           0 :         talloc_free(mem_ctx);
     508           0 :         printf("\n");
     509           0 :         return ret;
     510             : 
     511           0 : failed:
     512           0 :         talloc_free(mem_ctx);
     513           0 :         return false;
     514             : }

Generated by: LCOV version 1.14