2014-02-04 17:59:58 +04:00
/*
2015-09-10 16:07:59 +03:00
* Copyright ( C ) 2014 - 2015 Red Hat , Inc . All rights reserved .
2014-02-04 17:59:58 +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 "metadata.h"
# include "locking.h"
# include "lvm-string.h"
# include "toolcontext.h"
# include "display.h"
# include "segtype.h"
# include "activate.h"
# include "defaults.h"
2014-11-10 12:56:43 +03:00
# include "lv_alloc.h"
2014-02-04 17:59:58 +04:00
2014-10-06 14:22:03 +04:00
/* https://github.com/jthornber/thin-provisioning-tools/blob/master/caching/cache_metadata_size.cc */
# define DM_TRANSACTION_OVERHEAD 4096 /* KiB */
# define DM_BYTES_PER_BLOCK 16 /* bytes */
# define DM_HINT_OVERHEAD_PER_BLOCK 8 /* bytes */
2014-11-11 17:13:00 +03:00
# define DM_MAX_HINT_WIDTH (4+16) /* bytes. FIXME Configurable? */
2014-10-06 14:22:03 +04:00
2015-08-11 15:01:12 +03:00
int cache_mode_is_set ( const struct lv_segment * seg )
{
if ( seg_is_cache ( seg ) )
seg = first_seg ( seg - > pool_lv ) ;
return ( seg - > feature_flags & ( DM_CACHE_FEATURE_WRITEBACK |
DM_CACHE_FEATURE_WRITETHROUGH |
DM_CACHE_FEATURE_PASSTHROUGH ) ) ? 1 : 0 ;
}
const char * get_cache_mode_name ( const struct lv_segment * seg )
2014-10-02 01:06:01 +04:00
{
if ( seg - > feature_flags & DM_CACHE_FEATURE_WRITEBACK )
return " writeback " ;
if ( seg - > feature_flags & DM_CACHE_FEATURE_WRITETHROUGH )
return " writethrough " ;
2014-11-09 20:51:56 +03:00
if ( seg - > feature_flags & DM_CACHE_FEATURE_PASSTHROUGH )
return " passthrough " ;
2014-11-13 19:41:45 +03:00
log_error ( INTERNAL_ERROR " LV %s has uknown feature flags % " PRIu64 " . " ,
2014-11-09 20:51:56 +03:00
display_lvname ( seg - > lv ) , seg - > feature_flags ) ;
return NULL ;
}
2015-08-11 15:01:12 +03:00
int cache_set_mode ( struct lv_segment * seg , const char * str )
2014-11-09 20:51:56 +03:00
{
2015-08-11 15:01:12 +03:00
struct cmd_context * cmd = seg - > lv - > vg - > cmd ;
int id ;
uint64_t mode ;
if ( ! str & & ! seg_is_cache ( seg ) )
return 1 ; /* Defaults only for cache */
if ( seg_is_cache ( seg ) )
seg = first_seg ( seg - > pool_lv ) ;
if ( ! str ) {
if ( cache_mode_is_set ( seg ) )
return 1 ; /* Default already set in cache pool */
id = allocation_cache_mode_CFG ;
/* If present, check backward compatible settings */
if ( ! find_config_node ( cmd , cmd - > cft , id ) & &
find_config_node ( cmd , cmd - > cft , allocation_cache_pool_cachemode_CFG ) )
id = allocation_cache_pool_cachemode_CFG ;
str = find_config_tree_str ( cmd , id , NULL ) ;
}
2014-11-09 20:51:56 +03:00
if ( ! strcmp ( str , " writeback " ) )
2015-08-11 15:01:12 +03:00
mode = DM_CACHE_FEATURE_WRITEBACK ;
2014-11-09 20:51:56 +03:00
else if ( ! strcmp ( str , " writethrough " ) )
2015-08-11 15:01:12 +03:00
mode = DM_CACHE_FEATURE_WRITETHROUGH ;
else if ( ! strcmp ( str , " passthrough " ) )
mode = DM_CACHE_FEATURE_PASSTHROUGH ;
2014-11-09 20:51:56 +03:00
else {
2015-08-11 15:01:12 +03:00
log_error ( " Cannot set unknown cache mode \" %s \" . " , str ) ;
2014-11-09 20:51:56 +03:00
return 0 ;
}
2015-08-11 15:01:12 +03:00
seg - > feature_flags & = ~ ( DM_CACHE_FEATURE_WRITEBACK |
DM_CACHE_FEATURE_WRITETHROUGH |
DM_CACHE_FEATURE_PASSTHROUGH ) ;
seg - > feature_flags | = mode ;
2014-11-09 20:51:56 +03:00
return 1 ;
2014-10-02 01:06:01 +04:00
}
2015-09-10 16:07:59 +03:00
/*
* At least warn a user if certain cache stacks may present some problems
*/
void cache_check_for_warns ( const struct lv_segment * seg )
{
struct logical_volume * origin_lv = seg_lv ( seg , 0 ) ;
if ( lv_is_raid ( origin_lv ) & &
first_seg ( seg - > pool_lv ) - > feature_flags & DM_CACHE_FEATURE_WRITEBACK )
log_warn ( " WARNING: Data redundancy is lost with writeback "
" caching of raid logical volume! " ) ;
if ( lv_is_thin_pool_data ( seg - > lv ) )
log_warn ( " WARNING: Cached thin pool's data cannot be currently "
" resized and require manual uncache before resize! " ) ;
}
2014-10-06 14:22:51 +04:00
int update_cache_pool_params ( const struct segment_type * segtype ,
struct volume_group * vg , unsigned attr ,
2014-10-30 15:04:06 +03:00
int passed_args , uint32_t pool_data_extents ,
uint32_t * pool_metadata_extents ,
2014-07-23 00:20:18 +04:00
int * chunk_size_calc_method , uint32_t * chunk_size )
2014-02-04 21:50:27 +04:00
{
uint64_t min_meta_size ;
2014-10-06 14:22:03 +04:00
uint32_t extent_size = vg - > extent_size ;
2014-11-12 12:03:27 +03:00
uint64_t pool_metadata_size = ( uint64_t ) * pool_metadata_extents * vg - > extent_size ;
2014-02-04 21:50:27 +04:00
2014-07-23 00:20:18 +04:00
if ( ! ( passed_args & PASS_ARG_CHUNK_SIZE ) )
* chunk_size = DEFAULT_CACHE_POOL_CHUNK_SIZE * 2 ;
2014-10-06 14:22:51 +04:00
if ( ! validate_pool_chunk_size ( vg - > cmd , segtype , * chunk_size ) )
return_0 ;
2014-02-04 21:50:27 +04:00
/*
* Default meta size is :
2014-10-06 14:22:03 +04:00
* ( Overhead + mapping size + hint size )
2014-02-04 21:50:27 +04:00
*/
2014-10-30 15:04:06 +03:00
min_meta_size = ( uint64_t ) pool_data_extents * extent_size / * chunk_size ; /* nr_chunks */
2014-10-06 14:22:03 +04:00
min_meta_size * = ( DM_BYTES_PER_BLOCK + DM_MAX_HINT_WIDTH + DM_HINT_OVERHEAD_PER_BLOCK ) ;
min_meta_size = ( min_meta_size + ( SECTOR_SIZE - 1 ) ) > > SECTOR_SHIFT ; /* in sectors */
min_meta_size + = DM_TRANSACTION_OVERHEAD * ( 1024 > > SECTOR_SHIFT ) ;
/* Round up to extent size */
if ( min_meta_size % extent_size )
min_meta_size + = extent_size - min_meta_size % extent_size ;
2014-02-04 21:50:27 +04:00
2014-10-30 15:04:06 +03:00
if ( ! pool_metadata_size )
pool_metadata_size = min_meta_size ;
2014-02-04 21:50:27 +04:00
2014-10-30 15:04:06 +03:00
if ( pool_metadata_size > ( 2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE ) ) {
pool_metadata_size = 2 * DEFAULT_CACHE_POOL_MAX_METADATA_SIZE ;
2014-07-11 14:12:51 +04:00
if ( passed_args & PASS_ARG_POOL_METADATA_SIZE )
log_warn ( " WARNING: Maximum supported pool metadata size is %s. " ,
2014-10-30 15:04:06 +03:00
display_size ( vg - > cmd , pool_metadata_size ) ) ;
} else if ( pool_metadata_size < min_meta_size ) {
2014-07-11 14:12:51 +04:00
if ( passed_args & PASS_ARG_POOL_METADATA_SIZE )
2014-10-06 14:22:03 +04:00
log_warn ( " WARNING: Minimum required pool metadata size is %s "
2014-07-11 14:12:51 +04:00
" (needs extra %s). " ,
display_size ( vg - > cmd , min_meta_size ) ,
2014-10-30 15:04:06 +03:00
display_size ( vg - > cmd , min_meta_size - pool_metadata_size ) ) ;
pool_metadata_size = min_meta_size ;
2014-02-04 21:50:27 +04:00
}
2014-10-30 15:04:06 +03:00
if ( ! ( * pool_metadata_extents =
extents_from_size ( vg - > cmd , pool_metadata_size , extent_size ) ) )
return_0 ;
2014-02-04 21:50:27 +04:00
return 1 ;
}
2014-10-03 20:37:11 +04:00
/*
* Validate arguments for converting origin into cached volume with given cache pool .
*
* Always validates origin_lv , and when it is known also cache pool_lv
*/
2014-10-22 23:01:03 +04:00
int validate_lv_cache_create_pool ( const struct logical_volume * pool_lv )
2014-10-03 20:37:11 +04:00
{
struct lv_segment * seg ;
2014-10-22 23:01:03 +04:00
if ( ! lv_is_cache_pool ( pool_lv ) ) {
log_error ( " Logical volume %s is not a cache pool. " ,
display_lvname ( pool_lv ) ) ;
return 0 ;
}
if ( lv_is_locked ( pool_lv ) ) {
log_error ( " Cannot use locked cache pool %s. " ,
display_lvname ( pool_lv ) ) ;
return 0 ;
2014-10-03 20:37:11 +04:00
}
2014-10-22 23:01:03 +04:00
if ( ! dm_list_empty ( & pool_lv - > segs_using_this_lv ) ) {
seg = get_only_segment_using_this_lv ( pool_lv ) ;
log_error ( " Logical volume %s is already in use by %s " ,
display_lvname ( pool_lv ) ,
seg ? display_lvname ( seg - > lv ) : " another LV " ) ;
return 0 ;
}
return 1 ;
}
int validate_lv_cache_create_origin ( const struct logical_volume * origin_lv )
{
2014-10-20 16:58:29 +04:00
if ( lv_is_locked ( origin_lv ) ) {
log_error ( " Cannot use locked origin volume %s. " ,
display_lvname ( origin_lv ) ) ;
return 0 ;
}
2014-10-03 20:37:11 +04:00
/* For now we only support conversion of thin pool data volume */
if ( ! lv_is_visible ( origin_lv ) & & ! lv_is_thin_pool_data ( origin_lv ) ) {
log_error ( " Can't convert internal LV %s. " , display_lvname ( origin_lv ) ) ;
return 0 ;
}
/*
* Only linear , striped or raid supported .
* FIXME Tidy up all these type restrictions .
*/
if ( lv_is_cache_type ( origin_lv ) | |
lv_is_mirror_type ( origin_lv ) | |
lv_is_thin_volume ( origin_lv ) | | lv_is_thin_pool_metadata ( origin_lv ) | |
lv_is_origin ( origin_lv ) | | lv_is_merging_origin ( origin_lv ) | |
lv_is_cow ( origin_lv ) | | lv_is_merging_cow ( origin_lv ) | |
lv_is_external_origin ( origin_lv ) | |
lv_is_virtual ( origin_lv ) ) {
2014-10-20 16:53:48 +04:00
log_error ( " Cache is not supported with %s segment type of the original logical volume %s. " ,
first_seg ( origin_lv ) - > segtype - > name , display_lvname ( origin_lv ) ) ;
2014-10-03 20:37:11 +04:00
return 0 ;
}
return 1 ;
}
2014-02-04 17:59:58 +04:00
/*
* lv_cache_create
* @ pool
* @ origin
*
* Given a cache_pool and an origin , link the two and create a
* cached LV .
*
* Returns : cache LV on success , NULL on failure
*/
2014-10-03 20:37:11 +04:00
struct logical_volume * lv_cache_create ( struct logical_volume * pool_lv ,
struct logical_volume * origin_lv )
2014-02-04 17:59:58 +04:00
{
const struct segment_type * segtype ;
2014-10-03 20:37:11 +04:00
struct cmd_context * cmd = pool_lv - > vg - > cmd ;
struct logical_volume * cache_lv = origin_lv ;
2014-02-04 17:59:58 +04:00
struct lv_segment * seg ;
2014-10-22 23:01:03 +04:00
if ( ! validate_lv_cache_create_pool ( pool_lv ) | |
2014-11-02 19:03:14 +03:00
! validate_lv_cache_create_origin ( cache_lv ) )
2014-10-03 20:37:11 +04:00
return_NULL ;
2014-02-04 17:59:58 +04:00
2014-11-02 19:03:14 +03:00
if ( lv_is_thin_pool ( cache_lv ) )
cache_lv = seg_lv ( first_seg ( cache_lv ) , 0 ) ; /* cache _tdata */
2015-09-22 21:04:12 +03:00
if ( ! ( segtype = get_segtype_from_string ( cmd , SEG_TYPE_NAME_CACHE ) ) )
2014-02-04 17:59:58 +04:00
return_NULL ;
2014-10-03 20:37:11 +04:00
if ( ! insert_layer_for_lv ( cmd , cache_lv , CACHE , " _corig " ) )
2014-02-04 17:59:58 +04:00
return_NULL ;
seg = first_seg ( cache_lv ) ;
seg - > segtype = segtype ;
2014-10-03 20:37:11 +04:00
if ( ! attach_pool_lv ( seg , pool_lv , NULL , NULL ) )
2014-02-11 23:47:26 +04:00
return_NULL ;
2014-02-04 17:59:58 +04:00
return cache_lv ;
}
/*
* lv_cache_remove
* @ cache_lv
*
* Given a cache LV , remove the cache layer . This will unlink
* the origin and cache_pool , remove the cache LV layer , and promote
* the origin to a usable non - cached LV of the same name as the
* given cache_lv .
*
* Returns : 1 on success , 0 on failure
*/
int lv_cache_remove ( struct logical_volume * cache_lv )
{
2014-11-03 14:52:29 +03:00
int is_cleaner ;
2014-02-04 17:59:58 +04:00
uint64_t dirty_blocks ;
struct lv_segment * cache_seg = first_seg ( cache_lv ) ;
2014-04-01 20:02:36 +04:00
struct logical_volume * corigin_lv ;
2014-02-04 17:59:58 +04:00
struct logical_volume * cache_pool_lv ;
2014-11-03 14:52:29 +03:00
struct lv_status_cache * status ;
2014-02-04 17:59:58 +04:00
2014-04-01 19:55:07 +04:00
if ( ! lv_is_cache ( cache_lv ) ) {
2014-11-03 14:52:24 +03:00
log_error ( INTERNAL_ERROR " LV %s is not cache volume. " ,
display_lvname ( cache_lv ) ) ;
2014-04-01 19:55:07 +04:00
return 0 ;
}
2014-02-04 17:59:58 +04:00
2014-11-11 15:31:25 +03:00
if ( lv_is_pending_delete ( cache_lv ) ) {
log_error ( INTERNAL_ERROR " LV %s is already dropped cache volume. " ,
display_lvname ( cache_lv ) ) ;
2014-11-10 12:56:43 +03:00
goto remove ; /* Already dropped */
2014-11-11 15:31:25 +03:00
}
2014-11-10 12:56:43 +03:00
2014-11-10 12:07:41 +03:00
/* Localy active volume is needed for writeback */
2014-10-04 01:48:42 +04:00
if ( ! lv_is_active_locally ( cache_lv ) ) {
2014-11-10 12:07:41 +03:00
/* Give up any remote locks */
if ( ! deactivate_lv ( cache_lv - > vg - > cmd , cache_lv ) ) {
log_error ( " Cannot deactivate remotely active cache lv. " ) ;
return 0 ;
}
/* For inactive writethrough just drop cache layer */
if ( first_seg ( cache_seg - > pool_lv ) - > feature_flags &
DM_CACHE_FEATURE_WRITETHROUGH ) {
corigin_lv = seg_lv ( cache_seg , 0 ) ;
if ( ! detach_pool_lv ( cache_seg ) )
return_0 ;
if ( ! remove_layer_from_lv ( cache_lv , corigin_lv ) )
return_0 ;
if ( ! lv_remove ( corigin_lv ) )
return_0 ;
return 1 ;
}
/* Otherwise localy active volume is need to sync dirty blocks */
2014-10-04 01:48:42 +04:00
cache_lv - > status | = LV_TEMPORARY ;
if ( ! activate_lv_excl_local ( cache_lv - > vg - > cmd , cache_lv ) | |
! lv_is_active_locally ( cache_lv ) ) {
log_error ( " Failed to active cache locally %s. " ,
display_lvname ( cache_lv ) ) ;
return 0 ;
}
cache_lv - > status & = ~ LV_TEMPORARY ;
2014-04-01 20:02:36 +04:00
}
2014-02-04 17:59:58 +04:00
/*
* FIXME :
* Before the link can be broken , we must ensure that the
* cache has been flushed . This may already be the case
* if the cache mode is writethrough ( or the cleaner
* policy is in place from a previous half - finished attempt
* to remove the cache_pool ) . It could take a long time to
* flush the cache - it should probably be done in the background .
*
* Also , if we do perform the flush in the background and we
* happen to also be removing the cache / origin LV , then we
* could check if the cleaner policy is in place and simply
* remove the cache_pool then without waiting for the flush to
* complete .
*/
2014-11-03 14:52:29 +03:00
if ( ! lv_cache_status ( cache_lv , & status ) )
2014-02-04 17:59:58 +04:00
return_0 ;
2014-11-10 12:07:41 +03:00
dirty_blocks = status - > cache - > dirty_blocks ;
if ( ! ( status - > cache - > feature_flags & DM_CACHE_FEATURE_WRITETHROUGH ) )
dirty_blocks + + ; /* Not writethrough - always dirty */
2014-11-03 14:52:29 +03:00
is_cleaner = ! strcmp ( status - > cache - > policy_name , " cleaner " ) ;
dm_pool_destroy ( status - > mem ) ;
2014-02-04 17:59:58 +04:00
2014-11-10 12:07:41 +03:00
if ( dirty_blocks & & ! is_cleaner ) {
2014-11-09 22:18:00 +03:00
/* Switch to cleaner policy to flush the cache */
2014-04-01 19:55:07 +04:00
log_print_unless_silent ( " Flushing cache for %s. " , cache_lv - > name ) ;
2014-11-09 22:18:00 +03:00
cache_seg - > cleaner_policy = 1 ;
2014-02-04 17:59:58 +04:00
/* update the kernel to put the cleaner policy in place */
2014-11-09 22:18:00 +03:00
if ( ! lv_update_and_reload_origin ( cache_lv ) )
2014-11-03 14:52:24 +03:00
return_0 ;
2014-02-04 17:59:58 +04:00
}
//FIXME: use polling to do this...
2014-11-10 12:07:41 +03:00
while ( dirty_blocks ) {
2014-11-03 14:52:29 +03:00
if ( ! lv_cache_status ( cache_lv , & status ) )
2014-02-04 17:59:58 +04:00
return_0 ;
2014-11-03 14:52:29 +03:00
dirty_blocks = status - > cache - > dirty_blocks ;
dm_pool_destroy ( status - > mem ) ;
if ( dirty_blocks ) {
2015-07-06 17:09:17 +03:00
log_print_unless_silent ( FMTu64 " blocks must still be flushed. " ,
2014-11-03 14:52:29 +03:00
dirty_blocks ) ;
2014-04-01 19:55:07 +04:00
sleep ( 1 ) ;
2014-11-03 14:52:29 +03:00
}
2014-11-10 12:07:41 +03:00
}
2014-02-04 17:59:58 +04:00
2014-04-01 20:02:36 +04:00
cache_pool_lv = cache_seg - > pool_lv ;
if ( ! detach_pool_lv ( cache_seg ) )
2014-02-04 17:59:58 +04:00
return_0 ;
2014-11-10 12:56:43 +03:00
/*
* Drop layer from cache LV and make _corigin to appear again as regular LV
* And use ' existing ' _corigin volume to keep reference on cache - pool
* This way we still have a way to reference _corigin in dm table and we
* know it ' s been ' cache ' LV and we can drop all needed table entries via
* activation and deactivation of it .
*
* This ' cache ' LV without origin is temporary LV , which still could be
* easily operated by lvm2 commands - it could be activate / deactivated / removed .
* However in the dm - table it will use ' error ' target for _corigin volume .
*/
2014-04-01 20:02:36 +04:00
corigin_lv = seg_lv ( cache_seg , 0 ) ;
lv_set_visible ( corigin_lv ) ;
2014-11-06 22:36:53 +03:00
2014-04-01 20:02:36 +04:00
if ( ! remove_layer_from_lv ( cache_lv , corigin_lv ) )
2014-11-06 22:36:53 +03:00
return_0 ;
2014-02-04 17:59:58 +04:00
2014-11-10 12:56:43 +03:00
/* Replace 'error' with 'cache' segtype */
cache_seg = first_seg ( corigin_lv ) ;
2015-09-22 21:04:12 +03:00
if ( ! ( cache_seg - > segtype = get_segtype_from_string ( corigin_lv - > vg - > cmd , SEG_TYPE_NAME_CACHE ) ) )
2014-02-04 17:59:58 +04:00
return_0 ;
2014-11-10 12:56:43 +03:00
if ( ! ( cache_seg - > areas = dm_pool_zalloc ( cache_lv - > vg - > vgmem , sizeof ( * cache_seg - > areas ) ) ) )
return_0 ;
if ( ! set_lv_segment_area_lv ( cache_seg , 0 , cache_lv , 0 , 0 ) )
return_0 ;
2014-02-04 17:59:58 +04:00
2014-11-10 12:56:43 +03:00
cache_seg - > area_count = 1 ;
corigin_lv - > le_count = cache_lv - > le_count ;
corigin_lv - > size = cache_lv - > size ;
corigin_lv - > status | = LV_PENDING_DELETE ;
/* Reattach cache pool */
if ( ! attach_pool_lv ( cache_seg , cache_pool_lv , NULL , NULL ) )
2014-04-01 20:02:36 +04:00
return_0 ;
2014-11-10 12:56:43 +03:00
/* Suspend/resume also deactivates deleted LV via support of LV_PENDING_DELETE */
if ( ! lv_update_and_reload ( cache_lv ) )
2014-02-04 17:59:58 +04:00
return_0 ;
2014-11-10 12:56:43 +03:00
cache_lv = corigin_lv ;
remove :
if ( ! detach_pool_lv ( cache_seg ) )
2014-02-04 17:59:58 +04:00
return_0 ;
2014-04-01 20:02:36 +04:00
2014-11-10 12:56:43 +03:00
if ( ! lv_remove ( cache_lv ) ) /* Will use LV_PENDING_DELETE */
2014-02-04 17:59:58 +04:00
return_0 ;
return 1 ;
}
2014-07-17 17:12:21 +04:00
2014-08-15 15:08:30 +04:00
int lv_is_cache_origin ( const struct logical_volume * lv )
{
struct lv_segment * seg ;
/* Make sure there's exactly one segment in segs_using_this_lv! */
if ( dm_list_empty ( & lv - > segs_using_this_lv ) | |
( dm_list_size ( & lv - > segs_using_this_lv ) > 1 ) )
return 0 ;
seg = get_only_segment_using_this_lv ( lv ) ;
2014-11-10 12:56:43 +03:00
return seg & & lv_is_cache ( seg - > lv ) & & ! lv_is_pending_delete ( seg - > lv ) & & ( seg_lv ( seg , 0 ) = = lv ) ;
2014-08-15 15:08:30 +04:00
}
2014-11-02 20:36:41 +03:00
2015-08-17 16:35:43 +03:00
static const char * _get_default_cache_policy ( struct cmd_context * cmd )
{
2015-09-22 21:04:12 +03:00
const struct segment_type * segtype = get_segtype_from_string ( cmd , SEG_TYPE_NAME_CACHE ) ;
2015-08-17 16:35:43 +03:00
unsigned attr = ~ 0 ;
const char * def = NULL ;
if ( ! segtype | |
! segtype - > ops - > target_present | |
! segtype - > ops - > target_present ( cmd , NULL , & attr ) ) {
log_warn ( " WARNING: Cannot detect default cache policy, using \" "
DEFAULT_CACHE_POLICY " \" . " ) ;
return DEFAULT_CACHE_POLICY ;
}
if ( attr & CACHE_FEATURE_POLICY_SMQ )
def = " smq " ;
else if ( attr & CACHE_FEATURE_POLICY_MQ )
def = " mq " ;
else {
log_error ( " Default cache policy is not available. " ) ;
return NULL ;
}
log_debug_metadata ( " Detected default cache_policy \" %s \" . " , def ) ;
return def ;
}
2015-08-11 15:01:12 +03:00
int cache_set_policy ( struct lv_segment * seg , const char * name ,
const struct dm_config_tree * settings )
2014-11-19 20:38:30 +03:00
{
2014-11-20 14:05:40 +03:00
struct dm_config_node * cn ;
2015-08-11 15:01:12 +03:00
const struct dm_config_node * cns ;
2014-11-20 14:05:40 +03:00
struct dm_config_tree * old = NULL , * new = NULL , * tmp = NULL ;
int r = 0 ;
2015-08-11 15:01:12 +03:00
const int passed_seg_is_cache = seg_is_cache ( seg ) ;
2014-11-19 20:38:30 +03:00
2015-08-11 15:01:12 +03:00
if ( passed_seg_is_cache )
2014-11-19 20:38:30 +03:00
seg = first_seg ( seg - > pool_lv ) ;
2015-08-11 15:01:12 +03:00
if ( name ) {
if ( ! ( seg - > policy_name = dm_pool_strdup ( seg - > lv - > vg - > vgmem , name ) ) ) {
log_error ( " Failed to duplicate policy name. " ) ;
return 0 ;
}
2015-08-17 16:35:43 +03:00
} else if ( ! seg - > policy_name & & passed_seg_is_cache ) {
if ( ! ( seg - > policy_name = find_config_tree_str ( seg - > lv - > vg - > cmd , allocation_cache_policy_CFG , NULL ) ) & &
! ( seg - > policy_name = _get_default_cache_policy ( seg - > lv - > vg - > cmd ) ) )
return_0 ;
}
2015-08-11 15:01:12 +03:00
if ( settings ) {
if ( ! seg - > policy_name ) {
log_error ( INTERNAL_ERROR " Can't set policy settings without policy name. " ) ;
return 0 ;
}
if ( seg - > policy_settings ) {
if ( ! ( old = dm_config_create ( ) ) )
goto_out ;
if ( ! ( new = dm_config_create ( ) ) )
goto_out ;
new - > root = settings - > root ;
old - > root = seg - > policy_settings ;
new - > cascade = old ;
if ( ! ( tmp = dm_config_flatten ( new ) ) )
goto_out ;
}
if ( ( cn = dm_config_find_node ( ( tmp ) ? tmp - > root : settings - > root , " policy_settings " ) ) & &
! ( seg - > policy_settings = dm_config_clone_node_with_mem ( seg - > lv - > vg - > vgmem , cn , 0 ) ) )
2014-11-20 14:05:40 +03:00
goto_out ;
2015-08-11 15:01:12 +03:00
} else if ( passed_seg_is_cache & & /* Look for command's profile cache_policies */
( cns = find_config_tree_node ( seg - > lv - > vg - > cmd , allocation_cache_settings_CFG_SECTION , NULL ) ) ) {
/* Try to find our section for given policy */
for ( cn = cns - > child ; cn ; cn = cn - > sib ) {
/* Only matching section names */
if ( cn - > v | | strcmp ( cn - > key , seg - > policy_name ) ! = 0 )
continue ;
if ( ! cn - > child )
break ;
if ( ! ( new = dm_config_create ( ) ) )
goto_out ;
2014-11-20 14:05:40 +03:00
2015-08-11 15:01:12 +03:00
if ( ! ( new - > root = dm_config_clone_node_with_mem ( new - > mem ,
cn - > child , 1 ) ) )
goto_out ;
2014-11-19 20:38:30 +03:00
2015-08-11 15:01:12 +03:00
if ( ! ( seg - > policy_settings = dm_config_create_node ( new , " policy_settings " ) ) )
goto_out ;
seg - > policy_settings - > child = new - > root ;
break ; /* Only first match counts */
}
2015-07-15 12:06:40 +03:00
}
2014-11-20 14:05:40 +03:00
restart : /* remove any 'default" nodes */
2015-02-24 13:36:30 +03:00
cn = seg - > policy_settings ? seg - > policy_settings - > child : NULL ;
2014-11-20 14:05:40 +03:00
while ( cn ) {
if ( cn - > v - > type = = DM_CFG_STRING & & ! strcmp ( cn - > v - > v . str , " default " ) ) {
dm_config_remove_node ( seg - > policy_settings , cn ) ;
goto restart ;
}
cn = cn - > sib ;
}
2014-11-19 20:38:30 +03:00
2014-11-20 14:05:40 +03:00
r = 1 ;
out :
if ( tmp )
dm_config_destroy ( tmp ) ;
2015-07-15 12:06:40 +03:00
if ( new )
dm_config_destroy ( new ) ;
if ( old )
dm_config_destroy ( old ) ;
2014-11-20 14:05:40 +03:00
return r ;
2014-11-19 20:38:30 +03:00
}
2014-11-02 20:36:41 +03:00
/*
* Wipe cache pool metadata area before use .
*
* Activates metadata volume as ' cache - pool ' so regular wiping
* of existing visible volume may proceed .
*/
int wipe_cache_pool ( struct logical_volume * cache_pool_lv )
{
int r ;
/* Only unused cache-pool could be activated and wiped */
if ( ! lv_is_cache_pool ( cache_pool_lv ) | |
! dm_list_empty ( & cache_pool_lv - > segs_using_this_lv ) ) {
log_error ( INTERNAL_ERROR " Failed to wipe cache pool for volume %s. " ,
display_lvname ( cache_pool_lv ) ) ;
return 0 ;
}
cache_pool_lv - > status | = LV_TEMPORARY ;
if ( ! activate_lv_local ( cache_pool_lv - > vg - > cmd , cache_pool_lv ) ) {
log_error ( " Aborting. Failed to activate cache pool %s. " ,
display_lvname ( cache_pool_lv ) ) ;
return 0 ;
}
cache_pool_lv - > status & = ~ LV_TEMPORARY ;
if ( ! ( r = wipe_lv ( cache_pool_lv , ( struct wipe_params ) { . do_zero = 1 } ) ) ) {
log_error ( " Aborting. Failed to wipe cache pool %s. " ,
display_lvname ( cache_pool_lv ) ) ;
/* Delay return of error after deactivation */
}
/* Deactivate cleared cache-pool metadata */
if ( ! deactivate_lv ( cache_pool_lv - > vg - > cmd , cache_pool_lv ) ) {
log_error ( " Aborting. Could not deactivate cache pool %s. " ,
display_lvname ( cache_pool_lv ) ) ;
r = 0 ;
}
return r ;
}