2023-08-03 16:45:05 +03:00
/*
2008-01-25 07:00:11 +03:00
Unix SMB / CIFS implementation .
Copyright ( C ) Andrew Tridgell 2008
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
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
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
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 .
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
/*
test offline files
*/
# include "includes.h"
# include "system/time.h"
# include "system/filesys.h"
# include "libcli/libcli.h"
# include "torture/util.h"
# include "lib/events/events.h"
# include "libcli/composite/composite.h"
# include "libcli/smb_composite/smb_composite.h"
2011-03-19 02:42:42 +03:00
# include "torture/raw/proto.h"
2008-01-25 07:00:11 +03:00
# define BASEDIR "\\testoffline"
static int nconnections ;
static int numstates ;
static int num_connected ;
static int test_failed ;
extern int torture_numops ;
2008-02-07 15:05:44 +03:00
extern int torture_entries ;
2008-01-25 07:00:11 +03:00
static bool test_finished ;
2008-01-25 09:27:36 +03:00
enum offline_op { OP_LOADFILE , OP_SAVEFILE , OP_SETOFFLINE , OP_GETOFFLINE , OP_ENDOFLIST } ;
static double latencies [ OP_ENDOFLIST ] ;
static double worst_latencies [ OP_ENDOFLIST ] ;
2008-01-25 07:00:11 +03:00
# define FILE_SIZE 8192
struct offline_state {
struct torture_context * tctx ;
2008-12-29 22:24:57 +03:00
struct tevent_context * ev ;
2008-01-25 07:00:11 +03:00
struct smbcli_tree * tree ;
TALLOC_CTX * mem_ctx ;
2008-01-25 09:27:36 +03:00
int client ;
2008-01-25 07:00:11 +03:00
int fnum ;
uint32_t count ;
uint32_t lastcount ;
uint32_t fnumber ;
2008-01-25 07:00:45 +03:00
uint32_t offline_count ;
uint32_t online_count ;
2008-01-25 07:00:11 +03:00
char * fname ;
struct smb_composite_loadfile * loadfile ;
struct smb_composite_savefile * savefile ;
struct smbcli_request * req ;
enum offline_op op ;
2008-01-25 09:27:36 +03:00
struct timeval tv_start ;
2008-01-25 07:00:11 +03:00
} ;
static void test_offline ( struct offline_state * state ) ;
static char * filename ( TALLOC_CTX * ctx , int i )
{
char * s = talloc_asprintf ( ctx , BASEDIR " \\ file%u.dat " , i ) ;
return s ;
}
/*
called when a loadfile completes
*/
2023-08-03 16:45:05 +03:00
static void loadfile_callback ( struct composite_context * ctx )
2008-01-25 07:00:11 +03:00
{
struct offline_state * state = ctx - > async . private_data ;
NTSTATUS status ;
int i ;
status = smb_composite_loadfile_recv ( ctx , state - > mem_ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2023-08-03 16:45:05 +03:00
printf ( " Failed to read file '%s' - %s \n " ,
2008-01-25 07:00:11 +03:00
state - > loadfile - > in . fname , nt_errstr ( status ) ) ;
test_failed + + ;
2016-04-18 20:42:57 +03:00
return ;
2008-01-25 07:00:11 +03:00
}
/* check the data is correct */
if ( state - > loadfile - > out . size ! = FILE_SIZE ) {
2023-08-03 16:45:05 +03:00
printf ( " Wrong file size %u - expected %u \n " ,
2008-01-25 07:00:11 +03:00
state - > loadfile - > out . size , FILE_SIZE ) ;
test_failed + + ;
return ;
}
for ( i = 0 ; i < FILE_SIZE ; i + + ) {
2008-08-23 05:54:02 +04:00
if ( state - > loadfile - > out . data [ i ] ! = 1 + ( state - > fnumber % 255 ) ) {
2023-08-03 16:45:05 +03:00
printf ( " Bad data in file %u (got %u expected %u) \n " ,
state - > fnumber ,
2008-08-24 11:38:43 +04:00
state - > loadfile - > out . data [ i ] ,
1 + ( state - > fnumber % 255 ) ) ;
2008-01-25 07:00:11 +03:00
test_failed + + ;
return ;
}
}
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
talloc_steal ( state - > loadfile , state - > loadfile - > out . data ) ;
state - > count + + ;
talloc_free ( state - > loadfile ) ;
state - > loadfile = NULL ;
if ( ! test_finished ) {
test_offline ( state ) ;
}
}
/*
called when a savefile completes
*/
2023-08-03 16:45:05 +03:00
static void savefile_callback ( struct composite_context * ctx )
2008-01-25 07:00:11 +03:00
{
struct offline_state * state = ctx - > async . private_data ;
NTSTATUS status ;
status = smb_composite_savefile_recv ( ctx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2023-08-03 16:45:05 +03:00
printf ( " Failed to save file '%s' - %s \n " ,
2008-01-25 07:00:11 +03:00
state - > savefile - > in . fname , nt_errstr ( status ) ) ;
test_failed + + ;
}
state - > count + + ;
talloc_free ( state - > savefile ) ;
state - > savefile = NULL ;
if ( ! test_finished ) {
test_offline ( state ) ;
}
}
/*
called when a setoffline completes
*/
2023-08-03 16:45:05 +03:00
static void setoffline_callback ( struct smbcli_request * req )
2008-01-25 07:00:11 +03:00
{
2009-02-02 12:17:00 +03:00
struct offline_state * state = req - > async . private_data ;
2008-01-25 07:00:11 +03:00
NTSTATUS status ;
status = smbcli_request_simple_recv ( req ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2023-08-03 16:45:05 +03:00
printf ( " Failed to set offline file '%s' - %s \n " ,
2008-01-25 07:00:11 +03:00
state - > fname , nt_errstr ( status ) ) ;
test_failed + + ;
}
state - > req = NULL ;
state - > count + + ;
if ( ! test_finished ) {
test_offline ( state ) ;
}
}
/*
called when a getoffline completes
*/
2023-08-03 16:45:05 +03:00
static void getoffline_callback ( struct smbcli_request * req )
2008-01-25 07:00:11 +03:00
{
2009-02-02 12:17:00 +03:00
struct offline_state * state = req - > async . private_data ;
2008-01-25 07:00:11 +03:00
NTSTATUS status ;
union smb_fileinfo io ;
2016-04-18 20:42:57 +03:00
ZERO_STRUCT ( io ) ;
2008-01-25 07:00:45 +03:00
io . getattr . level = RAW_FILEINFO_GETATTR ;
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
status = smb_raw_pathinfo_recv ( req , state - > mem_ctx , & io ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2023-08-03 16:45:05 +03:00
printf ( " Failed to get offline file '%s' - %s \n " ,
2008-01-25 07:00:11 +03:00
state - > fname , nt_errstr ( status ) ) ;
test_failed + + ;
}
2008-01-25 07:00:45 +03:00
if ( io . getattr . out . attrib & FILE_ATTRIBUTE_OFFLINE ) {
state - > offline_count + + ;
} else {
state - > online_count + + ;
}
2008-01-25 07:00:11 +03:00
state - > req = NULL ;
state - > count + + ;
if ( ! test_finished ) {
test_offline ( state ) ;
}
}
/*
send the next offline file fetch request
*/
static void test_offline ( struct offline_state * state )
{
struct composite_context * ctx ;
2008-01-25 09:27:36 +03:00
double lat ;
lat = timeval_elapsed ( & state - > tv_start ) ;
if ( latencies [ state - > op ] < lat ) {
latencies [ state - > op ] = lat ;
}
2008-01-25 07:00:11 +03:00
state - > op = ( enum offline_op ) ( random ( ) % OP_ENDOFLIST ) ;
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
state - > fnumber = random ( ) % torture_numops ;
talloc_free ( state - > fname ) ;
state - > fname = filename ( state - > mem_ctx , state - > fnumber ) ;
2008-01-25 09:27:36 +03:00
state - > tv_start = timeval_current ( ) ;
2008-01-25 07:00:11 +03:00
switch ( state - > op ) {
case OP_LOADFILE :
state - > loadfile = talloc_zero ( state - > mem_ctx , struct smb_composite_loadfile ) ;
state - > loadfile - > in . fname = state - > fname ;
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
ctx = smb_composite_loadfile_send ( state - > tree , state - > loadfile ) ;
if ( ctx = = NULL ) {
printf ( " Failed to setup loadfile for %s \n " , state - > fname ) ;
test_failed = true ;
}
talloc_steal ( state - > loadfile , ctx ) ;
ctx - > async . fn = loadfile_callback ;
ctx - > async . private_data = state ;
break ;
case OP_SAVEFILE :
state - > savefile = talloc_zero ( state - > mem_ctx , struct smb_composite_savefile ) ;
state - > savefile - > in . fname = state - > fname ;
state - > savefile - > in . data = talloc_size ( state - > savefile , FILE_SIZE ) ;
state - > savefile - > in . size = FILE_SIZE ;
2008-08-24 11:42:29 +04:00
memset ( state - > savefile - > in . data , 1 + ( state - > fnumber % 255 ) , FILE_SIZE ) ;
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
ctx = smb_composite_savefile_send ( state - > tree , state - > savefile ) ;
if ( ctx = = NULL ) {
printf ( " Failed to setup savefile for %s \n " , state - > fname ) ;
test_failed = true ;
}
talloc_steal ( state - > savefile , ctx ) ;
ctx - > async . fn = savefile_callback ;
ctx - > async . private_data = state ;
break ;
case OP_SETOFFLINE : {
union smb_setfileinfo io ;
ZERO_STRUCT ( io ) ;
io . setattr . level = RAW_SFILEINFO_SETATTR ;
io . setattr . in . attrib = FILE_ATTRIBUTE_OFFLINE ;
io . setattr . in . file . path = state - > fname ;
2023-08-03 16:45:05 +03:00
/* make the file 1 hour old, to get past minimum age restrictions
2008-01-25 09:27:36 +03:00
for HSM systems */
io . setattr . in . write_time = time ( NULL ) - 60 * 60 ;
2008-01-25 07:00:11 +03:00
state - > req = smb_raw_setpathinfo_send ( state - > tree , & io ) ;
if ( state - > req = = NULL ) {
printf ( " Failed to setup setoffline for %s \n " , state - > fname ) ;
test_failed = true ;
}
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
state - > req - > async . fn = setoffline_callback ;
2009-02-02 12:17:00 +03:00
state - > req - > async . private_data = state ;
2008-01-25 07:00:11 +03:00
break ;
}
case OP_GETOFFLINE : {
union smb_fileinfo io ;
ZERO_STRUCT ( io ) ;
2008-01-25 07:00:45 +03:00
io . getattr . level = RAW_FILEINFO_GETATTR ;
io . getattr . in . file . path = state - > fname ;
2008-01-25 07:00:11 +03:00
state - > req = smb_raw_pathinfo_send ( state - > tree , & io ) ;
if ( state - > req = = NULL ) {
printf ( " Failed to setup getoffline for %s \n " , state - > fname ) ;
test_failed = true ;
}
2023-08-03 16:45:05 +03:00
2008-01-25 07:00:11 +03:00
state - > req - > async . fn = getoffline_callback ;
2009-02-02 12:17:00 +03:00
state - > req - > async . private_data = state ;
2008-01-25 07:00:11 +03:00
break ;
}
default :
printf ( " bad operation?? \n " ) ;
break ;
}
}
static void echo_completion ( struct smbcli_request * req )
{
2009-02-02 12:17:00 +03:00
struct offline_state * state = ( struct offline_state * ) req - > async . private_data ;
2008-01-25 07:00:11 +03:00
NTSTATUS status = smbcli_request_simple_recv ( req ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_END_OF_FILE ) | |
2010-02-04 12:19:05 +03:00
NT_STATUS_EQUAL ( status , NT_STATUS_LOCAL_DISCONNECT ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_CONNECTION_RESET ) ) {
2008-01-25 07:00:11 +03:00
talloc_free ( state - > tree ) ;
state - > tree = NULL ;
2023-08-03 16:45:05 +03:00
num_connected - - ;
2008-01-25 07:00:11 +03:00
DEBUG ( 0 , ( " lost connection \n " ) ) ;
test_failed + + ;
}
}
2023-08-03 16:45:05 +03:00
static void report_rate ( struct tevent_context * ev , struct tevent_timer * te ,
2008-01-25 07:00:11 +03:00
struct timeval t , void * private_data )
{
2023-08-03 16:45:05 +03:00
struct offline_state * state = talloc_get_type ( private_data ,
2008-01-25 07:00:11 +03:00
struct offline_state ) ;
int i ;
2008-01-25 09:27:36 +03:00
uint32_t total = 0 , total_offline = 0 , total_online = 0 ;
2008-01-25 07:00:11 +03:00
for ( i = 0 ; i < numstates ; i + + ) {
2008-01-25 07:00:45 +03:00
total + = state [ i ] . count - state [ i ] . lastcount ;
2008-01-25 09:27:36 +03:00
if ( timeval_elapsed ( & state [ i ] . tv_start ) > latencies [ state [ i ] . op ] ) {
latencies [ state [ i ] . op ] = timeval_elapsed ( & state [ i ] . tv_start ) ;
}
2023-08-03 16:45:05 +03:00
state [ i ] . lastcount = state [ i ] . count ;
2008-01-25 09:27:36 +03:00
total_online + = state [ i ] . online_count ;
total_offline + = state [ i ] . offline_count ;
2008-01-25 07:00:11 +03:00
}
2008-08-24 11:38:43 +04:00
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 " ,
2008-01-25 09:27:36 +03:00
total , total_offline , total_online ,
latencies [ OP_SETOFFLINE ] ,
2008-08-24 11:38:43 +04:00
worst_latencies [ OP_SETOFFLINE ] ,
2008-01-25 09:27:36 +03:00
latencies [ OP_GETOFFLINE ] ,
2008-08-24 11:38:43 +04:00
worst_latencies [ OP_GETOFFLINE ] ,
2008-01-25 09:27:36 +03:00
latencies [ OP_SAVEFILE ] ,
2008-08-24 11:38:43 +04:00
worst_latencies [ OP_SAVEFILE ] ,
latencies [ OP_LOADFILE ] ,
worst_latencies [ OP_LOADFILE ] ) ;
2008-01-25 07:00:11 +03:00
fflush ( stdout ) ;
2010-05-25 23:23:55 +04:00
tevent_add_timer ( ev , state , timeval_current_ofs ( 1 , 0 ) , report_rate , state ) ;
2008-01-25 07:00:11 +03:00
2008-01-25 09:27:36 +03:00
for ( i = 0 ; i < OP_ENDOFLIST ; i + + ) {
if ( latencies [ i ] > worst_latencies [ i ] ) {
worst_latencies [ i ] = latencies [ i ] ;
}
latencies [ i ] = 0 ;
}
2008-01-25 07:00:11 +03:00
/* send an echo on each interface to ensure it stays alive - this helps
with IP takeover */
for ( i = 0 ; i < numstates ; i + + ) {
struct smb_echo p ;
struct smbcli_request * req ;
if ( ! state [ i ] . tree ) {
continue ;
}
p . in . repeat_count = 1 ;
p . in . size = 0 ;
p . in . data = NULL ;
req = smb_raw_echo_send ( state [ i ] . tree - > session - > transport , & p ) ;
2009-02-02 12:17:00 +03:00
req - > async . private_data = & state [ i ] ;
2008-01-25 07:00:11 +03:00
req - > async . fn = echo_completion ;
}
}
2023-08-03 16:45:05 +03:00
/*
2008-01-25 07:00:11 +03:00
test offline file handling
*/
bool torture_test_offline ( struct torture_context * torture )
{
bool ret = true ;
TALLOC_CTX * mem_ctx = talloc_new ( torture ) ;
int i ;
int timelimit = torture_setting_int ( torture , " timelimit " , 10 ) ;
struct timeval tv ;
struct offline_state * state ;
struct smbcli_state * cli ;
bool progress ;
progress = torture_setting_bool ( torture , " progress " , true ) ;
2008-01-25 09:27:36 +03:00
nconnections = torture_setting_int ( torture , " nprocs " , 4 ) ;
2008-02-07 15:05:44 +03:00
numstates = nconnections * torture_entries ;
2008-01-25 07:00:11 +03:00
state = talloc_zero_array ( mem_ctx , struct offline_state , numstates ) ;
2008-01-25 09:27:36 +03:00
printf ( " Opening %d connections with %d simultaneous operations and %u files \n " , nconnections , numstates , torture_numops ) ;
2008-01-25 07:00:11 +03:00
for ( i = 0 ; i < nconnections ; i + + ) {
state [ i ] . tctx = torture ;
state [ i ] . mem_ctx = talloc_new ( state ) ;
2008-04-17 03:19:20 +04:00
state [ i ] . ev = torture - > ev ;
if ( ! torture_open_connection_ev ( & cli , i , torture , torture - > ev ) ) {
2008-01-25 07:00:11 +03:00
return false ;
}
state [ i ] . tree = cli - > tree ;
2008-01-25 09:27:36 +03:00
state [ i ] . client = i ;
/* allow more time for offline files */
state [ i ] . tree - > session - > transport - > options . request_timeout = 200 ;
2008-01-25 07:00:11 +03:00
}
/* the others are repeats on the earlier connections */
for ( i = nconnections ; i < numstates ; i + + ) {
state [ i ] . tctx = torture ;
state [ i ] . mem_ctx = talloc_new ( state ) ;
2008-04-17 03:19:20 +04:00
state [ i ] . ev = torture - > ev ;
2008-01-25 07:00:11 +03:00
state [ i ] . tree = state [ i % nconnections ] . tree ;
2008-01-25 09:27:36 +03:00
state [ i ] . client = i ;
2008-01-25 07:00:11 +03:00
}
num_connected = i ;
if ( ! torture_setup_dir ( cli , BASEDIR ) ) {
goto failed ;
}
/* pre-create files */
2008-01-25 09:27:36 +03:00
printf ( " Pre-creating %u files .... \n " , torture_numops ) ;
2008-01-25 07:00:11 +03:00
for ( i = 0 ; i < torture_numops ; i + + ) {
int fnum ;
char * fname = filename ( mem_ctx , i ) ;
char buf [ FILE_SIZE ] ;
NTSTATUS status ;
2008-08-23 05:54:02 +04:00
memset ( buf , 1 + ( i % 255 ) , sizeof ( buf ) ) ;
2008-01-25 07:00:11 +03:00
fnum = smbcli_open ( state [ 0 ] . tree , fname , O_RDWR | O_CREAT , DENY_NONE ) ;
if ( fnum = = - 1 ) {
printf ( " Failed to open %s on connection %d \n " , fname , i ) ;
goto failed ;
}
if ( smbcli_write ( state [ 0 ] . tree , fnum , 0 , buf , 0 , sizeof ( buf ) ) ! = sizeof ( buf ) ) {
printf ( " Failed to write file of size %u \n " , FILE_SIZE ) ;
goto failed ;
}
status = smbcli_close ( state [ 0 ] . tree , fnum ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Close failed - %s \n " , nt_errstr ( status ) ) ;
goto failed ;
}
talloc_free ( fname ) ;
}
/* start the async ops */
for ( i = 0 ; i < numstates ; i + + ) {
2008-01-25 09:27:36 +03:00
state [ i ] . tv_start = timeval_current ( ) ;
2008-01-25 07:00:11 +03:00
test_offline ( & state [ i ] ) ;
}
2023-08-03 16:45:05 +03:00
tv = timeval_current ( ) ;
2008-01-25 07:00:11 +03:00
if ( progress ) {
2010-05-25 23:23:55 +04:00
tevent_add_timer ( torture - > ev , state , timeval_current_ofs ( 1 , 0 ) , report_rate , state ) ;
2008-01-25 07:00:11 +03:00
}
printf ( " Running for %d seconds \n " , timelimit ) ;
while ( timeval_elapsed ( & tv ) < timelimit ) {
2010-05-25 23:23:55 +04:00
tevent_loop_once ( torture - > ev ) ;
2008-01-25 07:00:11 +03:00
if ( test_failed ) {
DEBUG ( 0 , ( " test failed \n " ) ) ;
goto failed ;
}
}
2008-01-25 07:00:45 +03:00
printf ( " \n Waiting for completion \n " ) ;
2008-01-25 07:00:11 +03:00
test_finished = true ;
for ( i = 0 ; i < numstates ; i + + ) {
2023-08-03 16:45:05 +03:00
while ( state [ i ] . loadfile | |
2008-01-25 07:00:11 +03:00
state [ i ] . savefile | |
state [ i ] . req ) {
2010-05-25 23:23:55 +04:00
tevent_loop_once ( torture - > ev ) ;
2008-01-25 07:00:11 +03:00
}
2023-08-03 16:45:05 +03:00
}
2008-01-25 07:00:11 +03:00
2008-01-25 09:27:36 +03:00
printf ( " worst latencies: set_lat=%.1f get_lat=%.1f save_lat=%.1f load_lat=%.1f \n " ,
worst_latencies [ OP_SETOFFLINE ] ,
worst_latencies [ OP_GETOFFLINE ] ,
worst_latencies [ OP_SAVEFILE ] ,
worst_latencies [ OP_LOADFILE ] ) ;
2008-01-25 07:00:11 +03:00
smbcli_deltree ( state [ 0 ] . tree , BASEDIR ) ;
talloc_free ( mem_ctx ) ;
printf ( " \n " ) ;
return ret ;
failed :
talloc_free ( mem_ctx ) ;
return false ;
}