2014-01-27 05:27:16 -06:00
/*
2016-04-25 13:39:30 +02:00
* Copyright ( C ) 2013 - 2016 Red Hat , Inc . All rights reserved .
2014-01-27 05:27:16 -06: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 ,
2016-01-21 11:49:46 +01:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2014-01-27 05:27:16 -06:00
*/
2018-06-08 13:40:53 +01:00
# include "base/memory/zalloc.h"
2018-05-14 10:30:20 +01:00
# include "lib/misc/lib.h"
# include "lib/commands/toolcontext.h"
# include "lib/metadata/segtype.h"
# include "lib/display/display.h"
# include "lib/format_text/text_export.h"
# include "lib/config/config.h"
# include "lib/datastruct/str_list.h"
# include "lib/misc/lvm-string.h"
# include "lib/activate/activate.h"
# include "lib/metadata/metadata.h"
# include "lib/metadata/lv_alloc.h"
# include "lib/config/defaults.h"
2014-01-27 05:27:16 -06:00
2015-07-23 11:32:09 +02:00
static const char _cache_module [ ] = " cache " ;
2016-04-25 13:39:30 +02:00
# define CACHE_POLICY_WHEN_MISSING "mq"
# define CACHE_MODE_WHEN_MISSING CACHE_MODE_WRITETHROUGH
2015-07-23 11:32:09 +02:00
/* TODO: using static field here, maybe should be a part of segment_type */
static unsigned _feature_mask ;
2014-01-27 05:27:16 -06: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 ;
2017-03-02 00:15:11 +01:00
static int _cache_out_line ( const char * line , void * _f )
{
log_print ( " Setting \t \t %s " , line ) ;
return 1 ;
}
static void _cache_display ( const struct lv_segment * seg )
{
const struct dm_config_node * n ;
2018-11-05 15:56:28 -06:00
const struct lv_segment * setting_seg = NULL ;
2019-01-30 09:55:34 -06:00
if ( seg_is_cache ( seg ) & & lv_is_cache_vol ( seg - > pool_lv ) )
2018-08-17 15:45:52 -05:00
setting_seg = seg ;
else if ( seg_is_cache_pool ( seg ) )
2018-11-05 15:56:28 -06:00
setting_seg = seg ;
else if ( seg_is_cache ( seg ) )
setting_seg = first_seg ( seg - > pool_lv ) ;
else
return ;
2017-03-02 00:15:11 +01:00
log_print ( " Chunk size \t \t %s " ,
2018-11-05 15:56:28 -06:00
display_size ( seg - > lv - > vg - > cmd , setting_seg - > chunk_size ) ) ;
2017-06-22 20:05:26 +02:00
2018-11-05 15:56:28 -06:00
if ( setting_seg - > cache_metadata_format ! = CACHE_METADATA_FORMAT_UNSELECTED )
log_print ( " Metadata format \t %u " , setting_seg - > cache_metadata_format ) ;
2017-06-22 20:05:26 +02:00
2018-11-05 15:56:28 -06:00
if ( setting_seg - > cache_mode ! = CACHE_MODE_UNSELECTED )
log_print ( " Mode \t \t %s " , get_cache_mode_name ( setting_seg ) ) ;
2017-06-22 20:05:26 +02:00
2018-11-05 15:56:28 -06:00
if ( setting_seg - > policy_name )
log_print ( " Policy \t \t %s " , setting_seg - > policy_name ) ;
2017-03-02 00:15:11 +01:00
2018-11-05 15:56:28 -06:00
if ( setting_seg - > policy_settings & &
( n = setting_seg - > policy_settings - > child ) )
2017-03-02 00:15:11 +01:00
dm_config_write_node ( n , _cache_out_line , NULL ) ;
log_print ( " " ) ;
}
2015-11-15 20:03:08 +01:00
/*
* When older metadata are loaded without newer settings ,
* set then to default settings ( the one that could have been
* used implicitely at that time ) .
*
* Needs both segments cache and cache_pool to be loaded .
*/
2016-04-25 13:39:30 +02:00
static void _fix_missing_defaults ( struct lv_segment * cpool_seg )
2015-11-15 20:03:08 +01:00
{
if ( ! cpool_seg - > policy_name ) {
2016-04-25 13:39:30 +02:00
cpool_seg - > policy_name = CACHE_POLICY_WHEN_MISSING ;
log_verbose ( " Cache pool %s is missing cache policy, using %s. " ,
display_lvname ( cpool_seg - > lv ) ,
2015-11-15 20:03:08 +01:00
cpool_seg - > policy_name ) ;
}
2017-03-01 12:26:56 +01:00
if ( cpool_seg - > cache_metadata_format = = CACHE_METADATA_FORMAT_UNSELECTED ) {
cpool_seg - > cache_metadata_format = CACHE_METADATA_FORMAT_1 ;
log_verbose ( " Cache pool %s uses implicit metadata format %u. " ,
display_lvname ( cpool_seg - > lv ) , cpool_seg - > cache_metadata_format ) ;
}
2017-03-03 14:52:32 +01:00
if ( cpool_seg - > cache_mode = = CACHE_MODE_UNSELECTED ) {
2016-04-25 13:39:30 +02:00
cpool_seg - > cache_mode = CACHE_MODE_WHEN_MISSING ;
log_verbose ( " Cache pool %s is missing cache mode, using %s. " ,
display_lvname ( cpool_seg - > lv ) ,
2015-11-15 20:03:08 +01:00
get_cache_mode_name ( cpool_seg ) ) ;
}
}
2014-01-27 05:27:16 -06:00
2018-11-05 15:23:23 -06:00
static int _settings_text_import ( struct lv_segment * seg ,
const struct dm_config_node * sn )
2014-01-27 05:27:16 -06:00
{
const char * str = NULL ;
2014-11-09 20:18:00 +01:00
struct dm_pool * mem = seg - > lv - > vg - > vgmem ;
2014-01-27 05:27:16 -06:00
2018-11-05 15:23:23 -06:00
if ( dm_config_has_node ( sn , " chunk_size " ) ) {
if ( ! dm_config_get_uint32 ( sn , " chunk_size " , & seg - > chunk_size ) )
return SEG_LOG_ERROR ( " Couldn't read cache chunk_size in " ) ;
}
2014-01-27 05:27:16 -06:00
/*
* Read in features :
2014-11-09 20:18:00 +01:00
* cache_mode = { passthrough | writethrough | writeback }
2014-01-27 05:27:16 -06:00
*
* ' cache_mode ' does not have to be present .
*/
if ( dm_config_has_node ( sn , " cache_mode " ) ) {
if ( ! ( str = dm_config_find_str ( sn , " cache_mode " , NULL ) ) )
return SEG_LOG_ERROR ( " cache_mode must be a string in " ) ;
2016-04-25 13:39:30 +02:00
if ( ! set_cache_mode ( & seg - > cache_mode , str ) )
2014-01-27 05:27:16 -06:00
return SEG_LOG_ERROR ( " Unknown cache_mode in " ) ;
2015-08-11 14:01:12 +02:00
}
2014-01-27 05:27:16 -06:00
2014-11-10 23:41:03 +01:00
if ( dm_config_has_node ( sn , " policy " ) ) {
if ( ! ( str = dm_config_find_str ( sn , " policy " , NULL ) ) )
return SEG_LOG_ERROR ( " policy must be a string in " ) ;
if ( ! ( seg - > policy_name = dm_pool_strdup ( mem , str ) ) )
return SEG_LOG_ERROR ( " Failed to duplicate policy in " ) ;
2015-07-15 10:54:49 +02:00
}
2014-11-10 23:41:03 +01:00
2014-01-27 05:27:16 -06:00
/*
2014-11-09 20:18:00 +01:00
* Read in policy args :
2014-11-10 23:41:03 +01:00
* policy_settings {
2014-11-09 20:18:00 +01:00
* migration_threshold = 2048
* sequention_threashold = 100
* random_threashold = 200
* read_promote_adjustment = 10
* write_promote_adjustment = 20
* discard_promote_adjustment = 40
2014-01-27 05:27:16 -06:00
*
2014-11-09 20:18:00 +01:00
* < key > = < value >
* < key > = < value >
* . . .
* }
2014-01-27 05:27:16 -06:00
*
2014-11-09 20:18:00 +01:00
* If the policy is not present , default policy is used .
2014-01-27 05:27:16 -06:00
*/
2014-11-10 23:41:03 +01:00
if ( ( sn = dm_config_find_node ( sn , " policy_settings " ) ) ) {
2015-08-11 15:11:45 +02:00
if ( ! seg - > policy_name )
return SEG_LOG_ERROR ( " policy_settings must have a policy_name in " ) ;
2014-11-10 23:41:03 +01:00
if ( sn - > v )
return SEG_LOG_ERROR ( " policy_settings must be a section in " ) ;
2014-11-09 20:18:00 +01:00
2014-11-10 23:41:03 +01:00
if ( ! ( seg - > policy_settings = dm_config_clone_node_with_mem ( mem , sn , 0 ) ) )
return_0 ;
}
2014-01-27 05:27:16 -06:00
2018-11-05 15:23:23 -06:00
return 1 ;
}
static int _settings_text_export ( const struct lv_segment * seg ,
struct formatter * f )
{
if ( seg - > chunk_size )
outf ( f , " chunk_size = % " PRIu32 , seg - > chunk_size ) ;
if ( seg - > cache_mode ! = CACHE_MODE_UNSELECTED ) {
const char * cache_mode ;
if ( ! ( cache_mode = cache_mode_num_to_str ( seg - > cache_mode ) ) )
return_0 ;
outf ( f , " cache_mode = \" %s \" " , cache_mode ) ;
}
if ( seg - > policy_name ) {
outf ( f , " policy = \" %s \" " , seg - > policy_name ) ;
if ( seg - > policy_settings ) {
if ( strcmp ( seg - > policy_settings - > key , " policy_settings " ) ) {
log_error ( INTERNAL_ERROR " Incorrect policy_settings tree, %s. " ,
seg - > policy_settings - > key ) ;
return 0 ;
}
if ( seg - > policy_settings - > child )
out_config_node ( f , seg - > policy_settings ) ;
}
}
return 1 ;
}
static int _cache_pool_text_import ( struct lv_segment * seg ,
const struct dm_config_node * sn ,
struct dm_hash_table * pv_hash __attribute__ ( ( unused ) ) )
{
struct logical_volume * data_lv , * meta_lv ;
const char * str = NULL ;
if ( ! dm_config_has_node ( sn , " data " ) )
return SEG_LOG_ERROR ( " Cache data not specified in " ) ;
if ( ! ( str = dm_config_find_str ( sn , " data " , NULL ) ) )
return SEG_LOG_ERROR ( " Cache data must be a string in " ) ;
if ( ! ( data_lv = find_lv ( seg - > lv - > vg , str ) ) )
return SEG_LOG_ERROR ( " Unknown logical volume %s specified for "
" cache data in " , str ) ;
if ( ! dm_config_has_node ( sn , " metadata " ) )
return SEG_LOG_ERROR ( " Cache metadata not specified in " ) ;
if ( ! ( str = dm_config_find_str ( sn , " metadata " , NULL ) ) )
return SEG_LOG_ERROR ( " Cache metadata must be a string in " ) ;
if ( ! ( meta_lv = find_lv ( seg - > lv - > vg , str ) ) )
return SEG_LOG_ERROR ( " Unknown logical volume %s specified for "
" cache metadata in " , str ) ;
if ( dm_config_has_node ( sn , " metadata_format " ) ) {
if ( ! dm_config_get_uint32 ( sn , " metadata_format " , & seg - > cache_metadata_format ) | |
( ( seg - > cache_metadata_format ! = CACHE_METADATA_FORMAT_1 ) & &
( seg - > cache_metadata_format ! = CACHE_METADATA_FORMAT_2 ) ) )
return SEG_LOG_ERROR ( " Unknown cache metadata format %u number in " ,
seg - > cache_metadata_format ) ;
if ( seg - > cache_metadata_format = = CACHE_METADATA_FORMAT_2 )
seg - > lv - > status | = LV_METADATA_FORMAT ;
}
if ( ! _settings_text_import ( seg , sn ) )
return_0 ;
2014-01-27 05:27:16 -06:00
if ( ! attach_pool_data_lv ( seg , data_lv ) )
return_0 ;
if ( ! attach_pool_metadata_lv ( seg , meta_lv ) )
return_0 ;
2016-04-25 13:39:30 +02:00
/* when cache pool is used, we require policy and mode to be defined */
if ( ! dm_list_empty ( & seg - > lv - > segs_using_this_lv ) )
_fix_missing_defaults ( seg ) ;
2015-11-15 20:03:08 +01:00
2014-01-27 05:27:16 -06:00
return 1 ;
}
static int _cache_pool_text_import_area_count ( const struct dm_config_node * sn ,
uint32_t * area_count )
{
* area_count = 1 ;
return 1 ;
}
static int _cache_pool_text_export ( const struct lv_segment * seg ,
struct formatter * f )
{
outf ( f , " data = \" %s \" " , seg_lv ( seg , 0 ) - > name ) ;
outf ( f , " metadata = \" %s \" " , seg - > metadata_lv - > name ) ;
2015-08-11 14:01:12 +02:00
2017-03-01 12:26:56 +01:00
switch ( seg - > cache_metadata_format ) {
case CACHE_METADATA_FORMAT_UNSELECTED :
/* Unselected format is not printed */
break ;
case CACHE_METADATA_FORMAT_1 :
/* If format 1 was already specified with cache pool, store it,
* otherwise format gets stored when LV is cached .
* NB : format 1 could be lost anytime , it ' s a default format .
* Older lvm2 tool can easily drop it .
*/
case CACHE_METADATA_FORMAT_2 : /* more in future ? */
outf ( f , " metadata_format = " FMTu32 , seg - > cache_metadata_format ) ;
break ;
default :
log_error ( INTERNAL_ERROR " LV %s is using unknown cache metadada format %u. " ,
display_lvname ( seg - > lv ) , seg - > cache_metadata_format ) ;
return 0 ;
}
2015-08-11 14:01:12 +02:00
/*
* Cache pool used by a cache LV holds data . Not ideal ,
* but not worth to break backward compatibility , by shifting
* content to cache segment
*/
2018-11-05 15:23:23 -06:00
if ( ! _settings_text_export ( seg , f ) )
return_0 ;
2014-01-27 05:27:16 -06:00
return 1 ;
}
static void _destroy ( struct segment_type * segtype )
{
2018-06-08 13:40:53 +01:00
free ( ( void * ) segtype ) ;
2014-01-27 05:27:16 -06:00
}
# ifdef DEVMAPPER_SUPPORT
2017-03-31 17:07:21 +02:00
2014-01-27 05:27:16 -06:00
static int _target_present ( struct cmd_context * cmd ,
2015-07-21 11:18:42 +02:00
const struct lv_segment * seg __attribute__ ( ( unused ) ) ,
2021-09-09 23:17:29 +02:00
unsigned * attributes )
2014-01-27 05:27:16 -06:00
{
2015-07-23 11:32:09 +02:00
/* List of features with their kernel target version */
static const struct feature {
2024-05-20 14:03:21 +02:00
uint16_t maj ;
uint16_t min ;
uint16_t cache_feature ;
uint16_t cache_alias ;
2015-07-23 11:32:09 +02:00
const char feature [ 12 ] ;
const char module [ 12 ] ; /* check dm-%s */
2024-05-20 14:03:21 +02:00
const char aliasing [ 24 ] ;
2015-07-23 11:32:09 +02:00
} _features [ ] = {
2017-02-26 20:19:07 +01:00
{ 1 , 10 , CACHE_FEATURE_METADATA2 , 0 , " metadata2 " } ,
2017-03-31 17:07:21 +02:00
/* Assumption: cache >=1.9 always aliases MQ policy */
2016-04-27 12:55:52 +02:00
{ 1 , 9 , CACHE_FEATURE_POLICY_SMQ , CACHE_FEATURE_POLICY_MQ , " policy_smq " , " cache-smq " ,
2024-02-08 14:58:32 +01:00
" and aliases cache-mq " } ,
{ 1 , 8 , CACHE_FEATURE_POLICY_SMQ , 0 , " policy_smq " , " cache-smq " } ,
{ 1 , 3 , CACHE_FEATURE_POLICY_MQ , 0 , " policy_mq " , " cache-mq " } ,
2015-07-23 11:32:09 +02:00
} ;
static const char _lvmconf [ ] = " global/cache_disabled_features " ;
static unsigned _attrs = 0 ;
2014-01-27 05:27:16 -06:00
static int _cache_checked = 0 ;
static int _cache_present = 0 ;
2015-07-23 11:32:09 +02:00
uint32_t maj , min , patchlevel ;
unsigned i ;
const struct dm_config_node * cn ;
const struct dm_config_value * cv ;
const char * str ;
2014-01-27 05:27:16 -06:00
2015-12-17 12:23:33 +01:00
if ( ! activation ( ) )
2016-05-06 13:59:13 +02:00
return 0 ;
2015-12-17 12:23:33 +01:00
2014-02-13 09:13:57 -06:00
if ( ! _cache_checked ) {
2015-12-17 12:23:33 +01:00
_cache_checked = 1 ;
2014-01-27 05:27:16 -06:00
2016-04-27 11:13:36 +02:00
if ( ! ( _cache_present = target_present_version ( cmd , TARGET_NAME_CACHE , 1 ,
& maj , & min , & patchlevel ) ) )
2015-12-17 12:23:33 +01:00
return_0 ;
2014-02-13 09:13:57 -06:00
if ( ( maj < 1 ) | |
( ( maj = = 1 ) & & ( min < 3 ) ) ) {
2015-07-23 11:32:09 +02:00
_cache_present = 0 ;
2015-12-17 12:23:33 +01:00
log_warn ( " WARNING: The cache kernel module is version %u.%u.%u. "
2015-07-23 11:32:09 +02:00
" Version 1.3.0+ is required. " ,
2014-02-13 09:13:57 -06:00
maj , min , patchlevel ) ;
return 0 ;
}
2015-07-23 11:32:09 +02:00
for ( i = 0 ; i < DM_ARRAY_SIZE ( _features ) ; + + i ) {
2016-04-27 12:55:52 +02:00
if ( _attrs & _features [ i ] . cache_feature )
continue ; /* already present */
2017-02-26 20:19:07 +01:00
if ( ! _features [ i ] . module [ 0 ] ) {
if ( ( maj > _features [ i ] . maj ) | |
( maj = = _features [ i ] . maj & & min > = _features [ i ] . min ) ) {
log_debug_activation ( " Cache supports %s. " ,
_features [ i ] . feature ) ;
_attrs | = _features [ i ] . cache_feature ;
}
continue ;
}
2015-07-23 11:32:09 +02:00
if ( ( ( maj > _features [ i ] . maj ) | |
( maj = = _features [ i ] . maj & & min > = _features [ i ] . min ) ) & &
2024-02-08 14:58:32 +01:00
module_present ( cmd , _features [ i ] . module ) ) {
2016-04-27 12:55:52 +02:00
log_debug_activation ( " Cache policy %s is available%s. " ,
_features [ i ] . module ,
2024-05-20 14:03:21 +02:00
_features [ i ] . aliasing ) ;
2016-04-27 12:55:52 +02:00
_attrs | = ( _features [ i ] . cache_feature | _features [ i ] . cache_alias ) ;
} else if ( ! _features [ i ] . cache_alias )
2015-07-23 11:32:09 +02:00
log_very_verbose ( " Target %s does not support %s. " ,
_cache_module , _features [ i ] . feature ) ;
}
}
if ( attributes ) {
if ( ! _feature_mask ) {
/* Support runtime lvm.conf changes, N.B. avoid 32 feature */
if ( ( cn = find_config_tree_array ( cmd , global_cache_disabled_features_CFG , NULL ) ) ) {
for ( cv = cn - > v ; cv ; cv = cv - > next ) {
if ( cv - > type ! = DM_CFG_STRING ) {
log_error ( " Ignoring invalid string in config file %s. " ,
_lvmconf ) ;
continue ;
}
str = cv - > v . str ;
if ( ! * str )
continue ;
for ( i = 0 ; i < DM_ARRAY_SIZE ( _features ) ; + + i )
if ( strcasecmp ( str , _features [ i ] . feature ) = = 0 )
_feature_mask | = _features [ i ] . cache_feature ;
}
}
_feature_mask = ~ _feature_mask ;
for ( i = 0 ; i < DM_ARRAY_SIZE ( _features ) ; + + i )
if ( ( _attrs & _features [ i ] . cache_feature ) & &
! ( _feature_mask & _features [ i ] . cache_feature ) )
log_very_verbose ( " Target %s %s support disabled by %s " ,
_cache_module , _features [ i ] . feature , _lvmconf ) ;
}
* attributes = _attrs & _feature_mask ;
2014-02-13 09:13:57 -06:00
}
2014-01-27 05:27:16 -06:00
return _cache_present ;
}
2014-04-29 23:41:17 +02:00
static int _modules_needed ( struct dm_pool * mem ,
const struct lv_segment * seg __attribute__ ( ( unused ) ) ,
struct dm_list * modules )
{
2016-03-22 17:46:15 +00:00
if ( ! str_list_add ( mem , modules , MODULE_NAME_CACHE ) ) {
2014-04-29 23:41:17 +02:00
log_error ( " String list allocation failed for cache module. " ) ;
return 0 ;
}
return 1 ;
}
2014-01-27 05:27:16 -06:00
# endif /* DEVMAPPER_SUPPORT */
2024-05-03 11:59:05 +02:00
static const struct segtype_handler _cache_pool_ops = {
2017-03-02 00:15:11 +01:00
. display = _cache_display ,
2014-01-27 05:27:16 -06:00
. text_import = _cache_pool_text_import ,
. text_import_area_count = _cache_pool_text_import_area_count ,
. text_export = _cache_pool_text_export ,
# ifdef DEVMAPPER_SUPPORT
. target_present = _target_present ,
2014-04-29 23:41:17 +02:00
. modules_needed = _modules_needed ,
2014-01-27 05:27:16 -06:00
# ifdef DMEVENTD
# endif /* DMEVENTD */
# endif
. destroy = _destroy ,
} ;
2014-01-27 05:29:35 -06:00
static int _cache_text_import ( struct lv_segment * seg ,
const struct dm_config_node * sn ,
struct dm_hash_table * pv_hash __attribute__ ( ( unused ) ) )
{
struct logical_volume * pool_lv , * origin_lv ;
2014-11-06 20:36:53 +01:00
const char * name ;
2018-08-17 15:45:52 -05:00
const char * uuid ;
2014-01-27 05:29:35 -06:00
if ( ! dm_config_has_node ( sn , " cache_pool " ) )
return SEG_LOG_ERROR ( " cache_pool not specified in " ) ;
if ( ! ( name = dm_config_find_str ( sn , " cache_pool " , NULL ) ) )
return SEG_LOG_ERROR ( " cache_pool must be a string in " ) ;
if ( ! ( pool_lv = find_lv ( seg - > lv - > vg , name ) ) )
return SEG_LOG_ERROR ( " Unknown logical volume %s specified for "
2014-11-06 20:36:53 +01:00
" cache_pool in " , name ) ;
2014-01-27 05:29:35 -06:00
if ( ! dm_config_has_node ( sn , " origin " ) )
return SEG_LOG_ERROR ( " Cache origin not specified in " ) ;
if ( ! ( name = dm_config_find_str ( sn , " origin " , NULL ) ) )
return SEG_LOG_ERROR ( " Cache origin must be a string in " ) ;
if ( ! ( origin_lv = find_lv ( seg - > lv - > vg , name ) ) )
return SEG_LOG_ERROR ( " Unknown logical volume %s specified for "
2014-11-06 20:36:53 +01:00
" cache origin in " , name ) ;
2014-01-27 05:29:35 -06:00
if ( ! set_lv_segment_area_lv ( seg , 0 , origin_lv , 0 , 0 ) )
return_0 ;
2014-11-09 20:18:00 +01:00
seg - > cleaner_policy = 0 ;
if ( dm_config_has_node ( sn , " cleaner " ) & &
! dm_config_get_uint32 ( sn , " cleaner " , & seg - > cleaner_policy ) )
return SEG_LOG_ERROR ( " Could not read cache cleaner in " ) ;
2014-11-10 10:56:43 +01:00
seg - > lv - > status | = strstr ( seg - > lv - > name , " _corig " ) ? LV_PENDING_DELETE : 0 ;
2018-08-17 15:45:52 -05:00
if ( ! _settings_text_import ( seg , sn ) )
return_0 ;
if ( dm_config_has_node ( sn , " metadata_format " ) ) {
if ( ! dm_config_get_uint32 ( sn , " metadata_format " , & seg - > cache_metadata_format ) )
return SEG_LOG_ERROR ( " Couldn't read cache metadata_format in " ) ;
if ( seg - > cache_metadata_format ! = CACHE_METADATA_FORMAT_2 )
return SEG_LOG_ERROR ( " Unknown cache metadata format %u number in " ,
seg - > cache_metadata_format ) ;
}
if ( dm_config_has_node ( sn , " metadata_start " ) ) {
if ( ! dm_config_get_uint64 ( sn , " metadata_start " , & seg - > metadata_start ) )
return SEG_LOG_ERROR ( " Couldn't read metadata_start in " ) ;
if ( ! dm_config_get_uint64 ( sn , " metadata_len " , & seg - > metadata_len ) )
return SEG_LOG_ERROR ( " Couldn't read metadata_len in " ) ;
if ( ! dm_config_get_uint64 ( sn , " data_start " , & seg - > data_start ) )
return SEG_LOG_ERROR ( " Couldn't read data_start in " ) ;
if ( ! dm_config_get_uint64 ( sn , " data_len " , & seg - > data_len ) )
return SEG_LOG_ERROR ( " Couldn't read data_len in " ) ;
2019-10-16 16:05:51 +02:00
/* Will use CVOL ID, when metadata_id is not provided */
if ( dm_config_has_node ( sn , " metadata_id " ) ) {
if ( ! ( seg - > metadata_id = dm_pool_alloc ( seg - > lv - > vg - > vgmem , sizeof ( * seg - > metadata_id ) ) ) )
return SEG_LOG_ERROR ( " Couldn't allocate metadata_id in " ) ;
if ( ! dm_config_get_str ( sn , " metadata_id " , & uuid ) )
return SEG_LOG_ERROR ( " Couldn't read metadata_id in " ) ;
if ( ! id_read_format ( seg - > metadata_id , uuid ) )
return SEG_LOG_ERROR ( " Couldn't format metadata_id in " ) ;
}
2018-08-17 15:45:52 -05:00
2019-10-16 16:05:51 +02:00
/* Will use CVOL ID, when data_id is not provided */
if ( dm_config_has_node ( sn , " data_id " ) ) {
if ( ! ( seg - > data_id = dm_pool_alloc ( seg - > lv - > vg - > vgmem , sizeof ( * seg - > data_id ) ) ) )
return SEG_LOG_ERROR ( " Couldn't allocate data_id in " ) ;
if ( ! dm_config_get_str ( sn , " data_id " , & uuid ) )
return SEG_LOG_ERROR ( " Couldn't read data_id in " ) ;
if ( ! id_read_format ( seg - > data_id , uuid ) )
return SEG_LOG_ERROR ( " Couldn't format data_id in " ) ;
}
2019-10-16 21:22:20 +02:00
pool_lv - > status | = LV_CACHE_VOL ; /* Mark as cachevol LV */
2018-08-17 15:45:52 -05:00
} else {
2019-01-30 09:55:34 -06:00
/* Do not call this when LV is cache_vol. */
2018-08-17 15:45:52 -05:00
/* load order is unknown, could be cache origin or pool LV, so check for both */
if ( ! dm_list_empty ( & pool_lv - > segments ) )
_fix_missing_defaults ( first_seg ( pool_lv ) ) ;
}
2015-11-15 20:03:08 +01:00
2019-10-16 21:22:20 +02:00
if ( ! attach_pool_lv ( seg , pool_lv , NULL , NULL , NULL ) )
return_0 ;
2014-01-27 05:29:35 -06:00
return 1 ;
}
static int _cache_text_import_area_count ( const struct dm_config_node * sn ,
uint32_t * area_count )
{
* area_count = 1 ;
return 1 ;
}
static int _cache_text_export ( const struct lv_segment * seg , struct formatter * f )
{
2018-08-17 15:45:52 -05:00
char buffer [ 40 ] ;
2014-01-27 05:29:35 -06:00
if ( ! seg_lv ( seg , 0 ) )
return_0 ;
outf ( f , " cache_pool = \" %s \" " , seg - > pool_lv - > name ) ;
outf ( f , " origin = \" %s \" " , seg_lv ( seg , 0 ) - > name ) ;
2014-11-09 20:18:00 +01:00
if ( seg - > cleaner_policy )
outf ( f , " cleaner = 1 " ) ;
2019-01-30 09:55:34 -06:00
if ( lv_is_cache_vol ( seg - > pool_lv ) ) {
2018-08-17 15:45:52 -05:00
outf ( f , " metadata_format = " FMTu32 , seg - > cache_metadata_format ) ;
if ( ! _settings_text_export ( seg , f ) )
return_0 ;
outf ( f , " metadata_start = " FMTu64 , seg - > metadata_start ) ;
outf ( f , " metadata_len = " FMTu64 , seg - > metadata_len ) ;
outf ( f , " data_start = " FMTu64 , seg - > data_start ) ;
outf ( f , " data_len = " FMTu64 , seg - > data_len ) ;
2019-10-16 16:05:51 +02:00
if ( seg - > metadata_id ) {
if ( ! id_write_format ( seg - > metadata_id , buffer , sizeof ( buffer ) ) )
return_0 ;
outf ( f , " metadata_id = \" %s \" " , buffer ) ;
}
2018-08-17 15:45:52 -05:00
2019-10-16 16:05:51 +02:00
if ( seg - > data_id ) {
if ( ! id_write_format ( seg - > data_id , buffer , sizeof ( buffer ) ) )
return_0 ;
outf ( f , " data_id = \" %s \" " , buffer ) ;
}
2018-08-17 15:45:52 -05:00
}
2014-01-27 05:29:35 -06:00
return 1 ;
}
2014-04-29 23:41:17 +02:00
# ifdef DEVMAPPER_SUPPORT
2014-01-27 05:29:35 -06:00
static int _cache_add_target_line ( struct dev_manager * dm ,
struct dm_pool * mem ,
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 ) ) )
{
2015-05-07 14:04:22 +02:00
struct lv_segment * cache_pool_seg ;
2018-11-05 16:05:28 -06:00
struct lv_segment * setting_seg ;
2021-09-12 17:41:53 +02:00
struct dm_config_node * policy_settings ;
struct dm_config_node * cn ;
unsigned i , j ;
2018-08-17 15:45:52 -05:00
union lvid metadata_lvid ;
union lvid data_lvid ;
2014-02-14 22:09:39 +01:00
char * metadata_uuid , * data_uuid , * origin_uuid ;
2016-04-25 13:39:30 +02:00
uint64_t feature_flags = 0 ;
2017-02-25 12:49:55 +01:00
unsigned attr ;
2014-02-14 22:09:39 +01:00
2015-05-07 14:04:22 +02:00
if ( ! seg - > pool_lv | | ! seg_is_cache ( seg ) ) {
log_error ( INTERNAL_ERROR " Passed segment is not cache. " ) ;
return 0 ;
}
2018-11-05 16:05:28 -06:00
log_debug ( " cache_add_target_line lv %s pool %s " , seg - > lv - > name , seg - > pool_lv - > name ) ;
2015-05-07 14:04:22 +02:00
cache_pool_seg = first_seg ( seg - > pool_lv ) ;
2018-11-05 16:05:28 -06:00
2019-01-30 09:55:34 -06:00
if ( lv_is_cache_vol ( seg - > pool_lv ) )
2018-08-17 15:45:52 -05:00
setting_seg = seg ;
else
setting_seg = cache_pool_seg ;
2018-11-05 16:05:28 -06:00
2016-04-25 13:39:30 +02:00
if ( seg - > cleaner_policy )
/* With cleaner policy always pass writethrough */
feature_flags | = DM_CACHE_FEATURE_WRITETHROUGH ;
else
2018-11-05 16:05:28 -06:00
switch ( setting_seg - > cache_mode ) {
2016-04-25 13:39:30 +02:00
default :
log_error ( INTERNAL_ERROR " LV %s has unknown cache mode %d. " ,
2018-11-05 16:05:28 -06:00
display_lvname ( seg - > lv ) , setting_seg - > cache_mode ) ;
2016-04-25 13:39:30 +02:00
/* Fall through */
case CACHE_MODE_WRITETHROUGH :
feature_flags | = DM_CACHE_FEATURE_WRITETHROUGH ;
break ;
case CACHE_MODE_WRITEBACK :
feature_flags | = DM_CACHE_FEATURE_WRITEBACK ;
break ;
case CACHE_MODE_PASSTHROUGH :
feature_flags | = DM_CACHE_FEATURE_PASSTHROUGH ;
break ;
}
2015-05-07 14:04:22 +02:00
2018-11-05 16:05:28 -06:00
switch ( setting_seg - > cache_metadata_format ) {
2017-02-25 12:49:55 +01:00
case CACHE_METADATA_FORMAT_1 : break ;
case CACHE_METADATA_FORMAT_2 :
if ( ! _target_present ( cmd , NULL , & attr ) )
return_0 ;
if ( ! ( attr & CACHE_FEATURE_METADATA2 ) ) {
log_error ( " LV %s has metadata format %u unsuported by kernel. " ,
2018-11-05 16:05:28 -06:00
display_lvname ( seg - > lv ) , setting_seg - > cache_metadata_format ) ;
2017-02-25 12:49:55 +01:00
return 0 ;
}
feature_flags | = DM_CACHE_FEATURE_METADATA2 ;
log_debug_activation ( " Using metadata2 format for %s. " , display_lvname ( seg - > lv ) ) ;
break ;
default :
log_error ( INTERNAL_ERROR " LV %s has unknown metadata format %u. " ,
2018-11-05 16:05:28 -06:00
display_lvname ( seg - > lv ) , setting_seg - > cache_metadata_format ) ;
2017-02-25 12:49:55 +01:00
return 0 ;
}
2018-08-17 15:45:52 -05:00
if ( ! ( origin_uuid = build_dm_uuid ( mem , seg_lv ( seg , 0 ) , NULL ) ) )
2014-01-27 05:29:35 -06:00
return_0 ;
2019-01-30 09:55:34 -06:00
if ( ! lv_is_cache_vol ( seg - > pool_lv ) ) {
2018-08-17 15:45:52 -05:00
/* We don't use start/len when using separate data/meta devices. */
if ( seg - > metadata_len | | seg - > data_len ) {
log_error ( INTERNAL_ERROR " LV %s using unsupported ranges with cache pool. " ,
display_lvname ( seg - > lv ) ) ;
return 0 ;
}
2014-01-27 05:29:35 -06:00