2011-02-23 20:48:06 +00:00
// (c) 2011 Thomas Schoebel-Theuer / 1&1 Internet AG
//#define BRICK_DEBUGGING
2013-01-20 22:09:09 +00:00
# define MARS_DEBUGGING
2011-03-02 09:30:56 +00:00
//#define IO_DEBUGGING
2011-02-23 20:48:06 +00:00
2013-04-11 12:19:18 +00:00
/* This MUST be updated whenever INCOMPATIBLE changes are made to the
* symlink tree in / mars / .
*
* Just adding a new symlink is usually not " incompatible " , if
* other tools like marsadm just ignore it .
*
* " incompatible " means that something may BREAK .
*/
# define SYMLINK_TREE_VERSION "0.1"
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/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>
2013-01-23 11:21:22 +00:00
# include "../lib_mapfree.h"
2011-02-23 20:48:06 +00:00
// 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
2013-07-01 08:22:18 +00:00
# define REPLAY_TOLERANCE (PAGE_SIZE + OVERHEAD)
2011-03-22 14:36:26 +00:00
#if 0
# define inline __attribute__((__noinline__))
# endif
2011-03-10 11:40:06 +00:00
2013-04-08 07:47:44 +00:00
// TODO: add human-readable timestamps
# define MARS_INF_TO(channel, fmt, args...) \
( { \
say_to ( channel , SAY_INFO , " %s: " fmt , say_class [ SAY_INFO ] , # # args ) ; \
MARS_INF ( fmt , # # args ) ; \
} )
# define MARS_WRN_TO(channel, fmt, args...) \
( { \
say_to ( channel , SAY_WARN , " %s: " fmt , say_class [ SAY_WARN ] , # # args ) ; \
MARS_WRN ( fmt , # # args ) ; \
} )
# define MARS_ERR_TO(channel, fmt, args...) \
( { \
say_to ( channel , SAY_ERROR , " %s: " fmt , say_class [ SAY_ERROR ] , # # args ) ; \
MARS_ERR ( fmt , # # args ) ; \
} )
2013-04-05 11:04:55 +00:00
loff_t global_total_space = 0 ;
EXPORT_SYMBOL_GPL ( global_total_space ) ;
loff_t global_remaining_space = 0 ;
EXPORT_SYMBOL_GPL ( global_remaining_space ) ;
2013-04-05 07:27:59 +00:00
int global_logrot_auto = CONFIG_MARS_LOGROT_AUTO ;
EXPORT_SYMBOL_GPL ( global_logrot_auto ) ;
2013-04-05 11:04:55 +00:00
int global_free_space_0 = CONFIG_MARS_MIN_SPACE_0 ;
EXPORT_SYMBOL_GPL ( global_free_space_0 ) ;
int global_free_space_1 = CONFIG_MARS_MIN_SPACE_1 ;
EXPORT_SYMBOL_GPL ( global_free_space_1 ) ;
int global_free_space_2 = CONFIG_MARS_MIN_SPACE_2 ;
EXPORT_SYMBOL_GPL ( global_free_space_2 ) ;
2013-04-05 07:27:59 +00:00
2013-04-05 11:04:55 +00:00
int global_free_space_3 = CONFIG_MARS_MIN_SPACE_3 ;
EXPORT_SYMBOL_GPL ( global_free_space_3 ) ;
2013-04-05 07:27:59 +00:00
2013-04-05 11:04:55 +00:00
int global_free_space_4 = CONFIG_MARS_MIN_SPACE_4 ;
EXPORT_SYMBOL_GPL ( global_free_space_4 ) ;
2013-04-05 07:27:59 +00:00
int mars_rollover_interval = CONFIG_MARS_ROLLOVER_INTERVAL ;
EXPORT_SYMBOL_GPL ( mars_rollover_interval ) ;
int mars_scan_interval = CONFIG_MARS_SCAN_INTERVAL ;
EXPORT_SYMBOL_GPL ( mars_scan_interval ) ;
int mars_propagate_interval = CONFIG_MARS_PROPAGATE_INTERVAL ;
EXPORT_SYMBOL_GPL ( mars_propagate_interval ) ;
int mars_sync_flip_interval = CONFIG_MARS_SYNC_FLIP_INTERVAL ;
EXPORT_SYMBOL_GPL ( mars_sync_flip_interval ) ;
int mars_fast_fullsync =
# ifdef CONFIG_MARS_FAST_FULLSYNC
1
# else
0
# endif
;
EXPORT_SYMBOL_GPL ( mars_fast_fullsync ) ;
2013-04-05 11:04:55 +00:00
int mars_emergency_mode = 0 ;
EXPORT_SYMBOL_GPL ( mars_emergency_mode ) ;
int mars_reset_emergency = 1 ;
EXPORT_SYMBOL_GPL ( mars_reset_emergency ) ;
# define IS_EXHAUSTED() (mars_emergency_mode > 0)
# define IS_EMERGENCY_SECONDARY() (mars_emergency_mode > 1)
# define IS_EMERGENCY_PRIMARY() (mars_emergency_mode > 2)
# define IS_JAMMED() (mars_emergency_mode > 3)
static
2013-04-11 12:19:18 +00:00
void _make_alivelink_str ( const char * name , const char * src )
2013-04-05 11:04:55 +00:00
{
char * dst = path_make ( " /mars/%s-%s " , name , my_id ( ) ) ;
if ( ! src | | ! dst ) {
MARS_ERR ( " cannot make alivelink paths \n " ) ;
goto err ;
}
MARS_DBG ( " '%s' -> '%s' \n " , src , dst ) ;
mars_symlink ( src , dst , NULL , 0 ) ;
err :
brick_string_free ( dst ) ;
2013-04-11 12:19:18 +00:00
}
static
void _make_alivelink ( const char * name , loff_t val )
{
char * src = path_make ( " %lld " , val ) ;
_make_alivelink_str ( name , src ) ;
2013-04-05 11:04:55 +00:00
brick_string_free ( src ) ;
}
static
int compute_emergency_mode ( void )
{
loff_t rest = 0 ;
loff_t limit = 0 ;
int mode = 4 ;
mars_remaining_space ( " /mars " , & global_total_space , & rest ) ;
# define CHECK_LIMIT(LIMIT_VAR) \
if ( LIMIT_VAR > 0 ) \
limit + = ( loff_t ) LIMIT_VAR * 1024 * 1024 ; \
if ( rest < limit ) { \
mars_emergency_mode = mode ; \
goto done ; \
} \
mode - - ; \
CHECK_LIMIT ( global_free_space_4 ) ;
CHECK_LIMIT ( global_free_space_3 ) ;
CHECK_LIMIT ( global_free_space_2 ) ;
CHECK_LIMIT ( global_free_space_1 ) ;
/* No limit has hit.
* Decrease the emergeny mode only in single steps .
*/
if ( mars_reset_emergency & & mars_emergency_mode > 0 ) {
mars_emergency_mode - - ;
}
done :
_make_alivelink ( " emergency " , mars_emergency_mode ) ;
global_remaining_space = rest - limit ;
_make_alivelink ( " rest-space " , global_remaining_space / ( 1024 * 1024 ) ) ;
limit + = global_free_space_0 ;
if ( unlikely ( global_total_space < limit ) ) {
2013-05-07 09:17:30 +00:00
return - ENOSPC ;
2013-04-05 11:04:55 +00:00
}
return 0 ;
}
///////////////////////////////////////////////////////////////////
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
2013-01-07 16:43:14 +00:00
# define MAX_INFOS 4
2012-08-08 13:50:41 +00:00
struct mars_rotate {
struct mars_global * global ;
struct copy_brick * sync_brick ;
struct mars_dent * replay_link ;
2013-05-14 11:54:55 +00:00
struct mars_brick * bio_brick ;
2012-08-08 13:50:41 +00:00
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 ;
2013-04-08 07:47:44 +00:00
struct say_channel * log_say ;
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
int inf_prev_sequence ;
2012-08-08 13:50:41 +00:00
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 ;
2013-01-04 09:42:43 +00:00
int copy_next_is_available ;
2012-08-08 13:50:41 +00:00
int relevant_serial ;
bool has_error ;
bool allow_update ;
2013-01-10 18:01:15 +00:00
bool forbid_replay ;
2012-08-08 13:50:41 +00:00
bool replay_mode ;
bool todo_primary ;
bool is_primary ;
bool old_is_primary ;
bool copy_is_done ;
2013-04-22 07:06:27 +00:00
bool created_hole ;
2013-01-07 16:43:14 +00:00
spinlock_t inf_lock ;
bool infs_is_dirty [ MAX_INFOS ] ;
struct trans_logger_info infs [ MAX_INFOS ] ;
2012-08-08 13:50:41 +00:00
} ;
///////////////////////////////////////////////////////////////////////
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
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-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
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-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 ;
2012-12-30 20:48:44 +00:00
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-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 ;
2013-01-22 11:10:12 +00:00
client_brick - > killme = true ;
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 ;
2013-01-22 11:10:12 +00:00
sio_brick - > killme = true ;
2011-11-14 13:12:33 +00:00
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 ;
2013-01-22 11:10:12 +00:00
aio_brick - > killme = true ;
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 ;
2013-01-22 11:10:12 +00:00
bio_brick - > killme = true ;
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-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 ;
2013-06-27 12:30:05 +00:00
loff_t end_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 ;
2013-01-22 11:10:12 +00:00
copy_brick - > killme = 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 - > 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 ;
2013-06-27 12:30:05 +00:00
if ( cc - > end_pos ! = - 1 ) {
if ( unlikely ( cc - > end_pos > copy_brick - > copy_end ) ) {
MARS_ERR ( " target size %lld is larger than actual size %lld on source \n " , cc - > end_pos , copy_brick - > copy_end ) ;
status = - EINVAL ;
goto done ;
}
copy_brick - > copy_end = cc - > end_pos ;
if ( unlikely ( cc - > end_pos > cc - > info [ 1 ] . current_size ) ) {
MARS_ERR ( " bad end position %lld is larger than actual size %lld on target \n " , cc - > end_pos , cc - > info [ 1 ] . current_size ) ;
status = - EINVAL ;
goto done ;
}
}
2011-08-25 10:16:32 +00:00
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 ','
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 ;
}
2013-01-20 14:40:47 +00:00
# define skip_part(s) _skip_part(s, ',', ':')
# define skip_sect(s) _skip_part(s, ':', 0)
2013-01-10 17:35:02 +00:00
static inline
int _skip_part ( const char * str , const char del1 , const char del2 )
{
int len = 0 ;
while ( str [ len ] & & str [ len ] ! = del1 & & ( ! del2 | | str [ len ] ! = del2 ) )
len + + ;
return len ;
}
static inline
int skip_dir ( const char * str )
{
int len = 0 ;
int res = 0 ;
for ( len = 0 ; str [ len ] ; len + + )
if ( str [ len ] = = ' / ' )
res = len + 1 ;
return res ;
}
static
int parse_logfile_name ( const char * str , int * seq , const char * * host )
{
char * _host ;
int count ;
int len = 0 ;
int len_host ;
* seq = 0 ;
* host = NULL ;
count = sscanf ( str , " log-%d-%n " , seq , & len ) ;
if ( unlikely ( count ! = 1 ) ) {
MARS_ERR ( " bad logfile name '%s', count=%d, len=%d \n " , str , count , len ) ;
return 0 ;
}
_host = brick_strdup ( str + len ) ;
if ( unlikely ( ! _host ) ) {
MARS_ERR ( " no MEM \n " ) ;
return 0 ;
}
len_host = skip_part ( _host ) ;
_host [ len_host ] = ' \0 ' ;
* host = _host ;
len + = len_host ;
return len ;
}
static
2013-04-08 07:47:44 +00:00
int compare_replaylinks ( struct mars_rotate * rot , const char * hosta , const char * hostb )
2013-01-10 17:35:02 +00:00
{
2013-04-08 07:47:44 +00:00
const char * linka = path_make ( " %s/replay-%s " , rot - > parent_path , hosta ) ;
const char * linkb = path_make ( " %s/replay-%s " , rot - > parent_path , hostb ) ;
2013-01-10 17:35:02 +00:00
const char * a = NULL ;
const char * b = NULL ;
int seqa ;
int seqb ;
int posa ;
int posb ;
loff_t offa ;
loff_t offb ;
int count ;
int res = - 2 ;
if ( unlikely ( ! linka | | ! linkb ) ) {
MARS_ERR ( " nen MEM " ) ;
goto done ;
}
a = mars_readlink ( linka ) ;
if ( unlikely ( ! a ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " cannot read replaylink '%s' \n " , linka ) ;
2013-01-10 17:35:02 +00:00
goto done ;
}
b = mars_readlink ( linkb ) ;
if ( unlikely ( ! b ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " cannot read replaylink '%s' \n " , linkb ) ;
2013-01-10 17:35:02 +00:00
goto done ;
}
count = sscanf ( a , " log-%d-%n " , & seqa , & posa ) ;
if ( unlikely ( count ! = 1 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link '%s' -> '%s' is malformed \n " , linka , a ) ;
2013-01-10 17:35:02 +00:00
}
count = sscanf ( b , " log-%d-%n " , & seqb , & posb ) ;
if ( unlikely ( count ! = 1 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link '%s' -> '%s' is malformed \n " , linkb , b ) ;
2013-01-10 17:35:02 +00:00
}
if ( seqa < seqb ) {
res = - 1 ;
goto done ;
} else if ( seqa > seqb ) {
res = 1 ;
goto done ;
}
posa + = skip_part ( a + posa ) ;
posb + = skip_part ( b + posb ) ;
if ( unlikely ( ! a [ posa + + ] ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link '%s' -> '%s' is malformed \n " , linka , a ) ;
2013-01-10 17:35:02 +00:00
}
if ( unlikely ( ! b [ posb + + ] ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link '%s' -> '%s' is malformed \n " , linkb , b ) ;
2013-01-10 17:35:02 +00:00
}
count = sscanf ( a + posa , " %lld " , & offa ) ;
if ( unlikely ( count ! = 1 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link '%s' -> '%s' is malformed \n " , linka , a ) ;
2013-01-10 17:35:02 +00:00
}
count = sscanf ( b + posb , " %lld " , & offb ) ;
if ( unlikely ( count ! = 1 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link '%s' -> '%s' is malformed \n " , linkb , b ) ;
2013-01-10 17:35:02 +00:00
}
if ( posa < posb ) {
res = - 1 ;
} else if ( posa > posb ) {
res = 1 ;
} else {
res = 0 ;
}
done :
brick_string_free ( a ) ;
brick_string_free ( b ) ;
brick_string_free ( linka ) ;
brick_string_free ( linkb ) ;
return res ;
}
2011-09-27 11:57:04 +00:00
///////////////////////////////////////////////////////////////////////
// status display
2012-12-17 07:25:17 +00:00
static
2013-01-09 11:09:04 +00:00
int _update_replay_link ( struct mars_rotate * rot , struct trans_logger_info * inf )
2012-12-17 07:25:17 +00:00
{
char * check = NULL ;
char * old = NULL ;
char * new = NULL ;
int status ;
2013-01-09 11:09:04 +00:00
int res = 0 ;
2012-12-17 07:25:17 +00:00
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 ) ;
2013-04-08 07:47:44 +00:00
if ( unlikely ( status < 0 ) ) {
MARS_ERR_TO ( rot - > log_say , " cannot create replay symlink '%s' -> '%s' status = %d \n " , old , new , status ) ;
2012-12-17 07:25:17 +00:00
} else {
2013-01-09 11:09:04 +00:00
res = 1 ;
2012-12-17 07:25:17 +00:00
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 ) ;
2013-01-09 11:09:04 +00:00
return res ;
2012-12-17 07:25:17 +00:00
}
static
2013-01-09 11:09:04 +00:00
int _update_version_link ( struct mars_rotate * rot , struct trans_logger_info * inf )
2012-12-17 07:25:17 +00:00
{
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 ;
2013-01-05 21:46:13 +00:00
char * prev_digest = NULL ;
2012-12-17 07:25:17 +00:00
int len ;
int i ;
int status ;
2013-01-09 11:09:04 +00:00
int res = 0 ;
2012-12-17 07:25:17 +00:00
if ( unlikely ( ! data | | ! digest | | ! old ) ) {
MARS_ERR ( " no MEM \n " ) ;
goto out ;
}
if ( likely ( inf - > inf_sequence > 1 ) ) {
2013-01-05 21:46:13 +00:00
if ( unlikely ( ( inf - > inf_sequence < rot - > inf_prev_sequence | |
inf - > inf_sequence > rot - > inf_prev_sequence + 1 ) & &
rot - > inf_prev_sequence ! = 0 ) ) {
2013-04-18 08:37:14 +00:00
char * skip_path = path_make ( " %s/skip-check-%s " , rot - > parent_path , my_id ( ) ) ;
char * skip_link = mars_readlink ( skip_path ) ;
int skip_nr = - 1 ;
if ( skip_link ) {
( void ) sscanf ( skip_link , " %d " , & skip_nr ) ;
brick_string_free ( skip_link ) ;
}
brick_string_free ( skip_path ) ;
if ( likely ( skip_nr ! = inf - > inf_sequence ) ) {
MARS_ERR_TO ( rot - > log_say , " SKIP in sequence numbers detected: %d != %d + 1 \n " , inf - > inf_sequence , rot - > inf_prev_sequence ) ;
goto out ;
}
MARS_WRN_TO ( rot - > log_say ,
" you explicitly requested to SKIP sequence numbers from %d to %d "
" -- THIS IS EXTREMELY RISKY "
" -- any inconsistencies are on your own! \n " ,
rot - > inf_prev_sequence , inf - > inf_sequence ) ;
2012-12-17 07:25:17 +00:00
}
2013-01-05 21:46:13 +00:00
prev = path_make ( " %s/version-%09d-%s " , rot - > parent_path , inf - > inf_sequence - 1 , my_id ( ) ) ;
if ( unlikely ( ! prev ) ) {
2012-12-17 08:35:49 +00:00
MARS_ERR ( " no MEM \n " ) ;
goto out ;
}
2013-01-05 21:46:13 +00:00
prev_link = mars_readlink ( prev ) ;
rot - > inf_prev_sequence = inf - > inf_sequence ;
2012-12-17 08:35:49 +00:00
}
2012-12-17 07:25:17 +00:00
2013-01-20 14:40:47 +00:00
len = sprintf ( data , " %d,%s,%lld:%s " , inf - > inf_sequence , inf - > inf_host , inf - > inf_log_pos , prev_link ? prev_link : " " ) ;
2012-12-17 08:35:49 +00:00
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
2013-01-05 21:46:13 +00:00
if ( likely ( prev_link ) ) {
2012-12-17 08:35:49 +00:00
char * tmp ;
2013-01-05 21:46:13 +00:00
prev_digest = brick_strdup ( prev_link ) ;
2012-12-17 08:35:49 +00:00
if ( unlikely ( ! prev_digest ) ) {
MARS_ERR ( " no MEM \n " ) ;
goto out ;
}
2013-01-20 14:40:47 +00:00
// take the part before ':'
2012-12-17 08:35:49 +00:00
for ( tmp = prev_digest ; * tmp ; tmp + + )
2013-01-20 14:40:47 +00:00
if ( * tmp = = ' : ' )
2012-12-17 08:35:49 +00:00
break ;
* tmp = ' \0 ' ;
}
2013-01-20 14:40:47 +00:00
len + = sprintf ( old + len , " ,log-%09d-%s,%lld:%s " , inf - > inf_sequence , inf - > inf_host , inf - > inf_log_pos , prev_digest ? 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 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " cannot create symlink '%s' -> '%s' status = %d \n " , old , new , status ) ;
2012-12-17 07:25:17 +00:00
} else {
2013-01-09 11:09:04 +00:00
res = 1 ;
2012-12-17 07:25:17 +00:00
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 ) ;
2013-01-05 21:46:13 +00:00
brick_string_free ( prev_digest ) ;
2013-01-09 11:09:04 +00:00
return res ;
2012-12-17 07:25:17 +00:00
}
static
void _update_info ( struct trans_logger_info * inf )
{
struct mars_rotate * rot = inf - > inf_private ;
2013-01-07 16:43:14 +00:00
int hash ;
unsigned long flags ;
2012-12-17 07:25:17 +00:00
if ( unlikely ( ! rot ) ) {
MARS_ERR ( " rot is NULL \n " ) ;
goto done ;
}
2013-01-05 21:46:13 +00:00
MARS_DBG ( " inf = %p '%s' seq = %d min_pos = %lld max_pos = %lld log_pos = %lld is_applying = %d is_logging = %d \n " ,
2012-12-17 07:25:17 +00:00
inf ,
SAFE_STR ( inf - > inf_host ) ,
inf - > inf_sequence ,
inf - > inf_min_pos ,
inf - > inf_max_pos ,
inf - > inf_log_pos ,
inf - > inf_is_applying ,
inf - > inf_is_logging ) ;
2013-01-07 16:43:14 +00:00
hash = inf - > inf_sequence % MAX_INFOS ;
if ( unlikely ( rot - > infs_is_dirty [ hash ] ) ) {
if ( unlikely ( rot - > infs [ hash ] . inf_sequence ! = inf - > inf_sequence ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " buffer %d: sequence trash %d -> %d. is the mar_light thread hanging? \n " , hash , rot - > infs [ hash ] . inf_sequence , inf - > inf_sequence ) ;
2013-01-07 16:43:14 +00:00
} else {
MARS_DBG ( " buffer %d is overwritten (sequence=%d) \n " , hash , inf - > inf_sequence ) ;
}
2012-12-17 07:25:17 +00:00
}
2013-01-07 16:43:14 +00:00
traced_lock ( & rot - > inf_lock , flags ) ;
memcpy ( & rot - > infs [ hash ] , inf , sizeof ( struct trans_logger_info ) ) ;
rot - > infs_is_dirty [ hash ] = true ;
traced_unlock ( & rot - > inf_lock , flags ) ;
2012-12-17 07:25:17 +00:00
2013-01-07 16:43:14 +00:00
mars_trigger ( ) ;
2012-12-17 07:25:17 +00:00
done : ;
}
2013-01-07 16:43:14 +00:00
static
void write_info_links ( struct mars_rotate * rot )
{
struct trans_logger_info inf ;
int count = 0 ;
for ( ; ; ) {
unsigned long flags ;
int hash = - 1 ;
int min = 0 ;
int i ;
traced_lock ( & rot - > inf_lock , flags ) ;
for ( i = 0 ; i < MAX_INFOS ; i + + ) {
if ( ! rot - > infs_is_dirty [ i ] )
continue ;
if ( ! min | | min > rot - > infs [ i ] . inf_sequence ) {
min = rot - > infs [ i ] . inf_sequence ;
hash = i ;
}
}
if ( hash < 0 ) {
traced_unlock ( & rot - > inf_lock , flags ) ;
break ;
}
rot - > infs_is_dirty [ hash ] = false ;
memcpy ( & inf , & rot - > infs [ hash ] , sizeof ( struct trans_logger_info ) ) ;
traced_unlock ( & rot - > inf_lock , flags ) ;
MARS_DBG ( " seq = %d min_pos = %lld max_pos = %lld log_pos = %lld is_applying = %d is_logging = %d \n " ,
inf . inf_sequence ,
inf . inf_min_pos ,
inf . inf_max_pos ,
inf . inf_log_pos ,
inf . inf_is_applying ,
inf . inf_is_logging ) ;
if ( inf . inf_is_logging | | inf . inf_is_applying ) {
2013-01-09 11:09:04 +00:00
count + = _update_replay_link ( rot , & inf ) ;
2013-01-07 16:43:14 +00:00
}
if ( inf . inf_is_logging | | inf . inf_is_applying ) {
2013-01-09 11:09:04 +00:00
count + = _update_version_link ( rot , & inf ) ;
2013-01-07 16:43:14 +00:00
}
}
2013-01-14 20:42:46 +00:00
if ( count ) {
if ( inf . inf_min_pos = = inf . inf_max_pos )
mars_trigger ( ) ;
2013-01-07 16:43:14 +00:00
mars_remote_trigger ( ) ;
2013-01-14 20:42:46 +00:00
}
2013-01-07 16:43:14 +00:00
}
2012-12-17 07:25:17 +00:00
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_sequence = new_sequence ,
. inf_min_pos = 0 ,
. inf_max_pos = 0 ,
. inf_log_pos = end_pos ,
. inf_is_applying = true ,
} ;
2013-01-07 16:43:14 +00:00
strncpy ( inf . inf_host , new_host , sizeof ( inf . inf_host ) ) ;
2012-12-17 07:25:17 +00:00
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 ) ;
mars_trigger ( ) ;
mars_remote_trigger ( ) ;
}
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 [ ] ,
2013-06-27 12:30:05 +00:00
loff_t start_pos , // -1 means at EOF of source
loff_t end_pos , // -1 means at EOF of target
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 ;
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 ;
2013-05-09 14:34:17 +00:00
bool switch_copy ;
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
2013-05-09 14:34:17 +00:00
switch_copy = _check_switch ( global , switch_path ) ;
2011-11-08 17:07:42 +00:00
copy = mars_find_brick ( global , & copy_brick_type , copy_path ) ;
2013-05-09 14:34:17 +00:00
if ( ! copy & & ! switch_copy )
2011-11-08 17:07:42 +00:00
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 ,
2012-12-26 18:35:49 +00:00
_set_bio_params ,
& clc [ i ] ,
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 * [ ] ) { } ,
2013-05-10 06:15:00 +00:00
switch_copy ? 2 : - 1 ,
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 ;
2013-06-27 12:30:05 +00:00
cc . end_pos = end_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-05-26 14:32:32 +00:00
_set_copy_params ,
2011-08-25 10:16:32 +00:00
& cc ,
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 } ,
2013-05-10 06:15:00 +00:00
( ! switch_copy | | IS_EXHAUSTED ( ) ) ? - 1 : 2 ,
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-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 ] ) ;
2013-05-09 14:34:17 +00:00
if ( copy ) {
copy - > show_status = _show_brick_status ;
2011-02-25 11:46:38 +00:00
}
if ( __copy )
2013-05-09 14:34:17 +00:00
* __copy = ( void * ) copy ;
2011-02-25 11:46:38 +00:00
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
2013-05-11 20:52:11 +00:00
static
DEFINE_SPINLOCK ( peer_lock ) ;
static
struct list_head peer_anchor = LIST_HEAD_INIT ( peer_anchor ) ;
2011-02-23 20:48:06 +00:00
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 ;
2013-05-11 20:52:11 +00:00
struct list_head peer_head ;
2011-03-22 14:36:26 +00:00
struct list_head remote_dent_list ;
2011-02-23 20:48:06 +00:00
int maxdepth ;
2013-05-11 20:52:11 +00:00
bool to_remote_trigger ;
bool from_remote_trigger ;
2011-02-23 20:48:06 +00:00
} ;
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 ;
2013-04-09 13:03:55 +00:00
# ifdef CONFIG_MARS_SEPARATE_PORTS
const char * tmp = path_make ( " %s@%s:%d " , file , peer , mars_net_default_port + 1 ) ;
# else
2011-03-22 14:36:26 +00:00
const char * tmp = path_make ( " %s@%s " , file , peer ) ;
2013-04-09 13:03:55 +00:00
# endif
2011-03-22 14:36:26 +00:00
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 ) ;
2013-06-27 12:30:05 +00:00
status = __make_copy ( global , NULL , switch_path , copy_path , NULL , argv , - 1 , - 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
2013-04-10 13:09:12 +00:00
// bookkeeping for serialization of logfile updates
if ( remote_dent - > d_serial = = rot - > copy_serial + 1 ) {
rot - > copy_next_is_available + + ;
}
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 ;
2013-01-04 09:42:43 +00:00
rot - > copy_next_is_available = 0 ;
2013-05-09 21:42:18 +00:00
} else {
MARS_DBG ( " allow_update = %d src_size = %lld dst_size = %lld local_dent = %p \n " , rot - > allow_update , src_size , dst_size , local_dent ) ;
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 = { } ;
2013-07-01 06:25:25 +00:00
const char * marker_path = NULL ;
2011-02-27 14:17:58 +00:00
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 ;
}
2013-07-01 06:25:25 +00:00
if ( ! strncmp ( remote_dent - > d_name , " .deleted- " , 9 ) ) {
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 ;
}
2013-07-01 06:25:25 +00:00
// check marker preventing concurrent updates from remote hosts when deletes are in progress
marker_path = backskip_replace ( remote_dent - > d_path , ' / ' , true , " /.deleted- " ) ;
if ( mars_stat ( marker_path , & local_stat , true ) > = 0 ) {
MARS_IO ( " marker '%s' exists, ignoring '%s' \n " , marker_path , remote_dent - > d_path ) ;
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-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 ) ;
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 :
2013-07-01 06:25:25 +00:00
brick_string_free ( marker_path ) ;
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
}
2013-05-11 20:52:11 +00:00
2011-09-27 08:46:14 +00:00
mars_free_dent_all ( NULL , & tmp_list ) ;
2013-05-11 20:52:11 +00:00
2011-03-22 14:36:26 +00:00
if ( run_trigger ) {
mars_trigger ( ) ;
}
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 ) ;
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 ;
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-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_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 ) ;
2013-05-11 20:52:11 +00:00
brick_msleep ( 1000 ) ;
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 ) ;
2013-05-11 20:52:11 +00:00
brick_msleep ( 2000 ) ;
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 ;
}
2013-05-11 20:52:11 +00:00
if ( peer - > from_remote_trigger ) {
pause_time = 0 ;
peer - > from_remote_trigger = false ;
MARS_DBG ( " got notify from peer. \n " ) ;
}
status = 0 ;
if ( peer - > to_remote_trigger ) {
pause_time = 0 ;
peer - > to_remote_trigger = false ;
MARS_DBG ( " sending notify to peer... \n " ) ;
2012-01-17 14:37:14 +00:00
cmd . cmd_code = CMD_NOTIFY ;
2013-05-11 20:52:11 +00:00
status = mars_send_struct ( & peer - > socket , & cmd , mars_cmd_meta ) ;
2012-01-17 14:37:14 +00:00
}
2013-05-11 20:52:11 +00:00
if ( likely ( status > = 0 ) ) {
cmd . cmd_code = CMD_GETENTS ;
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 ( 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 ) ;
2013-05-11 20:52:11 +00:00
brick_msleep ( 2000 ) ;
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
2013-05-11 20:52:11 +00:00
mars_trigger ( ) ;
2012-01-18 14:33:39 +00:00
mars_free_dent_all ( NULL , & old_list ) ;
}
2011-02-23 20:48:06 +00:00
2013-05-11 20:52:11 +00:00
brick_msleep ( 100 ) ;
2012-11-13 16:01:37 +00:00
if ( ! brick_thread_should_stop ( ) ) {
2013-04-05 07:27:59 +00:00
if ( pause_time < mars_propagate_interval )
2012-07-17 10:00:58 +00:00
pause_time + + ;
wait_event_interruptible_timeout ( remote_event ,
2013-05-11 20:52:11 +00:00
( peer - > to_remote_trigger | peer - > from_remote_trigger ) | |
2012-07-17 10:00:58 +00:00
( 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 :
2011-08-25 10:16:32 +00:00
brick_string_free ( real_peer ) ;
2011-02-23 20:48:06 +00:00
return 0 ;
}
2013-05-11 20:52:11 +00:00
static
void _make_alive ( void )
{
struct timespec now ;
char * tmp ;
get_lamport ( & now ) ;
tmp = path_make ( " %ld.%09ld " , now . tv_sec , now . tv_nsec ) ;
if ( likely ( tmp ) ) {
_make_alivelink_str ( " time " , tmp ) ;
brick_string_free ( tmp ) ;
}
_make_alivelink ( " alive " , mars_global & & mars_global - > global_power . button ? 1 : 0 ) ;
_make_alivelink_str ( " tree " , SYMLINK_TREE_VERSION ) ;
}
void from_remote_trigger ( void )
{
struct list_head * tmp ;
int count = 0 ;
unsigned long flags ;
_make_alive ( ) ;
// TODO: replace peer_lock with rw_lock
traced_lock ( & peer_lock , flags ) ;
for ( tmp = peer_anchor . next ; tmp ! = & peer_anchor ; tmp = tmp - > next ) {
struct mars_peerinfo * peer = container_of ( tmp , struct mars_peerinfo , peer_head ) ;
peer - > from_remote_trigger = true ;
count + + ;
}
traced_unlock ( & peer_lock , flags ) ;
MARS_DBG ( " got trigger for %d peers \n " , count ) ;
wake_up_interruptible_all ( & remote_event ) ;
}
EXPORT_SYMBOL_GPL ( from_remote_trigger ) ;
2012-01-17 14:37:14 +00:00
static
void __mars_remote_trigger ( void )
{
2013-05-11 20:52:11 +00:00
struct list_head * tmp ;
int count = 0 ;
unsigned long flags ;
// TODO: replace peer_lock with rw_lock
traced_lock ( & peer_lock , flags ) ;
for ( tmp = peer_anchor . next ; tmp ! = & peer_anchor ; tmp = tmp - > next ) {
struct mars_peerinfo * peer = container_of ( tmp , struct mars_peerinfo , peer_head ) ;
peer - > to_remote_trigger = true ;
count + + ;
}
traced_unlock ( & peer_lock , flags ) ;
MARS_DBG ( " triggered %d peers \n " , count ) ;
2012-01-17 14:37:14 +00:00
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 ;
}
2013-05-11 20:52:11 +00:00
traced_lock ( & peer_lock , flags ) ;
list_del_init ( & peer - > peer_head ) ;
traced_unlock ( & peer_lock , flags ) ;
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 ) {
2013-05-11 20:52:11 +00:00
unsigned long flags ;
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 ) ;
2013-05-11 20:52:11 +00:00
INIT_LIST_HEAD ( & peer - > peer_head ) ;
2011-03-22 14:36:26 +00:00
INIT_LIST_HEAD ( & peer - > remote_dent_list ) ;
2013-05-11 20:52:11 +00:00
traced_lock ( & peer_lock , flags ) ;
list_add_tail ( & peer - > peer_head , & peer_anchor ) ;
traced_unlock ( & peer_lock , flags ) ;
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 ( ) ;
}
}
2013-01-06 12:39:37 +00:00
static
const char * get_replaylink ( const char * parent_path , const char * host , const char * * linkpath )
{
const char * _linkpath = path_make ( " %s/replay-%s " , parent_path , host ) ;
* linkpath = _linkpath ;
if ( unlikely ( ! _linkpath ) ) {
MARS_ERR ( " no MEM \n " ) ;
return NULL ;
2012-01-16 15:35:41 +00:00
}
2013-01-06 12:39:37 +00:00
return mars_readlink ( _linkpath ) ;
}
2012-01-16 15:34:38 +00:00
2013-01-06 12:39:37 +00:00
static
const char * get_versionlink ( const char * parent_path , int seq , const char * host , const char * * linkpath )
{
const char * _linkpath = path_make ( " %s/version-%09d-%s " , parent_path , seq , host ) ;
* linkpath = _linkpath ;
if ( unlikely ( ! _linkpath ) ) {
MARS_ERR ( " no MEM \n " ) ;
return NULL ;
2012-01-16 15:34:38 +00:00
}
2013-01-06 12:39:37 +00:00
return mars_readlink ( _linkpath ) ;
}
2012-01-16 15:35:41 +00:00
2013-01-06 12:39:37 +00:00
static
2013-04-08 07:47:44 +00:00
bool is_switchover_possible ( struct mars_rotate * rot , const char * old_log_path , const char * new_log_path , bool skip_new )
2013-01-06 12:39:37 +00:00
{
const char * old_log_name = old_log_path + skip_dir ( old_log_path ) ;
const char * new_log_name = new_log_path + skip_dir ( new_log_path ) ;
const char * old_host = NULL ;
const char * new_host = NULL ;
const char * own_versionlink_path = NULL ;
const char * old_versionlink_path = NULL ;
const char * new_versionlink_path = NULL ;
const char * own_versionlink = NULL ;
const char * old_versionlink = NULL ;
const char * new_versionlink = NULL ;
const char * own_replaylink_path = NULL ;
const char * own_replaylink = NULL ;
2013-07-01 08:22:18 +00:00
loff_t own_r_val ;
loff_t own_v_val ;
2013-01-06 12:39:37 +00:00
int old_log_seq ;
int new_log_seq ;
int own_r_offset ;
int own_v_offset ;
int own_r_len ;
int own_v_len ;
int len1 ;
int len2 ;
int offs2 ;
bool res = false ;
if ( unlikely ( ! parse_logfile_name ( old_log_name , & old_log_seq , & old_host ) ) )
goto done ;
if ( unlikely ( ! parse_logfile_name ( new_log_name , & new_log_seq , & new_host ) ) )
goto done ;
// check: are the sequence numbers contiguous?
if ( unlikely ( new_log_seq ! = old_log_seq + 1 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " logfile sequence numbers are not contiguous (%d != %d + 1), old_log_path='%s' new_log_path='%s' \n " , new_log_seq , old_log_seq , old_log_path , new_log_path ) ;
2013-01-06 12:39:37 +00:00
goto done ;
2012-01-16 15:35:41 +00:00
}
2013-01-06 12:39:37 +00:00
// fetch all the versionlinks and test for their existence.
2013-04-08 07:47:44 +00:00
own_versionlink = get_versionlink ( rot - > parent_path , old_log_seq , my_id ( ) , & own_versionlink_path ) ;
2013-01-06 12:39:37 +00:00
if ( unlikely ( ! own_versionlink ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " cannot read my own versionlink '%s' \n " , SAFE_STR ( own_versionlink_path ) ) ;
2013-01-06 12:39:37 +00:00
goto done ;
}
2013-04-08 07:47:44 +00:00
old_versionlink = get_versionlink ( rot - > parent_path , old_log_seq , old_host , & old_versionlink_path ) ;
2013-01-06 12:39:37 +00:00
if ( unlikely ( ! old_versionlink ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " cannot read old versionlink '%s' \n " , SAFE_STR ( old_versionlink_path ) ) ;
2013-01-06 12:39:37 +00:00
goto done ;
}
2013-01-12 12:16:39 +00:00
if ( ! skip_new ) {
2013-04-08 07:47:44 +00:00
new_versionlink = get_versionlink ( rot - > parent_path , new_log_seq , new_host , & new_versionlink_path ) ;
2013-01-12 12:16:39 +00:00
if ( unlikely ( ! new_versionlink ) ) {
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " new versionlink '%s' does not yet exist, we must wait for it. \n " , SAFE_STR ( new_versionlink_path ) ) ;
2013-01-12 12:16:39 +00:00
goto done ;
}
2012-01-16 15:35:41 +00:00
}
2013-01-06 12:39:37 +00:00
// check: are the versionlinks correct?
if ( unlikely ( strcmp ( own_versionlink , old_versionlink ) ) ) {
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " old logfile is not yet completeley transferred, own_versionlink '%s' -> '%s' != old_versionlink '%s' -> '%s' \n " , own_versionlink_path , own_versionlink , old_versionlink_path , old_versionlink ) ;
2013-01-06 12:39:37 +00:00
goto done ;
2011-07-15 10:12:06 +00:00
}
2013-01-06 12:39:37 +00:00
// check: did I fully apply my old logfile data?
2013-04-08 07:47:44 +00:00
own_replaylink = get_replaylink ( rot - > parent_path , my_id ( ) , & own_replaylink_path ) ;
2013-01-06 12:39:37 +00:00
if ( unlikely ( ! own_replaylink ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " cannot read my own replaylink '%s' \n " , SAFE_STR ( own_replaylink_path ) ) ;
2013-01-06 12:39:37 +00:00
goto done ;
}
own_r_len = skip_part ( own_replaylink ) ;
own_v_offset = skip_part ( own_versionlink ) ;
if ( unlikely ( ! own_versionlink [ own_v_offset + + ] ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " own version link '%s' -> '%s' is malformed \n " , own_versionlink_path , own_versionlink ) ;
2013-01-06 12:39:37 +00:00
goto done ;
}
own_v_len = skip_part ( own_versionlink + own_v_offset ) ;
if ( unlikely ( own_r_len ! = own_v_len | |
strncmp ( own_replaylink , own_versionlink + own_v_offset , own_r_len ) ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " internal problem: logfile name mismatch between '%s' and '%s' \n " , own_replaylink , own_versionlink ) ;
2013-01-06 12:39:37 +00:00
goto done ;
}
if ( unlikely ( ! own_replaylink [ own_r_len ] ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " own replay link '%s' -> '%s' is malformed \n " , own_replaylink_path , own_replaylink ) ;
2013-01-06 12:39:37 +00:00
goto done ;
}
own_r_offset = own_r_len + 1 ;
if ( unlikely ( ! own_versionlink [ own_v_len ] ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " own version link '%s' -> '%s' is malformed \n " , own_versionlink_path , own_versionlink ) ;
2013-01-06 12:39:37 +00:00
goto done ;
}
own_v_offset + = own_r_len + 1 ;
own_r_len = skip_part ( own_replaylink + own_r_offset ) ;
own_v_len = skip_part ( own_versionlink + own_v_offset ) ;
2013-07-01 08:22:18 +00:00
own_r_val = own_v_val = 0 ;
if ( sscanf ( own_replaylink + own_r_offset , " %lld " , & own_r_val ) ! = 1 ) {
MARS_ERR_TO ( rot - > log_say , " own replay link '%s' -> '%s' is malformed \n " , own_replaylink_path , own_replaylink ) ;
goto done ;
}
if ( sscanf ( own_versionlink + own_v_offset , " %lld " , & own_v_val ) ! = 1 ) {
MARS_ERR_TO ( rot - > log_say , " own version link '%s' -> '%s' is malformed \n " , own_versionlink_path , own_versionlink ) ;
goto done ;
}
if ( unlikely ( own_r_len > own_v_len | | own_r_len + REPLAY_TOLERANCE < own_v_len ) ) {
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " log replay is not yet finished: '%s' and '%s' are reporting different positions. \n " , own_replaylink , own_versionlink ) ;
2013-01-06 12:39:37 +00:00
goto done ;
}
// last check: is the new versionlink based on the old one?
2013-01-12 12:16:39 +00:00
if ( ! skip_new ) {
len1 = skip_sect ( own_versionlink ) ;
offs2 = skip_sect ( new_versionlink ) ;
if ( unlikely ( ! new_versionlink [ offs2 + + ] ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " new version link '%s' -> '%s' is malformed \n " , new_versionlink_path , new_versionlink ) ;
2013-01-12 12:16:39 +00:00
goto done ;
}
len2 = skip_sect ( new_versionlink + offs2 ) ;
if ( unlikely ( len1 ! = len2 | |
strncmp ( own_versionlink , new_versionlink + offs2 , len1 ) ) ) {
2013-04-08 07:47:44 +00:00
MARS_WRN_TO ( rot - > log_say , " VERSION MISMATCH old '%s' -> '%s' new '%s' -> '%s' ==(%d,%d) ===> check for SPLIT BRAIN! \n " , own_versionlink_path , own_versionlink , new_versionlink_path , new_versionlink , len1 , len2 ) ;
2013-01-12 12:16:39 +00:00
goto done ;
}
2013-01-06 12:39:37 +00:00
}
// report success
res = true ;
MARS_DBG ( " VERSION OK '%s' -> '%s' \n " , own_versionlink_path , own_versionlink ) ;
done :
brick_string_free ( old_host ) ;
brick_string_free ( new_host ) ;
brick_string_free ( own_versionlink_path ) ;
brick_string_free ( old_versionlink_path ) ;
brick_string_free ( new_versionlink_path ) ;
brick_string_free ( own_versionlink ) ;
brick_string_free ( old_versionlink ) ;
brick_string_free ( new_versionlink ) ;
brick_string_free ( own_replaylink_path ) ;
brick_string_free ( own_replaylink ) ;
return res ;
2011-07-20 13:11:44 +00:00
}
2012-11-19 10:55:38 +00:00
static
void rot_destruct ( void * _rot )
{
struct mars_rotate * rot = _rot ;
if ( likely ( rot ) ) {
2013-01-07 16:43:14 +00:00
write_info_links ( rot ) ;
2013-04-08 07:47:44 +00:00
del_channel ( rot - > log_say ) ;
rot - > log_say = NULL ;
2012-11-19 10:55:38 +00:00
brick_string_free ( rot - > copy_path ) ;
brick_string_free ( rot - > parent_path ) ;
rot - > copy_path = NULL ;
rot - > parent_path = NULL ;
}
}
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 ;
2013-05-14 11:54:55 +00:00
struct mars_brick * bio_brick ;
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 ;
2013-05-09 14:34:17 +00:00
bool switch_on ;
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 ;
}
2013-01-07 16:43:14 +00:00
spin_lock_init ( & rot - > inf_lock ) ;
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 ;
2013-04-10 13:09:12 +00:00
rot - > copy_next_is_available = 0 ;
2011-02-23 20:48:06 +00:00
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 )
2013-04-08 07:47:44 +00:00
rot - > parent_path = brick_strdup ( parent_path ) ;
2012-08-08 13:50:41 +00:00
2013-04-08 07:47:44 +00:00
if ( unlikely ( ! rot - > log_say ) ) {
char * name = path_make ( " %s/logstatus-%s " , parent_path , my_id ( ) ) ;
if ( likely ( name ) ) {
rot - > log_say = make_channel ( name , false ) ;
brick_string_free ( name ) ;
}
}
2013-01-07 16:43:14 +00:00
write_info_links ( rot ) ;
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 ] ;
2013-01-07 16:43:14 +00:00
if ( trans_input & & trans_input - > is_operating ) {
2012-12-17 07:25:17 +00:00
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 ;
2013-05-09 14:34:17 +00:00
// check whether attach is allowed
switch_on = _check_allow ( global , parent , " attach " ) ;
2011-02-23 20:48:06 +00:00
/* 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 ,
2012-12-26 18:35:49 +00:00
_set_aio_params ,
2011-03-11 13:57:54 +00:00
NULL ,
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 * [ ] ) { } ,
2013-05-10 06:15:00 +00:00
rot - > trans_brick | | switch_on ? 2 : - 1 , // disallow detach when trans_logger is present
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
rot - > aio_brick = ( void * ) aio_brick ;
2013-05-09 14:34:17 +00:00
status = 0 ;
if ( unlikely ( ! aio_brick | | ! aio_brick - > power . led_on ) ) {
goto done ; // this may happen in case of detach
}
2013-05-14 11:54:55 +00:00
bio_brick = rot - > bio_brick ;
if ( unlikely ( ! bio_brick | | ! bio_brick - > power . led_on ) ) {
goto done ; // this may happen in case of detach
}
2011-02-23 20:48:06 +00:00
/* 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 ( rot - > is_primary & &
2013-04-05 07:27:59 +00:00
global_logrot_auto > 0 & &
unlikely ( rot - > aio_info . current_size > = ( loff_t ) global_logrot_auto * 1024 * 1024 * 1024 ) ) {
2012-02-28 11:02:35 +00:00
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 ) ;
}
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-03-11 13:57:54 +00:00
_set_trans_params ,
NULL ,
2011-03-01 09:34:36 +00:00
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 } ,
2013-05-10 06:15:00 +00:00
1 , // create when necessary, but leave in current state otherwise
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 ( ) ) ;
2013-05-09 14:34:17 +00:00
rot - > trans_brick = ( void * ) trans_brick ;
2011-03-01 09:34:36 +00:00
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
}
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 ) ;
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 ) {
2013-04-08 07:47:44 +00:00
MARS_WRN_TO ( rot - > log_say , " transaction logs are not consecutive at '%s' (%d ~> %d) \n " , dent - > d_path , prev_log - > d_serial , dent - > d_serial ) ;
2013-04-08 06:46:13 +00:00
// allow the primary to create a hole in the logfile sequence numbers
if ( ! rot - > todo_primary | | prev_log - > d_serial + 2 ! = dent - > d_serial ) {
status = - EINVAL ;
goto done ;
}
2011-02-23 20:48:06 +00:00
}
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
2013-04-08 06:46:13 +00:00
int _check_logging_status ( struct mars_rotate * rot , int * log_nr , long long * oldpos_start , long long * oldpos_end , long long * newpos )
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-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 ) ;
2013-04-08 06:46:13 +00:00
if ( sscanf ( rot - > replay_link - > d_argv [ 0 ] , " log-%d " , log_nr ) ! = 1 ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link has malformed logfile number '%s' \n " , rot - > replay_link - > d_argv [ 0 ] ) ;
2013-04-08 06:46:13 +00:00
goto done ;
}
2011-05-13 11:19:28 +00:00
if ( sscanf ( rot - > replay_link - > d_argv [ 1 ] , " %lld " , oldpos_start ) ! = 1 ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link has bad start position argument '%s' \n " , rot - > replay_link - > d_argv [ 1 ] ) ;
2011-05-13 11:19:28 +00:00
goto done ;
}
if ( sscanf ( rot - > replay_link - > d_argv [ 2 ] , " %lld " , oldpos_end ) ! = 1 ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link has 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 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay link 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 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " 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 ) {
2013-07-01 08:22:18 +00:00
if ( rot - > aio_info . current_size - * oldpos_start < REPLAY_TOLERANCE ) {
MARS_INF_TO ( rot - > log_say , " TOLERANCE: transaction log '%s' is treated as fully applied \n " , rot - > aio_dent - > d_path ) ;
status = 1 ;
} else {
MARS_INF_TO ( rot - > log_say , " 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 ) ;
status = 2 ;
}
2011-06-17 11:32:38 +00:00
} else if ( rot - > next_relevant_log ) {
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " 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 ) {
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " 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 ) ;
2011-06-17 11:32:38 +00:00
status = 1 ;
} else {
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " empty transaction log '%s' is usable for me as a primary node \n " , rot - > aio_dent - > d_path ) ;
2011-06-17 11:32:38 +00:00
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 ;
2013-04-08 06:46:13 +00:00
int log_nr = 0 ;
2011-02-23 20:48:06 +00:00
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.
*/
2013-04-08 06:46:13 +00:00
status = _check_logging_status ( rot , & log_nr , & 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 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " replay symlink has implausible values: start_pos = %lld dirty_pos = %lld end_pos = %lld \n " , start_pos , dirty_pos , end_pos ) ;
2012-12-06 08:34:41 +00:00
}
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 ) {
2013-01-12 12:16:39 +00:00
bool skip_new = ! rot - > next_next_relevant_log & & rot - > todo_primary ;
MARS_DBG ( " check switchover from '%s' to '%s' (size = %lld, next_next = %p, skip_new = %d) \n " , dent - > d_path , rot - > next_relevant_log - > d_path , rot - > next_relevant_log - > new_stat . size , rot - > next_next_relevant_log , skip_new ) ;
2013-04-08 07:47:44 +00:00
if ( is_switchover_possible ( rot , dent - > d_path , rot - > next_relevant_log - > d_path , skip_new ) ) {
MARS_INF_TO ( rot - > log_say , " start switchover from transaction log '%s' to '%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 ) ;
2011-10-05 14:59:29 +00:00
}
} else if ( rot - > todo_primary ) {
2013-04-08 06:46:13 +00:00
if ( dent - > d_serial > log_nr )
log_nr = dent - > d_serial ;
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " preparing new transaction log, number moves from %d to %d \n " , dent - > d_serial , log_nr + 1 ) ;
2013-04-08 06:46:13 +00:00
_make_new_replaylink ( rot , my_id ( ) , log_nr + 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
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " replaying transaction log '%s' from position %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
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " 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 :
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " bad internal status %d \n " , status ) ;
2011-02-23 20:48:06 +00:00
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
memset ( & trans_input - > inf , 0 , sizeof ( trans_input - > inf ) ) ;
2011-11-15 17:32:20 +00:00
2013-01-07 16:43:14 +00:00
strncpy ( trans_input - > inf . inf_host , log_dent - > d_rest , sizeof ( trans_input - > inf . inf_host ) ) ;
2012-12-17 07:25:17 +00:00
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
}
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 ] ;
2012-12-31 09:33:47 +00:00
struct trans_logger_input * new_input = trans_brick - > inputs [ log_nr ] ;
2011-11-03 11:17:59 +00:00
if ( ! trans_input - > connect ) {
2012-12-31 09:33:47 +00:00
MARS_DBG ( " ignoring unused old input %d \n " , old_nr ) ;
} else if ( ! new_input - > is_operating ) {
MARS_DBG ( " ignoring uninitialized new input %d \n " , log_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 & &
2012-12-31 09:33:47 +00:00
list_empty ( & trans_input - > pos_list ) & &
atomic_read ( & trans_input - > log_ref_count ) < = 0 ) {
2012-12-17 07:25:17 +00:00
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 & &
2013-04-08 06:46:13 +00:00
( rot - > next_relevant_log - > d_serial = = trans_brick - > inputs [ log_nr ] - > inf . inf_sequence + 1 | |
trans_brick - > cease_logging ) & &
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 ,
2012-12-26 18:35:49 +00:00
_set_aio_params ,
2011-11-03 11:17:59 +00:00
NULL ,
rot - > next_relevant_log - > d_path ,
( const struct generic_brick_type * ) & aio_brick_type ,
( const struct generic_brick_type * [ ] ) { } ,
2013-05-10 06:15:00 +00:00
2 , // create + activate
2011-11-03 11:17:59 +00:00
rot - > next_relevant_log - > d_path ,
( const char * [ ] ) { } ,
0 ) ;
if ( unlikely ( ! rot - > next_relevant_brick ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " could not open next transaction log '%s' \n " , rot - > next_relevant_log - > d_path ) ;
2011-11-03 11:17:59 +00:00
goto done ;
}
trans_input = trans_brick - > inputs [ next_nr ] ;
if ( unlikely ( ! trans_input ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " internal log input does not exist \n " ) ;
2011-11-03 11:17:59 +00:00
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 ) ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " internal connect failed \n " ) ;
2011-11-03 11:17:59 +00:00
goto done ;
}
trans_brick - > new_input_nr = next_nr ;
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " started logrotate switchover from '%s' to '%s' \n " , rot - > relevant_log - > d_path , rot - > next_relevant_log - > d_path ) ;
2011-11-03 11:17:59 +00:00
}
done : ;
}
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
_rotate_trans ( rot ) ;
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 ,
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
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 * [ ] ) { } ,
2013-05-10 06:15:00 +00:00
2 , // 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 ;
2013-07-01 08:17:38 +00:00
trans_brick - > replay_tolerance = 0 ;
if ( rot - > todo_primary )
2013-07-01 08:22:18 +00:00
trans_brick - > replay_tolerance = REPLAY_TOLERANCE ;
2012-12-17 07:25:17 +00:00
_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 ;
}
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 ;
2013-05-09 10:35:55 +00:00
bool is_attached ;
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)
*/
2013-04-05 11:04:55 +00:00
if ( IS_JAMMED ( ) ) {
2013-04-08 07:47:44 +00:00
//brick_say_logging = 0;
2013-04-22 07:06:27 +00:00
MARS_ERR_TO ( rot - > log_say , " DISK SPACE IS EXTREMELY LOW on %s \n " , rot - > parent_path ) ;
2013-04-05 11:04:55 +00:00
if ( rot - > todo_primary | | rot - > is_primary ) {
2012-07-23 07:17:18 +00:00
trans_brick - > cease_logging = true ;
2013-04-08 06:46:13 +00:00
rot - > inf_prev_sequence = 0 ; // disable checking
2013-04-05 11:04:55 +00:00
}
2013-04-22 07:06:27 +00:00
} else if ( ( trans_brick - > cease_logging | trans_brick - > stopped_logging ) & & rot - > created_hole & & ! IS_EXHAUSTED ( ) ) {
if ( ! trans_logger_resume ) {
MARS_INF_TO ( rot - > log_say , " emergency mode on %s could be turned off now, but /proc/sys/mars/logger_resume inhibits it. \n " , rot - > parent_path ) ;
} else {
trans_brick - > cease_logging = false ;
rot - > created_hole = false ;
MARS_INF_TO ( rot - > log_say , " emergency mode on %s will be turned off again \n " , rot - > parent_path ) ;
}
2012-07-23 07:17:18 +00:00
}
2013-04-22 07:06:27 +00:00
if ( trans_brick - > cease_logging | trans_brick - > stopped_logging ) {
2013-04-08 07:47:44 +00:00
MARS_ERR_TO ( rot - > log_say , " EMERGENCY MODE on %s: stopped transaction logging, and created a hole in the logfile sequence nubers. \n " , rot - > parent_path ) ;
2013-04-08 06:46:13 +00:00
/* Create a hole in the sequence of logfile numbers.
* The secondaries will later stumble over it .
*/
if ( trans_brick - > inputs [ trans_brick - > log_input_nr ] - > inf . inf_max_pos > 0 ) {
char * new_path = path_make ( " %s/log-%09d-%s " , rot - > parent_path , rot - > max_sequence + 2 , my_id ( ) ) ;
if ( likely ( new_path & & ! mars_find_dent ( global , new_path ) ) ) {
2013-04-08 07:47:44 +00:00
MARS_INF_TO ( rot - > log_say , " EMERGENCY: creating new logfile '%s' \n " , new_path ) ;
2013-04-08 06:46:13 +00:00
_create_new_logfile ( new_path ) ;
2013-04-22 07:06:27 +00:00
rot - > created_hole = true ;
2013-04-08 06:46:13 +00:00
}
brick_string_free ( new_path ) ;
}
}
2012-07-23 07:17:18 +00:00
2013-04-05 11:04:55 +00:00
if ( IS_EMERGENCY_PRIMARY ( ) | | ( ! rot - > todo_primary & & IS_EMERGENCY_SECONDARY ( ) ) ) {
2013-04-08 07:47:44 +00:00
MARS_WRN_TO ( rot - > log_say , " EMERGENCY: the space on /mars/ is very low. Expect some problems! \n " ) ;
2012-03-06 11:56:48 +00:00
if ( rot - > first_log & & rot - > first_log ! = rot - > relevant_log ) {
2013-04-08 07:47:44 +00:00
MARS_WRN_TO ( rot - > log_say , " EMERGENCY: ruthlessly freeing old logfile '%s', don't cry on any ramifications. \n " , rot - > first_log - > d_path ) ;
2012-03-06 11:56:48 +00:00
mars_unlink ( rot - > first_log - > d_path ) ;
rot - > first_log - > d_killme = true ;
2013-04-05 11:04:55 +00:00
// give it a chance to cease deleting next time
compute_emergency_mode ( ) ;
2012-03-06 11:56:48 +00:00
}
2013-04-08 07:47:44 +00:00
} else if ( IS_EXHAUSTED ( ) ) {
MARS_WRN_TO ( rot - > log_say , " EMERGENCY: the space on /mars/ is becoming low. Stopping all fetches of logfiles for secondary resources. \n " ) ;
2012-03-06 11:56:48 +00:00
}
2013-04-16 09:05:57 +00:00
if ( trans_brick - > replay_mode ) {
if ( trans_brick - > replay_code > 0 ) {
MARS_INF_TO ( rot - > log_say , " logfile apply ended successfully \n " ) ;
} else if ( trans_brick - > replay_code < 0 ) {
MARS_ERR_TO ( rot - > log_say , " logfile apply stopped with error = %d \n " , trans_brick - > replay_code ) ;
}
}
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 ) {
2013-01-04 11:00:03 +00:00
do_stop = trans_brick - > replay_code ! = 0 | |
! global - > global_power . button | |
2013-05-09 14:34:17 +00:00
! _check_allow ( global , parent , " allow-replay " ) | |
! _check_allow ( global , parent , " attach " ) ;
2011-05-13 11:19:28 +00:00
} else {
2013-05-09 14:34:17 +00:00
do_stop =
! rot - > if_brick & &
! rot - > is_primary & &
( ! rot - > todo_primary | |
! _check_allow ( global , parent , " attach " ) ) ;
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
} else {
_change_trans ( rot ) ;
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 & &
_check_allow ( global , parent , " allow-replay " ) ) ) ;
2013-01-10 18:01:15 +00:00
if ( do_start & & rot - > forbid_replay ) {
MARS_INF ( " cannot start replay because sync wants to start \n " ) ;
do_start = false ;
}
if ( do_start & & rot - > sync_brick & & ! rot - > sync_brick - > power . led_off ) {
MARS_INF ( " cannot start replay because sync is running \n " ) ;
do_start = false ;
}
MARS_DBG ( " rot->replay_mode = %d rot->start_pos = %lld rot->end_pos = %lld | do_start = %d \n " , rot - > replay_mode , rot - > start_pos , rot - > end_pos , do_start ) ;
2011-02-23 20:48:06 +00:00
if ( do_start ) {
status = _start_trans ( rot ) ;
}
}
done :
2013-05-09 21:42:18 +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 - > power . led_off | |
! global - > global_power . button | |
( copy_brick - > copy_last = = copy_brick - > copy_end & &
rot - > copy_next_is_available > 0 ) ) ) {
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 ;
mars_trigger ( ) ;
}
rot - > copy_brick = copy_brick ;
if ( ! copy_brick ) {
rot - > copy_serial = 0 ;
}
2013-05-09 14:34:17 +00:00
// remove trans_logger (when possible) upon detach
2013-05-09 10:35:55 +00:00
is_attached = ! ! rot - > trans_brick ;
_show_actual ( rot - > parent_path , " is-attached " , is_attached ) ;
2013-05-09 14:34:17 +00:00
if ( rot - > trans_brick & & rot - > trans_brick - > power . led_off & & ! rot - > trans_brick - > outputs [ 0 ] - > nr_connected ) {
bool do_attach = _check_allow ( global , parent , " attach " ) ;
MARS_DBG ( " do_attach = %d \n " , do_attach ) ;
if ( ! do_attach ) {
rot - > trans_brick - > killme = true ;
rot - > trans_brick = NULL ;
}
}
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-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 ( ) ) ;
2013-01-24 10:12:16 +00:00
MARS_DBG ( " todo_primary = %d is_primary = %d \n " , rot - > todo_primary , rot - > is_primary ) ;
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 ;
2013-05-14 11:54:55 +00:00
struct mars_rotate * rot ;
2011-02-23 20:48:06 +00:00
struct mars_brick * brick ;
2013-05-09 14:34:17 +00:00
bool switch_on ;
2011-02-27 14:17:58 +00:00
int status = 0 ;
2011-02-23 20:48:06 +00:00
2013-05-09 14:34:17 +00:00
if ( ! global | | ! global - > global_power . button | | ! dent - > d_parent ) {
2011-02-27 14:17:58 +00:00
goto done ;
2011-02-23 20:48:06 +00:00
}
2013-05-14 11:54:55 +00:00
rot = dent - > d_parent - > d_private ;
if ( ! rot )
goto done ;
2013-05-09 14:34:17 +00:00
switch_on = _check_allow ( global , dent - > d_parent , " attach " ) ;
2011-03-01 09:34:36 +00:00
brick =
make_brick_all ( global ,
2011-03-02 09:30:56 +00:00
dent ,
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
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 * [ ] ) { } ,
2013-05-10 06:15:00 +00:00
switch_on ? 2 : - 1 ,
2011-03-01 09:34:36 +00:00
dent - > d_path ,
( const char * [ ] ) { } ,
0 ) ;
2013-05-14 11:54:55 +00:00
rot - > bio_brick = brick ;
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 ;
2012-08-08 09:50:24 +00:00
/* Report the actual size of the device.
* It may be larger than the global size .
*/
2013-05-09 14:34:17 +00:00
if ( brick & & brick - > power . led_on ) {
2012-08-08 09:50:24 +00:00
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 ;
2013-06-04 12:40:10 +00:00
int open_count = 0 ;
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 ;
2013-06-04 12:40:10 +00:00
if ( ! rot | | ! rot - > parent_path ) {
2011-06-17 11:32:38 +00:00
MARS_DBG ( " nothing to do \n " ) ;
2013-06-04 12:40:10 +00:00
goto err ;
2011-02-23 20:48:06 +00:00
}
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 =
2013-05-04 19:54:12 +00:00
( rot - > if_brick & & atomic_read ( & rot - > if_brick - > 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 & &
2013-05-09 14:34:17 +00:00
rot - > trans_brick - > power . led_on & &
_check_allow ( global , dent - > d_parent , " attach " ) ) ;
2013-04-05 11:04:55 +00:00
if ( ! global - > global_power . button ) {
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-03-11 13:57:54 +00:00
_set_if_params ,
2012-08-08 13:50:41 +00:00
rot ,
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 } ,
2013-05-10 06:15:00 +00:00
switch_on ? 2 : - 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
}
2013-05-09 14:34:17 +00:00
if ( ! switch_on ) {
MARS_DBG ( " setting killme on if_brick \n " ) ;
dev_brick - > killme = true ;
}
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 ;
2013-06-04 12:40:10 +00:00
open_count = atomic_read ( & _dev_brick - > open_count ) ;
2011-03-08 16:45:52 +00:00
#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 :
2013-06-04 12:40:10 +00:00
__show_actual ( rot - > parent_path , " open-count " , open_count ) ;
rot - > is_primary =
rot - > if_brick & & ! rot - > if_brick - > power . led_off ;
2011-06-17 11:32:38 +00:00
_show_primary ( rot , parent ) ;
2013-06-04 12:40:10 +00:00
err :
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 ;
2013-05-09 14:34:17 +00:00
bool switch_on ;
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 ;
}
2013-05-09 14:34:17 +00:00
switch_on = _check_allow ( global , dent - > d_parent , " attach " ) ;
2011-03-01 09:34:36 +00:00
brick =
make_brick_all ( global ,
dent ,
2011-03-18 13:15:40 +00:00
_set_bio_params ,
2011-03-11 13:57:54 +00:00
NULL ,
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 * [ ] ) { } ,
2013-05-10 06:15:00 +00:00
switch_on ? 2 : - 1 ,
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-03-11 13:57:54 +00:00
_set_if_params ,
NULL ,
2011-03-01 09:34:36 +00:00
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 } ,
2013-05-10 06:15:00 +00:00
switch_on ? 2 : - 1 ,
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
2013-06-27 12:30:05 +00:00
status = __make_copy ( global , dent , switch_path , copy_path , dent - > d_parent - > d_path , ( const char * * ) dent - > d_argv , - 1 , - 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 ;
2013-05-09 14:34:17 +00:00
bool do_start ;
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
2013-05-09 14:34:17 +00:00
do_start = _check_allow ( global , dent - > d_parent , " attach " ) ;
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 ) {
2013-01-10 18:01:15 +00:00
rot - > forbid_replay = false ;
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 ;
}
2013-06-27 12:30:05 +00:00
if ( start_pos > = end_pos ) {
2011-07-08 07:02:14 +00:00
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 ) ;
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
*/
2013-01-10 18:01:15 +00:00
if ( do_start & &
2013-04-10 07:54:50 +00:00
rot - > trans_brick & &
! rot - > trans_brick - > power . led_off ) {
2013-01-10 18:01:15 +00:00
MARS_INF ( " cannot start sync because logger is working \n " ) ;
2013-01-10 17:35:02 +00:00
do_start = false ;
}
/* Disallow overwrite of newer data
*/
2013-04-08 07:47:44 +00:00
if ( do_start & & compare_replaylinks ( rot , peer , my_id ( ) ) < 0 ) {
2013-01-10 17:35:02 +00:00
MARS_INF ( " cannot start sync because my data is newer than the remote one at '%s'! \n " , peer ) ;
2012-01-31 13:17:59 +00:00
do_start = false ;
2013-01-10 18:01:15 +00:00
rot - > forbid_replay = true ;
2012-01-31 13:17:59 +00:00
}
2012-08-03 12:55:00 +00:00
/* Flip between replay and sync
*/
2013-04-05 07:27:59 +00:00
if ( do_start & & rot - > replay_mode & & rot - > end_pos > rot - > start_pos & &
mars_sync_flip_interval > = 8 ) {
2012-08-03 12:55:00 +00:00
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 ;
2013-04-05 07:27:59 +00:00
rot - > flip_start = jiffies + mars_sync_flip_interval * HZ ;
2012-08-03 12:55:00 +00:00
}
} else {
rot - > flip_start = 0 ;
}
2011-02-25 11:46:38 +00:00
/* Start copy
*/
2013-04-09 13:03:55 +00:00
# ifdef CONFIG_MARS_SEPARATE_PORTS
src = path_make ( " data-%s@%s:%d " , peer , peer , mars_net_default_port + 2 ) ;
# else
2011-03-03 09:02:10 +00:00
src = path_make ( " data-%s@%s " , peer , peer ) ;
2013-04-09 13:03:55 +00:00
# endif
2011-03-03 09:02:10 +00:00
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 ;
2013-01-10 18:01:15 +00:00
MARS_DBG ( " initial sync '%s' => '%s' do_start = %d \n " , src , dst , do_start ) ;
2011-02-25 11:46:38 +00:00
2011-03-01 18:00:14 +00:00
{
const char * argv [ 2 ] = { src , dst } ;
2013-06-27 12:30:05 +00:00
status = __make_copy ( global , dent , do_start ? switch_path : " " , copy_path , dent - > d_parent - > d_path , argv , start_pos , end_pos , mars_fast_fullsync > 0 , 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 ;
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 )
{
2013-06-26 13:18:32 +00:00
struct kstat stat ;
2011-10-24 10:54:15 +00:00
struct mars_global * global = buf ;
struct mars_dent * target ;
struct mars_dent * response ;
2013-07-01 06:25:25 +00:00
const char * marker_path = NULL ;
2011-10-24 10:54:15 +00:00
const char * response_path = NULL ;
2013-01-05 05:27:26 +00:00
struct mars_brick * brick ;
2011-10-24 10:54:15 +00:00
int max_serial = 0 ;
2013-06-26 13:18:32 +00:00
int status ;
2011-10-24 10:54:15 +00:00
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
2013-07-01 06:25:25 +00:00
// create a marker which prevents concurrent updates from remote hosts
marker_path = backskip_replace ( dent - > new_link , ' / ' , true , " /.deleted- " ) ;
if ( unlikely ( ! marker_path ) )
goto done ;
if ( mars_stat ( marker_path , & stat , true ) < 0 ) {
mars_symlink ( " 1 " , marker_path , NULL , 0 ) ;
}
2013-01-05 05:27:26 +00:00
brick = mars_find_brick ( global , NULL , dent - > new_link ) ;
if ( brick & & unlikely ( brick - > nr_outputs > 0 & & brick - > outputs [ 0 ] & & brick - > outputs [ 0 ] - > nr_connected ) ) {
MARS_WRN ( " target '%s' cannot be deleted, its brick '%s' in use \n " , dent - > new_link , SAFE_STR ( brick - > brick_name ) ) ;
goto done ;
}
2013-06-26 13:18:32 +00:00
status = - EAGAIN ;
2011-10-24 10:54:15 +00:00
target = _mars_find_dent ( global , dent - > new_link ) ;
if ( target ) {
2013-06-26 13:18:32 +00:00
status = mars_unlink ( dent - > new_link ) ;
2011-10-24 10:54:15 +00:00
target - > d_killme = true ;
2013-06-26 13:18:32 +00:00
MARS_DBG ( " target '%s' deleted (status = %d) and marked for removal \n " , dent - > new_link , status ) ;
} else if ( mars_stat ( dent - > new_link , & stat , true ) > = 0 ) {
if ( S_ISDIR ( stat . mode ) ) {
status = mars_rmdir ( dent - > new_link ) ;
MARS_DBG ( " rmdir '%s', status = %d \n " , dent - > new_link , status ) ;
} else {
status = mars_unlink ( dent - > new_link ) ;
MARS_DBG ( " unlink '%s', status = %d \n " , dent - > new_link , status ) ;
}
}
if ( status < 0 ) {
2011-10-24 10:54:15 +00:00
MARS_DBG ( " target '%s' does no longer exist \n " , dent - > new_link ) ;
2013-05-06 06:12:00 +00:00
if ( dent - > d_serial < = global - > deleted_border ) {
2013-07-01 06:25:25 +00:00
mars_unlink ( marker_path ) ;
2012-02-01 14:05:49 +00:00
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 :
2013-07-01 06:25:25 +00:00
brick_string_free ( marker_path ) ;
2011-10-24 10:54:15 +00:00
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 ,
2013-05-13 07:45:35 +00:00
// global ID
CL_UUID ,
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 ,
2013-05-11 08:21:25 +00:00
CL_TIME ,
2013-04-11 12:19:18 +00:00
CL_TREE ,
2013-04-05 11:04:55 +00:00
CL_EMERGENCY ,
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 ] = {
} ,
2013-05-13 07:45:35 +00:00
/* UUID, indentifying the whole cluster.
*/
[ CL_UUID ] = {
. cl_name = " uuid " ,
. cl_len = 4 ,
. cl_type = ' l ' ,
. cl_father = 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 ,
} ,
2013-05-11 08:21:25 +00:00
[ CL_TIME ] = {
. cl_name = " time- " ,
. cl_len = 5 ,
. cl_type = ' l ' ,
. cl_father = CL_ROOT ,
} ,
2013-04-11 12:19:18 +00:00
/* Show version indication for symlink tree.
*/
[ CL_TREE ] = {
. cl_name = " tree- " ,
. cl_len = 5 ,
. cl_type = ' l ' ,
. cl_father = CL_ROOT ,
} ,
2012-01-23 15:37:03 +00:00
/* Indicate whether filesystem is full
*/
2013-04-05 11:04:55 +00:00
[ CL_EMERGENCY ] = {
. cl_name = " emergency- " ,
2012-01-23 15:37:03 +00:00
. 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 ,
} ,
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-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 ) ,
. 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 ) ;
2013-01-22 11:13:09 +00:00
while ( _global . global_power . button | | ! list_empty ( & _global . brick_anchor ) ) {
2011-02-23 20:48:06 +00:00
int status ;
2012-01-17 10:48:56 +00:00
2013-01-09 18:20:10 +00:00
MARS_DBG ( " -------- NEW ROUND %d --------- \n " , atomic_read ( & server_handler_count ) ) ;
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 ;
}
2013-04-11 12:19:18 +00:00
2013-05-11 20:52:11 +00:00
_make_alive ( ) ;
2012-01-23 14:59:29 +00:00
2013-04-05 11:04:55 +00:00
compute_emergency_mode ( ) ;
2011-10-18 08:20:10 +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 ) {
2013-05-09 14:34:17 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , ( void * ) & copy_brick_type , true ) ;
2011-11-04 15:43:23 +00:00
MARS_DBG ( " kill copy bricks (when possible) = %d \n " , status ) ;
2011-10-18 11:35:33 +00:00
}
2013-05-09 14:34:17 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , NULL , false ) ;
MARS_DBG ( " kill main bricks (when possible) = %d \n " , status ) ;
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , ( void * ) & client_brick_type , true ) ;
2011-10-10 11:38:55 +00:00
MARS_DBG ( " kill client bricks (when possible) = %d \n " , status ) ;
2013-05-09 14:34:17 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , ( void * ) & aio_brick_type , true ) ;
2011-10-10 11:38:55 +00:00
MARS_DBG ( " kill aio bricks (when possible) = %d \n " , status ) ;
2013-05-09 14:34:17 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , ( void * ) & sio_brick_type , true ) ;
2011-11-14 13:12:33 +00:00
MARS_DBG ( " kill sio bricks (when possible) = %d \n " , status ) ;
2013-05-09 14:34:17 +00:00
status = mars_kill_brick_when_possible ( & _global , & _global . brick_anchor , false , ( void * ) & bio_brick_type , true ) ;
MARS_DBG ( " kill bio bricks (when possible) = %d \n " , status ) ;
2011-10-10 11:38:55 +00:00
2013-04-05 07:27:59 +00:00
if ( ( long long ) jiffies + mars_rollover_interval * HZ > = last_rollover ) {
2012-11-16 11:50:49 +00:00
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 ) ;
2013-01-22 10:30:52 +00:00
show_statistics ( & _global , " main " ) ;
2011-03-03 09:02:10 +00:00
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
2013-04-05 07:27:59 +00:00
wait_event_interruptible_timeout ( _global . main_event , _global . main_trigger , 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 ( ) ;
2013-05-11 20:52:11 +00:00
brick_msleep ( 1000 ) ;
2011-02-23 20:48:06 +00:00
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 ) ;
2013-01-22 10:30:52 +00:00
show_statistics ( & _global , " main " ) ;
2011-08-25 10:16:32 +00:00
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 ;
}
2013-05-13 07:53:57 +00:00
static
char * _mars_info ( void )
{
int max = PAGE_SIZE - 64 ;
char * txt = brick_string_alloc ( max ) ;
struct list_head * tmp ;
int dent_count = 0 ;
int brick_count = 0 ;
int pos = 0 ;
if ( unlikely ( ! txt | | ! mars_global ) ) {
brick_string_free ( txt ) ;
return NULL ;
}
txt [ - - max ] = ' \0 ' ; // safeguard
down_read ( & mars_global - > brick_mutex ) ;
for ( tmp = mars_global - > brick_anchor . next ; tmp ! = & mars_global - > brick_anchor ; tmp = tmp - > next ) {
struct mars_brick * test ;
brick_count + + ;
test = container_of ( tmp , struct mars_brick , global_brick_link ) ;
pos + = snprintf (
txt + pos , max - pos ,
" brick button=%d off=%d on=%d path='%s' \n " ,
test - > power . button ,
test - > power . led_off ,
test - > power . led_on ,
test - > brick_path
) ;
}
up_read ( & mars_global - > brick_mutex ) ;
down_read ( & mars_global - > dent_mutex ) ;
for ( tmp = mars_global - > dent_anchor . next ; tmp ! = & mars_global - > dent_anchor ; tmp = tmp - > next ) {
struct mars_dent * dent ;
dent_count + + ;
dent = container_of ( tmp , struct mars_dent , dent_link ) ;
#if 0 // usually there is not enough space in PAGE_SIZE
pos + = snprintf (
txt + pos , max - pos ,
" dent stamp=%ld.%09ld path='%s' value='%s' \n " ,
dent - > new_stat . mtime . tv_sec , dent - > new_stat . mtime . tv_nsec ,
SAFE_STR ( dent - > d_path ) ,
SAFE_STR ( dent - > new_link )
) ;
# endif
}
up_read ( & mars_global - > dent_mutex ) ;
pos + = snprintf (
txt + pos , max - pos ,
" SUMMARY: brick_count=%d dent_count=%d \n " ,
brick_count ,
dent_count
) ;
return txt ;
}
2011-11-14 17:52:05 +00:00
static struct mem_reservation global_reserve = {
. amount = {
2012-02-07 13:15:07 +00:00
[ 5 ] = 64 ,
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
2013-05-13 07:53:57 +00:00
mars_info = NULL ;
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 ( ) ;
2013-03-13 16:04:57 +00:00
printk ( KERN_INFO " stopped MARS \n " ) ;
2013-06-27 08:05:58 +00:00
/* Workaround for nasty race: some kernel threads have not yet
* really finished even _after_ kthread_stop ( ) and may execute
* some code which will disappear right after return from this
* function .
* A correct solution would probably need the help of the kernel
* scheduler .
*/
brick_msleep ( 1000 ) ;
2011-02-23 20:48:06 +00:00
}
static int __init init_light ( void )
{
2013-01-09 10:12:27 +00:00
extern int min_free_kbytes ;
int new_limit = 4096 ;
2011-08-25 10:16:32 +00:00
int status = 0 ;
2013-01-09 10:12:27 +00:00
// bump the min_free limit
if ( min_free_kbytes < new_limit )
min_free_kbytes = new_limit ;
2013-03-13 16:04:57 +00:00
printk ( KERN_INFO " loading MARS, BUILDTAG=%s BUILDHOST=%s BUILDDATE=%s \n " , BUILDTAG , BUILDHOST , BUILDDATE ) ;
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 ) ;
2013-01-23 11:21:22 +00:00
DO_INIT ( mars_mapfree ) ;
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 ) ;
2013-04-05 11:04:55 +00:00
status = compute_emergency_mode ( ) ;
if ( unlikely ( status < 0 ) ) {
MARS_ERR ( " Sorry, your /mars/ filesystem is too small! \n " ) ;
goto done ;
}
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 ;
2013-05-13 07:53:57 +00:00
mars_info = _mars_info ;
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 ) ;