2004-05-05 01:25:57 +04:00
/*
2008-01-30 17:00:02 +03: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 "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"
2004-05-05 01:25:57 +04:00
2013-10-09 16:50:51 +04:00
# define SEG_LOG_ERROR(t, p...) \
log_error ( t " segment %s of logical volume %s. " , # # p , \
dm_config_parent_name ( sn ) , seg - > lv - > name ) , 0 ;
2011-06-17 18:14:19 +04:00
static const char * _snap_target_name ( const struct lv_segment * seg ,
const struct lv_activate_opts * laopts )
2010-10-14 01:26:37 +04:00
{
2011-06-17 18:22:48 +04:00
if ( ! laopts - > no_merging & & ( seg - > status & MERGING ) )
2010-10-14 01:26:37 +04:00
return " snapshot-merge " ;
2014-10-20 22:09:42 +04:00
return lvseg_name ( seg ) ;
2010-10-14 01:26:37 +04:00
}
2011-08-30 18:55:15 +04:00
static int _snap_text_import ( struct lv_segment * seg , const struct dm_config_node * sn ,
2010-07-09 19:34:40 +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
struct logical_volume * org , * cow ;
2013-10-09 16:50:51 +04:00
const char * org_name = NULL , * cow_name = NULL ;
int merge = 0 ;
2004-05-05 01:25:57 +04:00
2011-08-30 18:55:15 +04:00
if ( ! dm_config_get_uint32 ( sn , " chunk_size " , & chunk_size ) ) {
2004-05-05 01:25:57 +04:00
log_error ( " Couldn't read chunk size for snapshot. " ) ;
return 0 ;
}
2013-10-09 16:50:51 +04:00
if ( dm_config_has_node ( sn , " merging_store " ) ) {
if ( ! ( cow_name = dm_config_find_str ( sn , " merging_store " , NULL ) ) )
return SEG_LOG_ERROR ( " Merging store must be a string in " ) ;
2010-01-13 04:35:49 +03:00
merge = 1 ;
2010-01-15 20:46:08 +03:00
}
2004-05-05 01:25:57 +04:00
2013-10-09 16:50:51 +04:00
if ( dm_config_has_node ( sn , " cow_store " ) ) {
if ( cow_name )
return SEG_LOG_ERROR ( " Both snapshot cow and merging storage were specified in " ) ;
if ( ! ( cow_name = dm_config_find_str ( sn , " cow_store " , NULL ) ) )
return SEG_LOG_ERROR ( " Cow store must be a string in " ) ;
2004-05-05 01:25:57 +04:00
}
2013-10-09 16:50:51 +04:00
if ( ! cow_name )
return SEG_LOG_ERROR ( " Snapshot cow storage not specified in " ) ;
2004-05-05 01:25:57 +04:00
2013-10-09 16:50:51 +04:00
if ( ! dm_config_has_node ( sn , " origin " ) )
return SEG_LOG_ERROR ( " Snapshot origin not specified in " ) ;
2004-05-05 01:25:57 +04:00
2013-10-09 16:50:51 +04:00
if ( ! ( org_name = dm_config_find_str ( sn , " origin " , NULL ) ) )
return SEG_LOG_ERROR ( " Snapshot origin must be a string in " ) ;
if ( ! ( cow = find_lv ( seg - > lv - > vg , cow_name ) ) )
return SEG_LOG_ERROR ( " Unknown logical volume %s specified for "
" snapshot cow store in " , cow_name ) ;
if ( ! ( org = find_lv ( seg - > lv - > vg , org_name ) ) )
return SEG_LOG_ERROR ( " Unknown logical volume %s specified for "
" snapshot origin in " , org_name ) ;
2004-05-05 01:25:57 +04:00
2010-01-13 04:35:49 +03:00
init_snapshot_seg ( seg , org , cow , chunk_size , merge ) ;
2004-05-05 01:25:57 +04:00
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 ) ;
2014-09-16 00:33:53 +04:00
2010-01-13 04:56:18 +03:00
if ( ! ( seg - > status & MERGING ) )
2010-01-13 04:35:49 +03:00
outf ( f , " cow_store = \" %s \" " , seg - > cow - > name ) ;
else
outf ( f , " merging_store = \" %s \" " , seg - > cow - > name ) ;
2004-05-05 01:25:57 +04:00
return 1 ;
}
2014-04-30 01:41:17 +04:00
# ifdef DEVMAPPER_SUPPORT
2010-01-15 19:35:26 +03:00
static int _snap_target_status_compatible ( const char * type )
{
return ( strcmp ( type , " snapshot-merge " ) = = 0 ) ;
}
2010-07-09 19:34:40 +04:00
static int _snap_target_percent ( void * * target_state __attribute__ ( ( unused ) ) ,
2014-06-09 14:08:27 +04:00
dm_percent_t * percent ,
2010-07-09 19:34:40 +04:00
struct dm_pool * mem __attribute__ ( ( unused ) ) ,
struct cmd_context * cmd __attribute__ ( ( unused ) ) ,
struct lv_segment * seg __attribute__ ( ( unused ) ) ,
2009-10-01 04:35:29 +04:00
char * params , uint64_t * total_numerator ,
uint64_t * total_denominator )
2004-05-05 01:25:57 +04:00
{
2013-05-26 19:04:14 +04:00
struct dm_status_snapshot * s ;
if ( ! dm_get_status_snapshot ( mem , params , & s ) )
return_0 ;
if ( s - > invalid )
2014-06-09 14:08:27 +04:00
* percent = DM_PERCENT_INVALID ;
2013-05-26 19:04:14 +04:00
else if ( s - > merge_failed )
2014-06-09 14:08:27 +04:00
* percent = LVM_PERCENT_MERGE_FAILED ;
2013-05-26 19:04:14 +04:00
else {
* total_numerator + = s - > used_sectors ;
* total_denominator + = s - > total_sectors ;
if ( s - > has_metadata_sectors & &
s - > used_sectors = = s - > metadata_sectors )
2014-06-09 14:08:27 +04:00
* percent = DM_PERCENT_0 ;
2013-05-26 19:04:14 +04:00
else if ( s - > used_sectors = = s - > total_sectors )
2014-06-09 14:08:27 +04:00
* percent = DM_PERCENT_100 ;
2009-10-01 04:35:29 +04:00
else
2014-06-09 14:08:27 +04:00
* percent = dm_make_percent ( * total_numerator , * total_denominator ) ;
2012-01-21 02:02:04 +04:00
}
2004-05-05 01:25:57 +04:00
return 1 ;
}
2009-02-28 23:04:24 +03:00
static int _snap_target_present ( struct cmd_context * cmd ,
2010-01-13 04:39:44 +03:00
const struct lv_segment * seg ,
2014-02-25 22:43:07 +04:00
unsigned * attributes )
2004-05-05 22:11:43 +04:00
{
2006-04-19 19:33:07 +04:00
static int _snap_checked = 0 ;
2010-01-13 04:39:44 +03:00
static int _snap_merge_checked = 0 ;
2006-04-19 19:33:07 +04:00
static int _snap_present = 0 ;
2010-01-13 04:39:44 +03:00
static int _snap_merge_present = 0 ;
2014-02-25 22:43:07 +04:00
static unsigned _snap_attrs = 0 ;
uint32_t maj , min , patchlevel ;
2004-05-05 22:11:43 +04:00
2010-01-13 04:39:44 +03:00
if ( ! _snap_checked ) {
2014-02-25 22:43:07 +04:00
_snap_checked = 1 ;
2009-02-28 23:04:24 +03:00
_snap_present = target_present ( cmd , " snapshot " , 1 ) & &
target_present ( cmd , " snapshot-origin " , 0 ) ;
2014-02-25 22:43:07 +04:00
if ( _snap_present & &
target_version ( " snapshot " , & maj , & min , & patchlevel ) & &
( maj > 1 | |
( maj = = 1 & & ( min > = 12 | | ( min = = 10 & & patchlevel > = 2 ) ) ) ) )
_snap_attrs | = SNAPSHOT_FEATURE_FIXED_LEAK ;
else
log_very_verbose ( " Target snapshot may leak metadata. " ) ;
2010-01-13 04:39:44 +03:00
}
2004-05-05 22:11:43 +04:00
2014-02-27 15:55:50 +04:00
if ( attributes )
* attributes = _snap_attrs ;
2014-02-25 22:43:07 +04:00
/* TODO: test everything at once */
2013-05-16 10:12:37 +04:00
if ( seg & & ( seg - > status & MERGING ) ) {
if ( ! _snap_merge_checked ) {
_snap_merge_present = target_present ( cmd , " snapshot-merge " , 0 ) ;
_snap_merge_checked = 1 ;
}
2010-01-13 04:39:44 +03:00
return _snap_present & & _snap_merge_present ;
}
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
2014-04-30 01:41:17 +04:00
# ifdef DMEVENTD
2008-01-09 18:32:19 +03:00
2010-08-17 02:54:35 +04:00
static const char * _get_snapshot_dso_path ( struct cmd_context * cmd )
2008-01-09 18:32:19 +03:00
{
2013-06-25 14:29:54 +04:00
return get_monitor_dso_path ( cmd , find_config_tree_str ( cmd , dmeventd_snapshot_library_CFG , NULL ) ) ;
2008-01-09 18:32:19 +03:00
}
2010-08-17 05:16:41 +04:00
/* FIXME Cache this */
2008-01-09 18:32:19 +03:00
static int _target_registered ( struct lv_segment * seg , int * pending )
{
2010-08-17 02:54:35 +04:00
return target_registered_with_dmeventd ( seg - > lv - > vg - > cmd , _get_snapshot_dso_path ( seg - > lv - > vg - > cmd ) ,
2010-08-17 05:16:41 +04:00
seg - > cow , pending ) ;
2008-01-09 18:32:19 +03:00
}
/* FIXME This gets run while suspended and performs banned operations. */
2010-08-17 02:54:35 +04:00
static int _target_set_events ( struct lv_segment * seg , int evmask , int set )
2008-01-09 18:32:19 +03:00
{
2010-08-17 02:54:35 +04:00
/* FIXME Make timeout (10) configurable */
return target_register_events ( seg - > lv - > vg - > cmd , _get_snapshot_dso_path ( seg - > lv - > vg - > cmd ) ,
2010-08-17 05:16:41 +04:00
seg - > cow , evmask , set , 10 ) ;
2008-01-09 18:32:19 +03:00
}
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 ) ;
}
2014-04-30 01:41:17 +04:00
# endif /* DMEVENTD */
2004-05-05 22:11:43 +04:00
2006-10-03 21:55:20 +04:00
static int _snap_modules_needed ( struct dm_pool * mem ,
2010-07-09 19:34:40 +04:00
const struct lv_segment * seg __attribute__ ( ( unused ) ) ,
2008-11-04 01:14:30 +03:00
struct dm_list * modules )
2006-10-03 21:55:20 +04:00
{
if ( ! str_list_add ( mem , modules , " snapshot " ) ) {
log_error ( " snapshot string list allocation failed " ) ;
return 0 ;
}
return 1 ;
}
2014-04-30 01:41:17 +04:00
# endif /* DEVMAPPER_SUPPORT */
2006-10-03 21:55:20 +04:00
2010-12-20 16:32:49 +03:00
static void _snap_destroy ( struct segment_type * segtype )
2004-05-05 01:25:57 +04:00
{
2010-12-20 16:32:49 +03:00
dm_free ( segtype ) ;
2004-05-05 01:25:57 +04:00
}
static struct segtype_handler _snapshot_ops = {
2010-10-14 01:26:37 +04:00
. target_name = _snap_target_name ,
2006-05-10 01:23:51 +04:00
. text_import = _snap_text_import ,
. text_export = _snap_text_export ,
2004-05-05 22:11:43 +04:00
# ifdef DEVMAPPER_SUPPORT
2014-04-30 01:41:17 +04:00
. target_status_compatible = _snap_target_status_compatible ,
2006-05-10 01:23:51 +04:00
. target_percent = _snap_target_percent ,
. target_present = _snap_target_present ,
2014-04-30 01:41:17 +04:00
. modules_needed = _snap_modules_needed ,
2011-04-29 04:21:13 +04:00
# ifdef DMEVENTD
2008-01-09 18:32:19 +03:00
. target_monitored = _target_registered ,
. target_monitor_events = _target_register_events ,
. target_unmonitor_events = _target_unregister_events ,
2011-04-29 04:21:13 +04:00
# endif /* DMEVENTD */
2004-05-05 22:11:43 +04:00
# endif
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
{
2011-03-26 00:59:42 +03:00
struct segment_type * segtype = dm_zalloc ( sizeof ( * segtype ) ) ;
2004-05-05 01:25:57 +04:00
2008-01-30 16:19:47 +03:00
if ( ! segtype )
return_NULL ;
2004-05-05 01:25:57 +04:00
segtype - > ops = & _snapshot_ops ;
2015-09-22 21:04:12 +03:00
segtype - > name = SEG_TYPE_NAME_SNAPSHOT ;
2014-11-10 20:44:37 +03:00
segtype - > flags = SEG_SNAPSHOT | SEG_CANNOT_BE_ZEROED | SEG_ONLY_EXCLUSIVE ;
2004-05-05 01:25:57 +04:00
2011-02-18 17:29:39 +03:00
# ifdef DEVMAPPER_SUPPORT
2011-04-29 04:21:13 +04:00
# ifdef DMEVENTD
2010-08-17 02:54:35 +04:00
if ( _get_snapshot_dso_path ( cmd ) )
2008-01-09 18:32:19 +03:00
segtype - > flags | = SEG_MONITORED ;
2011-04-29 04:21:13 +04:00
# endif /* DMEVENTD */
2008-01-09 18:32:19 +03:00
# 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 ;
}