2004-05-05 01:25:57 +04:00
/*
* Copyright ( C ) 2003 - 2004 Sistina Software , Inc . All rights reserved .
2008-01-09 18:32:19 +03:00
* Copyright ( C ) 2004 - 2008 Red Hat , Inc . All rights reserved .
2004-05-05 01:25:57 +04:00
*
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-05-05 01:25:57 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-05-05 01:25:57 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "lib.h"
# include "toolcontext.h"
# include "metadata.h"
2004-09-16 22:40:56 +04:00
# include "segtype.h"
2004-05-05 01:25:57 +04:00
# include "text_export.h"
# include "config.h"
2004-05-05 22:11:43 +04:00
# include "activate.h"
2006-10-03 21:55:20 +04:00
# include "str_list.h"
2008-01-09 18:32:19 +03:00
# ifdef DMEVENTD
# include "sharedlib.h"
# include <libdevmapper-event.h>
# endif
2004-05-05 01:25:57 +04:00
2006-04-19 19:33:07 +04:00
static const char * _snap_name ( const struct lv_segment * seg )
2004-05-05 01:25:57 +04:00
{
return seg - > segtype - > name ;
}
2006-04-19 19:33:07 +04:00
static int _snap_text_import ( struct lv_segment * seg , const struct config_node * sn ,
2006-05-11 21:58:58 +04:00
struct dm_hash_table * pv_hash __attribute ( ( unused ) ) )
2004-05-05 01:25:57 +04:00
{
2005-01-27 18:48:49 +03:00
uint32_t chunk_size ;
2004-05-05 01:25:57 +04:00
const char * org_name , * cow_name ;
struct logical_volume * org , * cow ;
seg - > lv - > status | = SNAPSHOT ;
if ( ! get_config_uint32 ( sn , " chunk_size " , & chunk_size ) ) {
log_error ( " Couldn't read chunk size for snapshot. " ) ;
return 0 ;
}
log_suppress ( 1 ) ;
if ( ! ( cow_name = find_config_str ( sn , " cow_store " , NULL ) ) ) {
log_suppress ( 0 ) ;
log_error ( " Snapshot cow storage not specified. " ) ;
return 0 ;
}
if ( ! ( org_name = find_config_str ( sn , " origin " , NULL ) ) ) {
log_suppress ( 0 ) ;
log_error ( " Snapshot origin not specified. " ) ;
return 0 ;
}
log_suppress ( 0 ) ;
if ( ! ( cow = find_lv ( seg - > lv - > vg , cow_name ) ) ) {
log_error ( " Unknown logical volume specified for "
" snapshot cow store. " ) ;
return 0 ;
}
if ( ! ( org = find_lv ( seg - > lv - > vg , org_name ) ) ) {
log_error ( " Unknown logical volume specified for "
" snapshot origin. " ) ;
return 0 ;
}
2007-11-02 23:40:05 +03:00
if ( ! vg_add_snapshot ( seg - > lv - > name , org , cow ,
2005-04-07 16:39:44 +04:00
& seg - > lv - > lvid , seg - > len , chunk_size ) ) {
2004-05-05 01:25:57 +04:00
stack ;
return 0 ;
}
return 1 ;
}
2006-04-19 19:33:07 +04:00
static int _snap_text_export ( const struct lv_segment * seg , struct formatter * f )
2004-05-05 01:25:57 +04:00
{
outf ( f , " chunk_size = %u " , seg - > chunk_size ) ;
outf ( f , " origin = \" %s \" " , seg - > origin - > name ) ;
outf ( f , " cow_store = \" %s \" " , seg - > cow - > name ) ;
return 1 ;
}
2004-05-05 22:11:43 +04:00
# ifdef DEVMAPPER_SUPPORT
2006-05-11 21:58:58 +04:00
static int _snap_target_percent ( void * * target_state __attribute ( ( unused ) ) ,
struct dm_pool * mem __attribute ( ( unused ) ) ,
2006-05-17 00:53:13 +04:00
struct cmd_context * cmd __attribute ( ( unused ) ) ,
2006-05-11 21:58:58 +04:00
struct lv_segment * seg __attribute ( ( unused ) ) ,
2004-05-05 01:25:57 +04:00
char * params , uint64_t * total_numerator ,
uint64_t * total_denominator , float * percent )
{
float percent2 ;
uint64_t numerator , denominator ;
2007-07-02 15:17:21 +04:00
if ( strchr ( params , ' / ' ) ) {
2004-05-05 01:25:57 +04:00
if ( sscanf ( params , " % " PRIu64 " /% " PRIu64 ,
& numerator , & denominator ) = = 2 ) {
* total_numerator + = numerator ;
* total_denominator + = denominator ;
}
} else if ( sscanf ( params , " %f " , & percent2 ) = = 1 ) {
* percent + = percent2 ;
* percent / = 2 ;
}
return 1 ;
}
2006-10-18 22:01:53 +04:00
static int _snap_target_present ( const struct lv_segment * seg __attribute ( ( unused ) ) )
2004-05-05 22:11:43 +04:00
{
2006-04-19 19:33:07 +04:00
static int _snap_checked = 0 ;
static int _snap_present = 0 ;
2004-05-05 22:11:43 +04:00
2006-04-19 19:33:07 +04:00
if ( ! _snap_checked )
_snap_present = target_present ( " snapshot " , 1 ) & &
2005-11-09 01:52:26 +03:00
target_present ( " snapshot-origin " , 0 ) ;
2004-05-05 22:11:43 +04:00
2006-04-19 19:33:07 +04:00
_snap_checked = 1 ;
2004-05-05 22:11:43 +04:00
2006-04-19 19:33:07 +04:00
return _snap_present ;
2004-05-05 22:11:43 +04:00
}
2008-01-09 18:32:19 +03:00
# ifdef DMEVENTD
static int _get_snapshot_dso_path ( struct cmd_context * cmd , char * * dso )
{
char * path ;
const char * libpath ;
if ( ! ( path = dm_pool_alloc ( cmd - > mem , PATH_MAX ) ) ) {
log_error ( " Failed to allocate dmeventd library path. " ) ;
return 0 ;
}
libpath = find_config_tree_str ( cmd , " dmeventd/snapshot_library " , NULL ) ;
if ( ! libpath )
return 0 ;
get_shared_library_path ( cmd , libpath , path , PATH_MAX ) ;
* dso = path ;
return 1 ;
}
static struct dm_event_handler * _create_dm_event_handler ( const char * dmname ,
const char * dso ,
const int timeout ,
enum dm_event_mask mask )
{
struct dm_event_handler * dmevh ;
if ( ! ( dmevh = dm_event_handler_create ( ) ) )
return_0 ;
if ( dm_event_handler_set_dso ( dmevh , dso ) )
goto fail ;
if ( dm_event_handler_set_dev_name ( dmevh , dmname ) )
goto fail ;
dm_event_handler_set_timeout ( dmevh , timeout ) ;
dm_event_handler_set_event_mask ( dmevh , mask ) ;
return dmevh ;
fail :
dm_event_handler_destroy ( dmevh ) ;
return NULL ;
}
static int _target_registered ( struct lv_segment * seg , int * pending )
{
char * dso , * name ;
struct logical_volume * lv ;
struct volume_group * vg ;
enum dm_event_mask evmask = 0 ;
struct dm_event_handler * dmevh ;
lv = seg - > lv ;
vg = lv - > vg ;
* pending = 0 ;
if ( ! _get_snapshot_dso_path ( vg - > cmd , & dso ) )
return_0 ;
if ( ! ( name = build_dm_name ( vg - > cmd - > mem , vg - > name , seg - > cow - > name , NULL ) ) )
return_0 ;
if ( ! ( dmevh = _create_dm_event_handler ( name , dso , 0 , DM_EVENT_ALL_ERRORS ) ) )
return_0 ;
if ( dm_event_get_registered_device ( dmevh , 0 ) ) {
dm_event_handler_destroy ( dmevh ) ;
return 0 ;
}
evmask = dm_event_handler_get_event_mask ( dmevh ) ;
if ( evmask & DM_EVENT_REGISTRATION_PENDING ) {
* pending = 1 ;
evmask & = ~ DM_EVENT_REGISTRATION_PENDING ;
}
dm_event_handler_destroy ( dmevh ) ;
return evmask ;
}
/* FIXME This gets run while suspended and performs banned operations. */
static int _target_set_events ( struct lv_segment * seg , int events , int set )
{
char * dso , * name ;
struct volume_group * vg = seg - > lv - > vg ;
struct dm_event_handler * dmevh ;
int r ;
if ( ! _get_snapshot_dso_path ( vg - > cmd , & dso ) )
return_0 ;
if ( ! ( name = build_dm_name ( vg - > cmd - > mem , vg - > name , seg - > cow - > name , NULL ) ) )
return_0 ;
/* FIXME: make timeout configurable */
if ( ! ( dmevh = _create_dm_event_handler ( name , dso , 10 ,
DM_EVENT_ALL_ERRORS | DM_EVENT_TIMEOUT ) ) )
return_0 ;
r = set ? dm_event_register_handler ( dmevh ) : dm_event_unregister_handler ( dmevh ) ;
dm_event_handler_destroy ( dmevh ) ;
if ( ! r )
return_0 ;
log_info ( " %s %s for events " , set ? " Registered " : " Unregistered " , name ) ;
return 1 ;
}
static int _target_register_events ( struct lv_segment * seg ,
int events )
{
return _target_set_events ( seg , events , 1 ) ;
}
static int _target_unregister_events ( struct lv_segment * seg ,
int events )
{
return _target_set_events ( seg , events , 0 ) ;
}
# endif /* DMEVENTD */
2004-05-05 22:11:43 +04:00
# endif
2006-10-03 21:55:20 +04:00
static int _snap_modules_needed ( struct dm_pool * mem ,
2007-08-22 18:38:18 +04:00
const struct lv_segment * seg __attribute ( ( unused ) ) ,
2006-10-03 21:55:20 +04:00
struct list * modules )
{
if ( ! str_list_add ( mem , modules , " snapshot " ) ) {
log_error ( " snapshot string list allocation failed " ) ;
return 0 ;
}
return 1 ;
}
2006-04-19 19:33:07 +04:00
static void _snap_destroy ( const struct segment_type * segtype )
2004-05-05 01:25:57 +04:00
{
2006-05-11 21:58:58 +04:00
dm_free ( ( void * ) segtype ) ;
2004-05-05 01:25:57 +04:00
}
static struct segtype_handler _snapshot_ops = {
2006-05-10 01:23:51 +04:00
. name = _snap_name ,
. text_import = _snap_text_import ,
. text_export = _snap_text_export ,
2004-05-05 22:11:43 +04:00
# ifdef DEVMAPPER_SUPPORT
2006-05-10 01:23:51 +04:00
. target_percent = _snap_target_percent ,
. target_present = _snap_target_present ,
2008-01-09 18:32:19 +03:00
# ifdef DMEVENTD
. target_monitored = _target_registered ,
. target_monitor_events = _target_register_events ,
. target_unmonitor_events = _target_unregister_events ,
# endif
2004-05-05 22:11:43 +04:00
# endif
2006-10-03 21:55:20 +04:00
. modules_needed = _snap_modules_needed ,
2006-05-10 01:23:51 +04:00
. destroy = _snap_destroy ,
2004-05-05 01:25:57 +04:00
} ;
# ifdef SNAPSHOT_INTERNAL
struct segment_type * init_snapshot_segtype ( struct cmd_context * cmd )
# else /* Shared */
struct segment_type * init_segtype ( struct cmd_context * cmd ) ;
struct segment_type * init_segtype ( struct cmd_context * cmd )
# endif
{
2005-10-17 03:03:59 +04:00
struct segment_type * segtype = dm_malloc ( sizeof ( * segtype ) ) ;
2008-01-11 20:44:26 +03:00
# ifdef DMEVENTD
2008-01-09 18:32:19 +03:00
char * dso ;
2008-01-11 20:44:26 +03:00
# endif
2004-05-05 01:25:57 +04:00
if ( ! segtype ) {
stack ;
return NULL ;
}
segtype - > cmd = cmd ;
segtype - > ops = & _snapshot_ops ;
segtype - > name = " snapshot " ;
segtype - > private = NULL ;
2004-05-11 20:01:58 +04:00
segtype - > flags = SEG_SNAPSHOT ;
2004-05-05 01:25:57 +04:00
2008-01-09 18:32:19 +03:00
# ifdef DMEVENTD
if ( _get_snapshot_dso_path ( cmd , & dso ) )
segtype - > flags | = SEG_MONITORED ;
# endif
2004-09-14 21:37:51 +04:00
log_very_verbose ( " Initialised segtype: %s " , segtype - > name ) ;
2004-05-05 01:25:57 +04:00
return segtype ;
}