2011-08-24 12:27:49 +04:00
/*
2012-01-19 19:21:23 +04:00
* Copyright ( C ) 2011 - 2012 Red Hat , Inc . All rights reserved .
2011-08-24 12:27:49 +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
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* 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"
# include "segtype.h"
# include "text_export.h"
# include "config.h"
# include "activate.h"
# include "str_list.h"
2011-12-21 17:08:11 +04:00
# include "defaults.h"
2011-08-24 12:27:49 +04:00
# ifdef DMEVENTD
# include "libdevmapper-event.h"
# endif
/* Dm kernel module name for thin provisiong */
# define THIN_MODULE "thin-pool"
2011-08-26 17:37:47 +04:00
/*
* Macro used as return argument - returns 0.
* return is left to be written in the function for better readability .
*/
# define SEG_LOG_ERROR(t, p...) \
log_error ( t " segment %s of logical volume %s. " , # # p , \
2011-08-30 18:55:15 +04:00
dm_config_parent_name ( sn ) , seg - > lv - > name ) , 0 ;
2011-08-26 17:37:47 +04:00
2012-06-28 16:47:34 +04:00
static int _thin_target_present ( struct cmd_context * cmd ,
const struct lv_segment * seg ,
unsigned * attributes ) ;
2011-08-25 14:00:09 +04:00
static const char * _thin_pool_name ( const struct lv_segment * seg )
{
return seg - > segtype - > name ;
}
2011-10-17 18:17:09 +04:00
static int _thin_pool_add_message ( struct lv_segment * seg ,
const char * key ,
const struct dm_config_node * sn )
{
const char * lv_name = NULL ;
struct logical_volume * lv = NULL ;
2011-11-03 18:37:23 +04:00
uint32_t delete_id = 0 ;
2011-10-17 18:17:09 +04:00
dm_thin_message_t type ;
2012-03-03 01:43:26 +04:00
/* Message must have only one from: create, delete */
2011-10-17 18:17:09 +04:00
if ( dm_config_get_str ( sn , " create " , & lv_name ) ) {
if ( ! ( lv = find_lv ( seg - > lv - > vg , lv_name ) ) )
return SEG_LOG_ERROR ( " Unknown LV %s for create message in " ,
lv_name ) ;
/* FIXME: switch to _SNAP later, if the created LV has an origin */
type = DM_THIN_MESSAGE_CREATE_THIN ;
}
2011-11-03 18:37:23 +04:00
if ( ! dm_config_get_uint32 ( sn , " delete " , & delete_id ) ) {
2011-10-17 18:17:09 +04:00
if ( ! lv )
return SEG_LOG_ERROR ( " Unknown message in " ) ;
} else {
if ( lv )
return SEG_LOG_ERROR ( " Unsupported message format in " ) ;
type = DM_THIN_MESSAGE_DELETE ;
}
2011-11-03 18:37:23 +04:00
if ( ! attach_pool_message ( seg , type , lv , delete_id , 1 ) )
2011-10-17 18:17:09 +04:00
return_0 ;
return 1 ;
}
2011-10-11 12:51:56 +04:00
static int _thin_pool_text_import ( struct lv_segment * seg ,
const struct dm_config_node * sn ,
struct dm_hash_table * pv_hash __attribute__ ( ( unused ) ) )
2011-08-25 14:00:09 +04:00
{
2011-09-01 14:16:32 +04:00
const char * lv_name ;
2011-09-07 02:43:56 +04:00
struct logical_volume * pool_data_lv , * pool_metadata_lv ;
2012-08-08 00:24:41 +04:00
const char * discards_str = NULL ;
2011-08-26 17:37:47 +04:00
2011-09-01 14:16:32 +04:00
if ( ! dm_config_get_str ( sn , " metadata " , & lv_name ) )
2011-09-07 02:35:44 +04:00
return SEG_LOG_ERROR ( " Metadata must be a string in " ) ;
2011-08-26 17:37:47 +04:00
2011-09-07 02:43:56 +04:00
if ( ! ( pool_metadata_lv = find_lv ( seg - > lv - > vg , lv_name ) ) )
2011-09-07 02:35:44 +04:00
return SEG_LOG_ERROR ( " Unknown metadata %s in " , lv_name ) ;
2011-08-26 17:37:47 +04:00
2011-10-22 20:45:25 +04:00
if ( ! dm_config_get_str ( sn , " pool " , & lv_name ) )
return SEG_LOG_ERROR ( " Pool must be a string in " ) ;
2011-09-07 02:43:56 +04:00
2011-10-22 20:45:25 +04:00
if ( ! ( pool_data_lv = find_lv ( seg - > lv - > vg , lv_name ) ) )
return SEG_LOG_ERROR ( " Unknown pool %s in " , lv_name ) ;
seg - > lv - > status | = THIN_POOL ;
2011-09-08 20:41:18 +04:00
if ( ! attach_pool_metadata_lv ( seg , pool_metadata_lv ) )
2011-09-07 02:43:56 +04:00
return_0 ;
2011-10-22 20:45:25 +04:00
if ( ! attach_pool_data_lv ( seg , pool_data_lv ) )
return_0 ;
2011-08-30 18:55:15 +04:00
if ( ! dm_config_get_uint64 ( sn , " transaction_id " , & seg - > transaction_id ) )
2011-08-26 17:37:47 +04:00
return SEG_LOG_ERROR ( " Could not read transaction_id for " ) ;
2012-01-24 04:55:03 +04:00
if ( ! dm_config_get_uint32 ( sn , " chunk_size " , & seg - > chunk_size ) )
return SEG_LOG_ERROR ( " Could not read chunk_size " ) ;
2011-10-22 20:45:25 +04:00
2012-08-08 00:24:41 +04:00
if ( dm_config_has_node ( sn , " discards " ) & &
2012-08-08 00:59:06 +04:00
! dm_config_get_str ( sn , " discards " , & discards_str ) )
2012-08-08 00:24:41 +04:00
return SEG_LOG_ERROR ( " Could not read discards for " ) ;
2012-06-28 16:47:34 +04:00
2012-08-08 00:24:41 +04:00
if ( ! discards_str )
2012-08-09 13:24:37 +04:00
seg - > discards = THIN_DISCARDS_IGNORE ;
2012-08-08 00:24:41 +04:00
else if ( ! get_pool_discards ( discards_str , & seg - > discards ) )
return SEG_LOG_ERROR ( " Discards option unsupported for " ) ;
2012-06-28 16:47:34 +04:00
2011-10-20 14:30:39 +04:00
if ( dm_config_has_node ( sn , " low_water_mark " ) & &
! dm_config_get_uint64 ( sn , " low_water_mark " , & seg - > low_water_mark ) )
2011-09-29 12:56:38 +04:00
return SEG_LOG_ERROR ( " Could not read low_water_mark " ) ;
2012-01-24 04:55:03 +04:00
if ( ( seg - > chunk_size < DM_THIN_MIN_DATA_BLOCK_SIZE ) | |
( seg - > chunk_size > DM_THIN_MAX_DATA_BLOCK_SIZE ) )
return SEG_LOG_ERROR ( " Unsupported value %u for chunk_size " ,
2011-10-06 15:06:36 +04:00
seg - > device_id ) ;
2011-09-01 14:16:32 +04:00
if ( dm_config_has_node ( sn , " zero_new_blocks " ) & &
2011-08-30 18:55:15 +04:00
! dm_config_get_uint32 ( sn , " zero_new_blocks " , & seg - > zero_new_blocks ) )
2011-08-26 17:37:47 +04:00
return SEG_LOG_ERROR ( " Could not read zero_new_blocks for " ) ;
2011-10-17 18:17:09 +04:00
/* Read messages */
for ( ; sn ; sn = sn - > sib )
if ( ! ( sn - > v ) & & ! _thin_pool_add_message ( seg , sn - > key , sn - > child ) )
return_0 ;
2011-09-08 20:41:18 +04:00
return 1 ;
}
static int _thin_pool_text_import_area_count ( const struct dm_config_node * sn ,
uint32_t * area_count )
{
* area_count = 1 ;
2011-08-25 14:00:09 +04:00
return 1 ;
}
static int _thin_pool_text_export ( const struct lv_segment * seg , struct formatter * f )
{
2011-10-17 18:17:09 +04:00
unsigned cnt = 0 ;
2011-10-20 14:31:27 +04:00
const struct lv_thin_message * tmsg ;
2011-10-17 18:17:09 +04:00
2012-01-19 19:23:50 +04:00
outf ( f , " metadata = \" %s \" " , seg - > metadata_lv - > name ) ;
2011-10-22 20:45:25 +04:00
outf ( f , " pool = \" %s \" " , seg_lv ( seg , 0 ) - > name ) ;
2011-08-26 17:37:47 +04:00
outf ( f , " transaction_id = % " PRIu64 , seg - > transaction_id ) ;
2012-01-24 04:55:03 +04:00
outsize ( f , ( uint64_t ) seg - > chunk_size ,
" chunk_size = %u " , seg - > chunk_size ) ;
2011-10-17 18:17:09 +04:00
2012-08-08 00:24:41 +04:00
switch ( seg - > discards ) {
case THIN_DISCARDS_PASSDOWN :
case THIN_DISCARDS_NO_PASSDOWN :
case THIN_DISCARDS_IGNORE :
outf ( f , " discards = \" %s \" " , get_pool_discards_name ( seg - > discards ) ) ;
2012-06-28 16:47:34 +04:00
break ;
default :
2012-08-08 00:24:41 +04:00
log_error ( INTERNAL_ERROR " Invalid discards value %d. " , seg - > discards ) ;
2012-06-28 16:47:34 +04:00
return 0 ;
}
2011-10-20 14:30:39 +04:00
if ( seg - > low_water_mark )
outf ( f , " low_water_mark = % " PRIu64 , seg - > low_water_mark ) ;
2011-08-26 17:37:47 +04:00
if ( seg - > zero_new_blocks )
outf ( f , " zero_new_blocks = 1 " ) ;
2011-10-17 18:17:09 +04:00
dm_list_iterate_items ( tmsg , & seg - > thin_messages ) {
/* Extra validation */
switch ( tmsg - > type ) {
case DM_THIN_MESSAGE_CREATE_SNAP :
case DM_THIN_MESSAGE_CREATE_THIN :
if ( ! lv_is_thin_volume ( tmsg - > u . lv ) ) {
log_error ( INTERNAL_ERROR
" LV %s is not a thin volume. " ,
tmsg - > u . lv - > name ) ;
return 0 ;
}
break ;
default :
break ;
}
if ( ! cnt )
outnl ( f ) ;
outf ( f , " message%d { " , + + cnt ) ;
out_inc_indent ( f ) ;
switch ( tmsg - > type ) {
case DM_THIN_MESSAGE_CREATE_SNAP :
case DM_THIN_MESSAGE_CREATE_THIN :
outf ( f , " create = \" %s \" " , tmsg - > u . lv - > name ) ;
break ;
case DM_THIN_MESSAGE_DELETE :
outf ( f , " delete = %d " , tmsg - > u . delete_id ) ;
break ;
default :
log_error ( INTERNAL_ERROR " Passed unsupported message. " ) ;
return 0 ;
}
out_dec_indent ( f ) ;
outf ( f , " } " ) ;
}
2011-08-25 14:00:09 +04:00
return 1 ;
}
2011-08-24 12:27:49 +04:00
2011-09-29 12:56:38 +04:00
# ifdef DEVMAPPER_SUPPORT
static int _thin_pool_add_target_line ( struct dev_manager * dm ,
2012-01-25 12:51:29 +04:00
struct dm_pool * mem ,
struct cmd_context * cmd ,
2011-10-11 12:51:56 +04:00
void * * target_state __attribute__ ( ( unused ) ) ,
struct lv_segment * seg ,
2012-01-25 12:51:29 +04:00
const struct lv_activate_opts * laopts ,
2011-10-11 12:51:56 +04:00
struct dm_tree_node * node , uint64_t len ,
uint32_t * pvmove_mirror_count __attribute__ ( ( unused ) ) )
2011-09-29 12:56:38 +04:00
{
2012-08-08 00:24:41 +04:00
static int _no_discards = 0 ;
2011-09-29 12:56:38 +04:00
char * metadata_dlid , * pool_dlid ;
2011-10-20 14:31:27 +04:00
const struct lv_thin_message * lmsg ;
2011-11-10 19:30:59 +04:00
const struct logical_volume * origin ;
2012-01-25 13:06:43 +04:00
struct lvinfo info ;
uint64_t transaction_id = 0 ;
2012-06-28 16:47:34 +04:00
unsigned attr ;
if ( ! _thin_target_present ( cmd , seg , & attr ) )
return_0 ;
2011-09-29 12:56:38 +04:00
2012-02-02 17:37:51 +04:00
if ( ! ( attr & THIN_FEATURE_BLOCK_SIZE ) & &
( seg - > chunk_size & ( seg - > chunk_size - 1 ) ) ) {
log_error ( " Thin pool target does not support %uKiB chunk size "
" (needs kernel >= 3.5). " , seg - > chunk_size / 2 ) ;
return 0 ;
}
2011-11-03 18:52:09 +04:00
if ( ! laopts - > real_pool ) {
if ( ! ( pool_dlid = build_dm_uuid ( mem , seg - > lv - > lvid . s , " tpool " ) ) ) {
log_error ( " Failed to build uuid for thin pool LV %s. " , seg - > pool_lv - > name ) ;
return 0 ;
}
2011-11-29 00:37:51 +04:00
if ( ! add_linear_area_to_dtree ( node , len , seg - > lv - > vg - > extent_size ,
cmd - > use_linear_target ,
seg - > lv - > vg - > name , seg - > lv - > name ) | |
2011-11-03 18:52:09 +04:00
! dm_tree_node_add_target_area ( node , NULL , pool_dlid , 0 ) )
return_0 ;
return 1 ;
}
2012-01-19 19:23:50 +04:00
if ( ! ( metadata_dlid = build_dm_uuid ( mem , seg - > metadata_lv - > lvid . s , NULL ) ) ) {
2011-10-17 18:17:30 +04:00
log_error ( " Failed to build uuid for metadata LV %s. " ,
2012-01-19 19:23:50 +04:00
seg - > metadata_lv - > name ) ;
2011-09-29 12:56:38 +04:00
return 0 ;
}
if ( ! ( pool_dlid = build_dm_uuid ( mem , seg_lv ( seg , 0 ) - > lvid . s , NULL ) ) ) {
2011-10-17 18:17:30 +04:00
log_error ( " Failed to build uuid for pool LV %s. " ,
seg_lv ( seg , 0 ) - > name ) ;
2011-09-29 12:56:38 +04:00
return 0 ;
}
2011-10-17 18:17:09 +04:00
if ( ! dm_tree_node_add_thin_pool_target ( node , len , seg - > transaction_id ,
metadata_dlid , pool_dlid ,
2012-01-24 04:55:03 +04:00
seg - > chunk_size , seg - > low_water_mark ,
2011-09-29 12:56:38 +04:00
seg - > zero_new_blocks ? 0 : 1 ) )
return_0 ;
2012-08-09 13:25:41 +04:00
if ( attr & THIN_FEATURE_DISCARDS ) {
2012-08-08 00:59:06 +04:00
/* FIXME: Check whether underlying dev supports discards */
if ( ! dm_tree_node_set_thin_pool_discard ( node ,
seg - > discards = = THIN_DISCARDS_IGNORE ,
seg - > discards = = THIN_DISCARDS_NO_PASSDOWN ) )
return_0 ;
2012-08-09 13:25:41 +04:00
} else if ( seg - > discards ! = THIN_DISCARDS_IGNORE )
2012-08-08 00:59:06 +04:00
log_warn_suppress ( _no_discards + + , " WARNING: Thin pool target does "
" not support discards (needs kernel >= 3.4). " ) ;
2012-06-28 16:47:34 +04:00
2012-01-25 13:06:43 +04:00
/*
* Add messages only for activation tree .
* Otherwise avoid checking for existence of suspended origin .
* Also transation_id is checked only when snapshot origin is active .
* ( This might change later )
*/
if ( ! laopts - > is_activate )
return 1 ;
2011-10-20 14:32:29 +04:00
dm_list_iterate_items ( lmsg , & seg - > thin_messages ) {
switch ( lmsg - > type ) {
case DM_THIN_MESSAGE_CREATE_THIN :
2011-11-10 19:30:59 +04:00
origin = first_seg ( lmsg - > u . lv ) - > origin ;
2012-01-25 13:06:43 +04:00
/* Check if the origin is suspended */
if ( origin & & lv_info ( cmd , origin , 0 , & info , 0 , 0 ) & &
info . exists & & ! info . suspended ) {
/* Origin is not suspended, but the transaction may have been
* already transfered , so test for transaction_id and
* allow to pass in the message for dmtree processing
* so it will skip all messages later .
*/
if ( ! lv_thin_pool_transaction_id ( seg - > lv , & transaction_id ) )
return_0 ; /* Thin pool should exist and work */
if ( transaction_id ! = seg - > transaction_id ) {
log_error ( " Can't create snapshot %s as origin %s is not suspended. " ,
lmsg - > u . lv - > name , origin - > name ) ;
return 0 ;
}
}
2011-11-10 19:30:59 +04:00
log_debug ( " Thin pool create_%s %s. " , ( ! origin ) ? " thin " : " snap " , lmsg - > u . lv - > name ) ;
2011-11-03 18:45:01 +04:00
if ( ! dm_tree_node_add_thin_pool_message ( node ,
2011-11-10 19:30:59 +04:00
( ! origin ) ? lmsg - > type : DM_THIN_MESSAGE_CREATE_SNAP ,
2011-11-03 18:45:01 +04:00
first_seg ( lmsg - > u . lv ) - > device_id ,
2011-11-10 19:30:59 +04:00
( ! origin ) ? 0 : first_seg ( origin ) - > device_id ) )
2011-10-20 14:32:29 +04:00
return_0 ;
break ;
case DM_THIN_MESSAGE_DELETE :
log_debug ( " Thin pool delete %u. " , lmsg - > u . delete_id ) ;
2011-11-03 18:45:01 +04:00
if ( ! dm_tree_node_add_thin_pool_message ( node ,
lmsg - > type ,
lmsg - > u . delete_id , 0 ) )
2011-10-20 14:32:29 +04:00
return_0 ;
break ;
default :
log_error ( INTERNAL_ERROR " Unsupported message. " ) ;
return 0 ;
2011-10-17 18:17:09 +04:00
}
2011-10-20 14:32:29 +04:00
}
2011-10-17 18:17:09 +04:00
2011-10-20 14:32:29 +04:00
if ( ! dm_list_empty ( & seg - > thin_messages ) ) {
/* Messages were passed, modify transaction_id as the last one */
2011-11-03 18:45:01 +04:00
log_debug ( " Thin pool set transaction id % " PRIu64 " . " , seg - > transaction_id ) ;
if ( ! dm_tree_node_add_thin_pool_message ( node ,
DM_THIN_MESSAGE_SET_TRANSACTION_ID ,
seg - > transaction_id - 1 ,
seg - > transaction_id ) )
2011-10-17 18:17:09 +04:00
return_0 ;
}
2011-09-29 12:56:38 +04:00
return 1 ;
}
2011-12-21 17:08:11 +04:00
static int _thin_pool_target_percent ( void * * target_state __attribute__ ( ( unused ) ) ,
percent_t * percent ,
struct dm_pool * mem ,
struct cmd_context * cmd __attribute__ ( ( unused ) ) ,
2012-01-19 19:21:23 +04:00
struct lv_segment * seg ,
2011-12-21 17:08:11 +04:00
char * params ,
uint64_t * total_numerator ,
uint64_t * total_denominator )
{
struct dm_status_thin_pool * s ;
if ( ! dm_get_status_thin_pool ( mem , params , & s ) )
return_0 ;
2012-01-19 19:42:18 +04:00
/* With 'seg' report metadata percent, otherwice data percent */
2012-01-19 19:21:23 +04:00
if ( seg ) {
* percent = make_percent ( s - > used_metadata_blocks ,
s - > total_metadata_blocks ) ;
* total_numerator + = s - > used_metadata_blocks ;
* total_denominator + = s - > total_metadata_blocks ;
} else {
* percent = make_percent ( s - > used_data_blocks ,
s - > total_data_blocks ) ;
* total_numerator + = s - > used_data_blocks ;
* total_denominator + = s - > total_data_blocks ;
}
2011-12-21 17:08:11 +04:00
return 1 ;
}
2012-03-20 21:42:19 +04:00
# ifdef DMEVENTD
static const char * _get_thin_dso_path ( struct cmd_context * cmd )
{
return get_monitor_dso_path ( cmd , find_config_tree_str ( cmd , " dmeventd/thin_library " ,
DEFAULT_DMEVENTD_THIN_LIB ) ) ;
}
/* FIXME Cache this */
static int _target_registered ( struct lv_segment * seg , int * pending )
{
return target_registered_with_dmeventd ( seg - > lv - > vg - > cmd ,
_get_thin_dso_path ( seg - > lv - > vg - > cmd ) ,
seg - > lv , pending ) ;
}
/* FIXME This gets run while suspended and performs banned operations. */
static int _target_set_events ( struct lv_segment * seg , int evmask , int set )
{
/* FIXME Make timeout (10) configurable */
return target_register_events ( seg - > lv - > vg - > cmd ,
_get_thin_dso_path ( seg - > lv - > vg - > cmd ) ,
seg - > lv , evmask , set , 10 ) ;
}
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 */
2011-12-21 17:08:11 +04:00
# endif /* DEVMAPPER_SUPPORT */
2011-09-29 12:56:38 +04:00
2011-08-24 12:27:49 +04:00
static const char * _thin_name ( const struct lv_segment * seg )
{
return seg - > segtype - > name ;
}
2011-10-11 12:51:56 +04:00
static int _thin_text_import ( struct lv_segment * seg ,
const struct dm_config_node * sn ,
struct dm_hash_table * pv_hash __attribute__ ( ( unused ) ) )
2011-08-24 12:27:49 +04:00
{
2011-09-01 14:16:32 +04:00
const char * lv_name ;
2011-11-07 15:03:47 +04:00
struct logical_volume * pool_lv , * origin = NULL ;
2011-08-26 17:37:47 +04:00
2011-09-01 14:16:32 +04:00
if ( ! dm_config_get_str ( sn , " thin_pool " , & lv_name ) )
2011-08-26 17:37:47 +04:00
return SEG_LOG_ERROR ( " Thin pool must be a string in " ) ;
2011-09-07 02:43:56 +04:00
if ( ! ( pool_lv = find_lv ( seg - > lv - > vg , lv_name ) ) )
2011-09-01 14:16:32 +04:00
return SEG_LOG_ERROR ( " Unknown thin pool %s in " , lv_name ) ;
2011-08-26 17:37:47 +04:00
2011-10-21 15:38:35 +04:00
if ( ! dm_config_get_uint64 ( sn , " transaction_id " , & seg - > transaction_id ) )
return SEG_LOG_ERROR ( " Could not read transaction_id for " ) ;
2011-09-01 14:16:32 +04:00
if ( dm_config_has_node ( sn , " origin " ) ) {
if ( ! dm_config_get_str ( sn , " origin " , & lv_name ) )
2011-09-07 02:35:44 +04:00
return SEG_LOG_ERROR ( " Origin must be a string in " ) ;
2011-08-26 17:37:47 +04:00
2011-11-07 15:03:47 +04:00
if ( ! ( origin = find_lv ( seg - > lv - > vg , lv_name ) ) )
2011-09-01 14:16:32 +04:00
return SEG_LOG_ERROR ( " Unknown origin %s in " , lv_name ) ;
2011-08-26 17:37:47 +04:00
}
2011-09-29 12:56:38 +04:00
if ( ! dm_config_get_uint32 ( sn , " device_id " , & seg - > device_id ) )
2011-08-26 17:37:47 +04:00
return SEG_LOG_ERROR ( " Could not read device_id for " ) ;
2011-10-06 15:06:36 +04:00
if ( seg - > device_id > DM_THIN_MAX_DEVICE_ID )
return SEG_LOG_ERROR ( " Unsupported value %u for device_id " ,
seg - > device_id ) ;
2011-11-07 15:03:47 +04:00
if ( ! attach_pool_lv ( seg , pool_lv , origin ) )
return_0 ;
2011-08-24 12:27:49 +04:00
return 1 ;
}
static int _thin_text_export ( const struct lv_segment * seg , struct formatter * f )
{
2011-09-07 02:43:56 +04:00
outf ( f , " thin_pool = \" %s \" " , seg - > pool_lv - > name ) ;
2011-10-21 15:38:35 +04:00
outf ( f , " transaction_id = % " PRIu64 , seg - > transaction_id ) ;
2011-09-29 12:56:38 +04:00
outf ( f , " device_id = %d " , seg - > device_id ) ;
2011-08-26 17:37:47 +04:00
2011-08-26 21:40:53 +04:00
if ( seg - > origin )
outf ( f , " origin = \" %s \" " , seg - > origin - > name ) ;
2011-08-26 17:37:47 +04:00
2011-08-24 12:27:49 +04:00
return 1 ;
}
# ifdef DEVMAPPER_SUPPORT
2011-09-29 12:56:38 +04:00
static int _thin_add_target_line ( struct dev_manager * dm ,
2011-10-31 02:00:57 +04:00
struct dm_pool * mem ,
2011-09-29 12:56:38 +04:00
struct cmd_context * cmd __attribute__ ( ( unused ) ) ,
void * * target_state __attribute__ ( ( unused ) ) ,
struct lv_segment * seg ,
const struct lv_activate_opts * laopts __attribute__ ( ( unused ) ) ,
struct dm_tree_node * node , uint64_t len ,
uint32_t * pvmove_mirror_count __attribute__ ( ( unused ) ) )
{
2011-11-03 18:52:09 +04:00
char * pool_dlid ;
uint32_t device_id = seg - > device_id ;
2011-09-29 12:56:38 +04:00
2011-11-03 18:52:09 +04:00
if ( ! ( pool_dlid = build_dm_uuid ( mem , seg - > pool_lv - > lvid . s , " tpool " ) ) ) {
log_error ( " Failed to build uuid for pool LV %s. " ,
seg - > pool_lv - > name ) ;
2011-09-29 12:56:38 +04:00
return 0 ;
}
2011-11-03 18:52:09 +04:00
if ( ! dm_tree_node_add_thin_target ( node , len , pool_dlid , device_id ) )
2011-09-29 12:56:38 +04:00
return_0 ;
return 1 ;
}
2012-01-19 19:27:54 +04:00
static int _thin_target_percent ( void * * target_state __attribute__ ( ( unused ) ) ,
percent_t * percent ,
struct dm_pool * mem ,
struct cmd_context * cmd __attribute__ ( ( unused ) ) ,
struct lv_segment * seg ,
char * params ,
uint64_t * total_numerator ,
uint64_t * total_denominator )
{
struct dm_status_thin * s ;
/* Status for thin device is in sectors */
if ( ! dm_get_status_thin ( mem , params , & s ) )
return_0 ;
if ( seg ) {
* percent = make_percent ( s - > mapped_sectors , seg - > lv - > size ) ;
* total_denominator + = seg - > lv - > size ;
} else {
/* No lv_segment info here */
* percent = PERCENT_INVALID ;
/* FIXME: Using denominator to pass the mapped info upward? */
* total_denominator + = s - > highest_mapped_sector ;
}
* total_numerator + = s - > mapped_sectors ;
return 1 ;
}
2011-08-24 12:27:49 +04:00
static int _thin_target_present ( struct cmd_context * cmd ,
const struct lv_segment * seg ,
2012-05-25 15:38:03 +04:00
unsigned * attributes )
2011-08-24 12:27:49 +04:00
{
static int _checked = 0 ;
static int _present = 0 ;
2012-05-25 15:38:03 +04:00
static int _attrs = 0 ;
uint32_t maj , min , patchlevel ;
2011-08-24 12:27:49 +04:00
if ( ! _checked ) {
2011-08-25 14:00:09 +04:00
_present = target_present ( cmd , THIN_MODULE , 1 ) ;
2012-05-25 15:38:03 +04:00
if ( ! target_version ( THIN_MODULE , & maj , & min , & patchlevel ) ) {
log_error ( " Cannot read " THIN_MODULE " target version. " ) ;
return 0 ;
}
if ( maj > = 1 & & min > = 1 )
2012-08-08 00:24:41 +04:00
_attrs | = THIN_FEATURE_DISCARDS ;
2012-05-25 15:38:03 +04:00
else
2012-08-07 23:40:19 +04:00
/* FIXME Log this as WARNING later only if the user asked for the feature to be used but it's not present */
log_debug ( " Target " THIN_MODULE " does not support discards. " ) ;
2012-05-25 15:38:03 +04:00
if ( maj > = 1 & & min > = 1 )
_attrs | = THIN_FEATURE_EXTERNAL_ORIGIN ;
else
2012-08-07 23:40:19 +04:00
/* FIXME Log this as WARNING later only if the user asked for the feature to be used but it's not present */
log_debug ( " Target " THIN_MODULE " does not support external origins. " ) ;
2012-02-02 17:37:51 +04:00
if ( maj > = 1 & & min > = 2 )
2012-05-25 15:38:03 +04:00
_attrs | = THIN_FEATURE_BLOCK_SIZE ;
else
2012-08-07 23:40:19 +04:00
/* FIXME Log this as WARNING later only if the user asked for the feature to be used but it's not present */
log_debug ( " Target " THIN_MODULE " does not support non power of 2 block sizes. " ) ;
2012-02-02 17:37:51 +04:00
2011-08-24 12:27:49 +04:00
_checked = 1 ;
}
2012-05-25 15:38:03 +04:00
if ( attributes )
* attributes = _attrs ;
2011-08-24 12:27:49 +04:00
return _present ;
}
# endif
static int _thin_modules_needed ( struct dm_pool * mem ,
const struct lv_segment * seg __attribute__ ( ( unused ) ) ,
struct dm_list * modules )
{
if ( ! str_list_add ( mem , modules , THIN_MODULE ) ) {
log_error ( " thin string list allocation failed " ) ;
return 0 ;
}
return 1 ;
}
static void _thin_destroy ( struct segment_type * segtype )
{
dm_free ( segtype ) ;
}
2011-08-25 14:00:09 +04:00
static struct segtype_handler _thin_pool_ops = {
. name = _thin_pool_name ,
. text_import = _thin_pool_text_import ,
2011-09-08 20:41:18 +04:00
. text_import_area_count = _thin_pool_text_import_area_count ,
2011-08-25 14:00:09 +04:00
. text_export = _thin_pool_text_export ,
2011-09-29 12:56:38 +04:00
# ifdef DEVMAPPER_SUPPORT
. add_target_line = _thin_pool_add_target_line ,
2011-12-21 17:08:11 +04:00
. target_percent = _thin_pool_target_percent ,
2011-09-29 12:56:38 +04:00
. target_present = _thin_target_present ,
2012-03-20 21:42:19 +04:00
# ifdef DMEVENTD
. target_monitored = _target_registered ,
. target_monitor_events = _target_register_events ,
. target_unmonitor_events = _target_unregister_events ,
# endif /* DMEVENTD */
2011-09-29 12:56:38 +04:00
# endif
2011-08-25 14:00:09 +04:00
. modules_needed = _thin_modules_needed ,
. destroy = _thin_destroy ,
} ;
2011-08-24 12:27:49 +04:00
static struct segtype_handler _thin_ops = {
. name = _thin_name ,
. text_import = _thin_text_import ,
. text_export = _thin_text_export ,
# ifdef DEVMAPPER_SUPPORT
2011-09-29 12:56:38 +04:00
. add_target_line = _thin_add_target_line ,
2012-01-19 19:27:54 +04:00
. target_percent = _thin_target_percent ,
2011-08-24 12:27:49 +04:00
. target_present = _thin_target_present ,
# endif
. modules_needed = _thin_modules_needed ,
. destroy = _thin_destroy ,
} ;
# ifdef THIN_INTERNAL
2011-08-25 14:00:09 +04:00
int init_thin_segtypes ( struct cmd_context * cmd , struct segtype_library * seglib )
# else /* Shared */
int init_multiple_segtypes ( struct cmd_context * cmd , struct segtype_library * seglib ) ;
int init_multiple_segtypes ( struct cmd_context * cmd , struct segtype_library * seglib )
2011-08-24 12:27:49 +04:00
# endif
{
2011-08-25 14:00:09 +04:00
static const struct {
struct segtype_handler * ops ;
const char name [ 16 ] ;
uint32_t flags ;
} reg_segtypes [ ] = {
2011-12-21 16:54:19 +04:00
{ & _thin_pool_ops , " thin-pool " , SEG_THIN_POOL } ,
2011-09-06 04:26:42 +04:00
/* FIXME Maybe use SEG_THIN_VOLUME instead of SEG_VIRTUAL */
{ & _thin_ops , " thin " , SEG_THIN_VOLUME | SEG_VIRTUAL }
2011-08-25 14:00:09 +04:00
} ;
struct segment_type * segtype ;
unsigned i ;
for ( i = 0 ; i < sizeof ( reg_segtypes ) / sizeof ( reg_segtypes [ 0 ] ) ; + + i ) {
segtype = dm_zalloc ( sizeof ( * segtype ) ) ;
if ( ! segtype ) {
log_error ( " Failed to allocate memory for %s segtype " ,
reg_segtypes [ i ] . name ) ;
return 0 ;
}
segtype - > ops = reg_segtypes [ i ] . ops ;
segtype - > name = reg_segtypes [ i ] . name ;
segtype - > flags = reg_segtypes [ i ] . flags ;
2011-08-24 12:27:49 +04:00
# ifdef DEVMAPPER_SUPPORT
# ifdef DMEVENTD
2012-02-15 17:49:51 +04:00
if ( ( reg_segtypes [ i ] . flags & SEG_THIN_POOL ) & &
_get_thin_dso_path ( cmd ) )
2011-12-21 17:08:11 +04:00
segtype - > flags | = SEG_MONITORED ;
# endif /* DMEVENTD */
2011-08-24 12:27:49 +04:00
# endif
2012-02-28 18:23:41 +04:00
if ( ! lvm_register_segtype ( seglib , segtype ) )
/* segtype is already destroyed */
2011-08-25 14:00:09 +04:00
return_0 ;
2011-08-24 12:27:49 +04:00
2011-08-25 14:00:09 +04:00
log_very_verbose ( " Initialised segtype: %s " , segtype - > name ) ;
}
return 1 ;
2011-08-24 12:27:49 +04:00
}