LCOV - code coverage report
Current view: top level - source4/torture/raw - openbench.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 0 261 0.0 %
Date: 2024-04-13 12:30:31 Functions: 0 9 0.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    open benchmark
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2007
       7             :    
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "torture/torture.h"
      24             : #include "libcli/raw/libcliraw.h"
      25             : #include "libcli/raw/raw_proto.h"
      26             : #include "system/time.h"
      27             : #include "system/filesys.h"
      28             : #include "libcli/libcli.h"
      29             : #include "torture/util.h"
      30             : #include "lib/events/events.h"
      31             : #include "lib/cmdline/cmdline.h"
      32             : #include "libcli/composite/composite.h"
      33             : #include "libcli/smb_composite/smb_composite.h"
      34             : #include "libcli/resolve/resolve.h"
      35             : #include "param/param.h"
      36             : #include "torture/raw/proto.h"
      37             : #include "libcli/smb/smbXcli_base.h"
      38             : #include "../lib/util/util_net.h"
      39             : 
      40             : #define BASEDIR "\\benchopen"
      41             : 
      42             : static int nprocs;
      43             : static int open_failed;
      44             : static int close_failed;
      45             : static char **fnames;
      46             : static int num_connected;
      47             : static struct tevent_timer *report_te;
      48             : 
      49             : struct benchopen_state {
      50             :         struct torture_context *tctx;
      51             :         TALLOC_CTX *mem_ctx;
      52             :         struct tevent_context *ev;
      53             :         struct smbcli_state *cli;
      54             :         struct smbcli_tree *tree;
      55             :         int client_num;
      56             :         int close_fnum;
      57             :         int open_fnum;
      58             :         int close_file_num;
      59             :         int open_file_num;
      60             :         int pending_file_num;
      61             :         int next_file_num;
      62             :         int count;
      63             :         int lastcount;
      64             :         union smb_open open_parms;
      65             :         int open_retries;
      66             :         union smb_close close_parms;
      67             :         struct smbcli_request *req_open;
      68             :         struct smbcli_request *req_close;
      69             :         struct smb_composite_connect reconnect;
      70             :         struct tevent_timer *te;
      71             : 
      72             :         /* these are used for reconnections */
      73             :         const char **dest_ports;
      74             :         const char *dest_host;
      75             :         const char *called_name;
      76             :         const char *service_type;
      77             : };
      78             : 
      79             : static void next_open(struct benchopen_state *state);
      80             : static void reopen_connection(struct tevent_context *ev, struct tevent_timer *te, 
      81             :                               struct timeval t, void *private_data);
      82             : 
      83             : 
      84             : /*
      85             :   complete an async reconnect
      86             :  */
      87           0 : static void reopen_connection_complete(struct composite_context *ctx)
      88             : {
      89           0 :         struct benchopen_state *state = (struct benchopen_state *)ctx->async.private_data;
      90           0 :         NTSTATUS status;
      91           0 :         struct smb_composite_connect *io = &state->reconnect;
      92             : 
      93           0 :         status = smb_composite_connect_recv(ctx, state->mem_ctx);
      94           0 :         if (!NT_STATUS_IS_OK(status)) {
      95           0 :                 talloc_free(state->te);
      96           0 :                 state->te = tevent_add_timer(state->ev, state->mem_ctx,
      97             :                                             timeval_current_ofs(1,0), 
      98             :                                             reopen_connection, state);
      99           0 :                 return;
     100             :         }
     101             : 
     102           0 :         state->tree = io->out.tree;
     103             : 
     104           0 :         num_connected++;
     105             : 
     106           0 :         DEBUG(0,("[%u] reconnect to %s finished (%u connected)\n",
     107             :                  state->client_num, state->dest_host, num_connected));
     108             : 
     109           0 :         state->open_fnum = -1;
     110           0 :         state->close_fnum = -1;
     111           0 :         next_open(state);
     112             : }
     113             : 
     114             :         
     115             : 
     116             : /*
     117             :   reopen a connection
     118             :  */
     119           0 : static void reopen_connection(struct tevent_context *ev, struct tevent_timer *te, 
     120             :                               struct timeval t, void *private_data)
     121             : {
     122           0 :         struct benchopen_state *state = (struct benchopen_state *)private_data;
     123           0 :         struct composite_context *ctx;
     124           0 :         struct smb_composite_connect *io = &state->reconnect;
     125           0 :         char *host, *share;
     126             : 
     127           0 :         state->te = NULL;
     128             : 
     129           0 :         if (!torture_get_conn_index(state->client_num, state->mem_ctx, state->tctx, &host, &share)) {
     130           0 :                 DEBUG(0,("Can't find host/share for reconnect?!\n"));
     131           0 :                 exit(1);
     132             :         }
     133             : 
     134           0 :         io->in.dest_host    = state->dest_host;
     135           0 :         io->in.dest_ports   = state->dest_ports;
     136           0 :         io->in.socket_options = lpcfg_socket_options(state->tctx->lp_ctx);
     137           0 :         io->in.called_name  = state->called_name;
     138           0 :         io->in.service      = share;
     139           0 :         io->in.service_type = state->service_type;
     140           0 :         io->in.credentials  = samba_cmdline_get_creds();
     141           0 :         io->in.fallback_to_anonymous = false;
     142           0 :         io->in.workgroup    = lpcfg_workgroup(state->tctx->lp_ctx);
     143           0 :         io->in.gensec_settings = lpcfg_gensec_settings(state->mem_ctx, state->tctx->lp_ctx);
     144           0 :         lpcfg_smbcli_options(state->tctx->lp_ctx, &io->in.options);
     145           0 :         lpcfg_smbcli_session_options(state->tctx->lp_ctx, &io->in.session_options);
     146             : 
     147             :         /* kill off the remnants of the old connection */
     148           0 :         talloc_free(state->tree);
     149           0 :         state->tree = NULL;
     150           0 :         state->open_fnum = -1;
     151           0 :         state->close_fnum = -1;
     152             : 
     153           0 :         ctx = smb_composite_connect_send(io, state->mem_ctx, 
     154           0 :                                          lpcfg_resolve_context(state->tctx->lp_ctx),
     155             :                                          state->ev);
     156           0 :         if (ctx == NULL) {
     157           0 :                 DEBUG(0,("Failed to setup async reconnect\n"));
     158           0 :                 exit(1);
     159             :         }
     160             : 
     161           0 :         ctx->async.fn = reopen_connection_complete;
     162           0 :         ctx->async.private_data = state;
     163           0 : }
     164             : 
     165             : static void open_completed(struct smbcli_request *req);
     166             : static void close_completed(struct smbcli_request *req);
     167             : 
     168             : 
     169           0 : static void next_open(struct benchopen_state *state)
     170             : {
     171           0 :         state->count++;
     172             : 
     173           0 :         state->pending_file_num = state->next_file_num;
     174           0 :         state->next_file_num = (state->next_file_num+1) % (3*nprocs);
     175             : 
     176           0 :         DEBUG(2,("[%d] opening %u\n", state->client_num, state->pending_file_num));
     177           0 :         state->open_parms.ntcreatex.level = RAW_OPEN_NTCREATEX;
     178           0 :         state->open_parms.ntcreatex.in.flags = 0;
     179           0 :         state->open_parms.ntcreatex.in.root_fid.fnum = 0;
     180           0 :         state->open_parms.ntcreatex.in.access_mask = SEC_RIGHTS_FILE_ALL;
     181           0 :         state->open_parms.ntcreatex.in.file_attr = FILE_ATTRIBUTE_NORMAL;
     182           0 :         state->open_parms.ntcreatex.in.alloc_size = 0;
     183           0 :         state->open_parms.ntcreatex.in.share_access = 0;
     184           0 :         state->open_parms.ntcreatex.in.open_disposition = NTCREATEX_DISP_OVERWRITE_IF;
     185           0 :         state->open_parms.ntcreatex.in.create_options = 0;
     186           0 :         state->open_parms.ntcreatex.in.impersonation = 0;
     187           0 :         state->open_parms.ntcreatex.in.security_flags = 0;
     188           0 :         state->open_parms.ntcreatex.in.fname = fnames[state->pending_file_num];
     189             : 
     190           0 :         state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
     191           0 :         state->req_open->async.fn = open_completed;
     192           0 :         state->req_open->async.private_data = state;
     193           0 : }
     194             : 
     195             : 
     196           0 : static void next_close(struct benchopen_state *state)
     197             : {
     198           0 :         if (state->close_fnum == -1) {
     199           0 :                 return;
     200             :         }
     201           0 :         DEBUG(2,("[%d] closing %d (fnum[%d])\n",
     202             :                  state->client_num, state->close_file_num, state->close_fnum));
     203           0 :         state->close_parms.close.level = RAW_CLOSE_CLOSE;
     204           0 :         state->close_parms.close.in.file.fnum = state->close_fnum;
     205           0 :         state->close_parms.close.in.write_time = 0;
     206             : 
     207           0 :         state->req_close = smb_raw_close_send(state->tree, &state->close_parms);
     208           0 :         state->req_close->async.fn = close_completed;
     209           0 :         state->req_close->async.private_data = state;
     210             : }
     211             : 
     212             : /*
     213             :   called when a open completes
     214             : */
     215           0 : static void open_completed(struct smbcli_request *req)
     216             : {
     217           0 :         struct benchopen_state *state = (struct benchopen_state *)req->async.private_data;
     218           0 :         TALLOC_CTX *tmp_ctx = talloc_new(state->mem_ctx);
     219           0 :         NTSTATUS status;
     220             : 
     221           0 :         status = smb_raw_open_recv(req, tmp_ctx, &state->open_parms);
     222             : 
     223           0 :         talloc_free(tmp_ctx);
     224             : 
     225           0 :         state->req_open = NULL;
     226             : 
     227           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
     228           0 :             NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
     229           0 :             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
     230           0 :                 talloc_free(state->tree);
     231           0 :                 talloc_free(state->cli);
     232           0 :                 state->tree = NULL;
     233           0 :                 state->cli = NULL;
     234           0 :                 num_connected--;        
     235           0 :                 DEBUG(0,("[%u] reopening connection to %s\n",
     236             :                          state->client_num, state->dest_host));
     237           0 :                 talloc_free(state->te);
     238           0 :                 state->te = tevent_add_timer(state->ev, state->mem_ctx,
     239             :                                             timeval_current_ofs(1,0), 
     240             :                                             reopen_connection, state);
     241           0 :                 return;
     242             :         }
     243             : 
     244           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION)) {
     245           0 :                 DEBUG(2,("[%d] retrying open %d\n",
     246             :                          state->client_num, state->pending_file_num));
     247           0 :                 state->open_retries++;
     248           0 :                 state->req_open = smb_raw_open_send(state->tree, &state->open_parms);
     249           0 :                 state->req_open->async.fn = open_completed;
     250           0 :                 state->req_open->async.private_data = state;
     251           0 :                 return;
     252             :         }
     253             : 
     254           0 :         if (!NT_STATUS_IS_OK(status)) {
     255           0 :                 open_failed++;
     256           0 :                 DEBUG(0,("[%u] open failed %d - %s\n",
     257             :                          state->client_num, state->pending_file_num,
     258             :                          nt_errstr(status)));
     259           0 :                 return;
     260             :         }
     261             : 
     262           0 :         state->close_file_num = state->open_file_num;
     263           0 :         state->close_fnum = state->open_fnum;
     264           0 :         state->open_file_num = state->pending_file_num;
     265           0 :         state->open_fnum = state->open_parms.ntcreatex.out.file.fnum;
     266             : 
     267           0 :         DEBUG(2,("[%d] open completed %d (fnum[%d])\n",
     268             :                  state->client_num, state->open_file_num, state->open_fnum));
     269             : 
     270           0 :         if (state->close_fnum != -1) {
     271           0 :                 next_close(state);
     272             :         }
     273             : 
     274           0 :         next_open(state);
     275             : }       
     276             : 
     277             : /*
     278             :   called when a close completes
     279             : */
     280           0 : static void close_completed(struct smbcli_request *req)
     281             : {
     282           0 :         struct benchopen_state *state = (struct benchopen_state *)req->async.private_data;
     283           0 :         NTSTATUS status = smbcli_request_simple_recv(req);
     284             : 
     285           0 :         state->req_close = NULL;
     286             : 
     287           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
     288           0 :             NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
     289           0 :             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
     290           0 :                 talloc_free(state->tree);
     291           0 :                 talloc_free(state->cli);
     292           0 :                 state->tree = NULL;
     293           0 :                 state->cli = NULL;
     294           0 :                 num_connected--;        
     295           0 :                 DEBUG(0,("[%u] reopening connection to %s\n",
     296             :                          state->client_num, state->dest_host));
     297           0 :                 talloc_free(state->te);
     298           0 :                 state->te = tevent_add_timer(state->ev, state->mem_ctx,
     299             :                                             timeval_current_ofs(1,0), 
     300             :                                             reopen_connection, state);
     301           0 :                 return;
     302             :         }
     303             : 
     304           0 :         if (!NT_STATUS_IS_OK(status)) {
     305           0 :                 close_failed++;
     306           0 :                 DEBUG(0,("[%u] close failed %d (fnum[%d]) - %s\n",
     307             :                          state->client_num, state->close_file_num,
     308             :                          state->close_fnum,
     309             :                          nt_errstr(status)));
     310           0 :                 return;
     311             :         }
     312             : 
     313           0 :         DEBUG(2,("[%d] close completed %d (fnum[%d])\n",
     314             :                  state->client_num, state->close_file_num,
     315             :                  state->close_fnum));
     316             : }       
     317             : 
     318           0 : static void echo_completion(struct smbcli_request *req)
     319             : {
     320           0 :         struct benchopen_state *state = (struct benchopen_state *)req->async.private_data;
     321           0 :         NTSTATUS status = smbcli_request_simple_recv(req);
     322           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE) ||
     323           0 :             NT_STATUS_EQUAL(status, NT_STATUS_LOCAL_DISCONNECT) ||
     324           0 :             NT_STATUS_EQUAL(status, NT_STATUS_CONNECTION_RESET)) {
     325           0 :                 talloc_free(state->tree);
     326           0 :                 state->tree = NULL;
     327           0 :                 num_connected--;        
     328           0 :                 DEBUG(0,("[%u] reopening connection to %s\n",
     329             :                          state->client_num, state->dest_host));
     330           0 :                 talloc_free(state->te);
     331           0 :                 state->te = tevent_add_timer(state->ev, state->mem_ctx,
     332             :                                             timeval_current_ofs(1,0), 
     333             :                                             reopen_connection, state);
     334             :         }
     335           0 : }
     336             : 
     337           0 : static void report_rate(struct tevent_context *ev, struct tevent_timer *te, 
     338             :                         struct timeval t, void *private_data)
     339             : {
     340           0 :         struct benchopen_state *state = talloc_get_type(private_data, 
     341             :                                                         struct benchopen_state);
     342           0 :         int i;
     343           0 :         for (i=0;i<nprocs;i++) {
     344           0 :                 printf("%5u ", (unsigned)(state[i].count - state[i].lastcount));
     345           0 :                 state[i].lastcount = state[i].count;
     346             :         }
     347           0 :         printf("\r");
     348           0 :         fflush(stdout);
     349           0 :         report_te = tevent_add_timer(ev, state, timeval_current_ofs(1, 0),
     350             :                                     report_rate, state);
     351             : 
     352             :         /* send an echo on each interface to ensure it stays alive - this helps
     353             :            with IP takeover */
     354           0 :         for (i=0;i<nprocs;i++) {
     355           0 :                 struct smb_echo p;
     356           0 :                 struct smbcli_request *req;
     357             : 
     358           0 :                 if (!state[i].tree) {
     359           0 :                         continue;
     360             :                 }
     361             : 
     362           0 :                 p.in.repeat_count = 1;
     363           0 :                 p.in.size = 0;
     364           0 :                 p.in.data = NULL;
     365           0 :                 req = smb_raw_echo_send(state[i].tree->session->transport, &p);
     366           0 :                 req->async.private_data = &state[i];
     367           0 :                 req->async.fn      = echo_completion;
     368             :         }
     369           0 : }
     370             : 
     371             : /* 
     372             :    benchmark open calls
     373             : */
     374           0 : bool torture_bench_open(struct torture_context *torture)
     375             : {
     376           0 :         bool ret = true;
     377           0 :         TALLOC_CTX *mem_ctx = talloc_new(torture);
     378           0 :         int i;
     379           0 :         int timelimit = torture_setting_int(torture, "timelimit", 10);
     380           0 :         struct timeval tv;
     381           0 :         struct benchopen_state *state;
     382           0 :         int total = 0;
     383           0 :         int total_retries = 0;
     384           0 :         int minops = 0;
     385           0 :         bool progress=false;
     386             : 
     387           0 :         progress = torture_setting_bool(torture, "progress", true);
     388             :         
     389           0 :         nprocs = torture_setting_int(torture, "nprocs", 4);
     390             : 
     391           0 :         state = talloc_zero_array(mem_ctx, struct benchopen_state, nprocs);
     392             : 
     393           0 :         printf("Opening %d connections\n", nprocs);
     394           0 :         for (i=0;i<nprocs;i++) {
     395           0 :                 const struct sockaddr_storage *dest_ss;
     396           0 :                 char addrstr[INET6_ADDRSTRLEN];
     397           0 :                 const char *dest_str;
     398           0 :                 uint16_t dest_port;
     399             : 
     400           0 :                 state[i].tctx = torture;
     401           0 :                 state[i].mem_ctx = talloc_new(state);
     402           0 :                 state[i].client_num = i;
     403           0 :                 state[i].ev = torture->ev;
     404           0 :                 if (!torture_open_connection_ev(&state[i].cli, i, torture, torture->ev)) {
     405           0 :                         return false;
     406             :                 }
     407           0 :                 talloc_steal(state[i].mem_ctx, state[i].cli);
     408           0 :                 state[i].tree = state[i].cli->tree;
     409             : 
     410           0 :                 dest_ss = smbXcli_conn_remote_sockaddr(
     411           0 :                                 state[i].tree->session->transport->conn);
     412           0 :                 dest_str = print_sockaddr(addrstr, sizeof(addrstr), dest_ss);
     413           0 :                 dest_port = get_sockaddr_port(dest_ss);
     414             : 
     415           0 :                 state[i].dest_host = talloc_strdup(state[i].mem_ctx, dest_str);
     416           0 :                 state[i].dest_ports = talloc_array(state[i].mem_ctx, 
     417             :                                                    const char *, 2);
     418           0 :                 state[i].dest_ports[0] = talloc_asprintf(state[i].dest_ports, 
     419             :                                                          "%u", dest_port);
     420           0 :                 state[i].dest_ports[1] = NULL;
     421           0 :                 state[i].called_name  = talloc_strdup(state[i].mem_ctx,
     422           0 :                                 smbXcli_conn_remote_name(state[i].tree->session->transport->conn));
     423           0 :                 state[i].service_type = talloc_strdup(state[i].mem_ctx, "?????");
     424             :         }
     425             : 
     426           0 :         num_connected = i;
     427             : 
     428           0 :         if (!torture_setup_dir(state[0].cli, BASEDIR)) {
     429           0 :                 goto failed;
     430             :         }
     431             : 
     432           0 :         fnames = talloc_array(mem_ctx, char *, 3*nprocs);
     433           0 :         for (i=0;i<3*nprocs;i++) {
     434           0 :                 fnames[i] = talloc_asprintf(fnames, "%s\\file%d.dat", BASEDIR, i);
     435             :         }
     436             : 
     437           0 :         for (i=0;i<nprocs;i++) {
     438             :                 /* all connections start with the same file */
     439           0 :                 state[i].next_file_num = 0;
     440           0 :                 state[i].open_fnum = -1;
     441           0 :                 state[i].close_fnum = -1;
     442           0 :                 next_open(&state[i]);
     443             :         }
     444             : 
     445           0 :         tv = timeval_current(); 
     446             : 
     447           0 :         if (progress) {
     448           0 :                 report_te = tevent_add_timer(torture->ev, state, timeval_current_ofs(1, 0),
     449             :                                             report_rate, state);
     450             :         }
     451             : 
     452           0 :         printf("Running for %d seconds\n", timelimit);
     453           0 :         while (timeval_elapsed(&tv) < timelimit) {
     454           0 :                 tevent_loop_once(torture->ev);
     455             : 
     456           0 :                 if (open_failed) {
     457           0 :                         DEBUG(0,("open failed\n"));
     458           0 :                         goto failed;
     459             :                 }
     460           0 :                 if (close_failed) {
     461           0 :                         DEBUG(0,("open failed\n"));
     462           0 :                         goto failed;
     463             :                 }
     464             :         }
     465             : 
     466           0 :         talloc_free(report_te);
     467           0 :         if (progress) {
     468           0 :                 for (i=0;i<nprocs;i++) {
     469           0 :                         printf("      ");
     470             :                 }
     471           0 :                 printf("\r");
     472             :         }
     473             : 
     474           0 :         minops = state[0].count;
     475           0 :         for (i=0;i<nprocs;i++) {
     476           0 :                 total += state[i].count;
     477           0 :                 total_retries += state[i].open_retries;
     478           0 :                 printf("[%d] %u ops (%u retries)\n",
     479           0 :                        i, state[i].count, state[i].open_retries);
     480           0 :                 if (state[i].count < minops) minops = state[i].count;
     481             :         }
     482           0 :         printf("%.2f ops/second (%d retries)\n",
     483           0 :                total/timeval_elapsed(&tv), total_retries);
     484           0 :         if (minops < 0.5*total/nprocs) {
     485           0 :                 printf("Failed: unbalanced open\n");
     486           0 :                 goto failed;
     487             :         }
     488             : 
     489           0 :         for (i=0;i<nprocs;i++) {
     490           0 :                 talloc_free(state[i].req_open);
     491           0 :                 talloc_free(state[i].req_close);
     492           0 :                 smb_raw_exit(state[i].tree->session);
     493             :         }
     494             : 
     495           0 :         smbcli_deltree(state[0].tree, BASEDIR);
     496           0 :         talloc_free(mem_ctx);
     497           0 :         return ret;
     498             : 
     499           0 : failed:
     500           0 :         talloc_free(mem_ctx);
     501           0 :         return false;
     502             : }

Generated by: LCOV version 1.14