2001-12-11 12:18:56 +00:00
/*
2008-01-30 14:00:02 +00:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2017-02-24 00:50:00 +01:00
* Copyright ( C ) 2004 - 2017 Red Hat , Inc . All rights reserved .
2001-12-11 12:18:56 +00:00
*
2004-03-30 19:35:44 +00: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-20 20:55:30 +00:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 19:35:44 +00:00
*
2007-08-20 20:55:30 +00:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 19:35:44 +00:00
* 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
2001-12-11 12:18:56 +00:00
*/
2018-05-14 10:30:20 +01:00
# include "lib/misc/lib.h"
# include "lib/metadata/metadata.h"
2001-12-11 12:18:56 +00:00
# include "import-export.h"
2018-05-14 10:30:20 +01:00
# include "lib/misc/lvm-string.h"
2001-12-11 12:18:56 +00:00
/*
* Bitsets held in the ' status ' flags get
* converted into arrays of strings .
*/
struct flag {
2024-10-20 01:57:30 +02:00
const char description [ 32 ] ;
2009-11-24 22:55:55 +00:00
const uint64_t mask ;
2008-07-10 11:30:57 +00:00
int kind ;
2001-12-11 12:18:56 +00:00
} ;
2010-01-07 14:47:57 +00:00
static const struct flag _vg_flags [ ] = {
2024-10-20 01:57:30 +02:00
/* Alphabetically sorted by description! */
{ " CLUSTERED " , CLUSTERED , STATUS_FLAG } ,
{ " EXPORTED " , EXPORTED_VG , STATUS_FLAG } ,
{ " NOAUTOACTIVATE " , NOAUTOACTIVATE , COMPATIBLE_FLAG } ,
{ " PVMOVE " , PVMOVE , STATUS_FLAG } ,
{ " READ " , LVM_READ , STATUS_FLAG } ,
{ " RESIZEABLE " , RESIZEABLE_VG , STATUS_FLAG } ,
{ " SHARED " , SHARED , STATUS_FLAG } ,
{ " WRITE " , LVM_WRITE , STATUS_FLAG } ,
{ " WRITE_LOCKED " , LVM_WRITE_LOCKED , COMPATIBLE_FLAG } ,
{ " " , ( PARTIAL_VG |
PRECOMMITTED |
ARCHIVED_VG ) , 0 } ,
2001-12-11 12:18:56 +00:00
} ;
2010-01-07 14:47:57 +00:00
static const struct flag _pv_flags [ ] = {
2024-10-20 01:57:30 +02:00
/* Alphabetically sorted by description! */
{ " ALLOCATABLE " , ALLOCATABLE_PV , STATUS_FLAG } ,
{ " EXPORTED " , EXPORTED_VG , STATUS_FLAG } ,
{ " MISSING " , MISSING_PV , COMPATIBLE_FLAG | STATUS_FLAG } , /* 1st. */
{ " " , ( PV_MOVED_VG |
UNLABELLED_PV ) , 0 } ,
2001-12-11 12:18:56 +00:00
} ;
2010-01-07 14:47:57 +00:00
static const struct flag _lv_flags [ ] = {
2024-10-20 01:57:30 +02:00
/* Alphabetically sorted by description! */
{ " ACTIVATION_SKIP " , LV_ACTIVATION_SKIP , COMPATIBLE_FLAG } ,
{ " CACHE_USES_CACHEVOL " , LV_CACHE_USES_CACHEVOL , SEGTYPE_FLAG } ,
{ " CACHE_VOL " , LV_CACHE_VOL , COMPATIBLE_FLAG } ,
{ " CROP_METADATA " , LV_CROP_METADATA , SEGTYPE_FLAG } ,
{ " ERROR_WHEN_FULL " , LV_ERROR_WHEN_FULL , COMPATIBLE_FLAG } ,
{ " FIXED_MINOR " , FIXED_MINOR , STATUS_FLAG } ,
{ " LOCKED " , LOCKED , STATUS_FLAG } ,
{ " METADATA_FORMAT " , LV_METADATA_FORMAT , SEGTYPE_FLAG } ,
{ " NOAUTOACTIVATE " , LV_NOAUTOACTIVATE , COMPATIBLE_FLAG } ,
{ " NOTSYNCED " , LV_NOTSYNCED , STATUS_FLAG } ,
{ " PVMOVE " , PVMOVE , STATUS_FLAG } ,
{ " READ " , LVM_READ , STATUS_FLAG } ,
{ " REBUILD " , LV_REBUILD , STATUS_FLAG } ,
{ " REMOVE_AFTER_RESHAPE " , LV_REMOVE_AFTER_RESHAPE , SEGTYPE_FLAG } ,
{ " RESHAPE " , LV_RESHAPE , SEGTYPE_FLAG } ,
{ " RESHAPE_DATA_OFFSET " , LV_RESHAPE_DATA_OFFSET , SEGTYPE_FLAG } ,
{ " RESHAPE_DELTA_DISKS_MINUS " , LV_RESHAPE_DELTA_DISKS_MINUS , SEGTYPE_FLAG } ,
{ " RESHAPE_DELTA_DISKS_PLUS " , LV_RESHAPE_DELTA_DISKS_PLUS , SEGTYPE_FLAG } ,
{ " VISIBLE " , VISIBLE_LV , STATUS_FLAG } ,
{ " WRITE " , LVM_WRITE , STATUS_FLAG } ,
{ " WRITEMOSTLY " , LV_WRITEMOSTLY , STATUS_FLAG } ,
{ " WRITE_LOCKED " , LVM_WRITE_LOCKED , COMPATIBLE_FLAG } ,
{ " " , ( LV_NOSCAN |
LV_TEMPORARY |
POOL_METADATA_SPARE |
LOCKD_SANLOCK_LV |
RAID |
RAID_META |
RAID_IMAGE |
MIRROR |
MIRROR_IMAGE |
MIRROR_LOG |
MIRRORED |
VIRTUAL |
SNAPSHOT |
MERGING |
CONVERTING |
PARTIAL_LV |
POSTORDER_FLAG |
VIRTUAL_ORIGIN |
THIN_VOLUME |
THIN_POOL |
THIN_POOL_DATA |
THIN_POOL_METADATA |
CACHE |
CACHE_POOL |
CACHE_POOL_DATA |
CACHE_POOL_METADATA |
LV_VDO |
LV_VDO_POOL |
LV_VDO_POOL_DATA |
WRITECACHE |
INTEGRITY |
INTEGRITY_METADATA |
LV_PENDING_DELETE | /* FIXME Display like COMPATIBLE_FLAG */
LV_REMOVED ) , 0 } ,
2001-12-11 12:18:56 +00:00
} ;
2024-10-20 01:57:30 +02:00
static const struct flag * _get_flags ( enum pv_vg_lv_e type , size_t * flags_count )
2001-12-11 12:18:56 +00:00
{
2017-05-26 15:47:17 +02:00
switch ( type ) {
2001-12-11 12:18:56 +00:00
case VG_FLAGS :
2024-10-20 01:57:30 +02:00
* flags_count = DM_ARRAY_SIZE ( _vg_flags ) ;
2001-12-11 12:18:56 +00:00
return _vg_flags ;
case PV_FLAGS :
2024-10-20 01:57:30 +02:00
* flags_count = DM_ARRAY_SIZE ( _pv_flags ) ;
2001-12-11 12:18:56 +00:00
return _pv_flags ;
case LV_FLAGS :
2024-10-20 01:57:30 +02:00
* flags_count = DM_ARRAY_SIZE ( _lv_flags ) ;
2001-12-11 12:18:56 +00:00
return _lv_flags ;
}
2017-05-26 15:45:37 +02:00
log_error ( INTERNAL_ERROR " Unknown flag set requested. " ) ;
2001-12-11 12:18:56 +00:00
return NULL ;
}
/*
* Converts a bitset to an array of string values ,
* using one of the tables defined at the top of
* the file .
*/
2017-05-26 15:47:17 +02:00
int print_flags ( char * buffer , size_t size , enum pv_vg_lv_e type , int mask , uint64_t status )
2001-12-11 12:18:56 +00:00
{
2024-10-20 01:57:30 +02:00
int first = 1 ;
2010-01-07 14:47:57 +00:00
const struct flag * flags ;
2024-10-20 01:57:30 +02:00
size_t flags_count ;
2001-12-11 12:18:56 +00:00
2024-10-20 01:57:30 +02:00
if ( ! ( flags = _get_flags ( type , & flags_count ) ) )
2008-01-30 13:19:47 +00:00
return_0 ;
2001-12-11 12:18:56 +00:00
2024-10-20 01:57:30 +02:00
if ( ! size )
return 0 ;
2024-10-23 14:38:21 +02:00
2024-10-20 01:57:30 +02:00
buffer [ 0 ] = 0 ;
2004-05-05 18:15:47 +00:00
2024-10-20 01:57:30 +02:00
for ( ; status ; + + flags ) {
if ( status & flags - > mask ) {
status & = ~ flags - > mask ;
2008-07-10 11:30:57 +00:00
2024-10-20 01:57:30 +02:00
if ( ! ( mask & flags - > kind ) ) {
if ( ! flags - > kind )
break ; /* Internal-only flag? */
2004-05-05 18:15:47 +00:00
continue ;
2024-10-20 01:57:30 +02:00
}
2004-05-05 18:15:47 +00:00
2024-10-20 22:14:39 +02:00
if ( ! emit_to_buffer ( & buffer , & size , " %s \" %s \" " ,
( ! first ) ? " , " : " " ,
2024-10-20 01:57:30 +02:00
flags - > description ) )
2017-05-29 12:43:07 +02:00
return_0 ;
2024-10-20 22:14:39 +02:00
first = 0 ;
2024-10-20 01:57:30 +02:00
} else if ( ! flags - > kind )
break ;
2001-12-11 12:18:56 +00:00
}
if ( status )
2013-10-10 13:34:43 +02:00
log_warn ( INTERNAL_ERROR " Metadata inconsistency: "
" Not all flags successfully exported. " ) ;
2001-12-11 12:18:56 +00:00
return 1 ;
}
2017-05-26 15:47:17 +02:00
int read_flags ( uint64_t * status , enum pv_vg_lv_e type , int mask , const struct dm_config_value * cv )
2001-12-11 12:18:56 +00:00
{
2009-11-24 22:55:55 +00:00
uint64_t s = UINT64_C ( 0 ) ;
2010-01-07 14:47:57 +00:00
const struct flag * flags ;
2024-10-20 01:57:30 +02:00
struct flag * found ;
size_t flags_count ;
typedef int ( * compare_fn_t ) ( const void * , const void * ) ;
2001-12-11 12:18:56 +00:00
2024-10-20 01:57:30 +02:00
if ( ! ( flags = _get_flags ( type , & flags_count ) ) )
2008-01-30 13:19:47 +00:00
return_0 ;
2001-12-11 12:18:56 +00:00
2011-08-30 14:55:15 +00:00
if ( cv - > type = = DM_CFG_EMPTY_ARRAY )
2002-11-18 14:04:08 +00:00
goto out ;
2001-12-11 12:18:56 +00:00
2024-06-13 23:06:09 +02:00
do {
2011-08-30 14:55:15 +00:00
if ( cv - > type ! = DM_CFG_STRING ) {
2009-07-15 20:02:46 +00:00
log_error ( " Status value is not a string. " ) ;
2002-11-18 14:04:08 +00:00
return 0 ;
}
2002-08-01 12:51:48 +00:00
2019-10-14 15:32:13 -05:00
/*
2024-10-20 01:57:30 +02:00
* v . str is a string as well as ' struct flag ' starts with string .
* So compare directly ' strcmp ( ) ' .
* Since the last flags entry is always empty " " , reduce count by 1
2019-10-14 15:32:13 -05:00
*/
2024-10-20 01:57:30 +02:00
if ( ( found = bsearch ( ( struct flag * ) cv - > v . str , flags , flags_count - 1 ,
sizeof ( struct flag ) , ( compare_fn_t ) strcmp ) ) ) {
if ( ( type = = LV_FLAGS ) & & ( found - > mask & LV_CACHE_VOL ) )
/*
* For a short time CACHE_VOL was a STATUS_FLAG , then it
* was changed to COMPATIBLE_FLAG , so we want to read it
* from either place .
*/
mask = ( STATUS_FLAG | COMPATIBLE_FLAG ) ;
if ( found - > kind & mask )
s | = found - > mask ;
} else {
if ( ( type = = VG_FLAGS ) & & ! strcmp ( cv - > v . str , " PARTIAL " ) ) {
2008-09-19 06:42:00 +00:00
/*
* Exception : We no longer write this flag out , but it
* might be encountered in old backup files , so restore
* it in that case . It is never part of live metadata
* though , so only vgcfgrestore needs to be concerned
* by this case .
*/
2024-10-20 01:57:30 +02:00
s | = PARTIAL_VG ;
} else if ( mask & STATUS_FLAG ) {
log_error ( " Unknown status flag '%s'. " , cv - > v . str ) ;
return 0 ;
}
2001-12-11 12:18:56 +00:00
}
2024-06-13 23:06:09 +02:00
} while ( ( cv = cv - > next ) ) ;
2001-12-11 12:18:56 +00:00
2002-11-18 14:04:08 +00:00
out :
2008-07-10 11:30:57 +00:00
* status | = s ;
2001-12-11 12:18:56 +00:00
return 1 ;
}
2017-05-29 14:20:05 +02:00
/*
* Parse extra status flags from segment " type " string .
* These flags are seen as INCOMPATIBLE by any older lvm2 code .
2024-10-23 16:35:55 +02:00
* Returns 0 and prints warning for an UNKNOWN flag .
2017-05-29 14:20:05 +02:00
*
* Note : using these segtype status flags instead of actual
2024-08-29 23:05:41 +02:00
* status flags ensures wanted incompatibility .
2017-05-29 14:20:05 +02:00
*/
2024-10-23 16:35:55 +02:00
int read_lvflags ( uint64_t * status , const char * flags_str )
2017-05-29 14:20:05 +02:00
{
2024-10-20 01:57:30 +02:00
const struct flag * flags ;
2024-10-23 16:35:55 +02:00
const char * delim ;
size_t len ;
2017-05-29 14:20:05 +02:00
2024-10-23 16:35:55 +02:00
do {
if ( ( delim = strchr ( flags_str , ' + ' ) ) )
len = delim - flags_str ;
else
len = strlen ( flags_str ) ;
2024-10-20 01:57:30 +02:00
/* Scan all lv_flags
* Not using bsearch ( ) ATM , as the string may end with ' + '
* and these segtypes are rare in metadata set */
for ( flags = _lv_flags ; flags - > kind ; + + flags )
if ( ( flags - > kind & SEGTYPE_FLAG ) & &
! strncmp ( flags_str , flags - > description , len ) & &
! flags - > description [ len ] ) {
* status | = flags - > mask ;
2024-10-23 16:35:55 +02:00
break ; /* Found matching flag */
}
2017-05-30 15:59:42 +02:00
2024-10-20 01:57:30 +02:00
if ( ! flags - > kind ) {
2024-10-23 16:35:55 +02:00
log_warn ( " WARNING: Unrecognised flag(s) %s. " , flags_str ) ;
return 0 ; /* Unknown flag is incompatible */
}
2017-05-30 15:59:42 +02:00
2024-10-23 16:35:55 +02:00
flags_str = delim + 1 ;
} while ( delim ) ; /* Till no more flags in type appear */
2017-05-29 14:20:05 +02:00
2024-10-23 16:35:55 +02:00
return 1 ;
2017-05-29 14:20:05 +02:00
}
int print_segtype_lvflags ( char * buffer , size_t size , uint64_t status )
{
2024-10-20 01:57:30 +02:00
const struct flag * flags ;
if ( ! size )
return 0 ;
2017-05-29 14:20:05 +02:00
buffer [ 0 ] = 0 ;
2024-10-20 01:57:30 +02:00
for ( flags = _lv_flags ; status & & flags - > kind ; + + flags ) {
if ( ( flags - > kind & SEGTYPE_FLAG ) & &
( status & flags - > mask ) & &
2017-05-29 14:20:05 +02:00
! emit_to_buffer ( & buffer , & size , " +%s " ,
2024-10-20 01:57:30 +02:00
flags - > description ) )
2017-05-29 14:20:05 +02:00
return 0 ;
2024-10-20 01:57:30 +02:00
status & = ~ flags - > mask ;
}
2017-05-29 14:20:05 +02:00
return 1 ;
}