2011-02-23 20:48:06 +00:00
// (c) 2011 Thomas Schoebel-Theuer / 1&1 Internet AG
//#define BRICK_DEBUGGING
//#define MARS_DEBUGGING
2011-03-02 09:30:56 +00:00
//#define IO_DEBUGGING
//#define STAT_DEBUGGING // here means: display full statistics
2011-02-23 20:48:06 +00:00
2011-08-31 11:42:04 +00:00
// disable this only for debugging!
# define RUN_PEERS
# define RUN_DATA
# define RUN_LOGINIT
# define RUN_PRIMARY
# define RUN_SYNCSTATUS
# define RUN_LOGFILES
# define RUN_REPLAY
# define RUN_DEVICE
2011-02-23 20:48:06 +00:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/string.h>
# include <linux/debug_locks.h>
# include <linux/major.h>
# include <linux/genhd.h>
# include <linux/blkdev.h>
2011-07-22 10:43:40 +00:00
# include "strategy.h"
2011-09-30 11:55:18 +00:00
# include "../buildtag.h"
2011-02-23 20:48:06 +00:00
# include <linux/wait.h>
// used brick types
2011-07-22 10:43:40 +00:00
# include "../mars_server.h"
# include "../mars_client.h"
# include "../mars_copy.h"
# include "../mars_bio.h"
2011-11-14 13:12:33 +00:00
# include "../mars_sio.h"
2011-07-22 10:43:40 +00:00
# include "../mars_aio.h"
# include "../mars_trans_logger.h"
# include "../mars_if.h"
2011-08-25 10:16:32 +00:00
# include "mars_proc.h"
2012-02-08 11:44:42 +00:00
# ifdef CONFIG_MARS_DEBUG // otherwise currently unused
2012-01-30 11:54:56 +00:00
# include "../mars_dummy.h"
# include "../mars_check.h"
# include "../mars_buf.h"
# include "../mars_usebuf.h"
# endif
2011-02-23 20:48:06 +00:00
2011-03-22 14:36:26 +00:00
#if 0
# define inline __attribute__((__noinline__))
# endif
2011-03-10 11:40:06 +00:00
2011-02-23 20:48:06 +00:00
static struct task_struct * main_thread = NULL ;
2011-02-28 18:00:32 +00:00
typedef int ( * light_worker_fn ) ( void * buf , struct mars_dent * dent ) ;
2011-02-23 20:48:06 +00:00
struct light_class {
char * cl_name ;
int cl_len ;
char cl_type ;
bool cl_hostcontext ;
bool cl_serial ;
2012-11-14 09:46:36 +00:00
bool cl_use_channel ;
2011-02-23 20:48:06 +00:00
int cl_father ;
2011-10-24 10:54:15 +00:00
light_worker_fn cl_prepare ;
2011-02-23 20:48:06 +00:00
light_worker_fn cl_forward ;
light_worker_fn cl_backward ;
} ;
2011-03-10 11:40:06 +00:00
///////////////////////////////////////////////////////////////////////
2012-08-08 13:50:41 +00:00
// needed for logfile rotation
struct mars_rotate {
struct mars_global * global ;
struct copy_brick * sync_brick ;
struct mars_dent * replay_link ;
struct mars_dent * aio_dent ;
struct aio_brick * aio_brick ;
struct mars_info aio_info ;
struct trans_logger_brick * trans_brick ;
struct mars_dent * first_log ;
struct mars_dent * relevant_log ;
struct mars_brick * relevant_brick ;
struct mars_dent * next_relevant_log ;
struct mars_brick * next_relevant_brick ;
struct mars_dent * next_next_relevant_log ;
struct mars_dent * prev_log ;
struct mars_dent * next_log ;
2012-07-23 07:17:18 +00:00
struct mars_dent * syncstatus_dent ;
2012-08-08 13:50:41 +00:00
struct if_brick * if_brick ;
const char * copy_path ;
2012-09-25 15:41:07 +00:00
const char * parent_path ;
2012-08-08 13:50:41 +00:00
struct copy_brick * copy_brick ;
2012-09-25 15:41:07 +00:00
struct mars_limiter replay_limiter ;
struct mars_limiter sync_limiter ;
struct mars_limiter file_limiter ;
2012-12-17 07:25:17 +00:00
struct semaphore inf_mutex ;
const char * inf_prev_version ;
int inf_prev_sequence ;
2012-08-08 13:50:41 +00:00
long long switchover_timeout ;
long long flip_start ;
loff_t dev_size ;
loff_t total_space ;
loff_t remaining_space ;
loff_t start_pos ;
loff_t end_pos ;
int max_sequence ;
int copy_serial ;
int relevant_serial ;
bool has_error ;
bool allow_update ;
bool allow_sync ;
bool allow_replay ;
bool replay_mode ;
bool todo_primary ;
bool is_primary ;
bool old_is_primary ;
bool copy_is_done ;
} ;
///////////////////////////////////////////////////////////////////////
2011-03-10 11:40:06 +00:00
// TUNING
2012-10-15 14:35:36 +00:00
int mars_mem_percent = 20 ;
2012-08-08 09:16:52 +00:00
EXPORT_SYMBOL_GPL ( mars_mem_percent ) ;
2012-02-11 22:32:21 +00:00
# define CONF_TRANS_SHADOW_LIMIT (1024 * 128) // don't fill the hashtable too much
2011-03-18 13:15:40 +00:00
# define CONF_TRANS_CHUNKSIZE (128 * 1024)
2011-11-14 14:21:15 +00:00
# define CONF_TRANS_MAX_MREF_SIZE PAGE_SIZE
2011-03-18 13:15:40 +00:00
//#define CONF_TRANS_ALIGN 512
# define CONF_TRANS_ALIGN 0
2011-03-29 14:40:40 +00:00
//#define TRANS_FAKE
2011-03-18 13:15:40 +00:00
2012-02-23 07:32:15 +00:00
# define CONF_TRANS_BATCHLEN 64
2011-03-29 14:40:40 +00:00
# define CONF_TRANS_PRIO MARS_PRIO_HIGH
2011-05-13 11:19:28 +00:00
# define CONF_TRANS_LOG_READS false
//#define CONF_TRANS_LOG_READS true
2011-05-26 14:32:32 +00:00
//#define CONF_TRANS_COMPLETION_SEMANTICS 2
# define CONF_TRANS_COMPLETION_SEMANTICS 0
2011-03-10 11:40:06 +00:00
2012-10-15 14:35:36 +00:00
# define CONF_ALL_BATCHLEN 1
2011-05-19 11:36:00 +00:00
# define CONF_ALL_PRIO MARS_PRIO_NORMAL
2011-03-18 13:15:40 +00:00
2011-03-24 16:05:46 +00:00
# define IF_SKIP_SYNC true
2011-03-30 12:02:50 +00:00
# define IF_MAX_PLUGGED 10000
2011-06-10 13:57:52 +00:00
# define IF_READAHEAD 0
//#define IF_READAHEAD 1
2011-05-06 10:25:52 +00:00
2011-06-10 13:57:52 +00:00
# define BIO_READAHEAD 0
//#define BIO_READAHEAD 1
2011-05-06 10:25:52 +00:00
# define BIO_NOIDLE true
# define BIO_SYNC true
# define BIO_UNPLUG true
# define AIO_WAIT_DURING_FDSYNC false
2011-03-11 13:57:54 +00:00
2011-06-17 11:32:38 +00:00
# define COPY_APPEND_MODE 0
//#define COPY_APPEND_MODE 1 // FIXME: does not work yet
2011-05-26 14:32:32 +00:00
# define COPY_PRIO MARS_PRIO_LOW
2011-11-08 12:33:13 +00:00
# ifdef CONFIG_MARS_MIN_SPACE
2012-08-14 14:32:06 +00:00
# define EXHAUSTED_LIMIT(max) ((max) / 100 * CONFIG_MARS_MIN_SPACE_PERCENT + global_free_space * 1024 * 1024)
2012-01-24 08:27:40 +00:00
# define EXHAUSTED(x,max) ((x) <= EXHAUSTED_LIMIT(max))
2011-11-08 12:33:13 +00:00
# else
2012-01-24 08:27:40 +00:00
# define EXHAUSTED_LIMIT(max) 0
2012-01-23 17:40:15 +00:00
# define EXHAUSTED(x,max) (false)
2011-11-08 12:33:13 +00:00
# endif
2012-07-23 07:17:18 +00:00
# define JAMMED(x) ((x) <= 1024 * 1024)
2011-03-10 11:40:06 +00:00
static
2011-08-25 10:16:32 +00:00
int _set_trans_params ( struct mars_brick * _brick , void * private )
2011-03-10 11:40:06 +00:00
{
2011-03-11 13:57:54 +00:00
struct trans_logger_brick * trans_brick = ( void * ) _brick ;
2011-03-18 13:15:40 +00:00
if ( _brick - > type ! = ( void * ) & trans_logger_brick_type ) {
MARS_ERR ( " bad brick type \n " ) ;
2011-08-25 10:16:32 +00:00
return - EINVAL ;
2011-03-18 13:15:40 +00:00
}
2012-02-11 19:01:16 +00:00
if ( ! trans_brick - > q_phase [ 1 ] . q_ordering ) {
trans_brick - > q_phase [ 0 ] . q_batchlen = CONF_TRANS_BATCHLEN ;
trans_brick - > q_phase [ 1 ] . q_batchlen = CONF_ALL_BATCHLEN ;
trans_brick - > q_phase [ 2 ] . q_batchlen = CONF_ALL_BATCHLEN ;
trans_brick - > q_phase [ 3 ] . q_batchlen = CONF_ALL_BATCHLEN ;
2011-04-29 09:36:10 +00:00
2012-02-11 19:01:16 +00:00
trans_brick - > q_phase [ 0 ] . q_io_prio = CONF_TRANS_PRIO ;
trans_brick - > q_phase [ 1 ] . q_io_prio = CONF_ALL_PRIO ;
trans_brick - > q_phase [ 2 ] . q_io_prio = CONF_ALL_PRIO ;
trans_brick - > q_phase [ 3 ] . q_io_prio = CONF_ALL_PRIO ;
2011-04-29 09:36:10 +00:00
2012-02-11 19:01:16 +00:00
trans_brick - > q_phase [ 1 ] . q_ordering = true ;
trans_brick - > q_phase [ 3 ] . q_ordering = true ;
2011-05-26 14:32:32 +00:00
2011-06-30 13:15:52 +00:00
trans_brick - > shadow_mem_limit = CONF_TRANS_SHADOW_LIMIT ;
2011-04-19 14:46:38 +00:00
trans_brick - > log_reads = CONF_TRANS_LOG_READS ;
2011-05-26 14:32:32 +00:00
trans_brick - > completion_semantics = CONF_TRANS_COMPLETION_SEMANTICS ;
2011-03-18 13:15:40 +00:00
# ifdef TRANS_FAKE
trans_brick - > debug_shortcut = true ;
2011-03-11 13:57:54 +00:00
# endif
2011-03-18 13:15:40 +00:00
2011-11-03 11:22:50 +00:00
trans_brick - > max_mref_size = CONF_TRANS_MAX_MREF_SIZE ;
2011-03-18 13:15:40 +00:00
trans_brick - > align_size = CONF_TRANS_ALIGN ;
trans_brick - > chunk_size = CONF_TRANS_CHUNKSIZE ;
2011-03-10 11:40:06 +00:00
}
2011-05-06 10:25:52 +00:00
MARS_INF ( " name = '%s' path = '%s' \n " , _brick - > brick_name , _brick - > brick_path ) ;
2011-08-25 10:16:32 +00:00
return 1 ;
2011-03-10 11:40:06 +00:00
}
2012-08-07 12:07:12 +00:00
struct client_cookie {
bool limit_mode ;
2012-12-26 18:35:49 +00:00
bool create_mode ;
2012-08-07 12:07:12 +00:00
} ;
2011-03-22 14:36:26 +00:00
static
2011-08-25 10:16:32 +00:00
int _set_client_params ( struct mars_brick * _brick , void * private )
2011-03-22 14:36:26 +00:00
{
2012-01-23 12:39:08 +00:00
struct client_brick * client_brick = ( void * ) _brick ;
2012-08-07 12:07:12 +00:00
struct client_cookie * clc = private ;
2012-08-14 14:12:59 +00:00
client_brick - > io_timeout = 0 ;
2012-08-07 12:07:12 +00:00
client_brick - > limit_mode = clc ? clc - > limit_mode : false ;
2011-05-06 10:25:52 +00:00
MARS_INF ( " name = '%s' path = '%s' \n " , _brick - > brick_name , _brick - > brick_path ) ;
2011-08-25 10:16:32 +00:00
return 1 ;
2011-03-22 14:36:26 +00:00
}
2011-11-14 13:12:33 +00:00
static
int _set_sio_params ( struct mars_brick * _brick , void * private )
{
struct sio_brick * sio_brick = ( void * ) _brick ;
if ( _brick - > type = = ( void * ) & client_brick_type ) {
return _set_client_params ( _brick , private ) ;
}
if ( _brick - > type ! = ( void * ) & sio_brick_type ) {
MARS_ERR ( " bad brick type \n " ) ;
return - EINVAL ;
}
sio_brick - > o_direct = false ; // important!
sio_brick - > o_fdsync = true ;
MARS_INF ( " name = '%s' path = '%s' \n " , _brick - > brick_name , _brick - > brick_path ) ;
return 1 ;
}
2011-03-11 13:57:54 +00:00
static
2011-08-25 10:16:32 +00:00
int _set_aio_params ( struct mars_brick * _brick , void * private )
2011-03-11 13:57:54 +00:00
{
struct aio_brick * aio_brick = ( void * ) _brick ;
2012-12-26 18:35:49 +00:00
struct client_cookie * clc = private ;
2011-03-22 14:36:26 +00:00
if ( _brick - > type = = ( void * ) & client_brick_type ) {
2011-08-25 10:16:32 +00:00
return _set_client_params ( _brick , private ) ;
2011-03-22 14:36:26 +00:00
}
2011-11-14 13:12:33 +00:00
if ( _brick - > type = = ( void * ) & sio_brick_type ) {
return _set_sio_params ( _brick , private ) ;
}
2011-03-18 13:15:40 +00:00
if ( _brick - > type ! = ( void * ) & aio_brick_type ) {
MARS_ERR ( " bad brick type \n " ) ;
2011-08-25 10:16:32 +00:00
return - EINVAL ;
2011-03-18 13:15:40 +00:00
}
2012-12-26 18:35:49 +00:00
aio_brick - > o_creat = clc & & clc - > create_mode ;
2011-03-11 13:57:54 +00:00
aio_brick - > o_direct = false ; // important!
aio_brick - > o_fdsync = true ;
2011-04-29 09:36:10 +00:00
aio_brick - > wait_during_fdsync = AIO_WAIT_DURING_FDSYNC ;
2011-05-06 10:25:52 +00:00
MARS_INF ( " name = '%s' path = '%s' \n " , _brick - > brick_name , _brick - > brick_path ) ;
2011-08-25 10:16:32 +00:00
return 1 ;
2011-03-11 13:57:54 +00:00
}
2011-03-18 13:15:40 +00:00
static
2011-08-25 10:16:32 +00:00
int _set_bio_params ( struct mars_brick * _brick , void * private )
2011-03-18 13:15:40 +00:00
{
struct bio_brick * bio_brick ;
2011-03-22 14:36:26 +00:00
if ( _brick - > type = = ( void * ) & client_brick_type ) {
2011-08-25 10:16:32 +00:00
return _set_client_params ( _brick , private ) ;
2011-03-22 14:36:26 +00:00
}
2011-03-18 13:15:40 +00:00
if ( _brick - > type = = ( void * ) & aio_brick_type ) {
2011-08-25 10:16:32 +00:00
return _set_aio_params ( _brick , private ) ;
2011-03-18 13:15:40 +00:00
}
2011-11-14 13:12:33 +00:00
if ( _brick - > type = = ( void * ) & sio_brick_type ) {
return _set_sio_params ( _brick , private ) ;
}
2011-03-18 13:15:40 +00:00
if ( _brick - > type ! = ( void * ) & bio_brick_type ) {
MARS_ERR ( " bad brick type \n " ) ;
2011-08-25 10:16:32 +00:00
return - EINVAL ;
2011-03-18 13:15:40 +00:00
}
bio_brick = ( void * ) _brick ;
bio_brick - > ra_pages = BIO_READAHEAD ;
2011-05-06 10:25:52 +00:00
bio_brick - > do_noidle = BIO_NOIDLE ;
bio_brick - > do_sync = BIO_SYNC ;
bio_brick - > do_unplug = BIO_UNPLUG ;
MARS_INF ( " name = '%s' path = '%s' \n " , _brick - > brick_name , _brick - > brick_path ) ;
2011-08-25 10:16:32 +00:00
return 1 ;
2011-03-18 13:15:40 +00:00
}
2011-03-11 13:57:54 +00:00
static
2011-08-25 10:16:32 +00:00
int _set_if_params ( struct mars_brick * _brick , void * private )
2011-03-11 13:57:54 +00:00
{
struct if_brick * if_brick = ( void * ) _brick ;
2012-08-08 13:50:41 +00:00
struct mars_rotate * rot = private ;
2011-03-18 13:15:40 +00:00
if ( _brick - > type ! = ( void * ) & if_brick_type ) {
MARS_ERR ( " bad brick type \n " ) ;
2011-08-25 10:16:32 +00:00
return - EINVAL ;
2011-03-18 13:15:40 +00:00
}
2012-08-08 13:50:41 +00:00
if ( rot )
if_brick - > dev_size = rot - > dev_size ;
2011-03-30 12:02:50 +00:00
if_brick - > max_plugged = IF_MAX_PLUGGED ;
2011-03-11 13:57:54 +00:00
if_brick - > readahead = IF_READAHEAD ;
2011-03-30 12:02:50 +00:00
if_brick - > skip_sync = IF_SKIP_SYNC ;
2012-08-08 13:50:41 +00:00
MARS_INF ( " name = '%s' path = '%s' size = %lld \n " , _brick - > brick_name , _brick - > brick_path , if_brick - > dev_size ) ;
2011-08-25 10:16:32 +00:00
return 1 ;
2011-03-11 13:57:54 +00:00
}
2011-03-10 11:40:06 +00:00
2011-08-25 10:16:32 +00:00
struct copy_cookie {
const char * argv [ 2 ] ;
const char * copy_path ;
loff_t start_pos ;
2012-08-02 08:47:42 +00:00
bool verify_mode ;
2011-08-25 10:16:32 +00:00
const char * fullpath [ 2 ] ;
struct mars_output * output [ 2 ] ;
struct mars_info info [ 2 ] ;
} ;
2011-05-26 14:32:32 +00:00
static
2011-08-25 10:16:32 +00:00
int _set_copy_params ( struct mars_brick * _brick , void * private )
2011-05-26 14:32:32 +00:00
{
struct copy_brick * copy_brick = ( void * ) _brick ;
2011-08-25 10:16:32 +00:00
struct copy_cookie * cc = private ;
int status = 1 ;
2011-05-26 14:32:32 +00:00
if ( _brick - > type ! = ( void * ) & copy_brick_type ) {
MARS_ERR ( " bad brick type \n " ) ;
2011-08-25 10:16:32 +00:00
status = - EINVAL ;
goto done ;
2011-05-26 14:32:32 +00:00
}
copy_brick - > append_mode = COPY_APPEND_MODE ;
copy_brick - > io_prio = COPY_PRIO ;
2012-08-02 08:47:42 +00:00
copy_brick - > verify_mode = cc - > verify_mode ;
copy_brick - > repair_mode = true ;
2011-05-26 14:32:32 +00:00
MARS_INF ( " name = '%s' path = '%s' \n " , _brick - > brick_name , _brick - > brick_path ) ;
2011-08-25 10:16:32 +00:00
/* Determine the copy area, switch on/off when necessary
*/
if ( ! copy_brick - > power . button & & copy_brick - > power . led_off ) {
int i ;
copy_brick - > copy_last = 0 ;
for ( i = 0 ; i < 2 ; i + + ) {
status = cc - > output [ i ] - > ops - > mars_get_info ( cc - > output [ i ] , & cc - > info [ i ] ) ;
if ( status < 0 ) {
2012-01-11 11:35:09 +00:00
MARS_WRN ( " cannot determine current size of '%s' \n " , cc - > argv [ i ] ) ;
2011-08-25 10:16:32 +00:00
goto done ;
}
MARS_DBG ( " %d '%s' current_size = %lld \n " , i , cc - > fullpath [ i ] , cc - > info [ i ] . current_size ) ;
}
copy_brick - > copy_start = cc - > info [ 1 ] . current_size ;
if ( cc - > start_pos ! = - 1 ) {
copy_brick - > copy_start = cc - > start_pos ;
if ( unlikely ( cc - > info [ 0 ] . current_size ! = cc - > info [ 1 ] . current_size ) ) {
MARS_ERR ( " oops, devices have different size %lld != %lld at '%s' \n " , cc - > info [ 0 ] . current_size , cc - > info [ 1 ] . current_size , cc - > copy_path ) ;
status = - EINVAL ;
goto done ;
}
if ( unlikely ( cc - > start_pos > cc - > info [ 0 ] . current_size ) ) {
MARS_ERR ( " bad start position %lld is larger than actual size %lld on '%s' \n " , cc - > start_pos , cc - > info [ 0 ] . current_size , cc - > copy_path ) ;
status = - EINVAL ;
goto done ;
}
}
MARS_DBG ( " copy_start = %lld \n " , copy_brick - > copy_start ) ;
copy_brick - > copy_end = cc - > info [ 0 ] . current_size ;
MARS_DBG ( " copy_end = %lld \n " , copy_brick - > copy_end ) ;
if ( copy_brick - > copy_start < copy_brick - > copy_end ) {
status = 1 ;
MARS_DBG ( " copy switch on \n " ) ;
}
} else if ( copy_brick - > power . button & & copy_brick - > power . led_on & & copy_brick - > copy_last = = copy_brick - > copy_end & & copy_brick - > copy_end > 0 ) {
status = 0 ;
MARS_DBG ( " copy switch off \n " ) ;
}
done :
return status ;
2011-05-26 14:32:32 +00:00
}
2011-02-23 20:48:06 +00:00
///////////////////////////////////////////////////////////////////////
// internal helpers
# define MARS_DELIM ','
2012-01-16 15:35:41 +00:00
static
2012-12-17 08:35:49 +00:00
char * _parse_versionlink ( const char * str , loff_t * pos )
2012-01-16 15:35:41 +00:00
{
char * res = NULL ;
const char * tmp ;
int count ;
int status ;
2012-12-17 08:35:49 +00:00
* pos = 0 ;
2012-01-16 15:35:41 +00:00
while ( * str & & * str + + ! = MARS_DELIM ) {
// empty
}
tmp = str ;
count = 0 ;
while ( * tmp & & * tmp ! = MARS_DELIM ) {
tmp + + ;
count + + ;
}
res = brick_string_alloc ( count + 1 ) ;
if ( unlikely ( ! res ) ) {
MARS_DBG ( " bad alloc \n " ) ;
goto done ;
}
strncpy ( res , str , count ) ;
res [ count ] = ' \0 ' ;
2012-12-17 08:35:49 +00:00
status = sscanf ( tmp , " ,%lld " , pos ) ;
if ( unlikely ( status ! = 1 ) ) {
2012-01-16 15:35:41 +00:00
MARS_DBG ( " status = %d \n " , status ) ;
brick_string_free ( res ) ;
res = NULL ;
}
done :
return res ;
}
2011-02-28 18:00:32 +00:00
static int _parse_args ( struct mars_dent * dent , char * str , int count )
2011-02-23 20:48:06 +00:00
{
int i ;
int status = - EINVAL ;
if ( ! str )
goto done ;
if ( ! dent - > d_args ) {
2011-08-12 11:09:48 +00:00
dent - > d_args = brick_strdup ( str ) ;
2011-02-23 20:48:06 +00:00
if ( ! dent - > d_args ) {
status = - ENOMEM ;
goto done ;
}
}
for ( i = 0 ; i < count ; i + + ) {
char * tmp ;
int len ;
if ( ! * str )
goto done ;
if ( i = = count - 1 ) {
len = strlen ( str ) ;
} else {
char * tmp = strchr ( str , MARS_DELIM ) ;
if ( ! tmp )
goto done ;
len = ( tmp - str ) ;
}
2011-08-25 10:16:32 +00:00
tmp = brick_string_alloc ( len + 1 ) ;
2011-02-23 20:48:06 +00:00
if ( ! tmp ) {
status = - ENOMEM ;
goto done ;
}
2011-08-12 11:09:48 +00:00
brick_string_free ( dent - > d_argv [ i ] ) ;
2011-02-23 20:48:06 +00:00
dent - > d_argv [ i ] = tmp ;
strncpy ( dent - > d_argv [ i ] , str , len ) ;
dent - > d_argv [ i ] [ len ] = ' \0 ' ;
str + = len ;
if ( i ! = count - 1 )
str + + ;
}
status = 0 ;
done :
if ( status < 0 ) {
MARS_ERR ( " bad syntax '%s' (should have %d args), status = %d \n " , dent - > d_args ? dent - > d_args : " " , count , status ) ;
}
return status ;
}
2011-11-08 17:07:42 +00:00
static
bool _check_switch ( struct mars_global * global , const char * path )
{
int res = false ;
struct mars_dent * allow_dent ;
allow_dent = mars_find_dent ( global , path ) ;
if ( ! allow_dent | | ! allow_dent - > new_link )
goto done ;
sscanf ( allow_dent - > new_link , " %d " , & res ) ;
MARS_DBG ( " '%s' -> %d \n " , path , res ) ;
done :
return res ;
}
static
bool _check_allow ( struct mars_global * global , struct mars_dent * parent , const char * name )
{
int res = false ;
char * path = path_make ( " %s/todo-%s/%s " , parent - > d_path , my_id ( ) , name ) ;
if ( ! path )
goto done ;
res = _check_switch ( global , path ) ;
done :
brick_string_free ( path ) ;
return res ;
}
2011-09-27 11:57:04 +00:00
///////////////////////////////////////////////////////////////////////
// status display
2012-12-17 07:25:17 +00:00
static
void _update_replay_link ( struct mars_rotate * rot , struct trans_logger_info * inf )
{
char * check = NULL ;
char * old = NULL ;
char * new = NULL ;
int status ;
old = path_make ( " log-%09d-%s,%lld,%lld " , inf - > inf_sequence , inf - > inf_host , inf - > inf_min_pos , inf - > inf_max_pos - inf - > inf_min_pos ) ;
if ( ! old ) {
goto out ;
}
new = path_make ( " %s/replay-%s " , rot - > parent_path , my_id ( ) ) ;
if ( ! new ) {
goto out ;
}
/* Check whether something really has changed (avoid
* useless / disturbing timestamp updates )
*/
check = mars_readlink ( new ) ;
if ( check & & ! strcmp ( check , old ) ) {
MARS_DBG ( " replay symlink '%s' -> '%s' has not changed \n " , old , new ) ;
goto out ;
}
2012-12-18 04:54:50 +00:00
status = mars_symlink ( old , new , NULL , 0 ) ;
2012-12-17 07:25:17 +00:00
if ( status < 0 ) {
MARS_ERR ( " cannot create symlink '%s' -> '%s' status = %d \n " , old , new , status ) ;
} else {
MARS_DBG ( " made replay symlink '%s' -> '%s' status = %d \n " , old , new , status ) ;
}
out :
brick_string_free ( new ) ;
brick_string_free ( old ) ;
brick_string_free ( check ) ;
}
static
void _update_version_link ( struct mars_rotate * rot , struct trans_logger_info * inf )
{
char * data = brick_string_alloc ( 0 ) ;
char * old = brick_string_alloc ( 0 ) ;
char * new = NULL ;
unsigned char * digest = brick_string_alloc ( 0 ) ;
char * prev = NULL ;
char * check = NULL ;
char * prev_link = NULL ;
2012-12-17 08:35:49 +00:00
char * prev_digest ;
2012-12-17 07:25:17 +00:00
int len ;
int i ;
int status ;
if ( unlikely ( ! data | | ! digest | | ! old ) ) {
MARS_ERR ( " no MEM \n " ) ;
goto out ;
}
if ( likely ( inf - > inf_sequence > 1 ) ) {
if ( unlikely ( inf - > inf_sequence < rot - > inf_prev_sequence & & rot - > inf_prev_version ) ) {
MARS_ERR ( " BACKSKIP in sequence numbers detected: %d < %d \n " , inf - > inf_sequence , rot - > inf_prev_sequence ) ;
goto out ;
}
if ( unlikely ( ! rot - > inf_prev_version | | inf - > inf_sequence ! = rot - > inf_prev_sequence + 1 ) ) {
prev = path_make ( " %s/version-%09d-%s " , rot - > parent_path , inf - > inf_sequence - 1 , my_id ( ) ) ;
if ( unlikely ( ! prev ) ) {
MARS_ERR ( " no MEM \n " ) ;
goto out ;
}
prev_link = mars_readlink ( prev ) ;
if ( unlikely ( ! prev_link ) ) {
MARS_ERR ( " cannot find previous version symlink '%s' \n " , SAFE_STR ( prev ) ) ;
goto out ;
}
brick_string_free ( rot - > inf_prev_version ) ;
rot - > inf_prev_version = brick_strdup ( prev_link ) ;
if ( unlikely ( ! rot - > inf_prev_version ) ) {
MARS_ERR ( " no MEM \n " ) ;
goto out ;
}
rot - > inf_prev_sequence = inf - > inf_sequence - 1 ;
}
}
2012-12-17 08:35:49 +00:00
if ( likely ( rot - > inf_prev_version ) ) {
char * tmp ;
prev_digest = brick_strdup ( rot - > inf_prev_version ) ;
if ( unlikely ( ! prev_digest ) ) {
MARS_ERR ( " no MEM \n " ) ;
goto out ;
}
// just take the hash part out of it
for ( tmp = prev_digest ; * tmp ; tmp + + )
if ( * tmp = = ' , ' )
break ;
* tmp = ' \0 ' ;
} else {
prev_digest = " " ;
}
2012-12-17 07:25:17 +00:00
2012-12-17 08:35:49 +00:00
len = sprintf ( data , " %s,%d,%lld,%s " , inf - > inf_host , inf - > inf_sequence , inf - > inf_log_pos , prev_digest ) ;
if ( prev_digest [ 0 ] )
brick_string_free ( prev_digest ) ;
2012-12-17 07:25:17 +00:00
MARS_DBG ( " data = '%s' len = %d \n " , data , len ) ;
mars_digest ( digest , data , len ) ;
len = 0 ;
for ( i = 0 ; i < mars_digest_size ; i + + ) {
len + = sprintf ( old + len , " %02x " , digest [ i ] ) ;
}
2012-12-17 08:35:49 +00:00
if ( likely ( rot - > inf_prev_version ) ) {
char * tmp ;
prev_digest = brick_strdup ( rot - > inf_prev_version ) ;
if ( unlikely ( ! prev_digest ) ) {
MARS_ERR ( " no MEM \n " ) ;
goto out ;
}
// take the part before ';'
for ( tmp = prev_digest ; * tmp ; tmp + + )
if ( * tmp = = ' ; ' )
break ;
* tmp = ' \0 ' ;
} else {
prev_digest = " " ;
}
len + = sprintf ( old + len , " ,%s,%lld,%d;%s " , inf - > inf_host , inf - > inf_log_pos , inf - > inf_sequence , prev_digest ) ;
if ( prev_digest [ 0 ] )
brick_string_free ( prev_digest ) ;
2012-12-17 07:25:17 +00:00
new = path_make ( " %s/version-%09d-%s " , rot - > parent_path , inf - > inf_sequence , my_id ( ) ) ;
if ( ! new ) {
MARS_ERR ( " no MEM \n " ) ;
goto out ;
}
/* Check whether something really has changed (avoid
* useless / disturbing timestamp updates )
*/
check = mars_readlink ( new ) ;
if ( likely ( check ) ) {
if ( ! strcmp ( check , old ) ) {
MARS_DBG ( " version symlink '%s' -> '%s' has not changed \n " , old , new ) ;
goto out ;
}
}
2012-12-18 04:54:50 +00:00
status = mars_symlink ( old , new , NULL , 0 ) ;
2012-12-17 07:25:17 +00:00
if ( unlikely ( status < 0 ) ) {
MARS_ERR ( " cannot create symlink '%s' -> '%s' status = %d \n " , old , new , status ) ;
} else {
MARS_DBG ( " make version symlink '%s' -> '%s' status = %d \n " , old , new , status ) ;
}
out :
brick_string_free ( new ) ;
brick_string_free ( prev ) ;
brick_string_free ( data ) ;
brick_string_free ( digest ) ;
brick_string_free ( old ) ;
brick_string_free ( check ) ;
brick_string_free ( prev_link ) ;
}
static
void _update_info ( struct trans_logger_info * inf )
{
struct mars_rotate * rot = inf - > inf_private ;
if ( unlikely ( ! rot ) ) {
MARS_ERR ( " rot is NULL \n " ) ;
goto done ;
}
down ( & rot - > inf_mutex ) ;
MARS_DBG ( " inf = %p '%s' seq = %d min_pos = %lld max_pos = %lld log_pos = %lld is_writeback = %d is_applying = %d is_logging = %d \n " ,
inf ,
SAFE_STR ( inf - > inf_host ) ,
inf - > inf_sequence ,
inf - > inf_min_pos ,
inf - > inf_max_pos ,
inf - > inf_log_pos ,
inf - > inf_is_writeback ,
inf - > inf_is_applying ,
inf - > inf_is_logging ) ;
if ( inf - > inf_is_writeback | | inf - > inf_is_applying ) {
_update_replay_link ( rot , inf ) ;
}
if ( inf - > inf_is_logging | | inf - > inf_is_applying ) {
_update_version_link ( rot , inf ) ;
}
up ( & rot - > inf_mutex ) ;
done : ;
}
static
void _make_new_replaylink ( struct mars_rotate * rot , char * new_host , int new_sequence , loff_t end_pos )
{
struct trans_logger_info inf = {
. inf_private = rot ,
. inf_host = new_host ,
. inf_sequence = new_sequence ,
. inf_min_pos = 0 ,
. inf_max_pos = 0 ,
. inf_log_pos = end_pos ,
. inf_is_applying = true ,
} ;
down ( & rot - > inf_mutex ) ;
MARS_DBG ( " new_host = '%s' new_sequence = %d end_pos = %lld \n " , new_host , new_sequence , end_pos ) ;
_update_replay_link ( rot , & inf ) ;
_update_version_link ( rot , & inf ) ;
up ( & rot - > inf_mutex ) ;
# ifdef CONFIG_MARS_FAST_TRIGGER
mars_trigger ( ) ;
mars_remote_trigger ( ) ;
# endif
}
2011-09-27 11:57:04 +00:00
static
2012-09-25 15:41:07 +00:00
int __show_actual ( const char * path , const char * name , int val )
2011-09-27 11:57:04 +00:00
{
char * src ;
char * dst = NULL ;
int status = - EINVAL ;
2012-09-25 15:41:07 +00:00
src = path_make ( " %d " , val ) ;
2011-09-27 11:57:04 +00:00
dst = path_make ( " %s/actual-%s/%s " , path , my_id ( ) , name ) ;
status = - ENOMEM ;
if ( ! dst )
goto done ;
2012-09-25 15:41:07 +00:00
2011-09-27 11:57:04 +00:00
MARS_DBG ( " symlink '%s' -> '%s' \n " , dst , src ) ;
status = mars_symlink ( src , dst , NULL , 0 ) ;
done :
2012-09-25 15:41:07 +00:00
brick_string_free ( src ) ;
2011-09-27 11:57:04 +00:00
brick_string_free ( dst ) ;
return status ;
}
2012-09-25 15:41:07 +00:00
static inline
int _show_actual ( const char * path , const char * name , bool val )
{
return __show_actual ( path , name , val ? 1 : 0 ) ;
}
2011-09-27 11:57:04 +00:00
static
void _show_primary ( struct mars_rotate * rot , struct mars_dent * parent )
{
int status ;
if ( ! rot | | ! parent ) {
return ;
}
status = _show_actual ( parent - > d_path , " is-primary " , rot - > is_primary ) ;
2012-01-17 14:37:14 +00:00
if ( rot - > is_primary ! = rot - > old_is_primary ) {
rot - > old_is_primary = rot - > is_primary ;
mars_remote_trigger ( ) ;
}
2011-09-27 11:57:04 +00:00
}
static
void _show_brick_status ( struct mars_brick * test , bool shutdown )
{
const char * path ;
char * src ;
char * dst ;
int status ;
path = test - > brick_path ;
if ( ! path ) {
MARS_WRN ( " bad path \n " ) ;
return ;
}
if ( * path ! = ' / ' ) {
MARS_WRN ( " bogus path '%s' \n " , path ) ;
return ;
}
src = ( test - > power . led_on & & ! shutdown ) ? " 1 " : " 0 " ;
dst = backskip_replace ( path , ' / ' , true , " /actual-%s/ " , my_id ( ) ) ;
if ( ! dst ) {
return ;
}
status = mars_symlink ( src , dst , NULL , 0 ) ;
MARS_DBG ( " status symlink '%s' -> '%s' status = %d \n " , dst , src , status ) ;
brick_string_free ( dst ) ;
}
static
void _show_status_all ( struct mars_global * global )
{
struct list_head * tmp ;
down_read ( & global - > brick_mutex ) ;
for ( tmp = global - > brick_anchor . next ; tmp ! = & global - > brick_anchor ; tmp = tmp - > next ) {
struct mars_brick * test ;
test = container_of ( tmp , struct mars_brick , global_brick_link ) ;
2011-09-29 08:15:21 +00:00
if ( ! test - > show_status )
2011-09-27 11:57:04 +00:00
continue ;
_show_brick_status ( test , false ) ;
}
up_read ( & global - > brick_mutex ) ;
}
2012-09-25 15:41:07 +00:00
static
void _show_rate ( struct mars_rotate * rot , struct mars_limiter * limiter , bool running , const char * name )
{
int rate = limiter - > lim_rate ;
if ( ! running )
rate = 0 ;
__show_actual ( rot - > parent_path , name , rate ) ;
}
2011-09-27 11:57:04 +00:00
2011-02-25 11:46:38 +00:00
///////////////////////////////////////////////////////////////////////
static
2011-03-01 09:34:36 +00:00
int __make_copy (
struct mars_global * global ,
struct mars_dent * belongs ,
2011-03-23 08:09:00 +00:00
const char * switch_path ,
2011-03-22 14:36:26 +00:00
const char * copy_path ,
2011-03-03 09:02:10 +00:00
const char * parent ,
2011-03-01 09:34:36 +00:00
const char * argv [ ] ,
2011-03-04 07:41:00 +00:00
loff_t start_pos , // -1 means at EOF
2012-08-02 08:47:42 +00:00
bool verify_mode ,
2012-08-07 12:07:12 +00:00
bool limit_mode ,
2011-03-01 09:34:36 +00:00
struct copy_brick * * __copy )
2011-02-25 11:46:38 +00:00
{
struct mars_brick * copy ;
struct copy_brick * _copy ;
2011-08-25 10:16:32 +00:00
struct copy_cookie cc = { } ;
2012-12-26 18:35:49 +00:00
struct client_cookie clc [ 2 ] = {
{
. limit_mode = limit_mode ,
} ,
{
. limit_mode = limit_mode ,
. create_mode = true ,
} ,
2012-08-07 12:07:12 +00:00
} ;
2011-02-25 11:46:38 +00:00
int i ;
2011-03-23 17:58:02 +00:00
int status = - EINVAL ;
2011-11-08 17:07:42 +00:00
if ( ! switch_path | | ! global ) {
2011-03-23 17:58:02 +00:00
goto done ;
}
2011-02-25 11:46:38 +00:00
2011-11-08 17:07:42 +00:00
// don't generate empty aio files if copy does not yet exist
copy = mars_find_brick ( global , & copy_brick_type , copy_path ) ;
if ( ! copy & & ! _check_switch ( global , switch_path ) )
goto done ;
// create/find predecessor aio bricks
2011-02-25 11:46:38 +00:00
for ( i = 0 ; i < 2 ; i + + ) {
2011-03-02 09:30:56 +00:00
struct mars_brick * aio ;
2011-03-03 09:02:10 +00:00
2011-08-25 10:16:32 +00:00
cc . argv [ i ] = argv [ i ] ;
2011-03-03 09:02:10 +00:00
if ( parent ) {
2011-08-25 10:16:32 +00:00
cc . fullpath [ i ] = path_make ( " %s/%s " , parent , argv [ i ] ) ;
if ( ! cc . fullpath [ i ] ) {
2011-03-03 09:02:10 +00:00
MARS_ERR ( " cannot make path '%s/%s' \n " , parent , argv [ i ] ) ;
goto done ;
}
} else {
2011-08-25 10:16:32 +00:00
cc . fullpath [ i ] = argv [ i ] ;
2011-03-03 09:02:10 +00:00
}
2011-03-02 09:30:56 +00:00
aio =
2011-03-01 09:34:36 +00:00
make_brick_all ( global ,
2011-03-11 13:57:54 +00:00
NULL ,
2011-09-02 12:17:40 +00:00
false ,
2012-12-26 18:35:49 +00:00
_set_bio_params ,
& clc [ i ] ,
2011-03-01 09:34:36 +00:00
10 * HZ ,
2011-03-03 09:02:10 +00:00
NULL ,
2011-03-22 14:36:26 +00:00
( const struct generic_brick_type * ) & bio_brick_type ,
2011-03-01 09:34:36 +00:00
( const struct generic_brick_type * [ ] ) { } ,
2011-03-23 08:09:00 +00:00
NULL ,
2011-11-03 11:31:47 +00:00
1 , // start always
2011-08-25 10:16:32 +00:00
cc . fullpath [ i ] ,
2011-03-01 09:34:36 +00:00
( const char * [ ] ) { } ,
2011-03-03 09:02:10 +00:00
0 ) ;
2011-03-02 09:30:56 +00:00
if ( ! aio ) {
2011-08-25 10:16:32 +00:00
MARS_DBG ( " cannot instantiate '%s' \n " , cc . fullpath [ i ] ) ;
2011-02-25 11:46:38 +00:00
goto done ;
}
2011-08-25 10:16:32 +00:00
cc . output [ i ] = aio - > outputs [ 0 ] ;
2011-02-25 11:46:38 +00:00
}
2011-08-25 10:16:32 +00:00
cc . copy_path = copy_path ;
cc . start_pos = start_pos ;
2012-08-02 08:47:42 +00:00
cc . verify_mode = verify_mode ;
2011-08-25 10:16:32 +00:00
2011-03-01 09:34:36 +00:00
copy =
make_brick_all ( global ,
belongs ,
2011-09-02 12:17:40 +00:00
false ,
2011-05-26 14:32:32 +00:00
_set_copy_params ,
2011-08-25 10:16:32 +00:00
& cc ,
10 * HZ ,
cc . fullpath [ 1 ] ,
2011-03-01 09:34:36 +00:00
( const struct generic_brick_type * ) & copy_brick_type ,
( const struct generic_brick_type * [ ] ) { NULL , NULL , NULL , NULL } ,
2011-03-03 09:02:10 +00:00
" %s " ,
2012-01-31 15:19:35 +00:00
( global - > exhausted | | ! switch_path [ 0 ] ) ? - 1 : 0 ,
2011-03-23 08:09:00 +00:00
" %s " ,
2011-03-03 09:02:10 +00:00
( const char * [ ] ) { " %s " , " %s " , " %s " , " %s " } ,
2011-03-02 09:30:56 +00:00
4 ,
2011-03-23 08:09:00 +00:00
switch_path ,
2011-03-22 14:36:26 +00:00
copy_path ,
2011-08-25 10:16:32 +00:00
cc . fullpath [ 0 ] ,
cc . fullpath [ 0 ] ,
cc . fullpath [ 1 ] ,
cc . fullpath [ 1 ] ) ;
2011-02-25 11:46:38 +00:00
if ( ! copy ) {
2011-06-17 11:32:38 +00:00
MARS_DBG ( " creation of copy brick '%s' failed \n " , copy_path ) ;
2011-03-01 09:34:36 +00:00
goto done ;
2011-02-25 11:46:38 +00:00
}
2011-09-27 11:57:04 +00:00
copy - > show_status = _show_brick_status ;
2011-02-25 11:46:38 +00:00
_copy = ( void * ) copy ;
if ( __copy )
* __copy = _copy ;
status = 0 ;
done :
MARS_DBG ( " status = %d \n " , status ) ;
2011-03-03 09:02:10 +00:00
for ( i = 0 ; i < 2 ; i + + ) {
2011-08-25 10:16:32 +00:00
if ( cc . fullpath [ i ] & & cc . fullpath [ i ] ! = argv [ i ] )
brick_string_free ( cc . fullpath [ i ] ) ;
2011-03-03 09:02:10 +00:00
}
2011-02-25 11:46:38 +00:00
return status ;
}
2011-02-23 20:48:06 +00:00
///////////////////////////////////////////////////////////////////////
// remote workers
struct mars_peerinfo {
2011-02-24 16:37:32 +00:00
struct mars_global * global ;
2011-02-23 20:48:06 +00:00
char * peer ;
char * path ;
2012-01-11 11:35:09 +00:00
struct mars_socket socket ;
2011-08-25 10:16:32 +00:00
struct task_struct * peer_thread ;
2011-03-22 14:36:26 +00:00
spinlock_t lock ;
struct list_head remote_dent_list ;
2011-02-23 20:48:06 +00:00
int maxdepth ;
} ;
2011-02-24 16:37:32 +00:00
static
2011-03-23 08:09:00 +00:00
bool _is_usable_dir ( const char * name )
{
if ( ! strncmp ( name , " resource- " , 9 )
2011-09-23 14:08:17 +00:00
| | ! strncmp ( name , " todo- " , 5 )
| | ! strncmp ( name , " actual- " , 7 )
2011-03-23 08:09:00 +00:00
| | ! strncmp ( name , " defaults " , 8 )
) {
return true ;
}
return false ;
}
static
bool _is_peer_logfile ( const char * name , const char * id )
2011-03-22 14:36:26 +00:00
{
int len = strlen ( name ) ;
int idlen = id ? strlen ( id ) : 4 + 9 + 1 ;
if ( len < = idlen | |
strncmp ( name , " log- " , 4 ) ! = 0 ) {
MARS_DBG ( " not a logfile at all: '%s' \n " , name ) ;
return false ;
}
if ( id & &
name [ len - idlen - 1 ] = = ' - ' & &
strncmp ( name + len - idlen , id , idlen ) = = 0 ) {
MARS_DBG ( " not a peer logfile: '%s' \n " , name ) ;
return false ;
}
MARS_DBG ( " found peer logfile: '%s' \n " , name ) ;
return true ;
}
static
2012-01-25 13:20:47 +00:00
int _update_file ( struct mars_rotate * rot , const char * switch_path , const char * copy_path , const char * file , const char * peer , loff_t end_pos )
2011-02-24 16:37:32 +00:00
{
2012-01-25 13:20:47 +00:00
struct mars_global * global = rot - > global ;
2011-03-22 14:36:26 +00:00
const char * tmp = path_make ( " %s@%s " , file , peer ) ;
const char * argv [ 2 ] = { tmp , file } ;
2011-03-04 07:41:00 +00:00
struct copy_brick * copy = NULL ;
2011-03-01 18:00:14 +00:00
int status = - ENOMEM ;
2011-02-24 16:37:32 +00:00
2012-01-25 13:20:47 +00:00
if ( unlikely ( ! tmp | | ! global ) )
2011-03-01 18:00:14 +00:00
goto done ;
2011-02-24 16:37:32 +00:00
2011-03-22 14:36:26 +00:00
MARS_DBG ( " src = '%s' dst = '%s' \n " , tmp , file ) ;
2012-08-07 12:07:12 +00:00
status = __make_copy ( global , NULL , switch_path , copy_path , NULL , argv , - 1 , false , false , & copy ) ;
2012-09-25 15:41:07 +00:00
if ( status > = 0 & & copy ) {
copy - > copy_limiter = & rot - > file_limiter ;
if ( ( ! copy - > append_mode | | copy - > power . led_off ) & &
end_pos > copy - > copy_end ) {
2011-03-22 14:36:26 +00:00
MARS_DBG ( " appending to '%s' %lld => %lld \n " , copy_path , copy - > copy_end , end_pos ) ;
2011-03-04 07:41:00 +00:00
copy - > copy_end = end_pos ;
}
}
2011-02-24 16:37:32 +00:00
2011-03-01 18:00:14 +00:00
done :
2011-10-05 14:59:29 +00:00
brick_string_free ( tmp ) ;
2011-02-24 16:37:32 +00:00
return status ;
}
static
2012-02-21 11:23:38 +00:00
int check_logfile ( const char * peer , struct mars_dent * remote_dent , struct mars_dent * local_dent , struct mars_dent * parent , loff_t dst_size )
2011-02-24 16:37:32 +00:00
{
2011-10-07 10:29:23 +00:00
loff_t src_size = remote_dent - > new_stat . size ;
2011-07-08 07:02:14 +00:00
struct mars_rotate * rot ;
2011-03-23 08:09:00 +00:00
const char * switch_path = NULL ;
2011-03-22 14:36:26 +00:00
struct copy_brick * copy_brick ;
int status = 0 ;
2011-02-24 16:37:32 +00:00
2011-03-25 10:34:54 +00:00
// plausibility checks
if ( unlikely ( dst_size > src_size ) ) {
MARS_WRN ( " my local copy is larger than the remote one, ignoring \n " ) ;
status = - EINVAL ;
2011-03-22 14:36:26 +00:00
goto done ;
2011-02-24 16:37:32 +00:00
}
2011-03-22 14:36:26 +00:00
2011-10-07 10:29:23 +00:00
// check whether we are participating in that resource
2011-07-08 07:02:14 +00:00
rot = parent - > d_private ;
if ( ! rot ) {
2011-11-08 17:07:42 +00:00
MARS_WRN ( " parent has no rot info \n " ) ;
2011-07-08 07:02:14 +00:00
status = - EINVAL ;
goto done ;
}
2012-02-21 11:23:38 +00:00
if ( ! rot - > copy_path ) {
MARS_WRN ( " parent has no copy_path \n " ) ;
status = - EINVAL ;
goto done ;
}
2011-07-08 07:02:14 +00:00
2011-03-22 14:36:26 +00:00
// check whether connection is allowed
2011-09-21 11:30:11 +00:00
switch_path = path_make ( " %s/todo-%s/connect " , parent - > d_path , my_id ( ) ) ;
2012-02-03 10:25:17 +00:00
// check whether copy is necessary
2012-02-21 11:23:38 +00:00
copy_brick = rot - > copy_brick ;
MARS_DBG ( " copy_brick = %p (remote '%s' %d) copy_serial = %d \n " , copy_brick , remote_dent - > d_path , remote_dent - > d_serial , rot - > copy_serial ) ;
2012-02-03 10:25:17 +00:00
if ( copy_brick ) {
2012-02-21 11:23:38 +00:00
if ( remote_dent - > d_serial = = rot - > copy_serial ) {
2012-02-03 10:25:17 +00:00
// treat copy brick instance underway
2012-02-21 11:23:38 +00:00
status = _update_file ( rot , switch_path , rot - > copy_path , remote_dent - > d_path , peer , src_size ) ;
MARS_DBG ( " re-update '%s' from peer '%s' status = %d \n " , remote_dent - > d_path , peer , status ) ;
2012-02-03 10:25:17 +00:00
}
2012-02-21 11:23:38 +00:00
} else if ( ! rot - > copy_serial & & rot - > allow_update & &
2012-02-03 10:25:17 +00:00
( dst_size < src_size | | ! local_dent ) ) {
// start copy brick instance
2012-02-21 11:23:38 +00:00
status = _update_file ( rot , switch_path , rot - > copy_path , remote_dent - > d_path , peer , src_size ) ;
MARS_DBG ( " update '%s' from peer '%s' status = %d \n " , remote_dent - > d_path , peer , status ) ;
rot - > copy_serial = remote_dent - > d_serial ;
2011-03-22 14:36:26 +00:00
}
done :
2011-10-05 14:59:29 +00:00
brick_string_free ( switch_path ) ;
2011-03-22 14:36:26 +00:00
return status ;
2011-02-24 16:37:32 +00:00
}
static
2011-10-07 10:29:23 +00:00
int run_bone ( struct mars_peerinfo * peer , struct mars_dent * remote_dent )
2011-02-23 20:48:06 +00:00
{
int status = 0 ;
2011-02-27 14:17:58 +00:00
struct kstat local_stat = { } ;
bool stat_ok ;
bool update_mtime = true ;
bool update_ctime = true ;
2011-03-22 14:36:26 +00:00
bool run_trigger = false ;
2011-02-24 16:37:32 +00:00
2011-10-07 10:29:23 +00:00
if ( ! strncmp ( remote_dent - > d_name , " .tmp " , 4 ) ) {
2011-02-24 16:37:32 +00:00
goto done ;
}
2011-10-07 10:29:23 +00:00
if ( ! strncmp ( remote_dent - > d_name , " ignore " , 6 ) ) {
2011-02-24 16:37:32 +00:00
goto done ;
}
2011-10-07 10:29:23 +00:00
status = mars_stat ( remote_dent - > d_path , & local_stat , true ) ;
2011-02-27 14:17:58 +00:00
stat_ok = ( status > = 0 ) ;
if ( stat_ok ) {
2011-10-07 10:29:23 +00:00
update_mtime = timespec_compare ( & remote_dent - > new_stat . mtime , & local_stat . mtime ) > 0 ;
update_ctime = timespec_compare ( & remote_dent - > new_stat . ctime , & local_stat . ctime ) > 0 ;
2011-02-27 14:17:58 +00:00
2012-01-24 09:06:33 +00:00
MARS_IO ( " timestamps '%s' remote = %ld.%09ld local = %ld.%09ld \n " , remote_dent - > d_path , remote_dent - > new_stat . mtime . tv_sec , remote_dent - > new_stat . mtime . tv_nsec , local_stat . mtime . tv_sec , local_stat . mtime . tv_nsec ) ;
2011-02-27 14:17:58 +00:00
2011-10-07 10:29:23 +00:00
if ( ( remote_dent - > new_stat . mode & S_IRWXU ) ! =
2011-02-27 14:17:58 +00:00
( local_stat . mode & S_IRWXU ) & &
update_ctime ) {
mode_t newmode = local_stat . mode ;
2012-01-24 09:06:33 +00:00
MARS_IO ( " chmod '%s' 0x%xd -> 0x%xd \n " , remote_dent - > d_path , newmode & S_IRWXU , remote_dent - > new_stat . mode & S_IRWXU ) ;
2011-02-27 14:17:58 +00:00
newmode & = ~ S_IRWXU ;
2011-10-07 10:29:23 +00:00
newmode | = ( remote_dent - > new_stat . mode & S_IRWXU ) ;
mars_chmod ( remote_dent - > d_path , newmode ) ;
2011-03-22 14:36:26 +00:00
run_trigger = true ;
2011-02-27 14:17:58 +00:00
}
2011-10-07 10:29:23 +00:00
if ( remote_dent - > new_stat . uid ! = local_stat . uid & & update_ctime ) {
2012-01-24 09:06:33 +00:00
MARS_IO ( " lchown '%s' %d -> %d \n " , remote_dent - > d_path , local_stat . uid , remote_dent - > new_stat . uid ) ;
2011-10-07 10:29:23 +00:00
mars_lchown ( remote_dent - > d_path , remote_dent - > new_stat . uid ) ;
2011-03-22 14:36:26 +00:00
run_trigger = true ;
2011-02-27 14:17:58 +00:00
}
}
2011-02-23 20:48:06 +00:00
2011-10-07 10:29:23 +00:00
if ( S_ISDIR ( remote_dent - > new_stat . mode ) ) {
if ( ! _is_usable_dir ( remote_dent - > d_name ) ) {
2012-01-24 09:06:33 +00:00
MARS_IO ( " ignoring directory '%s' \n " , remote_dent - > d_path ) ;
2011-02-24 16:37:32 +00:00
goto done ;
}
2011-02-27 14:17:58 +00:00
if ( ! stat_ok ) {
2011-10-07 10:29:23 +00:00
status = mars_mkdir ( remote_dent - > d_path ) ;
2012-01-24 09:06:33 +00:00
MARS_IO ( " create directory '%s' status = %d \n " , remote_dent - > d_path , status ) ;
2011-03-22 14:36:26 +00:00
if ( status > = 0 ) {
2011-10-07 10:29:23 +00:00
mars_chmod ( remote_dent - > d_path , remote_dent - > new_stat . mode ) ;
mars_lchown ( remote_dent - > d_path , remote_dent - > new_stat . uid ) ;
2011-03-22 14:36:26 +00:00
}
2011-02-23 20:48:06 +00:00
}
2011-10-07 10:29:23 +00:00
} else if ( S_ISLNK ( remote_dent - > new_stat . mode ) & & remote_dent - > new_link ) {
2011-02-27 14:17:58 +00:00
if ( ! stat_ok | | update_mtime ) {
2011-10-07 10:29:23 +00:00
status = mars_symlink ( remote_dent - > new_link , remote_dent - > d_path , & remote_dent - > new_stat . mtime , remote_dent - > new_stat . uid ) ;
2012-01-24 09:06:33 +00:00
MARS_IO ( " create symlink '%s' -> '%s' status = %d \n " , remote_dent - > d_path , remote_dent - > new_link , status ) ;
2011-03-22 14:36:26 +00:00
run_trigger = true ;
2011-02-24 16:37:32 +00:00
}
2011-10-07 10:29:23 +00:00
} else if ( S_ISREG ( remote_dent - > new_stat . mode ) & & _is_peer_logfile ( remote_dent - > d_name , my_id ( ) ) ) {
const char * parent_path = backskip_replace ( remote_dent - > d_path , ' / ' , false , " " ) ;
2011-03-22 14:36:26 +00:00
if ( likely ( parent_path ) ) {
struct mars_dent * parent = mars_find_dent ( peer - > global , parent_path ) ;
2011-10-07 10:29:23 +00:00
struct mars_dent * local_dent = mars_find_dent ( peer - > global , remote_dent - > d_path ) ;
2011-03-22 14:36:26 +00:00
if ( unlikely ( ! parent ) ) {
2012-01-24 09:06:33 +00:00
MARS_IO ( " ignoring non-existing local resource '%s' \n " , parent_path ) ;
2012-08-14 14:38:10 +00:00
# if defined(CONFIG_MARS_LOGDELETE_AUTO)
2012-03-06 11:56:48 +00:00
// don't copy old / outdated logfiles
} else if ( parent - > d_private & &
( ( struct mars_rotate * ) parent - > d_private ) - > relevant_serial > remote_dent - > d_serial ) {
MARS_IO ( " ignoring outdated remote logfile '%s' \n " , remote_dent - > d_path ) ;
# endif
2011-03-22 14:36:26 +00:00
} else {
2012-02-21 11:23:38 +00:00
status = check_logfile ( peer - > peer , remote_dent , local_dent , parent , local_stat . size ) ;
2011-02-24 16:37:32 +00:00
}
2011-08-12 11:09:48 +00:00
brick_string_free ( parent_path ) ;
2011-02-24 16:37:32 +00:00
}
2011-02-23 20:48:06 +00:00
} else {
2012-01-24 09:06:33 +00:00
MARS_IO ( " ignoring '%s' \n " , remote_dent - > d_path ) ;
2011-02-23 20:48:06 +00:00
}
2011-02-24 16:37:32 +00:00
done :
2011-03-22 14:36:26 +00:00
if ( status > = 0 ) {
status = run_trigger ? 1 : 0 ;
}
return status ;
}
static
int run_bones ( struct mars_peerinfo * peer )
{
LIST_HEAD ( tmp_list ) ;
struct list_head * tmp ;
unsigned long flags ;
bool run_trigger = false ;
int status = 0 ;
traced_lock ( & peer - > lock , flags ) ;
list_replace_init ( & peer - > remote_dent_list , & tmp_list ) ;
traced_unlock ( & peer - > lock , flags ) ;
2012-01-24 09:00:21 +00:00
MARS_DBG ( " remote_dent_list list_empty = %d \n " , list_empty ( & tmp_list ) ) ;
2011-03-22 14:36:26 +00:00
for ( tmp = tmp_list . next ; tmp ! = & tmp_list ; tmp = tmp - > next ) {
2011-10-07 10:29:23 +00:00
struct mars_dent * remote_dent = container_of ( tmp , struct mars_dent , dent_link ) ;
if ( ! remote_dent - > d_path ) {
2011-03-22 14:36:26 +00:00
MARS_DBG ( " NULL \n " ) ;
continue ;
}
2012-01-24 09:06:33 +00:00
MARS_IO ( " path = '%s' \n " , remote_dent - > d_path ) ;
2011-10-07 10:29:23 +00:00
status = run_bone ( peer , remote_dent ) ;
2011-03-22 14:36:26 +00:00
if ( status > 0 )
run_trigger = true ;
2011-10-07 10:29:23 +00:00
//MARS_DBG("path = '%s' worker status = %d\n", remote_dent->d_path, status);
2011-03-22 14:36:26 +00:00
}
2011-09-27 08:46:14 +00:00
mars_free_dent_all ( NULL , & tmp_list ) ;
2012-01-17 10:48:56 +00:00
# ifdef CONFIG_MARS_FAST_TRIGGER
2011-03-22 14:36:26 +00:00
if ( run_trigger ) {
mars_trigger ( ) ;
}
# endif
2011-02-23 20:48:06 +00:00
return status ;
}
///////////////////////////////////////////////////////////////////////
// remote working infrastructure
2011-02-24 16:37:32 +00:00
static
2012-01-11 11:35:09 +00:00
void _peer_cleanup ( struct mars_peerinfo * peer )
2011-02-23 20:48:06 +00:00
{
2012-01-11 11:35:09 +00:00
MARS_DBG ( " cleanup \n " ) ;
2012-11-30 10:52:21 +00:00
if ( mars_socket_is_alive ( & peer - > socket ) ) {
2012-01-11 11:35:09 +00:00
MARS_DBG ( " really shutdown socket \n " ) ;
mars_shutdown_socket ( & peer - > socket ) ;
2011-02-23 20:48:06 +00:00
}
2012-11-30 10:52:21 +00:00
mars_put_socket ( & peer - > socket ) ;
2011-02-23 20:48:06 +00:00
}
2012-01-17 14:37:14 +00:00
static DECLARE_WAIT_QUEUE_HEAD ( remote_event ) ;
static atomic_t remote_trigger_count = ATOMIC_INIT ( 0 ) ;
static atomic_t peer_thread_count = ATOMIC_INIT ( 0 ) ;
2011-02-24 16:37:32 +00:00
static
2012-01-11 11:35:09 +00:00
int peer_thread ( void * data )
2011-02-23 20:48:06 +00:00
{
struct mars_peerinfo * peer = data ;
2011-02-24 16:37:32 +00:00
char * real_peer ;
2011-02-23 20:48:06 +00:00
struct sockaddr_storage sockaddr = { } ;
2012-07-17 10:00:58 +00:00
int pause_time = 0 ;
2012-11-30 10:52:21 +00:00
bool do_kill = false ;
2012-01-24 09:00:21 +00:00
bool flip = false ;
2011-02-23 20:48:06 +00:00
int status ;
if ( ! peer )
return - 1 ;
2011-07-22 10:43:40 +00:00
real_peer = mars_translate_hostname ( peer - > peer ) ;
2012-01-11 11:35:09 +00:00
MARS_INF ( " -------- peer thread starting on peer '%s' (%s) \n " , peer - > peer , real_peer ) ;
2011-02-23 20:48:06 +00:00
2011-02-24 16:37:32 +00:00
status = mars_create_sockaddr ( & sockaddr , real_peer ) ;
2011-02-23 20:48:06 +00:00
if ( unlikely ( status < 0 ) ) {
2011-02-24 16:37:32 +00:00
MARS_ERR ( " unusable remote address '%s' (%s) \n " , real_peer , peer - > peer ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2012-01-17 14:37:14 +00:00
atomic_inc ( & peer_thread_count ) ;
2012-11-13 16:01:37 +00:00
while ( ! brick_thread_should_stop ( ) ) {
2011-02-23 20:48:06 +00:00
LIST_HEAD ( tmp_list ) ;
2011-03-22 14:36:26 +00:00
LIST_HEAD ( old_list ) ;
unsigned long flags ;
2011-02-23 20:48:06 +00:00
struct mars_cmd cmd = {
. cmd_code = CMD_GETENTS ,
. cmd_str1 = peer - > path ,
. cmd_int1 = peer - > maxdepth ,
} ;
2012-01-11 11:35:09 +00:00
if ( ! mars_socket_is_alive ( & peer - > socket ) ) {
2012-11-30 10:52:21 +00:00
if ( do_kill ) {
do_kill = false ;
2012-01-11 11:35:09 +00:00
_peer_cleanup ( peer ) ;
2012-09-17 10:11:25 +00:00
brick_msleep ( 5000 ) ;
2012-01-11 11:35:09 +00:00
continue ;
}
2012-08-06 13:04:32 +00:00
if ( ! mars_net_is_alive ) {
2012-09-17 10:11:25 +00:00
brick_msleep ( 1000 ) ;
2012-08-06 13:04:32 +00:00
continue ;
}
2012-01-11 11:35:09 +00:00
status = mars_create_socket ( & peer - > socket , & sockaddr , false ) ;
if ( unlikely ( status < 0 ) ) {
2011-02-24 16:37:32 +00:00
MARS_INF ( " no connection to '%s' \n " , real_peer ) ;
2012-09-17 10:11:25 +00:00
brick_msleep ( 5000 ) ;
2011-02-23 20:48:06 +00:00
continue ;
}
2012-11-30 10:52:21 +00:00
do_kill = true ;
2012-01-18 14:31:39 +00:00
peer - > socket . s_shutdown_on_err = true ;
2011-02-24 16:37:32 +00:00
MARS_DBG ( " successfully opened socket to '%s' \n " , real_peer ) ;
2012-09-17 10:11:25 +00:00
brick_msleep ( 100 ) ;
2011-02-23 20:48:06 +00:00
continue ;
}
2012-01-17 14:37:14 +00:00
/* This is not completely race-free, but does no harm.
* In worst case , network propagation will just take
* a litte longer ( see CONFIG_MARS_PROPAGATE_INTERVAL ) .
*/
2012-01-24 09:00:21 +00:00
if ( ! flip & & atomic_read ( & remote_trigger_count ) > 0 ) {
MARS_DBG ( " sending notify ... remote_tiogger_count = %d \n " , atomic_read ( & remote_trigger_count ) ) ;
2012-01-17 14:37:14 +00:00
atomic_dec ( & remote_trigger_count ) ;
cmd . cmd_code = CMD_NOTIFY ;
2012-01-24 09:00:21 +00:00
flip = true ;
2012-01-17 14:37:14 +00:00
}
2012-01-11 11:35:09 +00:00
status = mars_send_struct ( & peer - > socket , & cmd , mars_cmd_meta ) ;
2011-02-23 20:48:06 +00:00
if ( unlikely ( status < 0 ) ) {
2011-08-31 11:42:04 +00:00
MARS_WRN ( " communication error on send, status = %d \n " , status ) ;
2012-11-30 10:52:21 +00:00
if ( do_kill ) {
do_kill = false ;
_peer_cleanup ( peer ) ;
}
2012-09-17 10:11:25 +00:00
brick_msleep ( 2000 ) ;
2011-02-23 20:48:06 +00:00
continue ;
}
2012-01-24 09:00:21 +00:00
if ( cmd . cmd_code = = CMD_NOTIFY ) {
flip = false ;
2012-07-17 10:00:58 +00:00
pause_time = 0 ;
2012-09-17 10:11:25 +00:00
brick_msleep ( 1000 ) ;
2012-01-17 14:37:14 +00:00
continue ;
2012-01-24 09:00:21 +00:00
}
2011-02-23 20:48:06 +00:00
2012-01-24 09:00:21 +00:00
MARS_DBG ( " fetching remote dentry list \n " ) ;
2012-01-11 11:35:09 +00:00
status = mars_recv_dent_list ( & peer - > socket , & tmp_list ) ;
2011-02-23 20:48:06 +00:00
if ( unlikely ( status < 0 ) ) {
2011-08-31 11:42:04 +00:00
MARS_WRN ( " communication error on receive, status = %d \n " , status ) ;
2012-11-30 10:52:21 +00:00
if ( do_kill ) {
do_kill = false ;
_peer_cleanup ( peer ) ;
}
2012-11-29 14:35:41 +00:00
mars_free_dent_all ( NULL , & tmp_list ) ;
2012-09-17 10:11:25 +00:00
brick_msleep ( 5000 ) ;
2011-02-23 20:48:06 +00:00
continue ;
}
2012-01-18 14:33:39 +00:00
if ( likely ( ! list_empty ( & tmp_list ) ) ) {
2012-01-24 09:00:21 +00:00
MARS_DBG ( " got remote denties \n " ) ;
2011-02-23 20:48:06 +00:00
2012-01-18 14:33:39 +00:00
traced_lock ( & peer - > lock , flags ) ;
2011-03-22 14:36:26 +00:00
2012-01-18 14:33:39 +00:00
list_replace_init ( & peer - > remote_dent_list , & old_list ) ;
list_replace_init ( & tmp_list , & peer - > remote_dent_list ) ;
2011-02-23 20:48:06 +00:00
2012-01-18 14:33:39 +00:00
traced_unlock ( & peer - > lock , flags ) ;
2011-03-22 14:36:26 +00:00
2012-01-18 14:33:39 +00:00
mars_free_dent_all ( NULL , & old_list ) ;
}
2011-02-23 20:48:06 +00:00
2012-09-17 10:11:25 +00:00
brick_msleep ( 1000 ) ;
2012-11-13 16:01:37 +00:00
if ( ! brick_thread_should_stop ( ) ) {
2012-07-17 10:00:58 +00:00
if ( pause_time < CONFIG_MARS_PROPAGATE_INTERVAL )
pause_time + + ;
wait_event_interruptible_timeout ( remote_event ,
atomic_read ( & remote_trigger_count ) > 0 | |
( mars_global & & mars_global - > main_trigger ) ,
pause_time * HZ ) ;
}
2011-02-23 20:48:06 +00:00
}
2012-01-19 12:09:22 +00:00
MARS_INF ( " -------- peer thread terminating \n " ) ;
2011-02-23 20:48:06 +00:00
2012-11-30 10:52:21 +00:00
if ( do_kill ) {
_peer_cleanup ( peer ) ;
}
2011-02-23 20:48:06 +00:00
done :
2012-01-17 14:37:14 +00:00
atomic_dec ( & peer_thread_count ) ;
2011-08-25 10:16:32 +00:00
brick_string_free ( real_peer ) ;
2011-02-23 20:48:06 +00:00
return 0 ;
}
2012-01-17 14:37:14 +00:00
static
void __mars_remote_trigger ( void )
{
int count = atomic_read ( & peer_thread_count ) ;
atomic_add ( count , & remote_trigger_count ) ;
wake_up_interruptible_all ( & remote_event ) ;
}
2012-11-16 11:43:10 +00:00
static
bool is_shutdown ( void )
{
bool res = false ;
int used ;
if ( ( used = atomic_read ( & global_mshadow_count ) ) > 0 ) {
MARS_INF ( " global shutdown delayed: there are %d buffers in use, occupying %ld bytes \n " , used , atomic64_read ( & global_mshadow_used ) ) ;
} else {
int rounds = 3 ;
while ( ( used = atomic_read ( & mars_global_io_flying ) ) < = 0 ) {
if ( - - rounds < = 0 ) {
res = true ;
break ;
}
brick_msleep ( 30 ) ;
}
if ( ! res ) {
MARS_INF ( " global shutdown delayed: there are %d IO requests flying \n " , used ) ;
}
}
return res ;
}
2011-02-23 20:48:06 +00:00
///////////////////////////////////////////////////////////////////////
// helpers for worker functions
2011-02-28 18:00:32 +00:00
static int _kill_peer ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
2012-01-11 11:35:09 +00:00
LIST_HEAD ( tmp_list ) ;
2011-02-23 20:48:06 +00:00
struct mars_global * global = buf ;
struct mars_peerinfo * peer = dent - > d_private ;
2012-01-11 11:35:09 +00:00
unsigned long flags ;
2011-02-23 20:48:06 +00:00
if ( global - > global_power . button ) {
return 0 ;
}
if ( ! peer ) {
return 0 ;
}
2011-08-31 11:42:04 +00:00
MARS_INF ( " stopping peer thread... \n " ) ;
2012-01-11 11:35:09 +00:00
if ( peer - > peer_thread ) {
2012-11-13 16:01:37 +00:00
brick_thread_stop ( peer - > peer_thread ) ;
2012-01-11 11:35:09 +00:00
}
traced_lock ( & peer - > lock , flags ) ;
list_replace_init ( & peer - > remote_dent_list , & tmp_list ) ;
traced_unlock ( & peer - > lock , flags ) ;
mars_free_dent_all ( NULL , & tmp_list ) ;
brick_string_free ( peer - > peer ) ;
brick_string_free ( peer - > path ) ;
2011-02-23 20:48:06 +00:00
dent - > d_private = NULL ;
2011-08-31 11:42:04 +00:00
brick_mem_free ( peer ) ;
2011-02-23 20:48:06 +00:00
return 0 ;
}
2012-02-03 10:25:17 +00:00
static int _make_peer ( struct mars_global * global , struct mars_dent * dent , char * path )
2011-02-23 20:48:06 +00:00
{
static int serial = 0 ;
struct mars_peerinfo * peer ;
2012-02-03 10:25:17 +00:00
char * mypeer ;
char * parent_path ;
2011-02-23 20:48:06 +00:00
int status = 0 ;
2012-02-03 10:25:17 +00:00
if ( ! global | | ! global - > global_power . button | | ! dent | | ! dent - > new_link | | ! dent - > d_parent | | ! ( parent_path = dent - > d_parent - > d_path ) ) {
MARS_DBG ( " cannot work \n " ) ;
2011-02-23 20:48:06 +00:00
return 0 ;
}
2012-02-03 10:25:17 +00:00
mypeer = dent - > d_rest ;
2011-02-23 20:48:06 +00:00
if ( ! mypeer ) {
status = _parse_args ( dent , dent - > new_link , 1 ) ;
if ( status < 0 )
goto done ;
mypeer = dent - > d_argv [ 0 ] ;
}
MARS_DBG ( " peer '%s' \n " , mypeer ) ;
if ( ! dent - > d_private ) {
2011-08-12 11:09:48 +00:00
dent - > d_private = brick_zmem_alloc ( sizeof ( struct mars_peerinfo ) ) ;
2011-02-23 20:48:06 +00:00
if ( ! dent - > d_private ) {
MARS_ERR ( " no memory for peer structure \n " ) ;
2012-02-03 10:25:17 +00:00
status = - ENOMEM ;
goto done ;
2011-02-23 20:48:06 +00:00
}
peer = dent - > d_private ;
2011-02-24 16:37:32 +00:00
peer - > global = global ;
2011-08-31 11:42:04 +00:00
peer - > peer = brick_strdup ( mypeer ) ;
peer - > path = brick_strdup ( path ) ;
2011-02-23 20:48:06 +00:00
peer - > maxdepth = 2 ;
2011-03-22 14:36:26 +00:00
spin_lock_init ( & peer - > lock ) ;
INIT_LIST_HEAD ( & peer - > remote_dent_list ) ;
2011-02-23 20:48:06 +00:00
}
2011-03-22 14:36:26 +00:00
2011-02-23 20:48:06 +00:00
peer = dent - > d_private ;
2011-08-25 10:16:32 +00:00
if ( ! peer - > peer_thread ) {
2012-11-13 16:01:37 +00:00
peer - > peer_thread = brick_thread_create ( peer_thread , peer , " mars_peer%d " , serial + + ) ;
if ( unlikely ( ! peer - > peer_thread ) ) {
MARS_ERR ( " cannot start peer thread \n " ) ;
2011-02-23 20:48:06 +00:00
return - 1 ;
}
2012-11-13 16:01:37 +00:00
MARS_DBG ( " started peer thread \n " ) ;
2011-02-23 20:48:06 +00:00
}
2011-09-27 08:46:14 +00:00
/* This must be called by the main thread in order to
* avoid nasty races .
* The peer thread does nothing but fetching the dent list .
*/
2011-03-22 14:36:26 +00:00
status = run_bones ( peer ) ;
2011-02-23 20:48:06 +00:00
done :
return status ;
}
2011-02-28 18:00:32 +00:00
static int kill_scan ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
return _kill_peer ( buf , dent ) ;
}
2011-02-28 18:00:32 +00:00
static int make_scan ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
2011-02-24 16:37:32 +00:00
MARS_DBG ( " path = '%s' peer = '%s' \n " , dent - > d_path , dent - > d_rest ) ;
2011-03-22 14:36:26 +00:00
// don't connect to myself
2011-02-24 16:37:32 +00:00
if ( ! strcmp ( dent - > d_rest , my_id ( ) ) ) {
return 0 ;
}
2012-02-03 10:25:17 +00:00
return _make_peer ( buf , dent , " /mars " ) ;
2011-02-23 20:48:06 +00:00
}
static
2011-08-25 10:16:32 +00:00
int kill_any ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
struct mars_global * global = buf ;
2011-08-25 10:16:32 +00:00
struct list_head * tmp ;
2011-02-23 20:48:06 +00:00
2012-11-16 11:43:10 +00:00
if ( global - > global_power . button | | ! is_shutdown ( ) ) {
2011-02-23 20:48:06 +00:00
return 0 ;
}
2011-08-25 10:16:32 +00:00
for ( tmp = dent - > brick_list . next ; tmp ! = & dent - > brick_list ; tmp = tmp - > next ) {
struct mars_brick * brick = container_of ( tmp , struct mars_brick , dent_brick_link ) ;
if ( brick - > nr_outputs > 0 & & brick - > outputs [ 0 ] & & brick - > outputs [ 0 ] - > nr_connected ) {
MARS_DBG ( " cannot kill dent '%s' because brick '%s' is wired \n " , dent - > d_path , brick - > brick_path ) ;
return 0 ;
}
}
2011-03-01 18:00:14 +00:00
MARS_DBG ( " killing dent = '%s' \n " , dent - > d_path ) ;
2011-03-23 08:09:00 +00:00
mars_kill_dent ( dent ) ;
2011-09-27 11:57:04 +00:00
return 1 ;
2011-02-23 20:48:06 +00:00
}
///////////////////////////////////////////////////////////////////////
// handlers / helpers for logfile rotation
static
2011-03-23 17:58:02 +00:00
void _create_new_logfile ( const char * path )
2011-02-23 20:48:06 +00:00
{
struct file * f ;
const int flags = O_RDWR | O_CREAT | O_EXCL ;
const int prot = 0600 ;
mm_segment_t oldfs ;
oldfs = get_fs ( ) ;
set_fs ( get_ds ( ) ) ;
f = filp_open ( path , flags , prot ) ;
set_fs ( oldfs ) ;
2011-03-03 09:02:10 +00:00
if ( IS_ERR ( f ) ) {
2011-03-25 10:34:54 +00:00
int err = PTR_ERR ( f ) ;
if ( err = = - EEXIST ) {
MARS_INF ( " logfile '%s' already exists \n " , path ) ;
} else {
MARS_ERR ( " could not create logfile '%s' status = %d \n " , path , err ) ;
}
2011-03-03 09:02:10 +00:00
} else {
2011-02-23 20:48:06 +00:00
MARS_DBG ( " created empty logfile '%s' \n " , path ) ;
2011-03-03 09:02:10 +00:00
filp_close ( f , NULL ) ;
2011-02-23 20:48:06 +00:00
mars_trigger ( ) ;
}
}
2011-10-05 14:59:29 +00:00
static
2012-01-16 15:35:41 +00:00
int _check_versionlink ( struct mars_global * global , const char * parent_path , int sequence , loff_t target_end_pos )
2011-07-15 10:12:06 +00:00
{
2011-09-23 14:08:17 +00:00
char * my_version = NULL ;
2012-12-17 07:25:17 +00:00
char * my_version_link = NULL ;
2012-01-16 15:35:41 +00:00
char * other_version = NULL ;
2012-12-17 07:25:17 +00:00
char * other_version_link = NULL ;
2012-01-16 15:35:41 +00:00
char * from_host = NULL ;
2012-12-17 08:35:49 +00:00
loff_t pos = 0 ;
2011-07-15 10:12:06 +00:00
int status = - ENOMEM ;
2012-01-16 15:35:41 +00:00
my_version = path_make ( " %s/version-%09d-%s " , parent_path , sequence , my_id ( ) ) ;
2011-09-23 14:08:17 +00:00
if ( ! my_version ) {
2012-01-16 15:35:41 +00:00
MARS_WRN ( " out of memory " ) ;
2011-07-15 10:12:06 +00:00
goto out ;
}
status = - ENOENT ;
2012-12-17 07:25:17 +00:00
my_version_link = mars_readlink ( my_version ) ;
if ( ! my_version_link ) {
2012-01-16 15:35:41 +00:00
MARS_WRN ( " cannot find my own version symlink '%s' \n " , my_version ) ;
2011-07-20 13:11:44 +00:00
goto out ;
}
2012-12-17 08:35:49 +00:00
from_host = _parse_versionlink ( my_version_link , & pos ) ;
2012-01-16 15:35:41 +00:00
if ( ! from_host ) {
2012-12-17 07:25:17 +00:00
MARS_WRN ( " cannot parse '%s' \n " , my_version_link ) ;
2012-01-16 15:35:41 +00:00
goto out ;
}
2012-01-16 15:34:38 +00:00
2012-01-16 15:35:41 +00:00
if ( ! strcmp ( from_host , my_id ( ) ) ) {
MARS_DBG ( " found version stemming from myself, no check of other version necessary. \n " ) ;
status = 1 ;
2012-12-17 08:35:49 +00:00
if ( unlikely ( pos ! = target_end_pos ) ) {
MARS_WRN ( " pos = %lld != target_end_pos = %lld \n " , pos , target_end_pos ) ;
2012-01-16 15:35:41 +00:00
status = 0 ;
2012-01-16 13:25:31 +00:00
}
2012-01-16 15:35:41 +00:00
goto out ;
2012-01-16 15:34:38 +00:00
}
2012-01-16 15:35:41 +00:00
status = - ENOMEM ;
other_version = path_make ( " %s/version-%09d-%s " , parent_path , sequence , from_host ) ;
if ( ! other_version ) {
MARS_WRN ( " out of memory " ) ;
goto out ;
}
status = - ENOENT ;
2012-12-17 07:25:17 +00:00
other_version_link = mars_readlink ( other_version ) ;
if ( ! other_version_link ) {
2012-01-16 15:35:41 +00:00
MARS_WRN ( " cannot find other version symlink '%s' \n " , other_version ) ;
goto out ;
}
2012-12-17 07:25:17 +00:00
if ( ! strcmp ( my_version_link , other_version_link ) ) {
MARS_DBG ( " VERSION OK '%s' \n " , my_version_link ) ;
2012-01-16 15:35:41 +00:00
status = 1 ;
2011-07-15 10:12:06 +00:00
} else {
2012-12-17 07:25:17 +00:00
MARS_WRN ( " VERSION MISMATCH '%s' != '%s' => check for SPLIT BRAIN! \n " , my_version_link , other_version_link ) ;
2012-01-16 15:35:41 +00:00
status = 0 ;
2011-07-15 10:12:06 +00:00
}
out :
2011-09-23 14:08:17 +00:00
brick_string_free ( my_version ) ;
2012-12-17 07:25:17 +00:00
brick_string_free ( my_version_link ) ;
2012-01-16 15:35:41 +00:00
brick_string_free ( other_version ) ;
2012-12-17 07:25:17 +00:00
brick_string_free ( other_version_link ) ;
2012-01-16 15:35:41 +00:00
brick_string_free ( from_host ) ;
2011-07-20 13:11:44 +00:00
return status ;
}
2012-11-19 10:55:38 +00:00
static
void rot_destruct ( void * _rot )
{
struct mars_rotate * rot = _rot ;
if ( likely ( rot ) ) {
brick_string_free ( rot - > copy_path ) ;
brick_string_free ( rot - > parent_path ) ;
2012-12-17 07:25:17 +00:00
brick_string_free ( rot - > inf_prev_version ) ;
2012-11-19 10:55:38 +00:00
rot - > copy_path = NULL ;
rot - > parent_path = NULL ;
2012-12-17 07:25:17 +00:00
rot - > inf_prev_version = NULL ;
2012-11-19 10:55:38 +00:00
}
}
2011-02-23 20:48:06 +00:00
/* This must be called once at every round of logfile checking.
*/
static
2011-07-08 07:02:14 +00:00
int make_log_init ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
struct mars_global * global = buf ;
2011-07-08 07:02:14 +00:00
struct mars_dent * parent = dent - > d_parent ;
2011-02-23 20:48:06 +00:00
struct mars_brick * aio_brick ;
struct mars_brick * trans_brick ;
struct mars_rotate * rot = parent - > d_private ;
2011-02-28 18:00:32 +00:00
struct mars_dent * replay_link ;
struct mars_dent * aio_dent ;
2011-02-23 20:48:06 +00:00
struct mars_output * output ;
2011-11-08 12:33:13 +00:00
const char * parent_path ;
2011-03-23 17:58:02 +00:00
const char * replay_path = NULL ;
const char * aio_path = NULL ;
const char * switch_path = NULL ;
2011-11-08 12:33:13 +00:00
int status = 0 ;
2011-02-23 20:48:06 +00:00
2011-08-25 10:16:32 +00:00
if ( ! global - > global_power . button ) {
2011-11-08 12:33:13 +00:00
goto done ;
2011-08-25 10:16:32 +00:00
}
2011-11-08 12:33:13 +00:00
status = - EINVAL ;
CHECK_PTR ( parent , done ) ;
parent_path = parent - > d_path ;
CHECK_PTR ( parent_path , done ) ;
2011-08-25 10:16:32 +00:00
2011-02-23 20:48:06 +00:00
if ( ! rot ) {
2012-02-21 11:23:38 +00:00
const char * copy_path ;
2011-08-12 11:09:48 +00:00
rot = brick_zmem_alloc ( sizeof ( struct mars_rotate ) ) ;
2012-02-21 11:23:38 +00:00
if ( unlikely ( ! rot ) ) {
2011-02-23 20:48:06 +00:00
MARS_ERR ( " cannot allocate rot structure \n " ) ;
status = - ENOMEM ;
goto done ;
}
2012-12-17 07:25:17 +00:00
sema_init ( & rot - > inf_mutex , 1 ) ;
2012-02-21 11:23:38 +00:00
copy_path = path_make ( " %s/logfile-update " , parent_path ) ;
if ( unlikely ( ! copy_path ) ) {
MARS_ERR ( " cannot create copy_path \n " ) ;
brick_mem_free ( rot ) ;
status = - ENOMEM ;
goto done ;
}
rot - > copy_path = copy_path ;
2011-03-01 18:00:14 +00:00
rot - > global = global ;
2012-02-21 11:23:38 +00:00
parent - > d_private = rot ;
2012-11-19 10:55:38 +00:00
parent - > d_private_destruct = rot_destruct ;
2011-02-23 20:48:06 +00:00
}
rot - > replay_link = NULL ;
rot - > aio_dent = NULL ;
rot - > aio_brick = NULL ;
2012-03-06 11:56:48 +00:00
rot - > first_log = NULL ;
2011-02-23 20:48:06 +00:00
rot - > relevant_log = NULL ;
2011-03-01 18:00:14 +00:00
rot - > relevant_brick = NULL ;
2011-06-17 11:32:38 +00:00
rot - > next_relevant_log = NULL ;
2012-01-31 09:53:37 +00:00
rot - > next_next_relevant_log = NULL ;
2011-02-23 20:48:06 +00:00
rot - > prev_log = NULL ;
rot - > next_log = NULL ;
rot - > max_sequence = 0 ;
rot - > has_error = false ;
2012-08-08 13:50:41 +00:00
if ( dent - > new_link )
sscanf ( dent - > new_link , " %lld " , & rot - > dev_size ) ;
2012-09-25 15:41:07 +00:00
if ( ! rot - > parent_path )
rot - > parent_path = brick_strdup ( parent_path ) ;
2012-08-08 13:50:41 +00:00
2012-01-23 17:40:15 +00:00
mars_remaining_space ( parent_path , & rot - > total_space , & rot - > remaining_space ) ;
2011-11-08 12:33:13 +00:00
2011-02-23 20:48:06 +00:00
/* Fetch the replay status symlink.
* It must exist , and its value will control everything .
*/
2011-11-08 12:33:13 +00:00
replay_path = path_make ( " %s/replay-%s " , parent_path , my_id ( ) ) ;
2011-03-01 09:34:36 +00:00
if ( unlikely ( ! replay_path ) ) {
MARS_ERR ( " cannot make path \n " ) ;
status = - ENOMEM ;
goto done ;
}
2011-02-23 20:48:06 +00:00
2011-03-01 09:34:36 +00:00
replay_link = ( void * ) mars_find_dent ( global , replay_path ) ;
if ( unlikely ( ! replay_link | | ! replay_link - > new_link ) ) {
2011-03-22 14:36:26 +00:00
MARS_DBG ( " replay status symlink '%s' does not exist (%p) \n " , replay_path , replay_link ) ;
2012-01-31 13:17:59 +00:00
rot - > allow_update = false ;
2011-02-23 20:48:06 +00:00
status = - ENOENT ;
goto done ;
}
2011-05-13 11:19:28 +00:00
status = _parse_args ( replay_link , replay_link - > new_link , 3 ) ;
2011-03-01 09:34:36 +00:00
if ( unlikely ( status < 0 ) ) {
2011-02-23 20:48:06 +00:00
goto done ;
}
rot - > replay_link = replay_link ;
2011-11-15 17:32:20 +00:00
/* Fetch AIO dentry of the logfile.
2011-02-23 20:48:06 +00:00
*/
2012-09-10 10:37:37 +00:00
if ( rot - > trans_brick ) {
struct trans_logger_input * trans_input = rot - > trans_brick - > inputs [ rot - > trans_brick - > old_input_nr ] ;
2012-12-17 07:25:17 +00:00
if ( trans_input & & trans_input - > is_operating & & trans_input - > inf . inf_host ) {
aio_path = path_make ( " %s/log-%09d-%s " , parent_path , trans_input - > inf . inf_sequence , trans_input - > inf . inf_host ) ;
2012-09-10 10:37:37 +00:00
MARS_DBG ( " using logfile '%s' from trans_input %d (new=%d) \n " , SAFE_STR ( aio_path ) , rot - > trans_brick - > old_input_nr , rot - > trans_brick - > log_input_nr ) ;
2011-11-15 17:32:20 +00:00
}
}
if ( ! aio_path ) {
aio_path = path_make ( " %s/%s " , parent_path , replay_link - > d_argv [ 0 ] ) ;
MARS_DBG ( " using logfile '%s' from replay symlink \n " , SAFE_STR ( aio_path ) ) ;
}
2011-03-01 09:34:36 +00:00
if ( unlikely ( ! aio_path ) ) {
MARS_ERR ( " cannot make path \n " ) ;
status = - ENOMEM ;
goto done ;
}
2011-02-23 20:48:06 +00:00
2011-03-01 09:34:36 +00:00
aio_dent = ( void * ) mars_find_dent ( global , aio_path ) ;
2011-02-23 20:48:06 +00:00
if ( unlikely ( ! aio_dent ) ) {
2011-03-22 14:36:26 +00:00
MARS_DBG ( " logfile '%s' does not exist \n " , aio_path ) ;
2011-02-23 20:48:06 +00:00
status = - ENOENT ;
2011-09-27 08:46:14 +00:00
if ( rot - > todo_primary ) { // try to create an empty logfile
2011-03-01 09:34:36 +00:00
_create_new_logfile ( aio_path ) ;
2011-02-23 20:48:06 +00:00
}
goto done ;
}
rot - > aio_dent = aio_dent ;
/* Fetch / make the AIO brick instance
*/
2011-03-01 09:34:36 +00:00
aio_brick =
make_brick_all ( global ,
2011-03-02 09:30:56 +00:00
aio_dent ,
2011-09-02 12:17:40 +00:00
false ,
2012-12-26 18:35:49 +00:00
_set_aio_params ,
2011-03-11 13:57:54 +00:00
NULL ,
2011-03-02 09:30:56 +00:00
10 * HZ ,
2011-03-01 09:34:36 +00:00
aio_path ,
2011-03-07 10:27:38 +00:00
( const struct generic_brick_type * ) & aio_brick_type ,
2011-03-01 09:34:36 +00:00
( const struct generic_brick_type * [ ] ) { } ,
2011-03-23 08:09:00 +00:00
NULL ,
2011-11-03 11:31:47 +00:00
1 , // start always
2011-11-15 17:32:20 +00:00
" %s " ,
2011-03-01 09:34:36 +00:00
( const char * [ ] ) { } ,
0 ,
2011-11-15 17:32:20 +00:00
aio_path ) ;
2011-02-23 20:48:06 +00:00
if ( ! aio_brick ) {
2011-03-01 09:34:36 +00:00
MARS_ERR ( " cannot access '%s' \n " , aio_path ) ;
status = - EIO ;
goto done ;
2011-02-23 20:48:06 +00:00
}
rot - > aio_brick = ( void * ) aio_brick ;
/* Fetch the actual logfile size
*/
output = aio_brick - > outputs [ 0 ] ;
status = output - > ops - > mars_get_info ( output , & rot - > aio_info ) ;
if ( status < 0 ) {
2011-03-01 09:34:36 +00:00
MARS_ERR ( " cannot get info on '%s' \n " , aio_path ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-03-01 09:34:36 +00:00
MARS_DBG ( " logfile '%s' size = %lld \n " , aio_path , rot - > aio_info . current_size ) ;
2011-02-23 20:48:06 +00:00
2012-02-28 11:02:35 +00:00
# if defined(CONFIG_MARS_LOGROT_AUTO) && CONFIG_MARS_LOGROT_AUTO > 0
if ( rot - > is_primary & &
unlikely ( rot - > aio_info . current_size > = ( loff_t ) CONFIG_MARS_LOGROT_AUTO * 1024 * 1024 * 1024 ) ) {
char * new_path = path_make ( " %s/log-%09d-%s " , parent_path , aio_dent - > d_serial + 1 , my_id ( ) ) ;
if ( likely ( new_path & & ! mars_find_dent ( global , new_path ) ) ) {
MARS_INF ( " old logfile size = %lld, creating new logfile '%s' \n " , rot - > aio_info . current_size , new_path ) ;
_create_new_logfile ( new_path ) ;
}
brick_string_free ( new_path ) ;
}
# endif
2011-03-23 17:58:02 +00:00
// check whether attach is allowed
2011-11-08 12:33:13 +00:00
switch_path = path_make ( " %s/todo-%s/attach " , parent_path , my_id ( ) ) ;
2011-03-23 17:58:02 +00:00
2011-03-01 09:34:36 +00:00
/* Fetch / make the transaction logger.
* We deliberately " forget " to connect the log input here .
2011-08-25 10:16:32 +00:00
* Will be carried out later in make_log_step ( ) .
2011-03-01 09:34:36 +00:00
* The final switch - on will be started in make_log_finalize ( ) .
2011-02-23 20:48:06 +00:00
*/
2011-03-01 09:34:36 +00:00
trans_brick =
make_brick_all ( global ,
2011-08-25 10:16:32 +00:00
dent ,
2011-09-02 12:17:40 +00:00
false ,
2011-03-11 13:57:54 +00:00
_set_trans_params ,
NULL ,
2011-03-01 09:34:36 +00:00
0 ,
aio_path ,
( const struct generic_brick_type * ) & trans_logger_brick_type ,
2011-03-18 13:15:40 +00:00
( const struct generic_brick_type * [ ] ) { NULL } ,
2011-03-23 17:58:02 +00:00
switch_path ,
2011-11-03 11:31:47 +00:00
0 , // let switch decide
2011-03-03 09:02:10 +00:00
" %s/logger " ,
( const char * [ ] ) { " %s/data-%s " } ,
2011-03-01 09:34:36 +00:00
1 ,
2011-11-08 12:33:13 +00:00
parent_path ,
parent_path ,
2011-03-01 09:34:36 +00:00
my_id ( ) ) ;
status = - ENOENT ;
2011-02-23 20:48:06 +00:00
if ( ! trans_brick ) {
2011-03-01 09:34:36 +00:00
goto done ;
2011-02-23 20:48:06 +00:00
}
rot - > trans_brick = ( void * ) trans_brick ;
2012-09-25 15:41:07 +00:00
rot - > trans_brick - > replay_limiter = & rot - > replay_limiter ;
2011-02-23 20:48:06 +00:00
/* For safety, default is to try an (unnecessary) replay in case
* something goes wrong later .
*/
2012-08-03 08:42:51 +00:00
rot - > replay_mode = true ;
2011-02-23 20:48:06 +00:00
status = 0 ;
done :
2011-10-05 14:59:29 +00:00
brick_string_free ( aio_path ) ;
brick_string_free ( replay_path ) ;
brick_string_free ( switch_path ) ;
2011-02-23 20:48:06 +00:00
return status ;
}
2011-06-17 11:32:38 +00:00
/* Note: this is strictly called in d_serial order.
* This is important !
2011-02-23 20:48:06 +00:00
*/
static
2011-08-25 10:16:32 +00:00
int make_log_step ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
2011-06-17 11:32:38 +00:00
struct mars_global * global = buf ;
2011-02-28 18:00:32 +00:00
struct mars_dent * parent = dent - > d_parent ;
2011-10-24 11:00:55 +00:00
struct mars_rotate * rot ;
2011-06-17 11:32:38 +00:00
struct trans_logger_brick * trans_brick ;
struct mars_dent * prev_log ;
2011-02-23 20:48:06 +00:00
int status = - EINVAL ;
2011-10-24 11:00:55 +00:00
CHECK_PTR ( parent , err ) ;
rot = parent - > d_private ;
2012-12-03 08:43:26 +00:00
if ( ! rot )
goto err ;
2011-06-17 11:32:38 +00:00
CHECK_PTR ( rot , err ) ;
2011-02-23 20:48:06 +00:00
status = 0 ;
2011-06-17 11:32:38 +00:00
trans_brick = rot - > trans_brick ;
if ( ! global - > global_power . button | | ! dent - > d_parent | | ! trans_brick | | rot - > has_error ) {
MARS_DBG ( " nothing to do rot_error = %d \n " , rot - > has_error ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-06-17 11:32:38 +00:00
/* Check for consecutiveness of logfiles
*/
prev_log = rot - > next_log ;
if ( prev_log & & prev_log - > d_serial + 1 ! = dent - > d_serial ) {
2012-01-24 14:12:55 +00:00
MARS_WRN ( " transaction logs are not consecutive at '%s' (%d ~> %d) \n " , dent - > d_path , prev_log - > d_serial , dent - > d_serial ) ;
2011-06-17 11:32:38 +00:00
status = - EINVAL ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-06-17 11:32:38 +00:00
if ( dent - > d_serial > rot - > max_sequence ) {
rot - > max_sequence = dent - > d_serial ;
}
2012-03-06 11:56:48 +00:00
if ( ! rot - > first_log )
rot - > first_log = dent ;
2011-06-17 11:32:38 +00:00
/* Skip any logfiles after the relevant one.
* This should happen only when replaying multiple logfiles
* in sequence , or when starting a new logfile for writing .
*/
status = 0 ;
if ( rot - > relevant_log ) {
if ( ! rot - > next_relevant_log ) {
rot - > next_relevant_log = dent ;
2012-01-31 09:53:37 +00:00
} else if ( ! rot - > next_next_relevant_log ) {
rot - > next_next_relevant_log = dent ;
2011-06-17 11:32:38 +00:00
}
2012-01-31 09:53:37 +00:00
MARS_DBG ( " next_relevant_log = %p next_next_relevant_log = %p \n " , rot - > next_relevant_log , rot - > next_next_relevant_log ) ;
2011-06-17 11:32:38 +00:00
goto ok ;
}
/* Preconditions
*/
if ( ! rot - > replay_link | | ! rot - > aio_dent | | ! rot - > aio_brick ) {
2012-12-17 07:25:17 +00:00
MARS_DBG ( " nothing to do on '%s' \n " , dent - > d_path ) ;
2011-06-17 11:32:38 +00:00
goto ok ;
}
2011-10-05 14:59:29 +00:00
/* Remember the relevant log.
2011-06-17 11:32:38 +00:00
*/
if ( rot - > aio_dent - > d_serial = = dent - > d_serial ) {
2012-03-06 11:56:48 +00:00
rot - > relevant_serial = dent - > d_serial ;
2011-06-17 11:32:38 +00:00
rot - > relevant_log = dent ;
}
ok :
/* All ok: switch over the indicators.
*/
2012-12-17 07:25:17 +00:00
MARS_DBG ( " next_log = '%s' \n " , dent - > d_path ) ;
2011-06-17 11:32:38 +00:00
rot - > prev_log = rot - > next_log ;
rot - > next_log = dent ;
done :
if ( status < 0 ) {
MARS_DBG ( " rot_error status = %d \n " , status ) ;
rot - > has_error = true ;
}
err :
return status ;
}
/* Internal helper. Return codes:
* ret < 0 : error
* ret = = 0 : not relevant
* ret = = 1 : relevant , no transaction replay , switch to the next
* ret = = 2 : relevant for transaction replay
* ret = = 3 : relevant for appending
*/
static
int _check_logging_status ( struct mars_rotate * rot , long long * oldpos_start , long long * oldpos_end , long long * newpos )
{
struct mars_dent * dent = rot - > relevant_log ;
struct mars_dent * parent ;
2011-09-27 08:46:14 +00:00
struct mars_global * global = NULL ;
2011-06-17 11:32:38 +00:00
int status = 0 ;
if ( ! dent )
goto done ;
status = - EINVAL ;
parent = dent - > d_parent ;
CHECK_PTR ( parent , done ) ;
global = rot - > global ;
2011-08-31 11:42:04 +00:00
CHECK_PTR_NULL ( global , done ) ;
2011-06-17 11:32:38 +00:00
CHECK_PTR ( rot - > replay_link , done ) ;
CHECK_PTR ( rot - > aio_brick , done ) ;
2011-05-13 11:19:28 +00:00
if ( sscanf ( rot - > replay_link - > d_argv [ 1 ] , " %lld " , oldpos_start ) ! = 1 ) {
MARS_ERR ( " bad start position argument '%s' \n " , rot - > replay_link - > d_argv [ 1 ] ) ;
goto done ;
}
if ( sscanf ( rot - > replay_link - > d_argv [ 2 ] , " %lld " , oldpos_end ) ! = 1 ) {
MARS_ERR ( " bad end position argument '%s' \n " , rot - > replay_link - > d_argv [ 2 ] ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-05-13 11:19:28 +00:00
* oldpos_end + = * oldpos_start ;
if ( unlikely ( * oldpos_end < * oldpos_start ) ) {
MARS_ERR ( " end_pos %lld < start_pos %lld \n " , * oldpos_end , * oldpos_start ) ;
2012-12-06 08:21:01 +00:00
// safety: use the smaller value, it does not hurt
* oldpos_start = * oldpos_end ;
if ( unlikely ( * oldpos_start < 0 ) )
* oldpos_start = 0 ;
2011-05-13 11:19:28 +00:00
}
2011-02-23 20:48:06 +00:00
2012-12-06 08:34:41 +00:00
* newpos = rot - > aio_info . current_size ;
2011-05-13 11:19:28 +00:00
if ( unlikely ( rot - > aio_info . current_size < * oldpos_start ) ) {
MARS_ERR ( " oops, bad replay position attempted at logfile '%s' (file length %lld should never be smaller than requested position %lld, is your filesystem corrupted?) => please repair this by hand \n " , rot - > aio_dent - > d_path , rot - > aio_info . current_size , * oldpos_start ) ;
2011-06-17 11:32:38 +00:00
status = - EBADF ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-06-17 11:32:38 +00:00
status = 0 ;
2012-12-06 08:21:01 +00:00
if ( rot - > aio_info . current_size > * oldpos_start ) {
2011-05-13 11:19:28 +00:00
MARS_DBG ( " transaction log replay is necessary on '%s' from %lld to %lld (dirty region ends at %lld) \n " , rot - > aio_dent - > d_path , * oldpos_start , rot - > aio_info . current_size , * oldpos_end ) ;
2011-02-23 20:48:06 +00:00
status = 2 ;
2011-06-17 11:32:38 +00:00
} else if ( rot - > next_relevant_log ) {
MARS_DBG ( " transaction log '%s' is already applied, and the next one is available for switching \n " , rot - > aio_dent - > d_path ) ;
2011-02-23 20:48:06 +00:00
status = 1 ;
2011-09-27 08:46:14 +00:00
} else if ( rot - > todo_primary ) {
2011-10-05 14:59:29 +00:00
if ( rot - > aio_info . current_size > 0 | | strcmp ( dent - > d_rest , my_id ( ) ) ! = 0 ) {
2011-06-17 11:32:38 +00:00
MARS_DBG ( " transaction log '%s' is already applied (would be usable for appending at position %lld, but a fresh logfile will be used for safety reasons) \n " , rot - > aio_dent - > d_path , * oldpos_end ) ;
status = 1 ;
} else {
MARS_DBG ( " empty transaction log '%s' is usable for me as a primary node \n " , rot - > aio_dent - > d_path ) ;
status = 3 ;
}
2011-02-23 20:48:06 +00:00
} else {
2011-06-17 11:32:38 +00:00
MARS_DBG ( " transaction log '%s' is the last one, currently fully applied \n " , rot - > aio_dent - > d_path ) ;
status = 0 ;
2011-02-23 20:48:06 +00:00
}
done :
return status ;
}
static
2011-06-17 11:32:38 +00:00
int _make_logging_status ( struct mars_rotate * rot )
2011-02-23 20:48:06 +00:00
{
2011-06-17 11:32:38 +00:00
struct mars_dent * dent = rot - > relevant_log ;
struct mars_dent * parent ;
2011-09-27 08:46:14 +00:00
struct mars_global * global = NULL ;
2011-02-23 20:48:06 +00:00
struct trans_logger_brick * trans_brick ;
loff_t start_pos = 0 ;
2011-05-13 11:19:28 +00:00
loff_t dirty_pos = 0 ;
2011-02-23 20:48:06 +00:00
loff_t end_pos = 0 ;
2011-06-17 11:32:38 +00:00
int status = 0 ;
2011-02-23 20:48:06 +00:00
2011-06-17 11:32:38 +00:00
if ( ! dent )
goto done ;
status = - EINVAL ;
parent = dent - > d_parent ;
CHECK_PTR ( parent , done ) ;
global = rot - > global ;
2011-08-31 11:42:04 +00:00
CHECK_PTR_NULL ( global , done ) ;
2011-02-23 20:48:06 +00:00
status = 0 ;
trans_brick = rot - > trans_brick ;
2011-06-17 11:32:38 +00:00
if ( ! global - > global_power . button | | ! trans_brick | | rot - > has_error ) {
2011-03-01 09:34:36 +00:00
MARS_DBG ( " nothing to do rot_error = %d \n " , rot - > has_error ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
/* Find current logging status.
*/
2011-06-17 11:32:38 +00:00
status = _check_logging_status ( rot , & start_pos , & dirty_pos , & end_pos ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 ) {
goto done ;
}
2012-12-06 08:34:41 +00:00
if ( unlikely ( start_pos < 0 | | dirty_pos < start_pos | | end_pos < dirty_pos ) ) {
MARS_ERR ( " implausible values: start_pos = %lld dirty_pos = %lld end_pos = %lld \n " , start_pos , dirty_pos , end_pos ) ;
}
2011-02-23 20:48:06 +00:00
/* Relevant or not?
*/
switch ( status ) {
case 0 : // not relevant
goto ok ;
2011-04-08 09:52:46 +00:00
case 1 : /* Relevant, and transaction replay already finished.
2011-06-17 11:32:38 +00:00
* Allow switching over to a new logfile .
2011-03-07 05:55:10 +00:00
*/
2011-10-05 14:59:29 +00:00
if ( ! trans_brick - > power . button & & ! trans_brick - > power . led_on & & trans_brick - > power . led_off ) {
2012-02-24 10:49:57 +00:00
if ( rot - > next_relevant_log ) {
2012-01-31 13:17:59 +00:00
MARS_DBG ( " check switchover from '%s' to '%s' (size = %lld, next_next = %p, allow_replay = %d) \n " , dent - > d_path , rot - > next_relevant_log - > d_path , rot - > next_relevant_log - > new_stat . size , rot - > next_next_relevant_log , rot - > allow_replay ) ;
2012-02-02 16:25:50 +00:00
if ( ( rot - > next_relevant_log - > new_stat . size > 0 | | rot - > next_next_relevant_log | | ( long long ) jiffies > rot - > switchover_timeout + 30 * HZ ) & &
2012-01-31 13:17:59 +00:00
rot - > allow_replay & &
2012-01-31 09:53:37 +00:00
_check_versionlink ( global , parent - > d_path , dent - > d_serial , end_pos ) > 0 ) {
2012-02-02 16:25:50 +00:00
rot - > switchover_timeout = 0 ;
2012-01-13 11:35:03 +00:00
MARS_DBG ( " switching over from '%s' to next relevant transaction log '%s' \n " , dent - > d_path , rot - > next_relevant_log - > d_path ) ;
2012-12-17 07:25:17 +00:00
_make_new_replaylink ( rot , rot - > next_relevant_log - > d_rest , rot - > next_relevant_log - > d_serial , rot - > next_relevant_log - > new_stat . size ) ;
2012-02-02 16:25:50 +00:00
} else {
MARS_DBG ( " waiting for logfile to become stable \n " ) ;
if ( ! rot - > switchover_timeout )
rot - > switchover_timeout = jiffies ;
2011-10-05 14:59:29 +00:00
}
} else if ( rot - > todo_primary ) {
MARS_DBG ( " preparing new transaction log '%s' from version %d to %d \n " , dent - > d_path , dent - > d_serial , dent - > d_serial + 1 ) ;
2012-12-17 07:25:17 +00:00
_make_new_replaylink ( rot , my_id ( ) , dent - > d_serial + 1 , 0 ) ;
2011-10-05 14:59:29 +00:00
} else {
MARS_DBG ( " nothing to do on last transaction log '%s' \n " , dent - > d_path ) ;
}
2011-02-23 20:48:06 +00:00
}
status = - EAGAIN ;
goto done ;
case 2 : // relevant for transaction replay
MARS_DBG ( " replaying transaction log '%s' from %lld to %lld \n " , dent - > d_path , start_pos , end_pos ) ;
2012-08-03 08:42:51 +00:00
rot - > replay_mode = true ;
2011-02-23 20:48:06 +00:00
rot - > start_pos = start_pos ;
rot - > end_pos = end_pos ;
break ;
case 3 : // relevant for appending
MARS_DBG ( " appending to transaction log '%s' \n " , dent - > d_path ) ;
2012-08-03 08:42:51 +00:00
rot - > replay_mode = false ;
2011-02-23 20:48:06 +00:00
rot - > start_pos = 0 ;
rot - > end_pos = 0 ;
break ;
default :
MARS_ERR ( " bad internal status %d \n " , status ) ;
status = - EINVAL ;
goto done ;
}
ok :
/* All ok: switch over the indicators.
*/
rot - > prev_log = rot - > next_log ;
rot - > next_log = dent ;
done :
if ( status < 0 ) {
2011-03-01 18:00:14 +00:00
MARS_DBG ( " rot_error status = %d \n " , status ) ;
2011-02-23 20:48:06 +00:00
rot - > has_error = true ;
}
return status ;
}
static
2012-12-17 07:25:17 +00:00
void _init_trans_input ( struct trans_logger_input * trans_input , struct mars_dent * log_dent , struct mars_rotate * rot )
2011-11-03 11:17:59 +00:00
{
2012-12-17 07:25:17 +00:00
if ( unlikely ( trans_input - > connect | | trans_input - > is_operating ) ) {
2011-11-15 17:32:20 +00:00
MARS_ERR ( " this should not happen \n " ) ;
return ;
}
2012-12-17 07:25:17 +00:00
brick_string_free ( trans_input - > inf . inf_host ) ; // just for safety
2011-11-15 17:32:20 +00:00
2012-12-17 07:25:17 +00:00
memset ( & trans_input - > inf , 0 , sizeof ( trans_input - > inf ) ) ;
2011-11-15 17:32:20 +00:00
2012-12-17 07:25:17 +00:00
trans_input - > inf . inf_host = brick_strdup ( log_dent - > d_rest ) ;
trans_input - > inf . inf_sequence = log_dent - > d_serial ;
trans_input - > inf . inf_private = rot ;
trans_input - > inf . inf_callback = _update_info ;
MARS_DBG ( " initialized '%s' %d \n " , trans_input - > inf . inf_host , trans_input - > inf . inf_sequence ) ;
2011-11-03 11:17:59 +00:00
}
# ifdef CONFIG_MARS_LOGROT
static
int _get_free_input ( struct trans_logger_brick * trans_brick )
{
int nr = ( ( ( trans_brick - > log_input_nr - TL_INPUT_LOG1 ) + 1 ) % 2 ) + TL_INPUT_LOG1 ;
struct trans_logger_input * candidate ;
candidate = trans_brick - > inputs [ nr ] ;
2012-12-17 07:25:17 +00:00
if ( unlikely ( ! candidate ) ) {
MARS_ERR ( " input nr = %d is corrupted! \n " , nr ) ;
return - EEXIST ;
}
if ( unlikely ( candidate - > is_operating | | candidate - > connect ) ) {
MARS_DBG ( " nr = %d unusable! is_operating = %d connect = %p \n " , nr , candidate - > is_operating , candidate - > connect ) ;
2011-11-03 11:17:59 +00:00
return - EEXIST ;
}
2012-12-17 07:25:17 +00:00
MARS_DBG ( " got nr = %d \n " , nr ) ;
2011-11-03 11:17:59 +00:00
return nr ;
}
static
void _rotate_trans ( struct mars_rotate * rot )
2011-02-23 20:48:06 +00:00
{
struct trans_logger_brick * trans_brick = rot - > trans_brick ;
2011-11-03 11:17:59 +00:00
int old_nr = trans_brick - > old_input_nr ;
int log_nr = trans_brick - > log_input_nr ;
int next_nr ;
MARS_DBG ( " log_input_nr = %d old_input_nr = %d next_relevant_log = %p \n " , log_nr , old_nr , rot - > next_relevant_log ) ;
// try to cleanup old log
if ( log_nr ! = old_nr ) {
struct trans_logger_input * trans_input = trans_brick - > inputs [ old_nr ] ;
if ( ! trans_input - > connect ) {
MARS_DBG ( " ignoring unused input %d \n " , old_nr ) ;
2012-12-17 07:25:17 +00:00
} else if ( trans_input - > is_operating & &
trans_input - > inf . inf_min_pos = = trans_input - > inf . inf_max_pos & &
list_empty ( & trans_input - > pos_list ) ) {
int status ;
MARS_INF ( " cleanup old transaction log (%d -> %d) \n " , old_nr , log_nr ) ;
status = generic_disconnect ( ( void * ) trans_input ) ;
if ( unlikely ( status < 0 ) ) {
2011-11-03 11:17:59 +00:00
MARS_ERR ( " disconnect failed \n " ) ;
} else {
2012-01-17 14:37:14 +00:00
mars_remote_trigger ( ) ;
2011-11-03 11:17:59 +00:00
}
} else {
2012-12-17 07:25:17 +00:00
MARS_DBG ( " old transaction replay not yet finished: is_operating = %d pos %lld != %lld \n " ,
trans_input - > is_operating ,
trans_input - > inf . inf_min_pos ,
trans_input - > inf . inf_max_pos ) ;
2011-11-03 11:17:59 +00:00
}
2012-09-11 13:14:07 +00:00
} else
2011-11-03 11:17:59 +00:00
// try to setup new log
2012-09-11 13:14:07 +00:00
if ( log_nr = = trans_brick - > new_input_nr & &
2012-09-10 10:37:37 +00:00
rot - > next_relevant_log & &
2012-12-17 07:25:17 +00:00
( next_nr = _get_free_input ( trans_brick ) ) > = 0 ) {
2011-11-03 11:17:59 +00:00
struct trans_logger_input * trans_input ;
int status ;
2012-09-10 10:37:37 +00:00
2011-11-03 11:17:59 +00:00
MARS_DBG ( " start switchover %d -> %d \n " , old_nr , next_nr ) ;
2012-09-10 10:37:37 +00:00
2011-11-03 11:17:59 +00:00
rot - > next_relevant_brick =
make_brick_all ( rot - > global ,
rot - > next_relevant_log ,
false ,
2012-12-26 18:35:49 +00:00
_set_aio_params ,
2011-11-03 11:17:59 +00:00
NULL ,
10 * HZ ,
rot - > next_relevant_log - > d_path ,
( const struct generic_brick_type * ) & aio_brick_type ,
( const struct generic_brick_type * [ ] ) { } ,
NULL ,
2011-11-03 11:31:47 +00:00
0 , // let switch decide
2011-11-03 11:17:59 +00:00
rot - > next_relevant_log - > d_path ,
( const char * [ ] ) { } ,
0 ) ;
if ( unlikely ( ! rot - > next_relevant_brick ) ) {
MARS_ERR ( " could not open next transaction log '%s' \n " , rot - > next_relevant_log - > d_path ) ;
goto done ;
}
trans_input = trans_brick - > inputs [ next_nr ] ;
if ( unlikely ( ! trans_input ) ) {
MARS_ERR ( " log input does not exist \n " ) ;
goto done ;
}
2011-02-23 20:48:06 +00:00
2012-12-17 07:25:17 +00:00
_init_trans_input ( trans_input , rot - > next_relevant_log , rot ) ;
2011-11-03 11:17:59 +00:00
status = generic_connect ( ( void * ) trans_input , ( void * ) rot - > next_relevant_brick - > outputs [ 0 ] ) ;
if ( unlikely ( status < 0 ) ) {
MARS_ERR ( " connect failed \n " ) ;
goto done ;
}
trans_brick - > new_input_nr = next_nr ;
MARS_INF ( " started switchover to '%s' \n " , rot - > next_relevant_log - > d_path ) ;
}
done : ;
}
# endif
static
void _change_trans ( struct mars_rotate * rot )
{
struct trans_logger_brick * trans_brick = rot - > trans_brick ;
2012-08-03 08:42:51 +00:00
MARS_DBG ( " replay_mode = %d start_pos = %lld end_pos = %lld \n " , trans_brick - > replay_mode , rot - > start_pos , rot - > end_pos ) ;
2011-07-11 14:01:28 +00:00
2012-08-03 08:42:51 +00:00
if ( trans_brick - > replay_mode ) {
2011-06-01 12:55:06 +00:00
trans_brick - > replay_start_pos = rot - > start_pos ;
trans_brick - > replay_end_pos = rot - > end_pos ;
} else {
2011-11-03 11:17:59 +00:00
# ifdef CONFIG_MARS_LOGROT
_rotate_trans ( rot ) ;
# endif
2011-02-23 20:48:06 +00:00
}
2011-06-01 12:55:06 +00:00
}
static
int _start_trans ( struct mars_rotate * rot )
{
2012-12-17 07:25:17 +00:00
struct trans_logger_brick * trans_brick ;
2011-06-01 12:55:06 +00:00
struct trans_logger_input * trans_input ;
2011-11-03 11:17:59 +00:00
int nr ;
2011-06-01 12:55:06 +00:00
int status ;
2011-02-23 20:48:06 +00:00
/* Internal safety checks
*/
status = - EINVAL ;
2012-12-17 07:25:17 +00:00
if ( unlikely ( ! rot ) ) {
MARS_ERR ( " rot is NULL \n " ) ;
2011-06-01 12:55:06 +00:00
goto done ;
}
2012-12-17 07:25:17 +00:00
if ( unlikely ( ! rot - > aio_brick | | ! rot - > relevant_log ) ) {
MARS_ERR ( " aio %p or relevant log %p is missing, this should not happen \n " , rot - > aio_brick , rot - > relevant_log ) ;
2011-06-01 12:55:06 +00:00
goto done ;
}
2012-12-17 07:25:17 +00:00
trans_brick = rot - > trans_brick ;
if ( unlikely ( ! trans_brick ) ) {
MARS_ERR ( " logger instance does not exist \n " ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-06-01 12:55:06 +00:00
/* Update status when already working
*/
if ( trans_brick - > power . button | | ! trans_brick - > power . led_off ) {
_change_trans ( rot ) ;
status = 0 ;
2011-03-01 18:00:14 +00:00
goto done ;
}
2011-06-01 12:55:06 +00:00
2012-12-17 07:25:17 +00:00
/* Further safety checks.
2011-06-01 12:55:06 +00:00
*/
if ( unlikely ( rot - > relevant_brick ) ) {
MARS_ERR ( " log aio brick already present, this should not happen \n " ) ;
2011-05-13 11:19:28 +00:00
goto done ;
}
2012-12-17 07:25:17 +00:00
if ( unlikely ( trans_brick - > inputs [ TL_INPUT_LOG1 ] - > is_operating | | trans_brick - > inputs [ TL_INPUT_LOG2 ] - > is_operating ) ) {
MARS_ERR ( " some input is operating, this should not happen \n " ) ;
goto done ;
}
2011-02-23 20:48:06 +00:00
2012-12-17 07:25:17 +00:00
/* Allocate new input slot
2011-02-23 20:48:06 +00:00
*/
2012-12-17 07:25:17 +00:00
nr = _get_free_input ( trans_brick ) ;
if ( unlikely ( nr < TL_INPUT_LOG1 | | nr > TL_INPUT_LOG2 ) ) {
MARS_ERR ( " bad new_input_nr = %d \n " , nr ) ;
goto done ;
}
trans_brick - > new_input_nr = nr ;
trans_brick - > old_input_nr = nr ;
trans_brick - > log_input_nr = nr ;
trans_input = trans_brick - > inputs [ nr ] ;
if ( unlikely ( ! trans_input ) ) {
MARS_ERR ( " log input %d does not exist \n " , nr ) ;
goto done ;
2011-02-23 20:48:06 +00:00
}
2011-03-01 18:00:14 +00:00
/* Open new transaction log
*/
rot - > relevant_brick =
make_brick_all ( rot - > global ,
2011-03-02 09:30:56 +00:00
rot - > relevant_log ,
2011-09-02 12:17:40 +00:00
false ,
2012-12-26 18:35:49 +00:00
_set_aio_params ,
2011-03-11 13:57:54 +00:00
NULL ,
2011-03-01 18:00:14 +00:00
10 * HZ ,
rot - > relevant_log - > d_path ,
2011-03-07 10:27:38 +00:00
( const struct generic_brick_type * ) & aio_brick_type ,
2011-03-01 18:00:14 +00:00
( const struct generic_brick_type * [ ] ) { } ,
2011-03-23 08:09:00 +00:00
NULL ,
2011-11-03 11:31:47 +00:00
1 , // start always
2011-03-01 18:00:14 +00:00
rot - > relevant_log - > d_path ,
( const char * [ ] ) { } ,
0 ) ;
2012-12-17 07:25:17 +00:00
if ( unlikely ( ! rot - > relevant_brick ) ) {
MARS_ERR ( " log aio brick '%s' not open \n " , rot - > relevant_log - > d_path ) ;
2011-03-01 18:00:14 +00:00
goto done ;
}
2012-12-17 07:25:17 +00:00
/* Supply all relevant parameters
*/
trans_brick - > replay_mode = rot - > replay_mode ;
_init_trans_input ( trans_input , rot - > relevant_log , rot ) ;
2011-02-23 20:48:06 +00:00
/* Connect to new transaction log
*/
2011-05-13 11:19:28 +00:00
status = generic_connect ( ( void * ) trans_input , ( void * ) rot - > relevant_brick - > outputs [ 0 ] ) ;
2012-12-17 07:25:17 +00:00
if ( unlikely ( status < 0 ) ) {
MARS_ERR ( " initial connect failed \n " ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-06-01 12:55:06 +00:00
_change_trans ( rot ) ;
2011-02-23 20:48:06 +00:00
/* Switch on....
*/
2011-03-23 17:58:02 +00:00
status = mars_power_button ( ( void * ) trans_brick , true , false ) ;
2011-02-23 20:48:06 +00:00
MARS_DBG ( " status = %d \n " , status ) ;
done :
return status ;
}
static
2012-01-16 10:48:39 +00:00
int _stop_trans ( struct mars_rotate * rot , const char * parent_path )
2011-02-23 20:48:06 +00:00
{
struct trans_logger_brick * trans_brick = rot - > trans_brick ;
int status = 0 ;
2011-06-01 12:55:06 +00:00
if ( ! trans_brick ) {
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-03-23 17:58:02 +00:00
/* Switch off temporarily....
2011-02-23 20:48:06 +00:00
*/
2011-03-23 17:58:02 +00:00
status = mars_power_button ( ( void * ) trans_brick , false , false ) ;
2011-02-23 20:48:06 +00:00
MARS_DBG ( " status = %d \n " , status ) ;
2011-06-01 12:55:06 +00:00
if ( status < 0 ) {
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-06-01 12:55:06 +00:00
/* Disconnect old connection(s)
2011-02-23 20:48:06 +00:00
*/
2011-06-01 12:55:06 +00:00
if ( trans_brick - > power . led_off ) {
int i ;
2011-11-03 11:17:59 +00:00
for ( i = TL_INPUT_LOG1 ; i < = TL_INPUT_LOG2 ; i + + ) {
2011-06-01 12:55:06 +00:00
struct trans_logger_input * trans_input ;
trans_input = trans_brick - > inputs [ i ] ;
2012-12-17 07:25:17 +00:00
if ( trans_input & & ! trans_input - > is_operating ) {
2011-11-15 17:32:20 +00:00
if ( trans_input - > connect )
( void ) generic_disconnect ( ( void * ) trans_input ) ;
2011-06-01 12:55:06 +00:00
}
}
2011-02-23 20:48:06 +00:00
}
done :
return status ;
}
2012-07-23 07:17:18 +00:00
static
void override_all_syncstatus ( struct mars_global * global , struct mars_rotate * rot , char * parent_path )
{
char * prefix = NULL ;
struct mars_dent * * table = NULL ;
int count ;
int i ;
prefix = path_make ( " %s/syncstatus- " , parent_path ) ;
if ( ! prefix )
goto done ;
count = mars_find_dent_all ( global , prefix , & table ) ;
MARS_DBG ( " prefix='%s' count=%d \n " , prefix , count ) ;
for ( i = 0 ; i < count ; i + + ) {
struct mars_dent * dent = table [ i ] ;
int status ;
if ( ! dent | | ! dent - > d_path | | dent = = rot - > syncstatus_dent )
continue ;
status = mars_symlink ( " 0 " , dent - > d_path , NULL , 0 ) ;
MARS_DBG ( " clearing syncstatus link '%s' status=%d \n " , dent - > d_path , status ) ;
}
done :
if ( table )
brick_mem_free ( table ) ;
if ( prefix )
brick_string_free ( prefix ) ;
}
2011-02-23 20:48:06 +00:00
static
2011-08-25 10:16:32 +00:00
int make_log_finalize ( struct mars_global * global , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
2011-08-25 10:16:32 +00:00
struct mars_dent * parent = dent - > d_parent ;
2011-10-20 12:27:17 +00:00
struct mars_rotate * rot ;
2011-02-23 20:48:06 +00:00
struct trans_logger_brick * trans_brick ;
2012-02-21 11:23:38 +00:00
struct copy_brick * copy_brick ;
2011-02-23 20:48:06 +00:00
int status = - EINVAL ;
2012-01-31 13:17:59 +00:00
CHECK_PTR ( parent , err ) ;
2011-10-20 12:27:17 +00:00
rot = parent - > d_private ;
2012-12-03 08:43:26 +00:00
if ( ! rot )
goto err ;
2012-01-31 13:17:59 +00:00
CHECK_PTR ( rot , err ) ;
2011-02-23 20:48:06 +00:00
trans_brick = rot - > trans_brick ;
status = 0 ;
if ( ! trans_brick ) {
MARS_DBG ( " nothing to do \n " ) ;
goto done ;
}
2011-03-22 14:36:26 +00:00
2012-07-23 07:17:18 +00:00
/* Handle jamming (a very exceptional state)
*/
if ( global - > jammed ) {
if ( rot - > todo_primary | | rot - > is_primary )
trans_brick - > cease_logging = true ;
} else if ( ! rot - > todo_primary & & ! rot - > is_primary ) {
trans_brick - > cease_logging = false ;
}
if ( trans_brick - > cease_logging )
override_all_syncstatus ( global , rot , parent - > d_path ) ;
2012-02-21 11:23:38 +00:00
// check whether some copy has finished
copy_brick = ( struct copy_brick * ) mars_find_brick ( global , & copy_brick_type , rot - > copy_path ) ;
MARS_DBG ( " copy_path = '%s' copy_brick = %p \n " , rot - > copy_path , copy_brick ) ;
if ( copy_brick & & ( copy_brick - > copy_last = = copy_brick - > copy_end | | copy_brick - > power . led_off ) ) {
status = mars_kill_brick ( ( void * ) copy_brick ) ;
if ( status < 0 ) {
MARS_ERR ( " could not kill copy_brick, status = %d \n " , status ) ;
goto done ;
}
copy_brick = NULL ;
}
rot - > copy_brick = copy_brick ;
if ( ! copy_brick )
rot - > copy_serial = 0 ;
2012-08-14 14:38:10 +00:00
# if defined(CONFIG_MARS_LOGDELETE_AUTO)
2012-03-06 11:56:48 +00:00
# define LIMIT1 ((loff_t)EXHAUSTED_LIMIT(rot->total_space))
2012-08-14 14:38:10 +00:00
# define LIMIT2 ((loff_t)global_logdel_auto * 1024 * 1024)
2012-03-06 11:56:48 +00:00
if ( rot - > remaining_space < = LIMIT1 + LIMIT2 ) {
MARS_WRN ( " filesystem space = %lld kiB is lower than %lld + %lld = %lld \n " , rot - > remaining_space , LIMIT1 , LIMIT2 , LIMIT1 + LIMIT2 ) ;
if ( rot - > first_log & & rot - > first_log ! = rot - > relevant_log ) {
MARS_DBG ( " freeing old logfile '%s' \n " , rot - > first_log - > d_path ) ;
mars_unlink ( rot - > first_log - > d_path ) ;
rot - > first_log - > d_killme = true ;
}
}
# endif
2011-02-23 20:48:06 +00:00
/* Stopping is also possible in case of errors
*/
if ( trans_brick - > power . button & & trans_brick - > power . led_on & & ! trans_brick - > power . led_off ) {
2011-05-13 11:19:28 +00:00
bool do_stop = true ;
2012-08-03 08:42:51 +00:00
if ( trans_brick - > replay_mode ) {
2011-11-08 17:07:42 +00:00
do_stop = trans_brick - > replay_code ! = 0 | | ! _check_allow ( global , parent , " allow-replay " ) ;
2011-05-13 11:19:28 +00:00
} else {
2011-11-03 11:17:59 +00:00
do_stop = ! rot - > is_primary ;
2011-05-13 11:19:28 +00:00
}
2011-06-17 11:32:38 +00:00
2012-12-04 08:26:19 +00:00
MARS_DBG ( " replay_mode = %d replay_code = %d is_primary = %d do_stop = %d \n " , trans_brick - > replay_mode , trans_brick - > replay_code , rot - > is_primary , ( int ) do_stop ) ;
2011-02-23 20:48:06 +00:00
if ( do_stop ) {
2012-01-16 10:48:39 +00:00
status = _stop_trans ( rot , parent - > d_path ) ;
2011-11-03 11:17:59 +00:00
# ifdef CONFIG_MARS_LOGROT
} else {
_change_trans ( rot ) ;
# endif
2011-02-23 20:48:06 +00:00
}
goto done ;
}
2011-06-17 11:32:38 +00:00
2011-05-13 11:19:28 +00:00
/* Starting is only possible when no error occurred.
2011-02-23 20:48:06 +00:00
*/
if ( ! rot - > relevant_log | | rot - > has_error ) {
MARS_DBG ( " nothing to do \n " ) ;
goto done ;
}
/* Start when necessary
*/
if ( ! trans_brick - > power . button & & ! trans_brick - > power . led_on & & trans_brick - > power . led_off ) {
2011-06-17 11:32:38 +00:00
bool do_start ;
status = _make_logging_status ( rot ) ;
if ( status < = 0 ) {
goto done ;
}
2012-08-03 08:42:51 +00:00
do_start = ( ! rot - > replay_mode | |
2012-01-31 13:17:59 +00:00
( rot - > start_pos ! = rot - > end_pos & &
rot - > allow_replay & &
_check_allow ( global , parent , " allow-replay " ) ) ) ;
2012-08-03 08:42:51 +00:00
MARS_DBG ( " rot->replay_mode = %d rot->start_pos = %lld rot->end_pos = %lld rot->allow_replay = %d | do_start = %d \n " , rot - > replay_mode , rot - > start_pos , rot - > end_pos , rot - > allow_replay , do_start ) ;
2011-02-23 20:48:06 +00:00
if ( do_start ) {
status = _start_trans ( rot ) ;
}
}
done :
2012-08-02 12:59:55 +00:00
rot - > allow_sync = ( ! rot - > trans_brick | | rot - > trans_brick - > power . led_off ) ;
2012-09-25 15:41:07 +00:00
if ( rot - > trans_brick )
_show_rate ( rot , & rot - > replay_limiter , rot - > trans_brick - > power . led_on , " replay_rate " ) ;
if ( rot - > copy_brick )
_show_rate ( rot , & rot - > file_limiter , rot - > copy_brick - > power . led_on , " file_rate " ) ;
if ( rot - > sync_brick )
_show_rate ( rot , & rot - > sync_limiter , rot - > sync_brick - > power . led_on , " sync_rate " ) ;
2012-01-31 13:17:59 +00:00
err :
2011-02-23 20:48:06 +00:00
return status ;
}
///////////////////////////////////////////////////////////////////////
// specific handlers
static
2011-02-28 18:00:32 +00:00
int make_primary ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
2011-08-25 10:16:32 +00:00
struct mars_global * global = buf ;
2011-02-28 18:00:32 +00:00
struct mars_dent * parent ;
2011-02-27 14:17:58 +00:00
struct mars_rotate * rot ;
2011-02-23 20:48:06 +00:00
int status = - EINVAL ;
2011-08-25 10:16:32 +00:00
if ( ! global - > global_power . button ) {
status = 0 ;
goto done ;
}
2011-02-27 14:17:58 +00:00
parent = dent - > d_parent ;
CHECK_PTR ( parent , done ) ;
rot = parent - > d_private ;
2012-12-03 08:43:26 +00:00
if ( ! rot )
goto done ;
2011-02-23 20:48:06 +00:00
CHECK_PTR ( rot , done ) ;
2011-09-27 08:46:14 +00:00
rot - > todo_primary =
global - > global_power . button & & dent - > new_link & & ! strcmp ( dent - > new_link , my_id ( ) ) ;
2011-07-20 13:11:44 +00:00
rot - > is_primary =
2011-09-27 08:46:14 +00:00
rot - > if_brick & & ! rot - > if_brick - > power . led_off ;
2011-02-23 20:48:06 +00:00
status = 0 ;
done :
return status ;
}
static
2011-03-18 13:15:40 +00:00
int make_bio ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
struct mars_global * global = buf ;
struct mars_brick * brick ;
2011-02-27 14:17:58 +00:00
int status = 0 ;
2011-02-23 20:48:06 +00:00
2011-03-23 08:09:00 +00:00
if ( ! global - > global_power . button ) {
2011-02-27 14:17:58 +00:00
goto done ;
2011-02-23 20:48:06 +00:00
}
2012-08-08 09:50:24 +00:00
brick = mars_find_brick ( global , NULL , dent - > d_path ) ;
if ( brick ) {
goto check ;
2011-02-23 20:48:06 +00:00
}
2011-03-01 09:34:36 +00:00
brick =
make_brick_all ( global ,
2011-03-02 09:30:56 +00:00
dent ,
2011-09-02 12:17:40 +00:00
false ,
2011-03-18 13:15:40 +00:00
_set_bio_params ,
2011-03-11 13:57:54 +00:00
NULL ,
2011-03-01 09:34:36 +00:00
10 * HZ ,
dent - > d_path ,
2011-03-18 13:15:40 +00:00
( const struct generic_brick_type * ) & bio_brick_type ,
2011-03-01 09:34:36 +00:00
( const struct generic_brick_type * [ ] ) { } ,
2011-03-23 08:09:00 +00:00
NULL ,
2011-11-03 11:31:47 +00:00
1 , // start always
2011-03-01 09:34:36 +00:00
dent - > d_path ,
( const char * [ ] ) { } ,
0 ) ;
2011-02-27 14:17:58 +00:00
if ( unlikely ( ! brick ) ) {
status = - ENXIO ;
goto done ;
}
2011-02-23 20:48:06 +00:00
brick - > outputs [ 0 ] - > output_name = dent - > d_path ;
2011-03-23 17:58:02 +00:00
status = mars_power_button ( ( void * ) brick , true , false ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 ) {
2011-08-25 10:16:32 +00:00
kill_any ( buf , dent ) ;
2012-08-08 09:50:24 +00:00
goto done ;
}
check :
/* Report the actual size of the device.
* It may be larger than the global size .
*/
if ( brick & & brick - > power . led_on & & dent - > d_parent ) {
struct mars_info info = { } ;
struct mars_output * output ;
char * src = NULL ;
char * dst = NULL ;
output = brick - > outputs [ 0 ] ;
status = output - > ops - > mars_get_info ( output , & info ) ;
if ( status < 0 ) {
MARS_ERR ( " cannot get info on '%s' \n " , dent - > d_path ) ;
goto done ;
}
src = path_make ( " %lld " , info . current_size ) ;
dst = path_make ( " %s/actsize-%s " , dent - > d_parent - > d_path , my_id ( ) ) ;
if ( src & & dst ) {
( void ) mars_symlink ( src , dst , NULL , 0 ) ;
}
brick_string_free ( src ) ;
brick_string_free ( dst ) ;
2011-02-23 20:48:06 +00:00
}
2012-08-08 09:50:24 +00:00
2011-02-27 14:17:58 +00:00
done :
2011-02-23 20:48:06 +00:00
return status ;
}
2011-06-01 12:55:06 +00:00
static int make_replay ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
struct mars_global * global = buf ;
2011-02-28 18:00:32 +00:00
struct mars_dent * parent = dent - > d_parent ;
2011-02-23 20:48:06 +00:00
int status = 0 ;
2011-03-22 14:36:26 +00:00
if ( ! global - > global_power . button | | ! parent | | ! dent - > new_link ) {
2011-02-23 20:48:06 +00:00
MARS_DBG ( " nothing to do \n " ) ;
goto done ;
}
2011-08-25 10:16:32 +00:00
status = make_log_finalize ( global , dent ) ;
2011-02-23 20:48:06 +00:00
if ( status < 0 ) {
MARS_DBG ( " logger not initialized \n " ) ;
goto done ;
}
2011-06-01 12:55:06 +00:00
done :
return status ;
}
2011-06-17 11:32:38 +00:00
static
int make_dev ( void * buf , struct mars_dent * dent )
2011-06-01 12:55:06 +00:00
{
struct mars_global * global = buf ;
struct mars_dent * parent = dent - > d_parent ;
2011-06-17 11:32:38 +00:00
struct mars_rotate * rot = NULL ;
2011-06-01 12:55:06 +00:00
struct mars_brick * dev_brick ;
struct if_brick * _dev_brick ;
2011-07-15 10:12:06 +00:00
bool switch_on ;
2011-06-01 12:55:06 +00:00
int status = 0 ;
2011-06-17 11:32:38 +00:00
if ( ! parent | | ! dent - > new_link ) {
MARS_ERR ( " nothing to do \n " ) ;
return - EINVAL ;
}
2011-03-22 14:36:26 +00:00
rot = parent - > d_private ;
2011-06-17 11:32:38 +00:00
if ( ! rot ) {
MARS_DBG ( " nothing to do \n " ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-07-15 10:12:06 +00:00
if ( ! rot - > trans_brick ) {
MARS_DBG ( " transaction logger does not exist \n " ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-09-27 11:57:04 +00:00
if ( ! global - > global_power . button & &
( ! rot - > if_brick | | rot - > if_brick - > power . led_off ) ) {
MARS_DBG ( " nothing to do \n " ) ;
goto done ;
}
2012-08-08 13:50:41 +00:00
if ( rot - > dev_size < = 0 ) {
MARS_WRN ( " trying to create device '%s' with zero size \n " , dent - > d_path ) ;
goto done ;
}
2011-02-23 20:48:06 +00:00
status = _parse_args ( dent , dent - > new_link , 1 ) ;
if ( status < 0 ) {
2011-03-01 09:34:36 +00:00
MARS_DBG ( " fail \n " ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-03-01 18:00:14 +00:00
2011-07-15 10:12:06 +00:00
switch_on =
2011-07-20 13:11:44 +00:00
( rot - > if_brick & & atomic_read ( & rot - > if_brick - > inputs [ 0 ] - > open_count ) > 0 ) | |
2011-09-27 08:46:14 +00:00
( rot - > todo_primary & &
2012-08-03 08:42:51 +00:00
! rot - > trans_brick - > replay_mode & &
2011-07-20 13:11:44 +00:00
rot - > trans_brick - > power . led_on ) ;
2012-01-23 15:13:29 +00:00
if ( ! global - > global_power . button | | global - > exhausted ) {
2011-09-27 11:57:04 +00:00
switch_on = false ;
}
2011-07-15 10:12:06 +00:00
2011-03-01 09:34:36 +00:00
dev_brick =
make_brick_all ( global ,
dent ,
2011-09-02 12:17:40 +00:00
false ,
2011-03-11 13:57:54 +00:00
_set_if_params ,
2012-08-08 13:50:41 +00:00
rot ,
2011-03-01 09:34:36 +00:00
10 * HZ ,
2011-03-01 18:00:14 +00:00
dent - > d_argv [ 0 ] ,
2011-03-07 10:27:38 +00:00
( const struct generic_brick_type * ) & if_brick_type ,
2011-03-01 09:34:36 +00:00
( const struct generic_brick_type * [ ] ) { ( const struct generic_brick_type * ) & trans_logger_brick_type } ,
2011-11-03 11:31:47 +00:00
NULL ,
switch_on ? 1 : - 1 ,
2011-09-27 11:57:04 +00:00
" %s/device-%s " ,
2011-03-03 09:02:10 +00:00
( const char * [ ] ) { " %s/logger " } ,
2011-03-01 18:00:14 +00:00
1 ,
2011-03-22 14:36:26 +00:00
parent - > d_path ,
2011-03-03 09:02:10 +00:00
dent - > d_argv [ 0 ] ,
2011-03-22 14:36:26 +00:00
parent - > d_path ) ;
2011-06-17 11:32:38 +00:00
rot - > if_brick = ( void * ) dev_brick ;
2011-02-23 20:48:06 +00:00
if ( ! dev_brick ) {
2011-06-17 11:32:38 +00:00
MARS_DBG ( " device not shown \n " ) ;
goto done ;
2011-02-23 20:48:06 +00:00
}
2011-09-27 11:57:04 +00:00
dev_brick - > show_status = _show_brick_status ;
2011-03-08 16:45:52 +00:00
_dev_brick = ( void * ) dev_brick ;
#if 0
if ( _dev_brick - > has_closed ) {
_dev_brick - > has_closed = false ;
MARS_INF ( " rotating logfile for '%s' \n " , parent - > d_name ) ;
status = mars_power_button ( ( void * ) rot - > trans_brick , false ) ;
rot - > relevant_log = NULL ;
}
# endif
2011-02-23 20:48:06 +00:00
done :
2011-06-17 11:32:38 +00:00
_show_primary ( rot , parent ) ;
2011-02-23 20:48:06 +00:00
return status ;
}
2011-09-27 11:57:04 +00:00
static
int kill_dev ( void * buf , struct mars_dent * dent )
{
struct mars_dent * parent = dent - > d_parent ;
int status = kill_any ( buf , dent ) ;
if ( status > 0 & & parent ) {
struct mars_rotate * rot = parent - > d_private ;
if ( rot ) {
rot - > if_brick = NULL ;
}
}
return status ;
}
2011-02-28 18:00:32 +00:00
static int _make_direct ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
struct mars_global * global = buf ;
struct mars_brick * brick ;
2011-03-31 16:16:00 +00:00
char * src_path = NULL ;
2011-02-23 20:48:06 +00:00
int status ;
2011-03-31 16:16:00 +00:00
bool do_dealloc = false ;
2011-02-23 20:48:06 +00:00
if ( ! global - > global_power . button | | ! dent - > d_parent | | ! dent - > new_link ) {
return 0 ;
}
status = _parse_args ( dent , dent - > new_link , 2 ) ;
if ( status < 0 ) {
2011-03-11 13:57:54 +00:00
MARS_DBG ( " parse status = %d \n " , status ) ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-03-31 16:16:00 +00:00
src_path = dent - > d_argv [ 0 ] ;
if ( src_path [ 0 ] ! = ' / ' ) {
src_path = path_make ( " %s/%s " , dent - > d_parent - > d_path , dent - > d_argv [ 0 ] ) ;
2011-08-12 11:09:48 +00:00
if ( ! src_path ) {
MARS_DBG ( " fail \n " ) ;
status = - ENOMEM ;
goto done ;
}
2011-03-31 16:16:00 +00:00
do_dealloc = true ;
}
2011-03-01 09:34:36 +00:00
brick =
make_brick_all ( global ,
dent ,
2011-09-02 12:17:40 +00:00
false ,
2011-03-18 13:15:40 +00:00
_set_bio_params ,
2011-03-11 13:57:54 +00:00
NULL ,
2011-03-01 09:34:36 +00:00
10 * HZ ,
2011-03-31 16:16:00 +00:00
src_path ,
2011-03-18 13:15:40 +00:00
( const struct generic_brick_type * ) & bio_brick_type ,
2011-03-01 09:34:36 +00:00
( const struct generic_brick_type * [ ] ) { } ,
2011-03-23 08:09:00 +00:00
NULL ,
2011-11-03 11:31:47 +00:00
0 ,
2011-03-31 16:16:00 +00:00
" %s " ,
2011-03-01 09:34:36 +00:00
( const char * [ ] ) { } ,
2011-03-02 09:30:56 +00:00
0 ,
2011-03-31 16:16:00 +00:00
src_path ) ;
2011-03-01 09:34:36 +00:00
status = - 1 ;
2011-02-23 20:48:06 +00:00
if ( ! brick ) {
2011-03-01 09:34:36 +00:00
MARS_DBG ( " fail \n " ) ;
goto done ;
2011-02-23 20:48:06 +00:00
}
2011-03-01 09:34:36 +00:00
brick =
make_brick_all ( global ,
dent ,
2011-09-02 12:17:40 +00:00
false ,
2011-03-11 13:57:54 +00:00
_set_if_params ,
NULL ,
2011-03-01 09:34:36 +00:00
10 * HZ ,
dent - > d_argv [ 1 ] ,
2011-03-07 10:27:38 +00:00
( const struct generic_brick_type * ) & if_brick_type ,
2011-03-01 09:34:36 +00:00
( const struct generic_brick_type * [ ] ) { NULL } ,
2011-03-23 08:09:00 +00:00
NULL ,
2011-11-03 11:31:47 +00:00
0 ,
2011-09-27 11:57:04 +00:00
" %s/directdevice-%s " ,
2011-03-31 16:16:00 +00:00
( const char * [ ] ) { " %s " } ,
2011-03-02 09:30:56 +00:00
1 ,
2011-03-03 09:02:10 +00:00
dent - > d_parent - > d_path ,
dent - > d_argv [ 1 ] ,
2011-03-31 16:16:00 +00:00
src_path ) ;
2011-03-01 09:34:36 +00:00
status = - 1 ;
2011-02-23 20:48:06 +00:00
if ( ! brick ) {
2011-03-01 09:34:36 +00:00
MARS_DBG ( " fail \n " ) ;
goto done ;
2011-02-23 20:48:06 +00:00
}
2011-03-01 09:34:36 +00:00
2011-02-23 20:48:06 +00:00
status = 0 ;
done :
MARS_DBG ( " status = %d \n " , status ) ;
2011-08-12 11:09:48 +00:00
if ( do_dealloc & & src_path )
brick_string_free ( src_path ) ;
2011-02-23 20:48:06 +00:00
return status ;
}
2011-02-28 18:00:32 +00:00
static int _make_copy ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
2011-02-25 11:46:38 +00:00
struct mars_global * global = buf ;
2011-03-23 08:09:00 +00:00
const char * switch_path = NULL ;
2011-03-22 14:36:26 +00:00
const char * copy_path = NULL ;
2011-02-25 11:46:38 +00:00
int status ;
2011-02-23 20:48:06 +00:00
2011-02-25 11:46:38 +00:00
if ( ! global - > global_power . button | | ! dent - > d_parent | | ! dent - > new_link ) {
return 0 ;
2011-02-23 20:48:06 +00:00
}
2011-02-25 11:46:38 +00:00
status = _parse_args ( dent , dent - > new_link , 2 ) ;
if ( status < 0 ) {
goto done ;
2011-02-23 20:48:06 +00:00
}
2011-03-22 14:36:26 +00:00
copy_path = backskip_replace ( dent - > d_path , ' / ' , true , " /copy- " ) ;
if ( unlikely ( ! copy_path ) ) {
status = - ENOMEM ;
goto done ;
}
2011-03-23 17:58:02 +00:00
// check whether connection is allowed
2011-09-21 11:30:11 +00:00
switch_path = path_make ( " %s/todo-%s/connect " , dent - > d_parent - > d_path , my_id ( ) ) ;
2011-02-23 20:48:06 +00:00
2012-08-07 12:07:12 +00:00
status = __make_copy ( global , dent , switch_path , copy_path , dent - > d_parent - > d_path , ( const char * * ) dent - > d_argv , - 1 , false , true , NULL ) ;
2011-02-23 20:48:06 +00:00
done :
MARS_DBG ( " status = %d \n " , status ) ;
2011-03-22 14:36:26 +00:00
if ( copy_path )
2011-08-12 11:09:48 +00:00
brick_string_free ( copy_path ) ;
2011-03-23 17:58:02 +00:00
if ( switch_path )
2011-08-12 11:09:48 +00:00
brick_string_free ( switch_path ) ;
2011-02-23 20:48:06 +00:00
return status ;
}
2011-02-28 18:00:32 +00:00
static int make_sync ( void * buf , struct mars_dent * dent )
2011-02-23 20:48:06 +00:00
{
struct mars_global * global = buf ;
2011-07-08 07:02:14 +00:00
struct mars_rotate * rot ;
2011-02-25 11:46:38 +00:00
loff_t start_pos = 0 ;
2011-07-08 07:02:14 +00:00
loff_t end_pos = 0 ;
struct mars_dent * size_dent ;
2011-02-28 18:00:32 +00:00
struct mars_dent * connect_dent ;
2011-02-25 11:46:38 +00:00
char * peer ;
struct copy_brick * copy = NULL ;
2011-03-02 09:30:56 +00:00
char * tmp = NULL ;
2011-03-23 08:09:00 +00:00
const char * switch_path = NULL ;
2011-03-22 14:36:26 +00:00
const char * copy_path = NULL ;
const char * src = NULL ;
const char * dst = NULL ;
2011-10-20 12:27:17 +00:00
bool do_start = true ;
2011-02-23 20:48:06 +00:00
int status ;
2011-03-23 08:09:00 +00:00
if ( ! global - > global_power . button | | ! dent - > d_parent | | ! dent - > new_link ) {
2011-02-23 20:48:06 +00:00
return 0 ;
}
2011-02-25 11:46:38 +00:00
/* Analyze replay position
*/
status = sscanf ( dent - > new_link , " %lld " , & start_pos ) ;
if ( status ! = 1 ) {
MARS_ERR ( " bad syncstatus symlink syntax '%s' (%s) \n " , dent - > new_link , dent - > d_path ) ;
status = - EINVAL ;
goto done ;
}
2011-07-08 07:02:14 +00:00
rot = dent - > d_parent - > d_private ;
if ( rot ) {
2012-01-31 13:17:59 +00:00
rot - > allow_update = true ;
2012-07-23 07:17:18 +00:00
rot - > syncstatus_dent = dent ;
2011-07-08 07:02:14 +00:00
}
/* Sync necessary?
*/
tmp = path_make ( " %s/size " , dent - > d_parent - > d_path ) ;
status = - ENOMEM ;
if ( unlikely ( ! tmp ) )
goto done ;
size_dent = ( void * ) mars_find_dent ( global , tmp ) ;
if ( ! size_dent | | ! size_dent - > new_link ) {
2011-07-28 11:41:06 +00:00
MARS_ERR ( " cannot determine size '%s' \n " , tmp ) ;
2011-07-08 07:02:14 +00:00
status = - ENOENT ;
goto done ;
}
status = sscanf ( size_dent - > new_link , " %lld " , & end_pos ) ;
if ( status ! = 1 ) {
MARS_ERR ( " bad size symlink syntax '%s' (%s) \n " , size_dent - > new_link , tmp ) ;
status = - EINVAL ;
goto done ;
}
if ( start_pos = = end_pos ) {
MARS_DBG ( " no data sync necessary, size = %lld \n " , start_pos ) ;
2011-10-20 12:27:17 +00:00
do_start = false ;
2011-07-08 07:02:14 +00:00
}
2011-08-12 11:09:48 +00:00
brick_string_free ( tmp ) ;
2011-07-08 07:02:14 +00:00
2011-02-25 11:46:38 +00:00
/* Determine peer
*/
2011-03-03 09:02:10 +00:00
tmp = path_make ( " %s/connect-%s " , dent - > d_parent - > d_path , my_id ( ) ) ;
2011-03-02 09:30:56 +00:00
status = - ENOMEM ;
if ( unlikely ( ! tmp ) )
goto done ;
connect_dent = ( void * ) mars_find_dent ( global , tmp ) ;
2011-02-25 11:46:38 +00:00
if ( ! connect_dent | | ! connect_dent - > new_link ) {
2012-02-06 16:16:19 +00:00
MARS_WRN ( " cannot determine peer, symlink '%s' is missing => assuming that I am STANDALONE \n " , tmp ) ;
rot - > allow_replay = true ;
status = 0 ;
2011-02-23 20:48:06 +00:00
goto done ;
}
2011-02-25 11:46:38 +00:00
peer = connect_dent - > new_link ;
2012-01-31 13:17:59 +00:00
/* Disallow contemporary sync & logfile_apply
*/
2012-08-02 12:59:55 +00:00
if ( do_start & & ! rot - > allow_sync ) {
2012-01-31 13:17:59 +00:00
MARS_WRN ( " cannot start sync because logfile application is running! \n " ) ;
do_start = false ;
}
2012-08-03 12:55:00 +00:00
# if defined(CONFIG_MARS_SYNC_FLIP_INTERVAL) && CONFIG_MARS_SYNC_FLIP_INTERVAL > 0
/* Flip between replay and sync
*/
if ( do_start & & rot - > replay_mode & & rot - > end_pos > rot - > start_pos ) {
if ( ! rot - > flip_start ) {
rot - > flip_start = jiffies ;
} else if ( ( long long ) jiffies - rot - > flip_start > CONFIG_MARS_SYNC_FLIP_INTERVAL * HZ ) {
do_start = false ;
rot - > flip_start = jiffies + CONFIG_MARS_SYNC_FLIP_INTERVAL * HZ ;
}
} else {
rot - > flip_start = 0 ;
}
# endif
2011-02-25 11:46:38 +00:00
/* Start copy
*/
2011-03-03 09:02:10 +00:00
src = path_make ( " data-%s@%s " , peer , peer ) ;
dst = path_make ( " data-%s " , my_id ( ) ) ;
2011-03-22 14:36:26 +00:00
copy_path = backskip_replace ( dent - > d_path , ' / ' , true , " /copy- " ) ;
2011-03-01 18:00:14 +00:00
2011-03-23 17:58:02 +00:00
// check whether connection is allowed
2011-09-21 11:30:11 +00:00
switch_path = path_make ( " %s/todo-%s/sync " , dent - > d_parent - > d_path , my_id ( ) ) ;
2011-03-23 17:58:02 +00:00
2011-06-17 11:32:38 +00:00
status = - ENOMEM ;
if ( unlikely ( ! src | | ! dst | | ! copy_path | | ! switch_path ) )
goto done ;
2012-01-31 13:17:59 +00:00
MARS_DBG ( " initial sync '%s' => '%s' rot->allow_sync = %d do_start = %d \n " , src , dst , rot - > allow_sync , do_start ) ;
2011-02-25 11:46:38 +00:00
2011-03-01 18:00:14 +00:00
{
const char * argv [ 2 ] = { src , dst } ;
2012-08-02 08:47:42 +00:00
# ifdef CONFIG_MARS_FAST_FULLSYNC
# define VERIFY_MODE true
# else
# define VERIFY_MODE false
# endif
2012-08-07 12:07:12 +00:00
status = __make_copy ( global , dent , do_start ? switch_path : " " , copy_path , dent - > d_parent - > d_path , argv , start_pos , VERIFY_MODE , true , & copy ) ;
2012-09-25 15:41:07 +00:00
if ( copy )
copy - > copy_limiter = & rot - > sync_limiter ;
2012-01-31 13:17:59 +00:00
rot - > sync_brick = copy ;
rot - > allow_replay = ( ! copy | | copy - > power . led_off ) ;
2011-03-01 18:00:14 +00:00
}
2011-02-23 20:48:06 +00:00
2011-02-25 11:46:38 +00:00
/* Update syncstatus symlink
*/
2011-06-17 11:32:38 +00:00
if ( status > = 0 & & copy & &
( ( copy - > power . button & & copy - > power . led_on ) | |
( copy - > copy_last = = copy - > copy_end & & copy - > copy_end > 0 ) ) ) {
2011-08-12 11:09:48 +00:00
brick_string_free ( src ) ;
brick_string_free ( dst ) ;
2011-03-03 09:02:10 +00:00
src = path_make ( " %lld " , copy - > copy_last ) ;
dst = path_make ( " %s/syncstatus-%s " , dent - > d_parent - > d_path , my_id ( ) ) ;
2011-03-02 09:30:56 +00:00
status = - ENOMEM ;
if ( unlikely ( ! src | | ! dst ) )
goto done ;
2011-02-27 14:17:58 +00:00
status = mars_symlink ( src , dst , NULL , 0 ) ;
2012-08-02 14:45:40 +00:00
brick_string_free ( src ) ;
brick_string_free ( dst ) ;
src = path_make ( " %lld,%lld " , copy - > verify_ok_count , copy - > verify_error_count ) ;
dst = path_make ( " %s/verifystatus-%s " , dent - > d_parent - > d_path , my_id ( ) ) ;
status = - ENOMEM ;
if ( unlikely ( ! src | | ! dst ) )
goto done ;
status = mars_symlink ( src , dst , NULL , 0 ) ;
2011-02-25 11:46:38 +00:00
}
2011-02-23 20:48:06 +00:00
done :
MARS_DBG ( " status = %d \n " , status ) ;
2011-10-20 12:27:17 +00:00
brick_string_free ( tmp ) ;
brick_string_free ( src ) ;
brick_string_free ( dst ) ;
brick_string_free ( copy_path ) ;
brick_string_free ( switch_path ) ;
2011-02-23 20:48:06 +00:00
return status ;
}
2011-10-24 10:54:15 +00:00
static int prepare_delete ( void * buf , struct mars_dent * dent )
{
struct mars_global * global = buf ;
struct mars_dent * target ;
struct mars_dent * response ;
const char * response_path = NULL ;
int max_serial = 0 ;
2012-02-01 14:05:49 +00:00
if ( ! global | | ! dent | | ! dent - > new_link | | ! dent - > d_path ) {
2011-10-24 10:54:15 +00:00
goto done ;
}
2012-02-01 14:05:49 +00:00
2011-10-24 10:54:15 +00:00
target = _mars_find_dent ( global , dent - > new_link ) ;
if ( target ) {
mars_unlink ( dent - > new_link ) ;
target - > d_killme = true ;
MARS_DBG ( " target '%s' deleted and marked for removal \n " , dent - > new_link ) ;
} else {
MARS_DBG ( " target '%s' does no longer exist \n " , dent - > new_link ) ;
2012-02-01 14:05:49 +00:00
if ( dent - > d_serial < global - > deleted_border ) {
MARS_DBG ( " removing deletion symlink '%s' \n " , dent - > d_path ) ;
dent - > d_killme = true ;
mars_unlink ( dent - > d_path ) ;
}
2011-10-24 10:54:15 +00:00
}
response_path = path_make ( " /mars/todo-global/deleted-%s " , my_id ( ) ) ;
if ( ! response_path ) {
MARS_ERR ( " cannot build response path for '%s' \n " , dent - > new_link ) ;
goto done ;
}
response = _mars_find_dent ( global , response_path ) ;
if ( response & & response - > new_link ) {
sscanf ( response - > new_link , " %d " , & max_serial ) ;
}
if ( dent - > d_serial > max_serial ) {
char response_val [ 16 ] ;
max_serial = dent - > d_serial ;
snprintf ( response_val , sizeof ( response_val ) , " %09d " , max_serial ) ;
mars_symlink ( response_val , response_path , NULL , 0 ) ;
}
done :
brick_string_free ( response_path ) ;
return 0 ;
}
2012-02-01 14:05:49 +00:00
static int check_deleted ( void * buf , struct mars_dent * dent )
{
struct mars_global * global = buf ;
int serial = 0 ;
int status ;
if ( ! global | | ! dent | | ! dent - > new_link ) {
goto done ;
}
status = sscanf ( dent - > new_link , " %d " , & serial ) ;
if ( status ! = 1 | | serial < = 0 ) {
MARS_WRN ( " cannot parse symlink '%s' -> '%s' \n " , dent - > d_path , dent - > new_link ) ;
goto done ;
}
/* Compute the minimum of the deletion progress among
* the resource members .
*/
if ( serial < global - > deleted_min | | ! global - > deleted_min )
global - > deleted_min = serial ;
done :
return 0 ;
}
2011-02-23 20:48:06 +00:00
///////////////////////////////////////////////////////////////////////
// the order is important!
enum {
2011-02-25 11:46:38 +00:00
// root element: this must have index 0
CL_ROOT ,
2012-03-06 14:01:54 +00:00
// global userspace
CL_GLOBAL_USERSPACE ,
CL_GLOBAL_USERSPACE_ITEMS ,
2011-10-24 10:54:15 +00:00
// global todos
CL_GLOBAL_TODO ,
CL_GLOBAL_TODO_DELETE ,
2012-02-01 14:05:49 +00:00
CL_GLOBAL_TODO_DELETED ,
2011-02-25 11:46:38 +00:00
// replacement for DNS in kernelspace
2011-02-23 20:48:06 +00:00
CL_IPS ,
CL_PEERS ,
2011-10-18 08:20:10 +00:00
CL_ALIVE ,
2012-01-23 15:37:03 +00:00
CL_EXHAUSTED ,
2012-07-23 07:17:18 +00:00
CL_JAMMED ,
2012-01-24 08:27:40 +00:00
CL_REST_SPACE ,
2011-02-25 11:46:38 +00:00
// resource definitions
2011-02-23 20:48:06 +00:00
CL_RESOURCE ,
2012-03-06 14:01:54 +00:00
CL_RESOURCE_USERSPACE ,
CL_RESOURCE_USERSPACE_ITEMS ,
2011-06-10 13:57:52 +00:00
CL_DEFAULTS0 ,
CL_DEFAULTS ,
CL_DEFAULTS_ITEMS0 ,
CL_DEFAULTS_ITEMS ,
2011-09-21 11:30:11 +00:00
CL_TODO ,
CL_TODO_ITEMS ,
2011-06-10 13:57:52 +00:00
CL_ACTUAL ,
CL_ACTUAL_ITEMS ,
2011-02-25 11:46:38 +00:00
CL_CONNECT ,
2011-02-23 20:48:06 +00:00
CL_DATA ,
2011-07-08 07:02:14 +00:00
CL_SIZE ,
2012-08-08 09:50:24 +00:00
CL_ACTSIZE ,
2011-02-23 20:48:06 +00:00
CL_PRIMARY ,
CL__FILE ,
CL_SYNC ,
2012-08-02 14:45:40 +00:00
CL_VERIF ,
2011-02-23 20:48:06 +00:00
CL__COPY ,
CL__DIRECT ,
2011-05-13 11:19:28 +00:00
CL_VERSION ,
2011-02-23 20:48:06 +00:00
CL_LOG ,
2011-06-01 12:55:06 +00:00
CL_REPLAYSTATUS ,
2011-02-23 20:48:06 +00:00
CL_DEVICE ,
} ;
/* Please keep the order the same as in the enum.
*/
static const struct light_class light_classes [ ] = {
/* Placeholder for root node /mars/
*/
[ CL_ROOT ] = {
} ,
2012-03-06 14:01:54 +00:00
/* Subdirectory for global userspace items...
*/
[ CL_GLOBAL_USERSPACE ] = {
. cl_name = " userspace " ,
. cl_len = 9 ,
. cl_type = ' d ' ,
. cl_hostcontext = false ,
. cl_father = CL_ROOT ,
} ,
[ CL_GLOBAL_USERSPACE_ITEMS ] = {
. cl_name = " " ,
. cl_len = 0 , // catch any
. cl_type = ' l ' ,
. cl_father = CL_GLOBAL_USERSPACE ,
} ,
2011-10-24 10:54:15 +00:00
/* Subdirectory for global controlling items...
*/
[ CL_GLOBAL_TODO ] = {
. cl_name = " todo-global " ,
. cl_len = 11 ,
. cl_type = ' d ' ,
. cl_hostcontext = false ,
. cl_father = CL_ROOT ,
} ,
/* ... and its contents
*/
[ CL_GLOBAL_TODO_DELETE ] = {
. cl_name = " delete- " ,
. cl_len = 7 ,
. cl_type = ' l ' ,
. cl_serial = true ,
. cl_father = CL_GLOBAL_TODO ,
. cl_prepare = prepare_delete ,
} ,
2012-02-01 14:05:49 +00:00
[ CL_GLOBAL_TODO_DELETED ] = {
. cl_name = " deleted- " ,
. cl_len = 8 ,
2011-10-24 10:54:15 +00:00
. cl_type = ' l ' ,
. cl_father = CL_GLOBAL_TODO ,
2012-02-01 14:05:49 +00:00
. cl_prepare = check_deleted ,
2011-10-24 10:54:15 +00:00
} ,
2011-02-23 20:48:06 +00:00
/* Directory containing the addresses of all peers
*/
[ CL_IPS ] = {
. cl_name = " ips " ,
. cl_len = 3 ,
. cl_type = ' d ' ,
. cl_father = CL_ROOT ,
} ,
/* Anyone participating in a MARS cluster must
* be named here ( symlink pointing to the IP address ) .
* We have no DNS in kernel space .
*/
[ CL_PEERS ] = {
. cl_name = " ip- " ,
. cl_len = 3 ,
. cl_type = ' l ' ,
. cl_father = CL_IPS ,
2011-08-31 11:42:04 +00:00
# ifdef RUN_PEERS
2011-02-24 16:37:32 +00:00
. cl_forward = make_scan ,
# endif
2011-08-31 11:42:04 +00:00
. cl_backward = kill_scan ,
2011-02-23 20:48:06 +00:00
} ,
2011-10-18 08:20:10 +00:00
/* Indicate aliveness of all cluster paritcipants
* by the timestamp of this link .
*/
[ CL_ALIVE ] = {
. cl_name = " alive- " ,
. cl_len = 6 ,
. cl_type = ' l ' ,
. cl_father = CL_ROOT ,
} ,
2012-01-23 15:37:03 +00:00
/* Indicate whether filesystem is full
*/
[ CL_EXHAUSTED ] = {
. cl_name = " exhausted- " ,
. cl_len = 10 ,
. cl_type = ' l ' ,
. cl_father = CL_ROOT ,
} ,
2012-01-24 08:27:40 +00:00
/* dto as percentage
*/
2012-01-24 09:00:21 +00:00
[ CL_REST_SPACE ] = {
2012-01-24 08:27:40 +00:00
. cl_name = " rest-space- " ,
2012-01-24 08:30:50 +00:00
. cl_len = 11 ,
2012-01-24 08:27:40 +00:00
. cl_type = ' l ' ,
. cl_father = CL_ROOT ,
} ,
2012-07-23 07:17:18 +00:00
[ CL_JAMMED ] = {
. cl_name = " jammed- " ,
. cl_len = 7 ,
. cl_type = ' l ' ,
. cl_father = CL_ROOT ,
} ,
2011-02-23 20:48:06 +00:00
/* Directory containing all items of a resource
*/
[ CL_RESOURCE ] = {
. cl_name = " resource- " ,
. cl_len = 9 ,
. cl_type = ' d ' ,
2012-11-14 09:46:36 +00:00
. cl_use_channel = true ,
2011-02-23 20:48:06 +00:00
. cl_father = CL_ROOT ,
} ,
2011-06-10 13:57:52 +00:00
2012-03-06 14:01:54 +00:00
/* Subdirectory for resource-specific userspace items...
*/
[ CL_RESOURCE_USERSPACE ] = {
. cl_name = " userspace " ,
. cl_len = 9 ,
. cl_type = ' d ' ,
. cl_hostcontext = false ,
. cl_father = CL_RESOURCE ,
} ,
[ CL_RESOURCE_USERSPACE_ITEMS ] = {
. cl_name = " " ,
. cl_len = 0 , // catch any
. cl_type = ' l ' ,
. cl_father = CL_RESOURCE_USERSPACE ,
} ,
2011-06-10 13:57:52 +00:00
/* Subdirectory for defaults...
*/
[ CL_DEFAULTS0 ] = {
. cl_name = " defaults " ,
. cl_len = 8 ,
. cl_type = ' d ' ,
. cl_hostcontext = false ,
. cl_father = CL_RESOURCE ,
} ,
[ CL_DEFAULTS ] = {
. cl_name = " defaults- " ,
. cl_len = 9 ,
. cl_type = ' d ' ,
2011-07-15 10:12:06 +00:00
. cl_hostcontext = false ,
2011-06-10 13:57:52 +00:00
. cl_father = CL_RESOURCE ,
} ,
/* ... and its contents
*/
[ CL_DEFAULTS_ITEMS0 ] = {
. cl_name = " " ,
. cl_len = 0 , // catch any
. cl_type = ' l ' ,
. cl_father = CL_DEFAULTS0 ,
} ,
[ CL_DEFAULTS_ITEMS ] = {
. cl_name = " " ,
. cl_len = 0 , // catch any
. cl_type = ' l ' ,
. cl_father = CL_DEFAULTS ,
} ,
2011-03-23 17:58:02 +00:00
/* Subdirectory for controlling items...
*/
2011-09-21 11:30:11 +00:00
[ CL_TODO ] = {
. cl_name = " todo- " ,
2011-09-23 14:08:17 +00:00
. cl_len = 5 ,
2011-03-23 17:58:02 +00:00
. cl_type = ' d ' ,
2011-07-15 10:12:06 +00:00
. cl_hostcontext = false ,
2011-03-23 17:58:02 +00:00
. cl_father = CL_RESOURCE ,
} ,
/* ... and its contents
*/
2011-09-21 11:30:11 +00:00
[ CL_TODO_ITEMS ] = {
2011-03-23 17:58:02 +00:00
. cl_name = " " ,
. cl_len = 0 , // catch any
. cl_type = ' l ' ,
2011-09-21 11:30:11 +00:00
. cl_father = CL_TODO ,
2011-03-23 17:58:02 +00:00
} ,
2011-06-10 13:57:52 +00:00
/* Subdirectory for actual state
*/
[ CL_ACTUAL ] = {
. cl_name = " actual- " ,
. cl_len = 7 ,
. cl_type = ' d ' ,
2011-07-15 10:12:06 +00:00
. cl_hostcontext = false ,
2011-06-10 13:57:52 +00:00
. cl_father = CL_RESOURCE ,
} ,
/* ... and its contents
*/
[ CL_ACTUAL_ITEMS ] = {
. cl_name = " " ,
. cl_len = 0 , // catch any
. cl_type = ' l ' ,
. cl_father = CL_ACTUAL ,
} ,
2011-02-25 11:46:38 +00:00
/* Symlink indicating the current peer
*/
[ CL_CONNECT ] = {
. cl_name = " connect- " ,
. cl_len = 8 ,
. cl_type = ' l ' ,
2011-06-17 11:32:38 +00:00
. cl_hostcontext = false , // not used here
2011-02-25 11:46:38 +00:00
. cl_father = CL_RESOURCE ,
} ,
2011-02-23 20:48:06 +00:00
/* File or symlink to the real device / real (sparse) file
* when hostcontext is missing , the corresponding peer will
* not participate in that resource .
*/
[ CL_DATA ] = {
. cl_name = " data- " ,
. cl_len = 5 ,
. cl_type = ' F ' ,
. cl_hostcontext = true ,
. cl_father = CL_RESOURCE ,
2011-08-31 11:42:04 +00:00
# ifdef RUN_DATA
2011-03-18 13:15:40 +00:00
. cl_forward = make_bio ,
2011-08-31 11:42:04 +00:00
# endif
2011-08-25 10:16:32 +00:00
. cl_backward = kill_any ,
2011-02-23 20:48:06 +00:00
} ,
2011-07-08 07:02:14 +00:00
/* Symlink indicating the (common) size of the resource
*/
[ CL_SIZE ] = {
. cl_name = " size " ,
. cl_len = 4 ,
. cl_type = ' l ' ,
. cl_hostcontext = false ,
. cl_father = CL_RESOURCE ,
2011-08-31 11:42:04 +00:00
# ifdef RUN_LOGINIT
2011-07-08 07:02:14 +00:00
. cl_forward = make_log_init ,
2011-08-31 11:42:04 +00:00
# endif
2012-11-19 10:55:38 +00:00
. cl_backward = kill_any ,
2011-07-08 07:02:14 +00:00
} ,
2012-08-08 09:50:24 +00:00
/* Dito for each individual size
*/
[ CL_ACTSIZE ] = {
. cl_name = " actsize- " ,
. cl_len = 8 ,
. cl_type = ' l ' ,
. cl_hostcontext = true ,
. cl_father = CL_RESOURCE ,
} ,
2011-02-23 20:48:06 +00:00
/* Symlink pointing to the name of the primary node
*/
[ CL_PRIMARY ] = {
. cl_name = " primary " ,
. cl_len = 7 ,
. cl_type = ' l ' ,
. cl_hostcontext = false ,
. cl_father = CL_RESOURCE ,
2011-08-31 11:42:04 +00:00
# ifdef RUN_PRIMARY
2011-02-23 20:48:06 +00:00
. cl_forward = make_primary ,
2011-08-31 11:42:04 +00:00
# endif
2011-02-23 20:48:06 +00:00
. cl_backward = NULL ,
} ,
/* Only for testing: open local file
*/
[ CL__FILE ] = {
. cl_name = " _file- " ,
. cl_len = 6 ,
. cl_type = ' F ' ,
. cl_serial = true ,
. cl_hostcontext = true ,
. cl_father = CL_RESOURCE ,
2011-03-18 13:15:40 +00:00
. cl_forward = make_bio ,
2011-08-25 10:16:32 +00:00
. cl_backward = kill_any ,
2011-02-23 20:48:06 +00:00
} ,
/* symlink indicating the current status / end
* of initial data sync .
*/
[ CL_SYNC ] = {
. cl_name = " syncstatus- " ,
. cl_len = 11 ,
. cl_type = ' l ' ,
. cl_hostcontext = true ,
. cl_father = CL_RESOURCE ,
2011-08-31 11:42:04 +00:00
# ifdef RUN_SYNCSTATUS
2011-02-23 20:48:06 +00:00
. cl_forward = make_sync ,
2011-08-31 11:42:04 +00:00
# endif
2011-08-25 10:16:32 +00:00
. cl_backward = kill_any ,
2011-02-23 20:48:06 +00:00
} ,
2012-08-02 14:45:40 +00:00
/* informational symlink for verify status
* of initial data sync .
*/
[ CL_VERIF ] = {
. cl_name = " verifystatus- " ,
. cl_len = 13 ,
. cl_type = ' l ' ,
. cl_hostcontext = true ,
. cl_father = CL_RESOURCE ,
} ,
2011-02-23 20:48:06 +00:00
/* Only for testing: make a copy instance
*/
[ CL__COPY ] = {
. cl_name = " _copy- " ,
. cl_len = 6 ,
. cl_type = ' l ' ,
. cl_serial = true ,
. cl_hostcontext = true ,
. cl_father = CL_RESOURCE ,
. cl_forward = _make_copy ,
2011-08-25 10:16:32 +00:00
. cl_backward = kill_any ,
2011-02-23 20:48:06 +00:00
} ,
/* Only for testing: access local data
*/
[ CL__DIRECT ] = {
. cl_name = " _direct- " ,
. cl_len = 8 ,
. cl_type = ' l ' ,
. cl_serial = true ,
. cl_hostcontext = true ,
. cl_father = CL_RESOURCE ,
. cl_forward = _make_direct ,
2011-08-25 10:16:32 +00:00
. cl_backward = kill_any ,
2011-02-23 20:48:06 +00:00
} ,
2011-05-13 11:19:28 +00:00
/* Passive symlink indicating the split-brain crypto hash
*/
[ CL_VERSION ] = {
. cl_name = " version- " ,
. cl_len = 8 ,
. cl_type = ' l ' ,
. cl_serial = true ,
2011-07-15 10:12:06 +00:00
. cl_hostcontext = false ,
2011-05-13 11:19:28 +00:00
. cl_father = CL_RESOURCE ,
} ,
2011-02-23 20:48:06 +00:00
/* Logfiles for transaction logger
*/
[ CL_LOG ] = {
. cl_name = " log- " ,
. cl_len = 4 ,
. cl_type = ' F ' ,
. cl_serial = true ,
2011-10-05 14:59:29 +00:00
. cl_hostcontext = false ,
2011-02-23 20:48:06 +00:00
. cl_father = CL_RESOURCE ,
2011-08-31 11:42:04 +00:00
# ifdef RUN_LOGFILES
2011-08-25 10:16:32 +00:00
. cl_forward = make_log_step ,
2011-02-23 20:48:06 +00:00
# endif
2011-08-31 11:42:04 +00:00
. cl_backward = kill_any ,
2011-02-23 20:48:06 +00:00
} ,
2011-06-01 12:55:06 +00:00
/* Symlink indicating the last state of
* transaction log replay .
*/
[ CL_REPLAYSTATUS ] = {
. cl_name = " replay- " ,
. cl_len = 7 ,
. cl_type = ' l ' ,
. cl_hostcontext = true ,
. cl_father = CL_RESOURCE ,
2011-08-31 11:42:04 +00:00
# ifdef RUN_REPLAY
2011-06-01 12:55:06 +00:00
. cl_forward = make_replay ,
2011-08-31 11:42:04 +00:00
# endif
2011-08-25 10:16:32 +00:00
. cl_backward = kill_any ,
2011-06-01 12:55:06 +00:00
} ,
2011-02-23 20:48:06 +00:00
/* Name of the device appearing at the primary
*/
[ CL_DEVICE ] = {
. cl_name = " device- " ,
. cl_len = 7 ,
. cl_type = ' l ' ,
. cl_hostcontext = true ,
. cl_father = CL_RESOURCE ,
2011-08-31 11:42:04 +00:00
# ifdef RUN_DEVICE
2011-02-23 20:48:06 +00:00
. cl_forward = make_dev ,
2011-08-31 11:42:04 +00:00
# endif
2011-09-27 11:57:04 +00:00
. cl_backward = kill_dev ,
2011-02-23 20:48:06 +00:00
} ,
{ }
} ;
/* Helper routine to pre-determine the relevance of a name from the filesystem.
*/
2012-12-18 05:31:24 +00:00
int light_checker ( struct mars_dent * parent , const char * _name , int namlen , unsigned int d_type , int * prefix , int * serial , bool * use_channel )
2011-02-23 20:48:06 +00:00
{
int class ;
2011-03-01 18:00:14 +00:00
int status = - 2 ;
# ifdef MARS_DEBUGGING
2011-11-14 15:00:25 +00:00
const char * name = brick_strndup ( _name , namlen ) ;
2011-03-01 18:00:14 +00:00
if ( ! name )
return - ENOMEM ;
# else
const char * name = _name ;
# endif
2011-02-23 20:48:06 +00:00
//MARS_DBG("trying '%s' '%s'\n", path, name);
for ( class = CL_ROOT + 1 ; ; class + + ) {
const struct light_class * test = & light_classes [ class ] ;
int len = test - > cl_len ;
2011-03-23 17:58:02 +00:00
if ( ! test - > cl_name ) { // end of table
2011-02-23 20:48:06 +00:00
break ;
2011-03-23 17:58:02 +00:00
}
2011-02-23 20:48:06 +00:00
//MARS_DBG(" testing class '%s'\n", test->cl_name);
2011-03-23 17:58:02 +00:00
# ifdef MARS_DEBUGGING
2011-02-23 20:48:06 +00:00
if ( len ! = strlen ( test - > cl_name ) ) {
2011-03-23 17:58:02 +00:00
MARS_ERR ( " internal table '%s' mismatch: %d != %d \n " , test - > cl_name , len , ( int ) strlen ( test - > cl_name ) ) ;
2011-02-23 20:48:06 +00:00
len = strlen ( test - > cl_name ) ;
}
# endif
2011-03-23 17:58:02 +00:00
if ( test - > cl_father & &
( ! parent | | parent - > d_class ! = test - > cl_father ) ) {
continue ;
}
if ( len > 0 & &
( namlen < len | | memcmp ( name , test - > cl_name , len ) ) ) {
continue ;
}
//MARS_DBG("path '%s/%s' matches class %d '%s'\n", path, name, class, test->cl_name);
// check special contexts
if ( test - > cl_serial ) {
int plus = 0 ;
int count ;
count = sscanf ( name + len , " %d%n " , serial , & plus ) ;
if ( count < 1 ) {
//MARS_DBG("'%s' serial number mismatch at '%s'\n", name, name+len);
2012-08-06 07:38:21 +00:00
continue ;
2011-02-23 20:48:06 +00:00
}
2011-06-01 12:55:06 +00:00
//MARS_DBG("'%s' serial number = %d\n", name, *serial);
2011-03-23 17:58:02 +00:00
len + = plus ;
if ( name [ len ] = = ' - ' )
len + + ;
}
if ( prefix )
2011-02-23 20:48:06 +00:00
* prefix = len ;
2011-03-23 17:58:02 +00:00
if ( test - > cl_hostcontext ) {
if ( memcmp ( name + len , my_id ( ) , namlen - len ) ) {
//MARS_DBG("context mismatch '%s' at '%s'\n", name, name+len);
2012-08-06 07:38:21 +00:00
continue ;
2011-02-23 20:48:06 +00:00
}
}
2011-03-23 17:58:02 +00:00
// all ok
status = class ;
2012-11-14 09:46:36 +00:00
* use_channel = test - > cl_use_channel ;
2011-02-23 20:48:06 +00:00
}
2011-03-23 17:58:02 +00:00
2011-03-01 18:00:14 +00:00
# ifdef MARS_DEBUGGING
2011-08-12 11:09:48 +00:00
brick_string_free ( name ) ;
2011-03-01 18:00:14 +00:00
# endif
return status ;
2011-02-23 20:48:06 +00:00
}
/* Do some syntactic checks, then delegate work to the real worker functions
* from the light_classes [ ] table .
*/
2011-10-24 10:54:15 +00:00
static int light_worker ( struct mars_global * global , struct mars_dent * dent , bool prepare , bool direction )
2011-02-23 20:48:06 +00:00
{
light_worker_fn worker ;
int class = dent - > d_class ;
if ( class < 0 | | class > = sizeof ( light_classes ) / sizeof ( struct light_class ) ) {
MARS_ERR_ONCE ( dent , " bad internal class %d of '%s' \n " , class , dent - > d_path ) ;
return - EINVAL ;
}
switch ( light_classes [ class ] . cl_type ) {
case ' d ' :
if ( ! S_ISDIR ( dent - > new_stat . mode ) ) {
MARS_ERR_ONCE ( dent , " '%s' should be a directory, but is something else \n " , dent - > d_path ) ;
return - EINVAL ;
}
break ;
case ' f ' :
if ( ! S_ISREG ( dent - > new_stat . mode ) ) {
MARS_ERR_ONCE ( dent , " '%s' should be a regular file, but is something else \n " , dent - > d_path ) ;
return - EINVAL ;
}
break ;
case ' F ' :
if ( ! S_ISREG ( dent - > new_stat . mode ) & & ! S_ISLNK ( dent - > new_stat . mode ) ) {
MARS_ERR_ONCE ( dent , " '%s' should be a regular file or a symlink, but is something else \n " , dent - > d_path ) ;
return - EINVAL ;
}
break ;
case ' l ' :
if ( ! S_ISLNK ( dent - > new_stat . mode ) ) {
MARS_ERR_ONCE ( dent , " '%s' should be a symlink, but is something else \n " , dent - > d_path ) ;
return - EINVAL ;
}
break ;
}
if ( likely ( class > CL_ROOT ) ) {
int father = light_classes [ class ] . cl_father ;
if ( father = = CL_ROOT ) {
if ( unlikely ( dent - > d_parent ) ) {
2012-08-06 07:38:21 +00:00
MARS_ERR_ONCE ( dent , " '%s' class %d is not at the root of the hierarchy \n " , dent - > d_path , class ) ;
2011-02-23 20:48:06 +00:00
return - EINVAL ;
}
} else if ( unlikely ( ! dent - > d_parent | | dent - > d_parent - > d_class ! = father ) ) {
MARS_ERR_ONCE ( dent , " last component '%s' from '%s' is at the wrong position in the hierarchy (class = %d, parent_class = %d, parent = '%s') \n " , dent - > d_name , dent - > d_path , father , dent - > d_parent ? dent - > d_parent - > d_class : - 9999 , dent - > d_parent ? dent - > d_parent - > d_path : " " ) ;
return - EINVAL ;
}
}
2011-10-24 10:54:15 +00:00
if ( prepare ) {
worker = light_classes [ class ] . cl_prepare ;
} else if ( direction ) {
2011-02-23 20:48:06 +00:00
worker = light_classes [ class ] . cl_backward ;
} else {
worker = light_classes [ class ] . cl_forward ;
}
if ( worker ) {
int status ;
2012-01-17 10:48:56 +00:00
if ( ! direction )
MARS_DBG ( " --- start working %s on '%s' rest='%s' \n " , direction ? " backward " : " forward " , dent - > d_path , dent - > d_rest ) ;
2011-02-23 20:48:06 +00:00
status = worker ( global , ( void * ) dent ) ;
2012-01-17 10:48:56 +00:00
MARS_DBG ( " --- done, worked %s on '%s', status = %d \n " , direction ? " backward " : " forward " , dent - > d_path , status ) ;
2011-02-23 20:48:06 +00:00
return status ;
}
return 0 ;
}
2011-03-03 09:02:10 +00:00
# ifdef STAT_DEBUGGING
2011-08-31 11:42:04 +00:00
static
void _show_one ( struct mars_brick * test , int * brick_count )
{
int i ;
if ( * brick_count ) {
MARS_STAT ( " --------- \n " ) ;
}
2012-12-03 13:21:12 +00:00
MARS_STAT ( " BRICK type = %s path = '%s' name = '%s' "
" size_hint=%d "
" mrefs_alloc = %d "
" mrefs_apsect_alloc = %d "
" total_mrefs_alloc = %d "
" total_mrefs_aspects = %d "
" button = %d off = %d on = %d \n " ,
SAFE_STR ( test - > type - > type_name ) ,
SAFE_STR ( test - > brick_path ) ,
SAFE_STR ( test - > brick_name ) ,
test - > mref_object_layout . size_hint ,
atomic_read ( & test - > mref_object_layout . alloc_count ) ,
atomic_read ( & test - > mref_object_layout . aspect_count ) ,
atomic_read ( & test - > mref_object_layout . total_alloc_count ) ,
atomic_read ( & test - > mref_object_layout . total_aspect_count ) ,
test - > power . button ,
test - > power . led_off ,
test - > power . led_on ) ;
2011-08-31 11:42:04 +00:00
( * brick_count ) + + ;
if ( test - > ops & & test - > ops - > brick_statistics ) {
char * info = test - > ops - > brick_statistics ( test , 0 ) ;
if ( info ) {
MARS_STAT ( " %s " , info ) ;
brick_string_free ( info ) ;
}
}
2011-10-05 14:59:29 +00:00
for ( i = 0 ; i < test - > type - > max_inputs ; i + + ) {
2011-08-31 11:42:04 +00:00
struct mars_input * input = test - > inputs [ i ] ;
struct mars_output * output = input ? input - > connect : NULL ;
if ( output ) {
MARS_STAT ( " input %d connected with %s path = '%s' name = '%s' \n " , i , SAFE_STR ( output - > brick - > type - > type_name ) , SAFE_STR ( output - > brick - > brick_path ) , SAFE_STR ( output - > brick - > brick_name ) ) ;
} else {
MARS_STAT ( " input %d not connected \n " , i ) ;
}
}
2011-10-05 14:59:29 +00:00
for ( i = 0 ; i < test - > type - > max_outputs ; i + + ) {
2011-08-31 11:42:04 +00:00
struct mars_output * output = test - > outputs [ i ] ;
2011-10-05 14:59:29 +00:00
if ( output ) {
MARS_STAT ( " output %d nr_connected = %d \n " , i , output - > nr_connected ) ;
}
2011-08-31 11:42:04 +00:00
}
}
2011-03-03 09:02:10 +00:00
static
void _show_statist ( struct mars_global * global )
{
struct list_head * tmp ;
int dent_count = 0 ;
int brick_count = 0 ;
2011-08-12 11:09:48 +00:00
brick_mem_statistics ( ) ;
2011-06-10 13:57:52 +00:00
down_read ( & global - > brick_mutex ) ;
2011-08-31 11:42:04 +00:00
MARS_STAT ( " ================================== ordinary bricks: \n " ) ;
2011-03-03 09:02:10 +00:00
for ( tmp = global - > brick_anchor . next ; tmp ! = & global - > brick_anchor ; tmp = tmp - > next ) {
struct mars_brick * test ;
test = container_of ( tmp , struct mars_brick , global_brick_link ) ;
2011-08-31 11:42:04 +00:00
_show_one ( test , & brick_count ) ;
}
MARS_STAT ( " ================================== server bricks: \n " ) ;
for ( tmp = global - > server_anchor . next ; tmp ! = & global - > server_anchor ; tmp = tmp - > next ) {
struct mars_brick * test ;
test = container_of ( tmp , struct mars_brick , global_brick_link ) ;
_show_one ( test , & brick_count ) ;
2011-03-03 09:02:10 +00:00
}
2011-06-10 13:57:52 +00:00
up_read ( & global - > brick_mutex ) ;
2011-03-03 09:02:10 +00:00
2011-08-25 10:16:32 +00:00
MARS_STAT ( " ================================== dents: \n " ) ;
down_read ( & global - > dent_mutex ) ;
for ( tmp = global - > dent_anchor . next ; tmp ! = & global - > dent_anchor ; tmp = tmp - > next ) {
struct mars_dent * dent ;
struct list_head * sub ;
dent = container_of ( tmp , struct mars_dent , dent_link ) ;
2011-08-31 11:42:04 +00:00
MARS_STAT ( " dent %d '%s' '%s' stamp=%ld.%09ld \n " , dent - > d_class , SAFE_STR ( dent - > d_path ) , SAFE_STR ( dent - > new_link ) , dent - > new_stat . mtime . tv_sec , dent - > new_stat . mtime . tv_nsec ) ;
2011-08-25 10:16:32 +00:00
dent_count + + ;
for ( sub = dent - > brick_list . next ; sub ! = & dent - > brick_list ; sub = sub - > next ) {
struct mars_brick * test ;
test = container_of ( sub , struct mars_brick , dent_brick_link ) ;
2011-08-31 11:42:04 +00:00
MARS_STAT ( " owner of brick '%s' \n " , SAFE_STR ( test - > brick_path ) ) ;
2011-08-25 10:16:32 +00:00
}
}
up_read ( & global - > dent_mutex ) ;
2011-11-08 12:33:13 +00:00
MARS_INF ( " ==================== STATISTICS: %d dents, %d bricks, %lld KB free \n " , dent_count , brick_count , global - > remaining_space ) ;
2011-03-03 09:02:10 +00:00
}
# endif
2011-10-18 08:20:10 +00:00
static
2012-01-24 08:27:40 +00:00
void _make_alivelink ( const char * name , loff_t val )
2011-10-18 08:20:10 +00:00
{
2012-01-24 08:27:40 +00:00
char * src = path_make ( " %lld " , val ) ;
2012-01-23 14:59:29 +00:00
char * dst = path_make ( " /mars/%s-%s " , name , my_id ( ) ) ;
2012-01-24 09:28:47 +00:00
if ( ! src | | ! dst ) {
MARS_ERR ( " cannot make symlink paths \n " ) ;
goto err ;
}
2012-01-31 15:19:35 +00:00
MARS_DBG ( " '%s' -> '%s' \n " , src , dst ) ;
2011-10-18 08:20:10 +00:00
mars_symlink ( src , dst , NULL , 0 ) ;
2012-01-24 09:28:47 +00:00
err :
2011-10-18 08:20:10 +00:00
brick_string_free ( dst ) ;
2012-01-24 08:27:40 +00:00
brick_string_free ( src ) ;
2011-10-18 08:20:10 +00:00
}
2011-08-31 11:42:04 +00:00
static struct mars_global _global = {
. dent_anchor = LIST_HEAD_INIT ( _global . dent_anchor ) ,
. brick_anchor = LIST_HEAD_INIT ( _global . brick_anchor ) ,
. server_anchor = LIST_HEAD_INIT ( _global . server_anchor ) ,
. global_power = {
. button = true ,
} ,
. dent_mutex = __RWSEM_INITIALIZER ( _global . dent_mutex ) ,
. brick_mutex = __RWSEM_INITIALIZER ( _global . brick_mutex ) ,
. main_event = __WAIT_QUEUE_HEAD_INITIALIZER ( _global . main_event ) ,
} ;
2011-02-23 20:48:06 +00:00
static int light_thread ( void * data )
{
2012-11-16 11:50:49 +00:00
long long last_rollover = jiffies ;
2011-02-23 20:48:06 +00:00
char * id = my_id ( ) ;
int status = 0 ;
2011-08-31 11:42:04 +00:00
mars_global = & _global ;
2011-02-23 20:48:06 +00:00
if ( ! id | | strlen ( id ) < 2 ) {
MARS_ERR ( " invalid hostname \n " ) ;
status = - EFAULT ;
goto done ;
}
MARS_INF ( " -------- starting as host '%s' ---------- \n " , id ) ;
2011-08-31 11:42:04 +00:00
while ( _global . global_power . button | | ! list_empty ( & _global . brick_anchor ) ) {
2011-02-23 20:48:06 +00:00
int status ;
2012-01-24 08:27:40 +00:00
loff_t rest_space ;
2012-01-23 14:59:29 +00:00
bool exhausted ;
2012-07-23 07:17:18 +00:00
bool jammed ;
2012-01-17 10:48:56 +00:00
MARS_DBG ( " -------- NEW ROUND --------- \n " ) ;
2012-08-08 09:16:52 +00:00
if ( mars_mem_percent < 0 )
mars_mem_percent = 0 ;
if ( mars_mem_percent > 70 )
mars_mem_percent = 70 ;
2012-10-15 14:35:36 +00:00
brick_global_memlimit = ( long long ) brick_global_memavail * mars_mem_percent / 100 ;
2012-08-08 09:16:52 +00:00
2012-09-17 10:11:25 +00:00
brick_msleep ( 100 ) ;
2012-01-17 10:48:56 +00:00
2012-11-13 16:01:37 +00:00
if ( brick_thread_should_stop ( ) ) {
2012-08-06 13:04:32 +00:00
_global . global_power . button = false ;
mars_net_is_alive = false ;
}
2012-01-24 08:27:40 +00:00
_make_alivelink ( " alive " , _global . global_power . button ? 1 : 0 ) ;
2012-01-23 14:59:29 +00:00
2012-01-23 17:40:15 +00:00
mars_remaining_space ( " /mars " , & _global . total_space , & _global . remaining_space ) ;
2012-07-23 07:17:18 +00:00
2012-01-23 17:40:15 +00:00
exhausted = EXHAUSTED ( _global . remaining_space , _global . total_space ) ;
2012-01-23 15:13:29 +00:00
_global . exhausted = exhausted ;
2012-01-24 08:27:40 +00:00
_make_alivelink ( " exhausted " , exhausted ? 1 : 0 ) ;
2012-01-23 14:59:29 +00:00
if ( exhausted )
2012-07-23 07:17:18 +00:00
MARS_WRN ( " EXHAUSTED filesystem space = %lld \n " , _global . remaining_space ) ;
jammed = JAMMED ( _global . remaining_space ) ;
_global . jammed = jammed ;
_make_alivelink ( " jammed " , jammed ? 1 : 0 ) ;
if ( jammed )
MARS_WRN ( " JAMMED filesystem space = %lld, STOPPING TRANSACTION LOGGING \n " , _global . remaining_space ) ;
2012-01-24 08:27:40 +00:00
rest_space = _global . remaining_space - EXHAUSTED_LIMIT ( _global . total_space ) ;
_make_alivelink ( " rest-space " , rest_space ) ;
2011-10-18 08:20:10 +00:00
2012-11-16 11:43:10 +00:00
if ( ! _global . global_power . button & & is_shutdown ( ) ) {
MARS_INF ( " global shutdown of all bricks... \n " ) ;
brick_msleep ( 500 ) ;
mars_kill_brick_all ( & _global , & _global . server_anchor , false ) ;
2011-08-31 11:42:04 +00:00
}
2011-02-23 20:48:06 +00:00
2012-01-17 10:48:56 +00:00
MARS_DBG ( " -------- start worker --------- \n " ) ;
2012-02-01 14:05:49 +00:00
_global . deleted_min = 0 ;
2011-08-31 11:42:04 +00:00
status = mars_dent_work ( & _global , " /mars " , sizeof ( struct mars_dent ) , light_checker , light_worker , & _global , 3 ) ;
2012-02-01 14:05:49 +00:00
_global . deleted_border = _global . deleted_min ;
MARS_DBG ( " -------- worker deleted_min = %d status = %d \n " , _global . deleted_min , status ) ;
2011-02-23 20:48:06 +00:00
2011-10-18 11:35:33 +00:00
if ( ! _global . global_power . button ) {
2011-11-04 15:43:23 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , ( void * ) & copy_brick_type , false ) ;
MARS_DBG ( " kill copy bricks (when possible) = %d \n " , status ) ;
2011-10-18 11:35:33 +00:00
}
2011-11-04 15:43:23 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , ( void * ) & client_brick_type , false ) ;
2011-10-10 11:38:55 +00:00
MARS_DBG ( " kill client bricks (when possible) = %d \n " , status ) ;
2011-11-04 15:43:23 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , ( void * ) & aio_brick_type , false ) ;
2011-10-10 11:38:55 +00:00
MARS_DBG ( " kill aio bricks (when possible) = %d \n " , status ) ;
2011-11-14 13:12:33 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , ( void * ) & sio_brick_type , false ) ;
MARS_DBG ( " kill sio bricks (when possible) = %d \n " , status ) ;
2012-02-14 13:14:58 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . server_anchor , false , ( void * ) & aio_brick_type , false ) ;
2012-02-09 14:50:25 +00:00
MARS_DBG ( " kill server aio bricks (when possible) = %d \n " , status ) ;
2012-02-14 13:14:58 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . server_anchor , false , ( void * ) & sio_brick_type , false ) ;
2012-02-09 14:50:25 +00:00
MARS_DBG ( " kill server sio bricks (when possible) = %d \n " , status ) ;
2011-10-10 11:38:55 +00:00
2012-11-16 11:50:49 +00:00
if ( ( long long ) jiffies + rollover_time * HZ > = last_rollover ) {
last_rollover = jiffies ;
rollover_all ( ) ;
}
2012-02-02 10:16:06 +00:00
2011-09-27 11:57:04 +00:00
_show_status_all ( & _global ) ;
2011-03-03 09:02:10 +00:00
# ifdef STAT_DEBUGGING
2011-08-31 11:42:04 +00:00
_show_statist ( & _global ) ;
2011-03-03 09:02:10 +00:00
# endif
2012-10-15 14:35:36 +00:00
MARS_DBG ( " ban_count = %d ban_renew_count = %d \n " , mars_global_ban . ban_count , mars_global_ban . ban_renew_count ) ;
2012-09-17 10:11:25 +00:00
brick_msleep ( 500 ) ;
2011-02-27 14:17:58 +00:00
2012-01-17 10:48:56 +00:00
wait_event_interruptible_timeout ( _global . main_event , _global . main_trigger , CONFIG_MARS_SCAN_INTERVAL * HZ ) ;
2011-08-31 11:42:04 +00:00
_global . main_trigger = false ;
2011-02-23 20:48:06 +00:00
}
done :
MARS_INF ( " -------- cleaning up ---------- \n " ) ;
2012-01-17 14:37:14 +00:00
mars_remote_trigger ( ) ;
2012-09-17 10:11:25 +00:00
brick_msleep ( 2000 ) ;
2011-02-23 20:48:06 +00:00
2011-08-31 11:42:04 +00:00
mars_kill_brick_all ( & _global , & _global . server_anchor , false ) ;
2011-09-27 08:46:14 +00:00
mars_free_dent_all ( & _global , & _global . dent_anchor ) ;
2011-08-31 11:42:04 +00:00
mars_kill_brick_all ( & _global , & _global . brick_anchor , false ) ;
2011-02-23 20:48:06 +00:00
2011-09-27 11:57:04 +00:00
_show_status_all ( & _global ) ;
2011-08-25 10:16:32 +00:00
# ifdef STAT_DEBUGGING
2011-08-31 11:42:04 +00:00
_show_statist ( & _global ) ;
2011-08-25 10:16:32 +00:00
# endif
2011-02-23 20:48:06 +00:00
mars_global = NULL ;
MARS_INF ( " -------- done status = %d ---------- \n " , status ) ;
2011-03-02 09:30:56 +00:00
//cleanup_mm();
2011-02-23 20:48:06 +00:00
return status ;
}
2011-11-14 17:52:05 +00:00
static struct mem_reservation global_reserve = {
. amount = {
[ 1 ] = 32 ,
[ 2 ] = 32 ,
[ 3 ] = 32 ,
2012-02-07 13:15:07 +00:00
[ 4 ] = 64 ,
[ 5 ] = 64 ,
2011-11-14 17:52:05 +00:00
[ 6 ] = 64 ,
2012-01-23 10:23:41 +00:00
[ 7 ] = 2 ,
[ 8 ] = 2 ,
[ 9 ] = 1 ,
[ 10 ] = 1 ,
[ 11 ] = 0 ,
2011-11-14 17:52:05 +00:00
} ,
} ;
2011-08-25 10:16:32 +00:00
# ifdef CONFIG_MARS_HAVE_BIGMODULE
# define INIT_MAX 32
static char * exit_names [ INIT_MAX ] = { } ;
static void ( * exit_fn [ INIT_MAX ] ) ( void ) = { } ;
static int exit_fn_nr = 0 ;
# define DO_INIT(name) \
2012-01-11 11:35:09 +00:00
MARS_DBG ( " === starting module " # name " ... \n " ) ; \
2011-08-25 10:16:32 +00:00
do { \
if ( ( status = init_ # # name ( ) ) < 0 ) goto done ; \
exit_names [ exit_fn_nr ] = # name ; \
exit_fn [ exit_fn_nr + + ] = exit_ # # name ; \
} while ( 0 )
# endif
2012-01-17 14:37:14 +00:00
void ( * _mars_remote_trigger ) ( void ) ;
EXPORT_SYMBOL_GPL ( _mars_remote_trigger ) ;
2011-02-23 20:48:06 +00:00
static void __exit exit_light ( void )
{
2011-08-25 10:16:32 +00:00
MARS_DBG ( " ====================== stopping everything... \n " ) ;
2011-02-23 20:48:06 +00:00
// TODO: make this thread-safe.
2012-11-13 16:01:37 +00:00
if ( main_thread ) {
2011-08-25 10:16:32 +00:00
MARS_DBG ( " === stopping light thread... \n " ) ;
2012-01-17 10:48:56 +00:00
mars_trigger ( ) ;
2012-11-13 16:01:37 +00:00
MARS_INF ( " stopping main thread... \n " ) ;
brick_thread_stop ( main_thread ) ;
2011-02-23 20:48:06 +00:00
}
2011-08-25 10:16:32 +00:00
2012-01-17 14:37:14 +00:00
_mars_remote_trigger = NULL ;
2011-11-14 17:52:05 +00:00
brick_allow_freelist = false ;
2011-10-04 11:45:09 +00:00
# ifdef CONFIG_MARS_HAVE_BIGMODULE
2011-08-25 10:16:32 +00:00
while ( exit_fn_nr > 0 ) {
MARS_DBG ( " === stopping module %s ... \n " , exit_names [ exit_fn_nr - 1 ] ) ;
exit_fn [ - - exit_fn_nr ] ( ) ;
}
2011-10-04 11:45:09 +00:00
# endif
2011-08-25 10:16:32 +00:00
MARS_DBG ( " ====================== stopped everything. \n " ) ;
2012-01-10 10:29:22 +00:00
exit_say ( ) ;
2011-02-23 20:48:06 +00:00
}
2012-08-14 14:23:30 +00:00
int global_logrot_auto = CONFIG_MARS_LOGROT_AUTO ;
EXPORT_SYMBOL_GPL ( global_logrot_auto ) ;
2012-08-14 14:38:10 +00:00
int global_logdel_auto = CONFIG_MARS_LOGDELETE_AUTO ;
EXPORT_SYMBOL_GPL ( global_logdel_auto ) ;
2012-08-14 14:32:06 +00:00
int global_free_space = CONFIG_MARS_MIN_SPACE_BASE ;
EXPORT_SYMBOL_GPL ( global_free_space ) ;
2011-02-23 20:48:06 +00:00
static int __init init_light ( void )
{
2011-08-25 10:16:32 +00:00
int status = 0 ;
2012-01-10 12:55:50 +00:00
init_say ( ) ; // this must come first
2011-08-25 10:16:32 +00:00
# ifdef CONFIG_MARS_HAVE_BIGMODULE
/* be careful: order is important!
*/
DO_INIT ( brick_mem ) ;
DO_INIT ( brick ) ;
DO_INIT ( mars ) ;
2012-02-08 11:44:42 +00:00
# ifdef CONFIG_MARS_DEBUG // otherwise currently unused
2012-01-30 11:54:56 +00:00
DO_INIT ( mars_dummy ) ;
DO_INIT ( mars_check ) ;
DO_INIT ( mars_buf ) ;
DO_INIT ( mars_usebuf ) ;
# endif
2011-08-25 10:16:32 +00:00
DO_INIT ( log_format ) ;
DO_INIT ( mars_net ) ;
DO_INIT ( mars_server ) ;
DO_INIT ( mars_client ) ;
DO_INIT ( mars_aio ) ;
2011-11-14 13:12:33 +00:00
DO_INIT ( mars_sio ) ;
2011-08-25 10:16:32 +00:00
DO_INIT ( mars_bio ) ;
DO_INIT ( mars_if ) ;
DO_INIT ( mars_copy ) ;
DO_INIT ( mars_trans_logger ) ;
DO_INIT ( sy ) ;
DO_INIT ( sy_net ) ;
DO_INIT ( mars_proc ) ;
# endif
2011-11-14 17:52:05 +00:00
brick_mem_reserve ( & global_reserve ) ;
2012-11-13 16:01:37 +00:00
main_thread = brick_thread_create ( light_thread , NULL , " mars_light " ) ;
if ( unlikely ( ! main_thread ) ) {
status = - ENOENT ;
2011-08-25 10:16:32 +00:00
goto done ;
2011-02-23 20:48:06 +00:00
}
2011-11-14 17:52:05 +00:00
2011-08-25 10:16:32 +00:00
done :
if ( status < 0 ) {
MARS_ERR ( " module init failed with status = %d, exiting. \n " , status ) ;
exit_light ( ) ;
}
2012-01-17 14:37:14 +00:00
_mars_remote_trigger = __mars_remote_trigger ;
2011-08-25 10:16:32 +00:00
return status ;
2011-02-23 20:48:06 +00:00
}
2011-03-03 09:02:10 +00:00
// force module loading
const void * dummy1 = & client_brick_type ;
const void * dummy2 = & server_brick_type ;
2011-02-23 20:48:06 +00:00
MODULE_DESCRIPTION ( " MARS Light " ) ;
MODULE_AUTHOR ( " Thomas Schoebel-Theuer <tst@1und1.de> " ) ;
2011-10-04 11:45:09 +00:00
MODULE_VERSION ( BUILDTAG " ( " BUILDHOST " " BUILDDATE " ) " ) ;
2011-02-23 20:48:06 +00:00
MODULE_LICENSE ( " GPL " ) ;
module_init ( init_light ) ;
module_exit ( exit_light ) ;