2006-06-17 06:20:39 +04:00
/*
Unix SMB / CIFS implementation .
SMB torture tester
Copyright ( C ) Andrew Tridgell 1997 - 2003
Copyright ( C ) Jelmer Vernooij 2006
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2006-06-17 06:20:39 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2006-06-17 06:20:39 +04:00
*/
# include "includes.h"
# include "libcli/raw/libcliraw.h"
2008-04-02 06:53:27 +04:00
# include "libcli/raw/raw_proto.h"
2006-06-17 06:20:39 +04:00
# include "system/time.h"
# include "system/wait.h"
# include "system/filesys.h"
# include "libcli/raw/ioctl.h"
# include "libcli/libcli.h"
# include "lib/events/events.h"
# include "libcli/resolve/resolve.h"
# include "auth/credentials/credentials.h"
# include "librpc/gen_ndr/ndr_nbt.h"
2008-04-27 17:02:46 +04:00
# include "torture/smbtorture.h"
2006-06-17 06:20:39 +04:00
# include "torture/util.h"
2006-08-10 15:51:43 +04:00
# include "libcli/smb_composite/smb_composite.h"
# include "libcli/composite/composite.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2006-08-10 15:51:43 +04:00
extern struct cli_credentials * cmdline_credentials ;
2007-10-07 02:28:14 +04:00
static bool wait_lock ( struct smbcli_state * c , int fnum , uint32_t offset , uint32_t len )
2006-06-17 06:20:39 +04:00
{
while ( NT_STATUS_IS_ERR ( smbcli_lock ( c - > tree , fnum , offset , len , - 1 , WRITE_LOCK ) ) ) {
2007-10-07 02:28:14 +04:00
if ( ! check_error ( __location__ , c , ERRDOS , ERRlock , NT_STATUS_LOCK_NOT_GRANTED ) ) return false ;
2006-06-17 06:20:39 +04:00
}
2007-10-07 02:28:14 +04:00
return true ;
2006-06-17 06:20:39 +04:00
}
2007-10-07 02:28:14 +04:00
static bool rw_torture ( struct torture_context * tctx , struct smbcli_state * c )
2006-06-17 06:20:39 +04:00
{
const char * lockfname = " \\ torture.lck " ;
char * fname ;
int fnum ;
int fnum2 ;
pid_t pid2 , pid = getpid ( ) ;
int i , j ;
uint8_t buf [ 1024 ] ;
2007-10-07 02:28:14 +04:00
bool correct = true ;
2006-06-17 06:20:39 +04:00
fnum2 = smbcli_open ( c - > tree , lockfname , O_RDWR | O_CREAT | O_EXCL ,
DENY_NONE ) ;
if ( fnum2 = = - 1 )
fnum2 = smbcli_open ( c - > tree , lockfname , O_RDWR , DENY_NONE ) ;
if ( fnum2 = = - 1 ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " open of %s failed (%s) \n " , lockfname , smbcli_errstr ( c - > tree ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-06-17 06:20:39 +04:00
}
2007-02-23 16:15:56 +03:00
generate_random_buffer ( buf , sizeof ( buf ) ) ;
2006-06-17 06:20:39 +04:00
for ( i = 0 ; i < torture_numops ; i + + ) {
uint_t n = ( uint_t ) random ( ) % 10 ;
if ( i % 10 = = 0 ) {
2007-04-30 01:37:29 +04:00
if ( torture_setting_bool ( tctx , " progress " , true ) ) {
torture_comment ( tctx , " %d \r " , i ) ;
fflush ( stdout ) ;
}
2006-06-17 06:20:39 +04:00
}
asprintf ( & fname , " \\ torture.%u " , n ) ;
if ( ! wait_lock ( c , fnum2 , n * sizeof ( int ) , sizeof ( int ) ) ) {
2007-10-07 02:28:14 +04:00
return false ;
2006-06-17 06:20:39 +04:00
}
fnum = smbcli_open ( c - > tree , fname , O_RDWR | O_CREAT | O_TRUNC , DENY_ALL ) ;
if ( fnum = = - 1 ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " open failed (%s) \n " , smbcli_errstr ( c - > tree ) ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
break ;
}
if ( smbcli_write ( c - > tree , fnum , 0 , & pid , 0 , sizeof ( pid ) ) ! = sizeof ( pid ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " write failed (%s) \n " , smbcli_errstr ( c - > tree ) ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
for ( j = 0 ; j < 50 ; j + + ) {
if ( smbcli_write ( c - > tree , fnum , 0 , buf ,
sizeof ( pid ) + ( j * sizeof ( buf ) ) ,
sizeof ( buf ) ) ! = sizeof ( buf ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " write failed (%s) \n " , smbcli_errstr ( c - > tree ) ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
}
pid2 = 0 ;
if ( smbcli_read ( c - > tree , fnum , & pid2 , 0 , sizeof ( pid ) ) ! = sizeof ( pid ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " read failed (%s) \n " , smbcli_errstr ( c - > tree ) ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
if ( pid2 ! = pid ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " data corruption! \n " ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
if ( NT_STATUS_IS_ERR ( smbcli_close ( c - > tree , fnum ) ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " close failed (%s) \n " , smbcli_errstr ( c - > tree ) ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
if ( NT_STATUS_IS_ERR ( smbcli_unlink ( c - > tree , fname ) ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " unlink failed (%s) \n " , smbcli_errstr ( c - > tree ) ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
if ( NT_STATUS_IS_ERR ( smbcli_unlock ( c - > tree , fnum2 , n * sizeof ( int ) , sizeof ( int ) ) ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " unlock failed (%s) \n " , smbcli_errstr ( c - > tree ) ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
free ( fname ) ;
}
smbcli_close ( c - > tree , fnum2 ) ;
smbcli_unlink ( c - > tree , lockfname ) ;
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " %d \n " , i ) ;
2006-06-17 06:20:39 +04:00
return correct ;
}
2007-10-07 02:28:14 +04:00
bool run_torture ( struct torture_context * tctx , struct smbcli_state * cli , int dummy )
2006-06-17 06:20:39 +04:00
{
2006-10-16 17:06:41 +04:00
return rw_torture ( tctx , cli ) ;
2006-06-17 06:20:39 +04:00
}
/*
see how many RPC pipes we can open at once
*/
2007-10-07 02:28:14 +04:00
bool run_pipe_number ( struct torture_context * tctx ,
2006-10-16 17:06:41 +04:00
struct smbcli_state * cli1 )
2006-06-17 06:20:39 +04:00
{
const char * pipe_name = " \\ WKSSVC " ;
int fnum ;
int num_pipes = 0 ;
while ( 1 ) {
fnum = smbcli_nt_create_full ( cli1 - > tree , pipe_name , 0 , SEC_FILE_READ_DATA , FILE_ATTRIBUTE_NORMAL ,
NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE , NTCREATEX_DISP_OPEN_IF , 0 , 0 ) ;
if ( fnum = = - 1 ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Open of pipe %s failed with error (%s) \n " , pipe_name , smbcli_errstr ( cli1 - > tree ) ) ;
2006-06-17 06:20:39 +04:00
break ;
}
num_pipes + + ;
2007-04-30 01:37:29 +04:00
if ( torture_setting_bool ( tctx , " progress " , true ) ) {
torture_comment ( tctx , " %d \r " , num_pipes ) ;
fflush ( stdout ) ;
}
2006-06-17 06:20:39 +04:00
}
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " pipe_number test - we can open %d %s pipes. \n " , num_pipes , pipe_name ) ;
2007-10-07 02:28:14 +04:00
return true ;
2006-06-17 06:20:39 +04:00
}
/*
open N connections to the server and just hold them open
used for testing performance when there are N idle users
already connected
*/
2007-10-07 02:28:14 +04:00
bool torture_holdcon ( struct torture_context * tctx )
2006-06-17 06:20:39 +04:00
{
int i ;
struct smbcli_state * * cli ;
int num_dead = 0 ;
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Opening %d connections \n " , torture_numops ) ;
2006-06-17 06:20:39 +04:00
cli = malloc_array_p ( struct smbcli_state * , torture_numops ) ;
for ( i = 0 ; i < torture_numops ; i + + ) {
2007-12-03 17:53:07 +03:00
if ( ! torture_open_connection ( & cli [ i ] , tctx , i ) ) {
2007-10-07 02:28:14 +04:00
return false ;
2006-06-17 06:20:39 +04:00
}
2007-04-30 01:37:29 +04:00
if ( torture_setting_bool ( tctx , " progress " , true ) ) {
torture_comment ( tctx , " opened %d connections \r " , i ) ;
fflush ( stdout ) ;
}
2006-06-17 06:20:39 +04:00
}
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " \n Starting pings \n " ) ;
2006-06-17 06:20:39 +04:00
while ( 1 ) {
for ( i = 0 ; i < torture_numops ; i + + ) {
NTSTATUS status ;
if ( cli [ i ] ) {
status = smbcli_chkpath ( cli [ i ] - > tree , " \\ " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Connection %d is dead \n " , i ) ;
2006-06-17 06:20:39 +04:00
cli [ i ] = NULL ;
num_dead + + ;
}
usleep ( 100 ) ;
}
}
if ( num_dead = = torture_numops ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " All connections dead - finishing \n " ) ;
2006-06-17 06:20:39 +04:00
break ;
}
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " . " ) ;
2006-06-17 06:20:39 +04:00
fflush ( stdout ) ;
}
2007-10-07 02:28:14 +04:00
return true ;
2006-06-17 06:20:39 +04:00
}
/*
test how many open files this server supports on the one socket
*/
2007-10-07 02:28:14 +04:00
bool run_maxfidtest ( struct torture_context * tctx , struct smbcli_state * cli , int dummy )
2006-06-17 06:20:39 +04:00
{
# define MAXFID_TEMPLATE "\\maxfid\\fid%d\\maxfid.%d.%d"
char * fname ;
int fnums [ 0x11000 ] , i ;
int retries = 4 , maxfid ;
2007-10-07 02:28:14 +04:00
bool correct = true ;
2006-06-17 06:20:39 +04:00
if ( retries < = 0 ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " failed to connect \n " ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-06-17 06:20:39 +04:00
}
if ( smbcli_deltree ( cli - > tree , " \\ maxfid " ) = = - 1 ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Failed to deltree \\ maxfid - %s \n " ,
2006-06-17 06:20:39 +04:00
smbcli_errstr ( cli - > tree ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-06-17 06:20:39 +04:00
}
if ( NT_STATUS_IS_ERR ( smbcli_mkdir ( cli - > tree , " \\ maxfid " ) ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Failed to mkdir \\ maxfid, error=%s \n " ,
2006-06-17 06:20:39 +04:00
smbcli_errstr ( cli - > tree ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-06-17 06:20:39 +04:00
}
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Testing maximum number of open files \n " ) ;
2006-06-17 06:20:39 +04:00
for ( i = 0 ; i < 0x11000 ; i + + ) {
if ( i % 1000 = = 0 ) {
asprintf ( & fname , " \\ maxfid \\ fid%d " , i / 1000 ) ;
if ( NT_STATUS_IS_ERR ( smbcli_mkdir ( cli - > tree , fname ) ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Failed to mkdir %s, error=%s \n " ,
2006-06-17 06:20:39 +04:00
fname , smbcli_errstr ( cli - > tree ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-06-17 06:20:39 +04:00
}
free ( fname ) ;
}
asprintf ( & fname , MAXFID_TEMPLATE , i / 1000 , i , ( int ) getpid ( ) ) ;
if ( ( fnums [ i ] = smbcli_open ( cli - > tree , fname ,
O_RDWR | O_CREAT | O_TRUNC , DENY_NONE ) ) = =
- 1 ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " open of %s failed (%s) \n " ,
2006-06-17 06:20:39 +04:00
fname , smbcli_errstr ( cli - > tree ) ) ;
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " maximum fnum is %d \n " , i ) ;
2006-06-17 06:20:39 +04:00
break ;
}
free ( fname ) ;
2007-04-30 01:37:29 +04:00
if ( torture_setting_bool ( tctx , " progress " , true ) ) {
torture_comment ( tctx , " %6d \r " , i ) ;
fflush ( stdout ) ;
}
2006-06-17 06:20:39 +04:00
}
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " %6d \n " , i ) ;
2006-06-17 06:20:39 +04:00
i - - ;
maxfid = i ;
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " cleaning up \n " ) ;
2006-06-17 06:20:39 +04:00
for ( i = 0 ; i < maxfid / 2 ; i + + ) {
asprintf ( & fname , MAXFID_TEMPLATE , i / 1000 , i , ( int ) getpid ( ) ) ;
if ( NT_STATUS_IS_ERR ( smbcli_close ( cli - > tree , fnums [ i ] ) ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Close of fnum %d failed - %s \n " , fnums [ i ] , smbcli_errstr ( cli - > tree ) ) ;
2006-06-17 06:20:39 +04:00
}
if ( NT_STATUS_IS_ERR ( smbcli_unlink ( cli - > tree , fname ) ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " unlink of %s failed (%s) \n " ,
2006-06-17 06:20:39 +04:00
fname , smbcli_errstr ( cli - > tree ) ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
free ( fname ) ;
asprintf ( & fname , MAXFID_TEMPLATE , ( maxfid - i ) / 1000 , maxfid - i , ( int ) getpid ( ) ) ;
if ( NT_STATUS_IS_ERR ( smbcli_close ( cli - > tree , fnums [ maxfid - i ] ) ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Close of fnum %d failed - %s \n " , fnums [ maxfid - i ] , smbcli_errstr ( cli - > tree ) ) ;
2006-06-17 06:20:39 +04:00
}
if ( NT_STATUS_IS_ERR ( smbcli_unlink ( cli - > tree , fname ) ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " unlink of %s failed (%s) \n " ,
2006-06-17 06:20:39 +04:00
fname , smbcli_errstr ( cli - > tree ) ) ;
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
free ( fname ) ;
2007-04-30 01:37:29 +04:00
if ( torture_setting_bool ( tctx , " progress " , true ) ) {
torture_comment ( tctx , " %6d %6d \r " , i , maxfid - i ) ;
fflush ( stdout ) ;
}
2006-06-17 06:20:39 +04:00
}
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " %6d \n " , 0 ) ;
2006-06-17 06:20:39 +04:00
if ( smbcli_deltree ( cli - > tree , " \\ maxfid " ) = = - 1 ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Failed to deltree \\ maxfid - %s \n " ,
2006-06-17 06:20:39 +04:00
smbcli_errstr ( cli - > tree ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-06-17 06:20:39 +04:00
}
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " maxfid test finished \n " ) ;
2006-06-17 06:20:39 +04:00
if ( ! torture_close_connection ( cli ) ) {
2007-10-07 02:28:14 +04:00
correct = false ;
2006-06-17 06:20:39 +04:00
}
return correct ;
# undef MAXFID_TEMPLATE
}
/*
sees what IOCTLs are supported
*/
2007-10-07 02:28:14 +04:00
bool torture_ioctl_test ( struct torture_context * tctx ,
2006-10-16 17:06:41 +04:00
struct smbcli_state * cli )
2006-06-17 06:20:39 +04:00
{
uint16_t device , function ;
int fnum ;
const char * fname = " \\ ioctl.dat " ;
NTSTATUS status ;
union smb_ioctl parms ;
TALLOC_CTX * mem_ctx ;
2006-10-16 17:06:41 +04:00
mem_ctx = talloc_named_const ( tctx , 0 , " ioctl_test " ) ;
2006-06-17 06:20:39 +04:00
smbcli_unlink ( cli - > tree , fname ) ;
fnum = smbcli_open ( cli - > tree , fname , O_RDWR | O_CREAT | O_EXCL , DENY_NONE ) ;
if ( fnum = = - 1 ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " open of %s failed (%s) \n " , fname , smbcli_errstr ( cli - > tree ) ) ;
2007-10-07 02:28:14 +04:00
return false ;
2006-06-17 06:20:39 +04:00
}
parms . ioctl . level = RAW_IOCTL_IOCTL ;
parms . ioctl . in . file . fnum = fnum ;
parms . ioctl . in . request = IOCTL_QUERY_JOB_INFO ;
status = smb_raw_ioctl ( cli - > tree , mem_ctx , & parms ) ;
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " ioctl job info: %s \n " , smbcli_errstr ( cli - > tree ) ) ;
2006-06-17 06:20:39 +04:00
for ( device = 0 ; device < 0x100 ; device + + ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " testing device=0x%x \n " , device ) ;
2006-06-17 06:20:39 +04:00
for ( function = 0 ; function < 0x100 ; function + + ) {
parms . ioctl . in . request = ( device < < 16 ) | function ;
status = smb_raw_ioctl ( cli - > tree , mem_ctx , & parms ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " ioctl device=0x%x function=0x%x OK : %d bytes \n " ,
2006-06-17 06:20:39 +04:00
device , function , ( int ) parms . ioctl . out . blob . length ) ;
}
}
}
2007-10-07 02:28:14 +04:00
return true ;
2006-06-17 06:20:39 +04:00
}
2007-02-11 13:42:48 +03:00
static void benchrw_callback ( struct smbcli_request * req ) ;
enum benchrw_stage {
START ,
OPEN_CONNECTION ,
CLEANUP_TESTDIR ,
MK_TESTDIR ,
OPEN_FILE ,
INITIAL_WRITE ,
READ_WRITE_DATA ,
MAX_OPS_REACHED ,
ERROR ,
CLOSE_FILE ,
CLEANUP ,
FINISHED
} ;
struct benchrw_state {
struct torture_context * tctx ;
char * dname ;
char * fname ;
uint16_t fnum ;
int nr ;
struct smbcli_tree * cli ;
uint8_t * buffer ;
int writecnt ;
int readcnt ;
int completed ;
2007-02-11 15:03:25 +03:00
int num_parallel_requests ;
2007-02-11 13:42:48 +03:00
void * req_params ;
enum benchrw_stage mode ;
struct params {
struct unclist {
const char * host ;
const char * share ;
} * * unc ;
const char * workgroup ;
int retry ;
unsigned int writeblocks ;
unsigned int blocksize ;
unsigned int writeratio ;
2007-02-11 15:03:25 +03:00
int num_parallel_requests ;
2007-02-11 13:42:48 +03:00
} * lp_params ;
} ;
2006-08-10 15:51:43 +04:00
/*
init params using lp_parm_xxx
return number of unclist entries
*/
2007-02-11 13:42:48 +03:00
static int init_benchrw_params ( struct torture_context * tctx ,
struct params * lpar )
2006-08-10 15:51:43 +04:00
{
2006-08-13 14:20:21 +04:00
char * * unc_list = NULL ;
int num_unc_names = 0 , conn_index = 0 , empty_lines = 0 ;
const char * p ;
2006-10-18 18:23:19 +04:00
lpar - > retry = torture_setting_int ( tctx , " retry " , 3 ) ;
lpar - > blocksize = torture_setting_int ( tctx , " blocksize " , 65535 ) ;
lpar - > writeblocks = torture_setting_int ( tctx , " writeblocks " , 15 ) ;
lpar - > writeratio = torture_setting_int ( tctx , " writeratio " , 5 ) ;
2007-02-11 15:03:25 +03:00
lpar - > num_parallel_requests = torture_setting_int (
tctx , " parallel_requests " , 5 ) ;
2007-12-03 02:28:22 +03:00
lpar - > workgroup = lp_workgroup ( tctx - > lp_ctx ) ;
2006-08-10 15:51:43 +04:00
2006-10-18 18:23:19 +04:00
p = torture_setting_string ( tctx , " unclist " , NULL ) ;
2006-08-10 15:51:43 +04:00
if ( p ) {
char * h , * s ;
unc_list = file_lines_load ( p , & num_unc_names , NULL ) ;
if ( ! unc_list | | num_unc_names < = 0 ) {
2007-02-11 13:42:48 +03:00
torture_comment ( tctx , " Failed to load unc names list "
" from '%s' \n " , p ) ;
2006-08-10 15:51:43 +04:00
exit ( 1 ) ;
}
2007-02-11 13:42:48 +03:00
lpar - > unc = talloc_array ( tctx , struct unclist * ,
( num_unc_names - empty_lines ) ) ;
2006-08-10 15:51:43 +04:00
for ( conn_index = 0 ; conn_index < num_unc_names ; conn_index + + ) {
/* ignore empty lines */
if ( strlen ( unc_list [ conn_index % num_unc_names ] ) = = 0 ) {
empty_lines + + ;
continue ;
}
2007-02-11 13:42:48 +03:00
if ( ! smbcli_parse_unc (
unc_list [ conn_index % num_unc_names ] ,
NULL , & h , & s ) ) {
torture_comment (
tctx , " Failed to parse UNC "
" name %s \n " ,
unc_list [ conn_index % num_unc_names ] ) ;
2006-08-10 15:51:43 +04:00
exit ( 1 ) ;
}
2007-02-11 13:42:48 +03:00
lpar - > unc [ conn_index - empty_lines ] =
talloc ( tctx , struct unclist ) ;
lpar - > unc [ conn_index - empty_lines ] - > host = h ;
lpar - > unc [ conn_index - empty_lines ] - > share = s ;
2006-08-10 15:51:43 +04:00
}
return num_unc_names - empty_lines ;
} else {
2006-10-16 17:06:41 +04:00
lpar - > unc = talloc_array ( tctx , struct unclist * , 1 ) ;
lpar - > unc [ 0 ] = talloc ( tctx , struct unclist ) ;
2007-02-11 13:42:48 +03:00
lpar - > unc [ 0 ] - > host = torture_setting_string ( tctx , " host " ,
NULL ) ;
lpar - > unc [ 0 ] - > share = torture_setting_string ( tctx , " share " ,
NULL ) ;
2006-08-10 15:51:43 +04:00
return 1 ;
}
}
/*
Called when the reads & writes are finished . closes the file .
*/
2007-02-11 13:42:48 +03:00
static NTSTATUS benchrw_close ( struct torture_context * tctx ,
struct smbcli_request * req ,
struct benchrw_state * state )
2006-08-10 15:51:43 +04:00
{
union smb_close close_parms ;
NT_STATUS_NOT_OK_RETURN ( req - > status ) ;
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Close file %d (%d) \n " , state - > nr , state - > fnum ) ;
2006-08-10 15:51:43 +04:00
close_parms . close . level = RAW_CLOSE_CLOSE ;
close_parms . close . in . file . fnum = state - > fnum ;
close_parms . close . in . write_time = 0 ;
state - > mode = CLOSE_FILE ;
req = smb_raw_close_send ( state - > cli , & close_parms ) ;
NT_STATUS_HAVE_NO_MEMORY ( req ) ;
/*register the callback function!*/
req - > async . fn = benchrw_callback ;
req - > async . private = state ;
return NT_STATUS_OK ;
}
2007-02-11 15:03:25 +03:00
static NTSTATUS benchrw_readwrite ( struct torture_context * tctx ,
struct benchrw_state * state ) ;
static void benchrw_callback ( struct smbcli_request * req ) ;
static void benchrw_rw_callback ( struct smbcli_request * req )
{
struct benchrw_state * state = req - > async . private ;
struct torture_context * tctx = state - > tctx ;
if ( ! NT_STATUS_IS_OK ( req - > status ) ) {
state - > mode = ERROR ;
return ;
}
state - > completed + + ;
state - > num_parallel_requests - - ;
if ( ( state - > completed > = torture_numops )
& & ( state - > num_parallel_requests = = 0 ) ) {
benchrw_callback ( req ) ;
talloc_free ( req ) ;
return ;
}
talloc_free ( req ) ;
if ( state - > completed + state - > num_parallel_requests
< torture_numops ) {
benchrw_readwrite ( tctx , state ) ;
}
}
2006-08-10 15:51:43 +04:00
/*
Called when the initial write is completed is done . write or read a file .
*/
2007-02-11 13:42:48 +03:00
static NTSTATUS benchrw_readwrite ( struct torture_context * tctx ,
struct benchrw_state * state )
2006-08-10 15:51:43 +04:00
{
2007-02-11 15:03:25 +03:00
struct smbcli_request * req ;
2006-08-10 15:51:43 +04:00
union smb_read rd ;
union smb_write wr ;
2007-02-11 15:03:25 +03:00
/* randomize between writes and reads*/
2007-08-28 04:16:58 +04:00
if ( random ( ) % state - > lp_params - > writeratio = = 0 ) {
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Callback WRITE file:%d (%d/%d) \n " ,
2006-08-10 15:51:43 +04:00
state - > nr , state - > completed , torture_numops ) ;
wr . generic . level = RAW_WRITE_WRITEX ;
wr . writex . in . file . fnum = state - > fnum ;
wr . writex . in . offset = 0 ;
wr . writex . in . wmode = 0 ;
wr . writex . in . remaining = 0 ;
wr . writex . in . count = state - > lp_params - > blocksize ;
wr . writex . in . data = state - > buffer ;
state - > readcnt = 0 ;
req = smb_raw_write_send ( state - > cli , & wr ) ;
2007-02-11 15:03:25 +03:00
}
else {
2007-02-11 13:42:48 +03:00
torture_comment ( tctx ,
" Callback READ file:%d (%d/%d) Offset:%d \n " ,
2006-08-10 15:51:43 +04:00
state - > nr , state - > completed , torture_numops ,
( state - > readcnt * state - > lp_params - > blocksize ) ) ;
2007-06-17 20:46:44 +04:00
rd . generic . level = RAW_READ_READX ;
rd . readx . in . file . fnum = state - > fnum ;
2007-06-18 18:06:04 +04:00
rd . readx . in . offset = state - > readcnt * state - > lp_params - > blocksize ;
2007-06-17 20:46:44 +04:00
rd . readx . in . mincnt = state - > lp_params - > blocksize ;
rd . readx . in . maxcnt = rd . readx . in . mincnt ;
rd . readx . in . remaining = 0 ;
rd . readx . out . data = state - > buffer ;
2007-10-07 02:28:14 +04:00
rd . readx . in . read_for_execute = false ;
2006-08-10 15:51:43 +04:00
if ( state - > readcnt < state - > lp_params - > writeblocks ) {
state - > readcnt + + ;
} else {
/*start reading from beginn of file*/
state - > readcnt = 0 ;
}
req = smb_raw_read_send ( state - > cli , & rd ) ;
}
2007-02-11 15:03:25 +03:00
state - > num_parallel_requests + = 1 ;
2006-08-10 15:51:43 +04:00
NT_STATUS_HAVE_NO_MEMORY ( req ) ;
/*register the callback function!*/
2007-02-11 15:03:25 +03:00
req - > async . fn = benchrw_rw_callback ;
2006-08-10 15:51:43 +04:00
req - > async . private = state ;
return NT_STATUS_OK ;
}
/*
Called when the open is done . writes to the file .
*/
2007-02-11 13:42:48 +03:00
static NTSTATUS benchrw_open ( struct torture_context * tctx ,
struct smbcli_request * req ,
struct benchrw_state * state )
2006-08-10 15:51:43 +04:00
{
union smb_write wr ;
if ( state - > mode = = OPEN_FILE ) {
NTSTATUS status ;
2006-12-20 10:46:22 +03:00
status = smb_raw_open_recv ( req , tctx , (
2006-08-10 15:51:43 +04:00
union smb_open * ) state - > req_params ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
state - > fnum = ( ( union smb_open * ) state - > req_params )
- > openx . out . file . fnum ;
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " File opened (%d) \n " , state - > fnum ) ;
2006-08-10 15:51:43 +04:00
state - > mode = INITIAL_WRITE ;
}
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Write initial test file:%d (%d/%d) \n " , state - > nr ,
2006-08-10 15:51:43 +04:00
( state - > writecnt + 1 ) * state - > lp_params - > blocksize ,
( state - > lp_params - > writeblocks * state - > lp_params - > blocksize ) ) ;
wr . generic . level = RAW_WRITE_WRITEX ;
wr . writex . in . file . fnum = state - > fnum ;
wr . writex . in . offset = state - > writecnt *
state - > lp_params - > blocksize ;
wr . writex . in . wmode = 0 ;
wr . writex . in . remaining = ( state - > lp_params - > writeblocks *
state - > lp_params - > blocksize ) -
( ( state - > writecnt + 1 ) * state - >
lp_params - > blocksize ) ;
wr . writex . in . count = state - > lp_params - > blocksize ;
wr . writex . in . data = state - > buffer ;
state - > writecnt + + ;
if ( state - > writecnt = = state - > lp_params - > writeblocks ) {
state - > mode = READ_WRITE_DATA ;
}
req = smb_raw_write_send ( state - > cli , & wr ) ;
NT_STATUS_HAVE_NO_MEMORY ( req ) ;
/*register the callback function!*/
req - > async . fn = benchrw_callback ;
req - > async . private = state ;
return NT_STATUS_OK ;
}
/*
Called when the mkdir is done . Opens a file .
*/
2007-02-11 13:42:48 +03:00
static NTSTATUS benchrw_mkdir ( struct torture_context * tctx ,
struct smbcli_request * req ,
struct benchrw_state * state )
2006-08-10 15:51:43 +04:00
{
union smb_open * open_parms ;
2006-08-13 16:34:41 +04:00
uint8_t * writedata ;
2006-08-10 15:51:43 +04:00
NT_STATUS_NOT_OK_RETURN ( req - > status ) ;
/* open/create the files */
2006-10-30 03:17:16 +03:00
torture_comment ( tctx , " Open File %d/%d \n " , state - > nr + 1 ,
2007-08-26 22:24:12 +04:00
torture_setting_int ( tctx , " nprocs " , 4 ) ) ;
2006-12-20 10:46:22 +03:00
open_parms = talloc_zero ( tctx , union smb_open ) ;
2006-08-10 15:51:43 +04:00
NT_STATUS_HAVE_NO_MEMORY ( open_parms ) ;
open_parms - > openx . level = RAW_OPEN_OPENX ;
open_parms - > openx . in . flags = 0 ;
open_parms - > openx . in . open_mode = OPENX_MODE_ACCESS_RDWR ;
open_parms - > openx . in . search_attrs =
FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN ;
open_parms - > openx . in . file_attrs = 0 ;
open_parms - > openx . in . write_time = 0 ;
open_parms - > openx . in . open_func = OPENX_OPEN_FUNC_CREATE ;
open_parms - > openx . in . size = 0 ;
open_parms - > openx . in . timeout = 0 ;
open_parms - > openx . in . fname = state - > fname ;
2006-12-20 10:46:22 +03:00
writedata = talloc_size ( tctx , state - > lp_params - > blocksize ) ;
2006-08-10 15:51:43 +04:00
NT_STATUS_HAVE_NO_MEMORY ( writedata ) ;
generate_random_buffer ( writedata , state - > lp_params - > blocksize ) ;
state - > buffer = writedata ;
state - > writecnt = 1 ;
state - > readcnt = 0 ;
state - > req_params = open_parms ;
state - > mode = OPEN_FILE ;
req = smb_raw_open_send ( state - > cli , open_parms ) ;
NT_STATUS_HAVE_NO_MEMORY ( req ) ;
/*register the callback function!*/
req - > async . fn = benchrw_callback ;
req - > async . private = state ;
return NT_STATUS_OK ;
}
/*
handler for completion of a sub - request of the bench - rw test
*/
2006-10-16 17:06:41 +04:00
static void benchrw_callback ( struct smbcli_request * req )
2006-08-10 15:51:43 +04:00
{
struct benchrw_state * state = req - > async . private ;
2006-10-16 17:06:41 +04:00
struct torture_context * tctx = state - > tctx ;
2006-08-10 15:51:43 +04:00
/*dont send new requests when torture_numops is reached*/
2007-02-11 15:03:25 +03:00
if ( ( state - > mode = = READ_WRITE_DATA )
& & ( state - > completed > = torture_numops ) ) {
2006-08-10 15:51:43 +04:00
state - > mode = MAX_OPS_REACHED ;
}
switch ( state - > mode ) {
case MK_TESTDIR :
2007-02-11 13:42:48 +03:00
if ( ! NT_STATUS_IS_OK ( benchrw_mkdir ( tctx , req , state ) ) ) {
torture_comment ( tctx , " Failed to create the test "
" directory - %s \n " ,
nt_errstr ( req - > status ) ) ;
2006-08-10 15:51:43 +04:00
state - > mode = ERROR ;
return ;
}
break ;
case OPEN_FILE :
case INITIAL_WRITE :
2006-10-16 17:06:41 +04:00
if ( ! NT_STATUS_IS_OK ( benchrw_open ( tctx , req , state ) ) ) {
2007-02-11 13:42:48 +03:00
torture_comment ( tctx , " Failed to open/write the "
" file - %s \n " ,
nt_errstr ( req - > status ) ) ;
2006-08-10 15:51:43 +04:00
state - > mode = ERROR ;
2007-06-18 18:06:04 +04:00
state - > readcnt = 0 ;
2006-08-10 15:51:43 +04:00
return ;
}
break ;
case READ_WRITE_DATA :
2007-02-11 15:03:25 +03:00
while ( state - > num_parallel_requests
< state - > lp_params - > num_parallel_requests ) {
NTSTATUS status ;
status = benchrw_readwrite ( tctx , state ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
torture_comment ( tctx , " Failed to read/write "
" the file - %s \n " ,
nt_errstr ( req - > status ) ) ;
state - > mode = ERROR ;
return ;
}
2006-08-10 15:51:43 +04:00
}
break ;
case MAX_OPS_REACHED :
2006-10-16 17:06:41 +04:00
if ( ! NT_STATUS_IS_OK ( benchrw_close ( tctx , req , state ) ) ) {
2007-02-11 13:42:48 +03:00
torture_comment ( tctx , " Failed to read/write/close "
" the file - %s \n " ,
nt_errstr ( req - > status ) ) ;
2006-08-10 15:51:43 +04:00
state - > mode = ERROR ;
return ;
}
break ;
case CLOSE_FILE :
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " File %d closed \n " , state - > nr ) ;
2006-08-10 15:51:43 +04:00
if ( ! NT_STATUS_IS_OK ( req - > status ) ) {
2007-02-11 13:42:48 +03:00
torture_comment ( tctx , " Failed to close the "
" file - %s \n " ,
nt_errstr ( req - > status ) ) ;
2006-08-10 15:51:43 +04:00
state - > mode = ERROR ;
return ;
}
state - > mode = CLEANUP ;
return ;
default :
break ;
}
}
/* open connection async callback function*/
2006-10-16 17:06:41 +04:00
static void async_open_callback ( struct composite_context * con )
2006-08-10 15:51:43 +04:00
{
struct benchrw_state * state = con - > async . private_data ;
2006-10-16 17:06:41 +04:00
struct torture_context * tctx = state - > tctx ;
2006-08-10 15:51:43 +04:00
int retry = state - > lp_params - > retry ;
if ( NT_STATUS_IS_OK ( con - > status ) ) {
state - > cli = ( ( struct smb_composite_connect * )
state - > req_params ) - > out . tree ;
state - > mode = CLEANUP_TESTDIR ;
} else {
if ( state - > writecnt < retry ) {
2007-02-11 13:42:48 +03:00
torture_comment ( tctx , " Failed to open connection: "
" %d, Retry (%d/%d) \n " ,
2006-08-10 15:51:43 +04:00
state - > nr , state - > writecnt , retry ) ;
state - > writecnt + + ;
state - > mode = START ;
usleep ( 1000 ) ;
} else {
2007-02-11 13:42:48 +03:00
torture_comment ( tctx , " Failed to open connection "
" (%d) - %s \n " ,
2006-08-10 15:51:43 +04:00
state - > nr , nt_errstr ( con - > status ) ) ;
state - > mode = ERROR ;
}
return ;
}
}
/*
establishs a smbcli_tree from scratch ( async )
*/
2006-10-16 17:06:41 +04:00
static struct composite_context * torture_connect_async (
struct torture_context * tctx ,
2006-08-10 15:51:43 +04:00
struct smb_composite_connect * smb ,
TALLOC_CTX * mem_ctx ,
struct event_context * ev ,
const char * host ,
const char * share ,
const char * workgroup )
{
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Open Connection to %s/%s \n " , host , share ) ;
2006-08-10 15:51:43 +04:00
smb - > in . dest_host = talloc_strdup ( mem_ctx , host ) ;
smb - > in . service = talloc_strdup ( mem_ctx , share ) ;
2007-12-12 04:15:29 +03:00
smb - > in . dest_ports = lp_smb_ports ( tctx - > lp_ctx ) ;
2006-08-10 15:51:43 +04:00
smb - > in . called_name = strupper_talloc ( mem_ctx , host ) ;
smb - > in . service_type = NULL ;
smb - > in . credentials = cmdline_credentials ;
2007-10-07 02:28:14 +04:00
smb - > in . fallback_to_anonymous = false ;
2006-08-10 15:51:43 +04:00
smb - > in . workgroup = workgroup ;
2008-01-04 02:22:12 +03:00
lp_smbcli_options ( tctx - > lp_ctx , & smb - > in . options ) ;
2006-08-10 15:51:43 +04:00
2008-01-03 03:39:01 +03:00
return smb_composite_connect_send ( smb , mem_ctx ,
lp_resolve_context ( tctx - > lp_ctx ) , ev ) ;
2006-08-10 15:51:43 +04:00
}
2007-10-07 02:28:14 +04:00
bool run_benchrw ( struct torture_context * tctx )
2006-08-10 15:51:43 +04:00
{
struct smb_composite_connect * smb_con ;
const char * fname = " \\ rwtest.dat " ;
struct smbcli_request * req ;
struct benchrw_state * * state ;
int i , num_unc_names ;
struct event_context * ev ;
struct composite_context * req1 ;
struct params lpparams ;
union smb_mkdir parms ;
int finished = 0 ;
2007-10-07 02:28:14 +04:00
bool success = true ;
2007-08-26 22:24:12 +04:00
int torture_nprocs = torture_setting_int ( tctx , " nprocs " , 4 ) ;
2006-08-10 15:51:43 +04:00
2007-02-11 13:42:48 +03:00
torture_comment ( tctx , " Start BENCH-READWRITE num_ops=%d "
" num_nprocs=%d \n " ,
torture_numops , torture_nprocs ) ;
2006-08-10 15:51:43 +04:00
/*init talloc context*/
2007-05-17 12:47:04 +04:00
ev = tctx - > ev ;
2006-10-16 17:06:41 +04:00
state = talloc_array ( tctx , struct benchrw_state * , torture_nprocs ) ;
2006-08-10 15:51:43 +04:00
/* init params using lp_parm_xxx */
2006-10-16 17:06:41 +04:00
num_unc_names = init_benchrw_params ( tctx , & lpparams ) ;
2006-08-10 15:51:43 +04:00
/* init private data structs*/
for ( i = 0 ; i < torture_nprocs ; i + + ) {
2006-10-16 17:06:41 +04:00
state [ i ] = talloc ( tctx , struct benchrw_state ) ;
state [ i ] - > tctx = tctx ;
2006-08-10 15:51:43 +04:00
state [ i ] - > completed = 0 ;
2007-02-11 15:03:25 +03:00
state [ i ] - > num_parallel_requests = 0 ;
2006-08-10 15:51:43 +04:00
state [ i ] - > lp_params = & lpparams ;
state [ i ] - > nr = i ;
2006-10-16 17:06:41 +04:00
state [ i ] - > dname = talloc_asprintf ( tctx , " benchrw%d " , i ) ;
state [ i ] - > fname = talloc_asprintf ( tctx , " %s%s " ,
2007-02-11 13:42:48 +03:00
state [ i ] - > dname , fname ) ;
2006-08-10 15:51:43 +04:00
state [ i ] - > mode = START ;
state [ i ] - > writecnt = 0 ;
}
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Starting async requests \n " ) ;
2006-08-10 15:51:43 +04:00
while ( finished ! = torture_nprocs ) {
finished = 0 ;
for ( i = 0 ; i < torture_nprocs ; i + + ) {
switch ( state [ i ] - > mode ) {
/*open multiple connections with the same userid */
case START :
2007-02-11 13:42:48 +03:00
smb_con = talloc (
tctx , struct smb_composite_connect ) ;
2006-08-10 15:51:43 +04:00
state [ i ] - > req_params = smb_con ;
state [ i ] - > mode = OPEN_CONNECTION ;
2007-02-11 13:42:48 +03:00
req1 = torture_connect_async (
tctx , smb_con , tctx , ev ,
lpparams . unc [ i % num_unc_names ] - > host ,
lpparams . unc [ i % num_unc_names ] - > share ,
lpparams . workgroup ) ;
2006-08-10 15:51:43 +04:00
/* register callback fn + private data */
req1 - > async . fn = async_open_callback ;
req1 - > async . private_data = state [ i ] ;
break ;
/*setup test dirs (sync)*/
case CLEANUP_TESTDIR :
2006-10-16 17:06:41 +04:00
torture_comment ( tctx , " Setup test dir %d \n " , i ) ;
2006-08-10 15:51:43 +04:00
smb_raw_exit ( state [ i ] - > cli - > session ) ;
if ( smbcli_deltree ( state [ i ] - > cli ,
state [ i ] - > dname ) = = - 1 ) {
2007-02-11 13:42:48 +03:00
torture_comment (
tctx ,
" Unable to delete %s - %s \n " ,
2006-08-10 15:51:43 +04:00
state [ i ] - > dname ,
smbcli_errstr ( state [ i ] - > cli ) ) ;
state [ i ] - > mode = ERROR ;
break ;
}
state [ i ] - > mode = MK_TESTDIR ;
parms . mkdir . level = RAW_MKDIR_MKDIR ;
parms . mkdir . in . path = state [ i ] - > dname ;
req = smb_raw_mkdir_send ( state [ i ] - > cli , & parms ) ;
/* register callback fn + private data */
req - > async . fn = benchrw_callback ;
req - > async . private = state [ i ] ;
break ;
/* error occured , finish */
case ERROR :
finished + + ;
2007-10-07 02:28:14 +04:00
success = false ;
2006-08-10 15:51:43 +04:00
break ;
/* cleanup , close connection */
case CLEANUP :
2007-02-11 13:42:48 +03:00
torture_comment ( tctx , " Deleting test dir %s "
" %d/%d \n " , state [ i ] - > dname ,
2006-08-10 15:51:43 +04:00
i + 1 , torture_nprocs ) ;
smbcli_deltree ( state [ i ] - > cli , state [ i ] - > dname ) ;
if ( NT_STATUS_IS_ERR ( smb_tree_disconnect (
2007-02-11 13:42:48 +03:00
state [ i ] - > cli ) ) ) {
torture_comment ( tctx , " ERROR: Tree "
" disconnect failed " ) ;
2006-08-10 15:51:43 +04:00
state [ i ] - > mode = ERROR ;
break ;
}
state [ i ] - > mode = FINISHED ;
case FINISHED :
finished + + ;
break ;
default :
event_loop_once ( ev ) ;
}
}
}
return success ;
}