2018-04-27 16:24:05 +03:00
/*
* Copyright ( C ) 2018 Red Hat , Inc . All rights reserved .
*
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
# define _GNU_SOURCE
# include <errno.h>
# include <stdio.h>
# include <stdlib.h>
# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
# include "bcache.h"
# include "framework.h"
# include "units.h"
//----------------------------------------------------------------
# define SECTOR_SIZE 512
2018-05-01 12:47:40 +03:00
# define BLOCK_SIZE_SECTORS 8
# define NR_BLOCKS 64
2018-04-27 16:24:05 +03:00
struct fixture {
struct io_engine * e ;
2018-04-30 19:09:24 +03:00
uint8_t * data ;
2018-04-27 16:24:05 +03:00
char fname [ 64 ] ;
int fd ;
} ;
2018-05-01 12:47:40 +03:00
static void _fill_buffer ( uint8_t * buffer , uint8_t seed , size_t count )
2018-04-27 16:24:05 +03:00
{
2018-04-30 19:09:24 +03:00
unsigned i ;
2018-05-01 12:47:40 +03:00
uint8_t b = seed ;
for ( i = 0 ; i < count ; i + + ) {
buffer [ i ] = b ;
b = ( ( b < < 5 ) + b ) + i ;
}
}
static void _check_buffer ( uint8_t * buffer , uint8_t seed , size_t count )
{
unsigned i ;
uint8_t b = seed ;
for ( i = 0 ; i < count ; i + + ) {
T_ASSERT_EQUAL ( buffer [ i ] , b ) ;
b = ( ( b < < 5 ) + b ) + i ;
}
}
static void _print_buffer ( const char * name , uint8_t * buffer , size_t count )
{
unsigned col ;
fprintf ( stderr , " %s: \n " , name ) ;
while ( count ) {
for ( col = 0 ; count & & col < 20 ; col + + ) {
fprintf ( stderr , " %x, " , ( unsigned ) * buffer ) ;
col + + ;
buffer + + ;
count - - ;
}
fprintf ( stderr , " \n " ) ;
}
}
static void * _fix_init ( void )
{
2018-04-27 16:24:05 +03:00
struct fixture * f = malloc ( sizeof ( * f ) ) ;
T_ASSERT ( f ) ;
f - > e = create_async_io_engine ( ) ;
T_ASSERT ( f - > e ) ;
2018-04-30 19:09:24 +03:00
if ( posix_memalign ( ( void * * ) & f - > data , 4096 , SECTOR_SIZE * BLOCK_SIZE_SECTORS ) )
2018-04-30 18:55:19 +03:00
test_fail ( " posix_memalign failed " ) ;
2018-04-27 16:24:05 +03:00
snprintf ( f - > fname , sizeof ( f - > fname ) , " unit-test-XXXXXX " ) ;
f - > fd = mkostemp ( f - > fname , O_RDWR | O_CREAT | O_EXCL ) ;
T_ASSERT ( f - > fd > = 0 ) ;
2018-05-01 14:07:33 +03:00
_fill_buffer ( f - > data , 123 , SECTOR_SIZE * BLOCK_SIZE_SECTORS ) ;
2018-04-30 19:09:24 +03:00
2018-04-27 16:24:05 +03:00
write ( f - > fd , f - > data , SECTOR_SIZE * BLOCK_SIZE_SECTORS ) ;
lseek ( f - > fd , 0 , SEEK_SET ) ;
return f ;
}
static void _fix_exit ( void * fixture )
{
struct fixture * f = fixture ;
close ( f - > fd ) ;
unlink ( f - > fname ) ;
free ( f - > data ) ;
2018-05-01 12:47:40 +03:00
if ( f - > e )
f - > e - > destroy ( f - > e ) ;
2018-04-27 16:24:05 +03:00
free ( f ) ;
}
static void _test_create ( void * fixture )
{
// empty
}
struct io {
bool completed ;
int error ;
} ;
static void _io_init ( struct io * io )
{
io - > completed = false ;
io - > error = 0 ;
}
static void _complete_io ( void * context , int io_error )
{
struct io * io = context ;
io - > completed = true ;
io - > error = io_error ;
}
static void _test_read ( void * fixture )
{
struct fixture * f = fixture ;
struct io io ;
_io_init ( & io ) ;
T_ASSERT ( f - > e - > issue ( f - > e , DIR_READ , f - > fd , 0 , BLOCK_SIZE_SECTORS , f - > data , & io ) ) ;
T_ASSERT ( f - > e - > wait ( f - > e , _complete_io ) ) ;
T_ASSERT ( io . completed ) ;
T_ASSERT ( ! io . error ) ;
2018-05-01 12:47:40 +03:00
_check_buffer ( f - > data , 123 , sizeof ( f - > data ) ) ;
2018-04-27 16:24:05 +03:00
}
static void _test_write ( void * fixture )
{
struct fixture * f = fixture ;
struct io io ;
_io_init ( & io ) ;
T_ASSERT ( f - > e - > issue ( f - > e , DIR_WRITE , f - > fd , 0 , BLOCK_SIZE_SECTORS , f - > data , & io ) ) ;
T_ASSERT ( f - > e - > wait ( f - > e , _complete_io ) ) ;
T_ASSERT ( io . completed ) ;
T_ASSERT ( ! io . error ) ;
}
2018-05-01 12:47:40 +03:00
static void _test_write_bytes ( void * fixture )
{
struct fixture * f = fixture ;
unsigned offset = 345 ;
char buf_out [ 32 ] ;
char buf_in [ 32 ] ;
struct bcache * cache = bcache_create ( 8 , BLOCK_SIZE_SECTORS , f - > e ) ;
T_ASSERT ( cache ) ;
// T_ASSERT(bcache_read_bytes(cache, f->fd, offset, sizeof(buf_in), buf_in));
_fill_buffer ( ( uint8_t * ) buf_out , 234 , sizeof ( buf_out ) ) ;
T_ASSERT ( bcache_write_bytes ( cache , f - > fd , offset , sizeof ( buf_out ) , buf_out ) ) ;
T_ASSERT ( bcache_read_bytes ( cache , f - > fd , offset , sizeof ( buf_in ) , buf_in ) ) ;
_print_buffer ( " buf_out " , ( uint8_t * ) buf_out , sizeof ( buf_out ) ) ;
_print_buffer ( " buf_in " , ( uint8_t * ) buf_in , sizeof ( buf_in ) ) ;
T_ASSERT ( ! memcmp ( buf_out , buf_in , sizeof ( buf_out ) ) ) ;
bcache_destroy ( cache ) ;
f - > e = NULL ; // already destroyed
}
2018-04-27 16:24:05 +03:00
//----------------------------------------------------------------
# define T(path, desc, fn) register_test(ts, " / base / device / bcache / io-engine / " path, desc, fn)
static struct test_suite * _tests ( void )
{
struct test_suite * ts = test_suite_create ( _fix_init , _fix_exit ) ;
if ( ! ts ) {
fprintf ( stderr , " out of memory \n " ) ;
exit ( 1 ) ;
}
T ( " create-destroy " , " simple create/destroy " , _test_create ) ;
2018-05-01 14:07:33 +03:00
T ( " read " , " read sanity check " , _test_read ) ;
T ( " write " , " write sanity check " , _test_write ) ;
2018-05-01 12:47:40 +03:00
T ( " bcache-write-bytes " , " test the utility fns " , _test_write_bytes ) ;
2018-04-27 16:24:05 +03:00
return ts ;
}
void io_engine_tests ( struct dm_list * all_tests )
{
dm_list_add ( all_tests , & _tests ( ) - > list ) ;
}