2001-09-25 16:49:28 +04:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2007-08-21 00:55:30 +04:00
* Copyright ( C ) 2004 - 2007 Red Hat , Inc . All rights reserved .
2001-09-25 16:49:28 +04:00
*
2004-03-30 23:35:44 +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-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +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
2001-09-25 16:49:28 +04:00
*/
2002-11-18 17:04:08 +03:00
# include "lib.h"
2001-10-12 14:32:06 +04:00
# include "device.h"
2001-10-01 19:14:39 +04:00
# include "metadata.h"
2002-02-11 23:50:53 +03:00
# include "toolcontext.h"
2002-02-25 15:56:16 +03:00
# include "lvm-string.h"
2008-01-16 01:56:30 +03:00
# include "lvm-file.h"
2003-07-05 02:34:56 +04:00
# include "lvmcache.h"
# include "memlock.h"
2005-04-20 00:52:35 +04:00
# include "str_list.h"
# include "pv_alloc.h"
2005-10-25 23:08:21 +04:00
# include "activate.h"
2006-11-10 21:24:11 +03:00
# include "display.h"
2007-06-06 23:40:28 +04:00
# include "locking.h"
2007-08-21 21:38:20 +04:00
# include "archiver.h"
2001-09-25 16:49:28 +04:00
2006-08-17 23:53:36 +04:00
# include <sys/param.h>
2007-06-13 01:20:20 +04:00
/*
2007-06-13 01:39:49 +04:00
* FIXME : Check for valid handle before dereferencing field or log error ?
2007-06-13 01:20:20 +04:00
*/
2007-06-13 01:39:49 +04:00
# define pv_field(handle, field) \
2007-11-02 23:40:05 +03:00
( ( ( const struct physical_volume * ) ( handle ) ) - > field )
2007-06-13 01:20:20 +04:00
2007-06-11 22:29:30 +04:00
static struct physical_volume * _pv_read ( struct cmd_context * cmd ,
const char * pv_name ,
struct list * mdas ,
uint64_t * label_sector ,
int warnings ) ;
static struct physical_volume * _pv_create ( const struct format_type * fmt ,
struct device * dev ,
struct id * id , uint64_t size ,
uint64_t pe_start ,
uint32_t existing_extent_count ,
uint32_t existing_extent_size ,
int pvmetadatacopies ,
uint64_t pvmetadatasize , struct list * mdas ) ;
static int _pv_write ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
struct physical_volume * pv ,
struct list * mdas , int64_t label_sector ) ;
static struct physical_volume * _find_pv_by_name ( struct cmd_context * cmd ,
const char * pv_name ) ;
static struct pv_list * _find_pv_in_vg ( struct volume_group * vg , const char * pv_name ) ;
static struct physical_volume * _find_pv_in_vg_by_uuid ( struct volume_group * vg ,
struct id * id ) ;
2006-08-17 23:30:59 +04:00
unsigned long pe_align ( void )
{
2006-08-17 23:53:36 +04:00
return MAX ( 65536UL , lvm_getpagesize ( ) ) > > SECTOR_SHIFT ;
2006-08-17 23:30:59 +04:00
}
2007-07-12 09:04:42 +04:00
/**
* add_pv_to_vg - Add a physical volume to a volume group
* @ vg - volume group to add to
* @ pv_name - name of the pv ( to be removed )
* @ pv - physical volume to add to volume group
*
* Returns :
* 0 - failure
* 1 - success
* FIXME : remove pv_name - obtain safely from pv
*/
int add_pv_to_vg ( struct volume_group * vg , const char * pv_name ,
struct physical_volume * pv )
2001-10-12 18:25:53 +04:00
{
2001-10-15 22:39:40 +04:00
struct pv_list * pvl ;
2007-07-03 01:48:30 +04:00
struct format_instance * fid = vg - > fid ;
2005-10-17 03:03:59 +04:00
struct dm_pool * mem = fid - > fmt - > cmd - > mem ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
log_verbose ( " Adding physical volume '%s' to volume group '%s' " ,
2001-11-10 01:01:04 +03:00
pv_name , vg - > name ) ;
2001-10-15 22:39:40 +04:00
2005-10-17 03:03:59 +04:00
if ( ! ( pvl = dm_pool_zalloc ( mem , sizeof ( * pvl ) ) ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " pv_list allocation for '%s' failed " , pv_name ) ;
2001-10-12 18:25:53 +04:00
return 0 ;
}
2007-11-02 16:06:42 +03:00
if ( ! is_orphan_vg ( pv - > vg_name ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " Physical volume '%s' is already in volume group "
" '%s' " , pv_name , pv - > vg_name ) ;
2001-10-15 16:49:58 +04:00
return 0 ;
}
2001-10-12 18:25:53 +04:00
2002-11-18 17:04:08 +03:00
if ( pv - > fmt ! = fid - > fmt ) {
log_error ( " Physical volume %s is of different format type (%s) " ,
pv_name , pv - > fmt - > name ) ;
return 0 ;
}
2005-10-25 23:08:21 +04:00
/* Ensure PV doesn't depend on another PV already in the VG */
2006-05-11 21:58:58 +04:00
if ( pv_uses_vg ( pv , vg ) ) {
2005-10-25 23:08:21 +04:00
log_error ( " Physical volume %s might be constructed from same "
" volume group %s " , pv_name , vg - > name ) ;
return 0 ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( pv - > vg_name = dm_pool_strdup ( mem , vg - > name ) ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " vg->name allocation failed for '%s' " , pv_name ) ;
2001-10-12 18:25:53 +04:00
return 0 ;
}
2006-04-13 01:23:04 +04:00
memcpy ( & pv - > vgid , & vg - > id , sizeof ( vg - > id ) ) ;
2001-10-16 00:29:15 +04:00
/* Units of 512-byte sectors */
2001-10-12 18:25:53 +04:00
pv - > pe_size = vg - > extent_size ;
2002-04-24 22:20:51 +04:00
/* FIXME Do proper rounding-up alignment? */
/* Reserved space for label; this holds 0 for PVs created by LVM1 */
2006-08-17 23:30:59 +04:00
if ( pv - > pe_start < pe_align ( ) )
pv - > pe_start = pe_align ( ) ;
2002-04-24 22:20:51 +04:00
2001-10-12 18:25:53 +04:00
/*
2006-10-08 03:06:18 +04:00
* pe_count must always be calculated by pv_setup
2001-10-12 18:25:53 +04:00
*/
2002-04-24 22:20:51 +04:00
pv - > pe_alloc_count = 0 ;
2001-10-12 18:25:53 +04:00
2003-03-24 21:08:53 +03:00
if ( ! fid - > fmt - > ops - > pv_setup ( fid - > fmt , UINT64_C ( 0 ) , 0 ,
vg - > extent_size , 0 , UINT64_C ( 0 ) ,
2002-11-18 17:04:08 +03:00
& fid - > metadata_areas , pv , vg ) ) {
2002-01-28 00:30:47 +03:00
log_error ( " Format-specific setup of physical volume '%s' "
2001-10-15 22:39:40 +04:00
" failed. " , pv_name ) ;
return 0 ;
}
2007-06-11 22:29:30 +04:00
if ( _find_pv_in_vg ( vg , pv_name ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " Physical volume '%s' listed more than once. " ,
pv_name ) ;
2001-10-12 18:25:53 +04:00
return 0 ;
}
2003-11-06 23:33:34 +03:00
if ( vg - > pv_count & & ( vg - > pv_count = = vg - > max_pv ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " No space for '%s' - volume group '%s' "
" holds max %d physical volume(s). " , pv_name ,
vg - > name , vg - > max_pv ) ;
return 0 ;
}
2005-05-03 21:28:23 +04:00
if ( ! alloc_pv_segment_whole_pv ( mem , pv ) ) {
stack ;
2005-05-09 21:41:36 +04:00
return 0 ;
2005-05-03 21:28:23 +04:00
}
2001-10-15 22:39:40 +04:00
2005-05-03 21:28:23 +04:00
pvl - > pv = pv ;
2001-10-31 15:47:01 +03:00
list_add ( & vg - > pvs , & pvl - > list ) ;
2005-05-03 21:28:23 +04:00
2006-11-10 21:24:11 +03:00
if ( ( uint64_t ) vg - > extent_count + pv - > pe_count > UINT32_MAX ) {
log_error ( " Unable to add %s to %s: new extent count (% "
PRIu64 " ) exceeds limit (% " PRIu32 " ). " ,
pv_name , vg - > name ,
( uint64_t ) vg - > extent_count + pv - > pe_count ,
UINT32_MAX ) ;
return 0 ;
}
2001-10-12 18:25:53 +04:00
vg - > pv_count + + ;
2001-11-06 22:02:26 +03:00
vg - > extent_count + = pv - > pe_count ;
vg - > free_count + = pv - > pe_count ;
2001-10-12 18:25:53 +04:00
return 1 ;
}
2005-04-20 00:44:21 +04:00
static int _copy_pv ( struct physical_volume * pv_to ,
struct physical_volume * pv_from )
2005-04-18 03:59:04 +04:00
{
memcpy ( pv_to , pv_from , sizeof ( * pv_to ) ) ;
2005-04-20 00:52:35 +04:00
if ( ! str_list_dup ( pv_to - > fmt - > cmd - > mem , & pv_to - > tags , & pv_from - > tags ) ) {
log_error ( " PV tags duplication failed " ) ;
return 0 ;
}
if ( ! peg_dup ( pv_to - > fmt - > cmd - > mem , & pv_to - > segments ,
2005-05-11 19:02:49 +04:00
& pv_from - > segments ) ) {
2005-04-20 00:52:35 +04:00
stack ;
return 0 ;
}
return 1 ;
2005-04-18 03:59:04 +04:00
}
2005-04-18 03:57:44 +04:00
int get_pv_from_vg_by_id ( const struct format_type * fmt , const char * vg_name ,
2006-04-13 01:23:04 +04:00
const char * vgid , const char * pvid ,
struct physical_volume * pv )
2005-04-18 03:57:44 +04:00
{
struct volume_group * vg ;
struct pv_list * pvl ;
int consistent = 0 ;
2006-04-13 01:23:04 +04:00
if ( ! ( vg = vg_read ( fmt - > cmd , vg_name , vgid , & consistent ) ) ) {
2005-04-20 00:44:21 +04:00
log_error ( " get_pv_from_vg_by_id: vg_read failed to read VG %s " ,
2005-04-18 03:57:44 +04:00
vg_name ) ;
return 0 ;
}
if ( ! consistent )
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: Volume group %s is not consistent " ,
vg_name ) ;
2005-04-18 03:57:44 +04:00
2005-06-01 20:51:55 +04:00
list_iterate_items ( pvl , & vg - > pvs ) {
2006-04-13 01:23:04 +04:00
if ( id_equal ( & pvl - > pv - > id , ( const struct id * ) pvid ) ) {
2005-04-20 00:44:21 +04:00
if ( ! _copy_pv ( pv , pvl - > pv ) ) {
stack ;
return 0 ;
}
2005-04-18 03:57:44 +04:00
return 1 ;
}
}
2005-04-20 00:44:21 +04:00
2005-04-18 03:57:44 +04:00
return 0 ;
}
2008-01-16 01:56:30 +03:00
static int validate_new_vg_name ( struct cmd_context * cmd , const char * vg_name )
{
char vg_path [ PATH_MAX ] ;
if ( ! validate_name ( vg_name ) )
return 0 ;
snprintf ( vg_path , PATH_MAX , " %s%s " , cmd - > dev_dir , vg_name ) ;
if ( path_exists ( vg_path ) ) {
log_error ( " %s: already exists in filesystem " , vg_path ) ;
return 0 ;
}
return 1 ;
}
int validate_vg_rename_params ( struct cmd_context * cmd ,
const char * vg_name_old ,
const char * vg_name_new )
{
unsigned length ;
char * dev_dir ;
dev_dir = cmd - > dev_dir ;
length = strlen ( dev_dir ) ;
/* Check sanity of new name */
if ( strlen ( vg_name_new ) > NAME_LEN - length - 2 ) {
log_error ( " New volume group path exceeds maximum length "
" of %d! " , NAME_LEN - length - 2 ) ;
return 0 ;
}
if ( ! validate_new_vg_name ( cmd , vg_name_new ) ) {
log_error ( " New volume group name \" %s \" is invalid " ,
vg_name_new ) ;
return 0 ;
}
if ( ! strcmp ( vg_name_old , vg_name_new ) ) {
log_error ( " Old and new volume group names must differ " ) ;
return 0 ;
}
return 1 ;
}
2002-12-20 02:25:55 +03:00
int vg_rename ( struct cmd_context * cmd , struct volume_group * vg ,
const char * new_name )
{
2005-10-17 03:03:59 +04:00
struct dm_pool * mem = cmd - > mem ;
2005-06-01 20:51:55 +04:00
struct pv_list * pvl ;
2002-12-20 02:25:55 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( vg - > name = dm_pool_strdup ( mem , new_name ) ) ) {
2002-12-20 02:25:55 +03:00
log_error ( " vg->name allocation failed for '%s' " , new_name ) ;
return 0 ;
}
2005-06-01 20:51:55 +04:00
list_iterate_items ( pvl , & vg - > pvs ) {
2005-10-17 03:03:59 +04:00
if ( ! ( pvl - > pv - > vg_name = dm_pool_strdup ( mem , new_name ) ) ) {
2002-12-20 02:25:55 +03:00
log_error ( " pv->vg_name allocation failed for '%s' " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pvl - > pv ) ) ;
2002-12-20 02:25:55 +03:00
return 0 ;
}
}
return 1 ;
}
2007-08-28 20:14:49 +04:00
static int remove_lvs_in_vg ( struct cmd_context * cmd ,
struct volume_group * vg ,
force_t force )
{
struct lv_list * lvl ;
list_iterate_items ( lvl , & vg - > lvs )
if ( ! lv_remove_single ( cmd , lvl - > lv , force ) )
return 0 ;
return 1 ;
}
/* FIXME: remove redundant vg_name */
2007-08-21 21:38:20 +04:00
int vg_remove_single ( struct cmd_context * cmd , const char * vg_name ,
struct volume_group * vg , int consistent ,
2007-08-22 18:38:18 +04:00
force_t force __attribute ( ( unused ) ) )
2007-08-21 21:38:20 +04:00
{
struct physical_volume * pv ;
struct pv_list * pvl ;
int ret = 1 ;
if ( ! vg | | ! consistent | | ( vg_status ( vg ) & PARTIAL_VG ) ) {
log_error ( " Volume group \" %s \" not found or inconsistent. " ,
vg_name ) ;
log_error ( " Consider vgreduce --removemissing if metadata "
" is inconsistent. " ) ;
return 0 ;
}
if ( ! vg_check_status ( vg , EXPORTED_VG ) )
return 0 ;
2007-08-28 20:14:49 +04:00
if ( vg - > lv_count ) {
if ( ( force = = PROMPT ) & &
( yes_no_prompt ( " Do you really want to remove volume "
" group \" %s \" containing %d "
" logical volumes? [y/n]: " ,
vg_name , vg - > lv_count ) = = ' n ' ) ) {
log_print ( " Volume group \" %s \" not removed " , vg_name ) ;
return 0 ;
}
if ( ! remove_lvs_in_vg ( cmd , vg , force ) )
return 0 ;
}
2007-08-21 21:38:20 +04:00
if ( vg - > lv_count ) {
log_error ( " Volume group \" %s \" still contains %d "
" logical volume(s) " , vg_name , vg - > lv_count ) ;
return 0 ;
}
if ( ! archive ( vg ) )
return 0 ;
if ( ! vg_remove ( vg ) ) {
log_error ( " vg_remove %s failed " , vg_name ) ;
return 0 ;
}
/* init physical volumes */
list_iterate_items ( pvl , & vg - > pvs ) {
pv = pvl - > pv ;
log_verbose ( " Removing physical volume \" %s \" from "
2007-10-12 18:29:32 +04:00
" volume group \" %s \" " , pv_dev_name ( pv ) , vg_name ) ;
2007-08-21 21:38:20 +04:00
pv - > vg_name = ORPHAN ;
pv - > status = ALLOCATABLE_PV ;
if ( ! dev_get_size ( pv_dev ( pv ) , & pv - > size ) ) {
2007-10-12 18:29:32 +04:00
log_error ( " %s: Couldn't get size. " , pv_dev_name ( pv ) ) ;
2007-08-21 21:38:20 +04:00
ret = 0 ;
continue ;
}
/* FIXME Write to same sector label was read from */
if ( ! pv_write ( cmd , pv , NULL , INT64_C ( - 1 ) ) ) {
log_error ( " Failed to remove physical volume \" %s \" "
" from volume group \" %s \" " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) , vg_name ) ;
2007-08-21 21:38:20 +04:00
ret = 0 ;
}
}
backup_remove ( cmd , vg_name ) ;
if ( ret )
log_print ( " Volume group \" %s \" successfully removed " , vg_name ) ;
else
log_error ( " Volume group \" %s \" not properly removed " , vg_name ) ;
return ret ;
}
2007-06-19 04:33:43 +04:00
int vg_extend ( struct volume_group * vg , int pv_count , char * * pv_names )
2001-10-16 02:04:27 +04:00
{
int i ;
2007-07-12 09:04:42 +04:00
struct physical_volume * pv ;
2001-10-16 02:04:27 +04:00
/* attach each pv */
2007-07-12 09:04:42 +04:00
for ( i = 0 ; i < pv_count ; i + + ) {
2007-07-12 19:38:53 +04:00
if ( ! ( pv = pv_by_path ( vg - > fid - > fmt - > cmd , pv_names [ i ] ) ) ) {
2007-07-12 09:04:42 +04:00
log_error ( " %s not identified as an existing "
" physical volume " , pv_names [ i ] ) ;
2007-07-12 08:12:04 +04:00
goto bad ;
2007-07-12 09:04:42 +04:00
}
if ( ! add_pv_to_vg ( vg , pv_names [ i ] , pv ) )
goto bad ;
}
2001-10-16 02:04:27 +04:00
2002-11-18 17:04:08 +03:00
/* FIXME Decide whether to initialise and add new mdahs to format instance */
2001-10-16 02:04:27 +04:00
return 1 ;
2007-07-12 08:12:04 +04:00
bad :
log_error ( " Unable to add physical volume '%s' to "
" volume group '%s'. " , pv_names [ i ] , vg - > name ) ;
return 0 ;
2001-10-16 02:04:27 +04:00
}
2001-11-12 18:10:01 +03:00
const char * strip_dir ( const char * vg_name , const char * dev_dir )
2001-11-12 15:16:57 +03:00
{
2002-12-20 02:25:55 +03:00
size_t len = strlen ( dev_dir ) ;
2001-11-12 15:16:57 +03:00
if ( ! strncmp ( vg_name , dev_dir , len ) )
vg_name + = len ;
return vg_name ;
}
2008-01-15 00:07:58 +03:00
/*
* Validate parameters to vg_create ( ) before calling .
2008-01-16 22:54:39 +03:00
* FIXME : Move inside vg_create library function .
* FIXME : Change vgcreate_params struct to individual gets / sets
2008-01-15 00:07:58 +03:00
*/
int validate_vg_create_params ( struct cmd_context * cmd ,
struct vgcreate_params * vp )
{
if ( ! validate_new_vg_name ( cmd , vp - > vg_name ) ) {
log_error ( " New volume group name \" %s \" is invalid " ,
vp - > vg_name ) ;
return 1 ;
}
if ( vp - > alloc = = ALLOC_INHERIT ) {
log_error ( " Volume Group allocation policy cannot inherit "
" from anything " ) ;
return 1 ;
}
if ( ! vp - > extent_size ) {
log_error ( " Physical extent size may not be zero " ) ;
return 1 ;
}
if ( ! ( cmd - > fmt - > features & FMT_UNLIMITED_VOLS ) ) {
if ( ! vp - > max_lv )
vp - > max_lv = 255 ;
if ( ! vp - > max_pv )
vp - > max_pv = 255 ;
if ( vp - > max_lv > 255 | | vp - > max_pv > 255 ) {
log_error ( " Number of volumes may not exceed 255 " ) ;
return 1 ;
}
}
return 0 ;
}
2002-04-24 22:20:51 +04:00
struct volume_group * vg_create ( struct cmd_context * cmd , const char * vg_name ,
2002-12-20 02:25:55 +03:00
uint32_t extent_size , uint32_t max_pv ,
2004-05-19 02:12:53 +04:00
uint32_t max_lv , alloc_policy_t alloc ,
int pv_count , char * * pv_names )
2001-10-12 18:25:53 +04:00
{
struct volume_group * vg ;
2005-10-17 03:03:59 +04:00
struct dm_pool * mem = cmd - > mem ;
2002-11-18 17:04:08 +03:00
int consistent = 0 ;
2003-04-30 19:23:43 +04:00
int old_partial ;
2001-10-12 18:25:53 +04:00
2005-10-17 03:03:59 +04:00
if ( ! ( vg = dm_pool_zalloc ( mem , sizeof ( * vg ) ) ) ) {
2001-10-12 18:25:53 +04:00
stack ;
return NULL ;
}
/* is this vg name already in use ? */
2003-04-30 19:23:43 +04:00
old_partial = partial_mode ( ) ;
2002-01-29 20:23:33 +03:00
init_partial ( 1 ) ;
2006-04-13 01:23:04 +04:00
if ( vg_read ( cmd , vg_name , NULL , & consistent ) ) {
2001-10-15 22:39:40 +04:00
log_err ( " A volume group called '%s' already exists. " , vg_name ) ;
2001-10-12 18:25:53 +04:00
goto bad ;
}
2003-04-30 19:23:43 +04:00
init_partial ( old_partial ) ;
2001-10-12 18:25:53 +04:00
if ( ! id_create ( & vg - > id ) ) {
2002-04-24 22:20:51 +04:00
log_err ( " Couldn't create uuid for volume group '%s'. " , vg_name ) ;
2001-10-12 18:25:53 +04:00
goto bad ;
}
2001-11-14 16:52:38 +03:00
/* Strip dev_dir if present */
2002-04-24 22:20:51 +04:00
vg_name = strip_dir ( vg_name , cmd - > dev_dir ) ;
2001-10-15 22:39:40 +04:00
2002-04-24 22:20:51 +04:00
vg - > cmd = cmd ;
2002-01-07 18:27:55 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( vg - > name = dm_pool_strdup ( mem , vg_name ) ) ) {
2001-10-12 18:25:53 +04:00
stack ;
goto bad ;
}
2002-04-24 22:20:51 +04:00
vg - > seqno = 0 ;
2002-01-11 02:21:07 +03:00
vg - > status = ( RESIZEABLE_VG | LVM_READ | LVM_WRITE ) ;
2007-04-26 20:44:59 +04:00
if ( ! ( vg - > system_id = dm_pool_alloc ( mem , NAME_LEN ) ) )
goto_bad ;
2002-01-30 15:47:29 +03:00
* vg - > system_id = ' \0 ' ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
vg - > extent_size = extent_size ;
vg - > extent_count = 0 ;
vg - > free_count = 0 ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
vg - > max_lv = max_lv ;
vg - > max_pv = max_pv ;
2001-10-12 18:25:53 +04:00
2004-05-19 02:12:53 +04:00
vg - > alloc = alloc ;
2001-10-15 22:39:40 +04:00
vg - > pv_count = 0 ;
2001-10-31 15:47:01 +03:00
list_init ( & vg - > pvs ) ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
vg - > lv_count = 0 ;
2001-10-31 15:47:01 +03:00
list_init ( & vg - > lvs ) ;
2001-10-12 18:25:53 +04:00
2002-02-14 18:06:24 +03:00
vg - > snapshot_count = 0 ;
2004-03-08 20:19:15 +03:00
list_init ( & vg - > tags ) ;
2002-04-24 22:20:51 +04:00
if ( ! ( vg - > fid = cmd - > fmt - > ops - > create_instance ( cmd - > fmt , vg_name ,
2006-04-13 01:23:04 +04:00
NULL , NULL ) ) ) {
2002-04-24 22:20:51 +04:00
log_error ( " Failed to create format instance " ) ;
goto bad ;
}
2003-08-27 01:12:06 +04:00
if ( vg - > fid - > fmt - > ops - > vg_setup & &
! vg - > fid - > fmt - > ops - > vg_setup ( vg - > fid , vg ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " Format specific setup of volume group '%s' failed. " ,
vg_name ) ;
2001-10-12 18:25:53 +04:00
goto bad ;
}
/* attach the pv's */
2007-06-19 04:33:43 +04:00
if ( ! vg_extend ( vg , pv_count , pv_names ) )
2007-04-26 20:44:59 +04:00
goto_bad ;
2001-10-12 18:25:53 +04:00
return vg ;
2002-04-24 22:20:51 +04:00
bad :
2005-10-17 03:03:59 +04:00
dm_pool_free ( mem , vg ) ;
2001-10-12 18:25:53 +04:00
return NULL ;
}
2005-04-18 18:56:42 +04:00
static int _recalc_extents ( uint32_t * extents , const char * desc1 ,
const char * desc2 , uint32_t old_size ,
uint32_t new_size )
{
uint64_t size = ( uint64_t ) old_size * ( * extents ) ;
if ( size % new_size ) {
log_error ( " New size % " PRIu64 " for %s%s not an exact number "
" of new extents. " , size , desc1 , desc2 ) ;
return 0 ;
}
size / = new_size ;
if ( size > UINT32_MAX ) {
log_error ( " New extent count % " PRIu64 " for %s%s exceeds "
" 32 bits. " , size , desc1 , desc2 ) ;
return 0 ;
}
* extents = ( uint32_t ) size ;
return 1 ;
}
2007-08-22 18:38:18 +04:00
int vg_change_pesize ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
struct volume_group * vg , uint32_t new_size )
2005-04-18 18:56:42 +04:00
{
uint32_t old_size = vg - > extent_size ;
struct pv_list * pvl ;
struct lv_list * lvl ;
struct physical_volume * pv ;
struct logical_volume * lv ;
struct lv_segment * seg ;
2005-05-03 21:28:23 +04:00
struct pv_segment * pvseg ;
2005-04-18 18:56:42 +04:00
uint32_t s ;
vg - > extent_size = new_size ;
if ( vg - > fid - > fmt - > ops - > vg_setup & &
! vg - > fid - > fmt - > ops - > vg_setup ( vg - > fid , vg ) ) {
stack ;
return 0 ;
}
if ( ! _recalc_extents ( & vg - > extent_count , vg - > name , " " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
if ( ! _recalc_extents ( & vg - > free_count , vg - > name , " free space " ,
old_size , new_size ) ) {
stack ;
return 0 ;
}
/* foreach PV */
list_iterate_items ( pvl , & vg - > pvs ) {
pv = pvl - > pv ;
pv - > pe_size = new_size ;
2007-10-12 18:29:32 +04:00
if ( ! _recalc_extents ( & pv - > pe_count , pv_dev_name ( pv ) , " " ,
2005-04-18 18:56:42 +04:00
old_size , new_size ) ) {
stack ;
return 0 ;
}
2007-10-12 18:29:32 +04:00
if ( ! _recalc_extents ( & pv - > pe_alloc_count , pv_dev_name ( pv ) ,
2005-04-18 18:56:42 +04:00
" allocated space " , old_size , new_size ) ) {
stack ;
return 0 ;
}
2005-05-03 21:28:23 +04:00
2005-05-11 19:02:49 +04:00
/* foreach free PV Segment */
list_iterate_items ( pvseg , & pv - > segments ) {
if ( pvseg - > lvseg )
continue ;
2007-10-12 18:29:32 +04:00
if ( ! _recalc_extents ( & pvseg - > pe , pv_dev_name ( pv ) ,
2005-05-03 21:28:23 +04:00
" PV segment start " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
2007-10-12 18:29:32 +04:00
if ( ! _recalc_extents ( & pvseg - > len , pv_dev_name ( pv ) ,
2005-05-03 21:28:23 +04:00
" PV segment length " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
}
2005-04-18 18:56:42 +04:00
}
/* foreach LV */
list_iterate_items ( lvl , & vg - > lvs ) {
lv = lvl - > lv ;
if ( ! _recalc_extents ( & lv - > le_count , lv - > name , " " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
list_iterate_items ( seg , & lv - > segments ) {
if ( ! _recalc_extents ( & seg - > le , lv - > name ,
" segment start " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
if ( ! _recalc_extents ( & seg - > len , lv - > name ,
" segment length " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
if ( ! _recalc_extents ( & seg - > area_len , lv - > name ,
" area length " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
if ( ! _recalc_extents ( & seg - > extents_copied , lv - > name ,
" extents moved " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
/* foreach area */
for ( s = 0 ; s < seg - > area_count ; s + + ) {
2005-06-01 20:51:55 +04:00
switch ( seg_type ( seg , s ) ) {
2005-04-18 18:56:42 +04:00
case AREA_PV :
if ( ! _recalc_extents
2005-06-01 20:51:55 +04:00
( & seg_pe ( seg , s ) ,
2005-05-03 21:28:23 +04:00
lv - > name ,
" pvseg start " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
if ( ! _recalc_extents
2005-06-01 20:51:55 +04:00
( & seg_pvseg ( seg , s ) - > len ,
2005-05-03 21:28:23 +04:00
lv - > name ,
" pvseg length " , old_size ,
2005-04-18 18:56:42 +04:00
new_size ) ) {
stack ;
return 0 ;
}
break ;
case AREA_LV :
if ( ! _recalc_extents
2005-06-01 20:51:55 +04:00
( & seg_le ( seg , s ) , lv - > name ,
2005-04-18 18:56:42 +04:00
" area start " , old_size ,
new_size ) ) {
stack ;
return 0 ;
}
break ;
2005-06-14 21:54:48 +04:00
case AREA_UNASSIGNED :
log_error ( " Unassigned area %u found in "
" segment " , s ) ;
2005-04-18 18:56:42 +04:00
return 0 ;
}
}
}
}
return 1 ;
}
2007-08-22 18:38:18 +04:00
int vg_split_mdas ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
struct volume_group * vg_from , struct volume_group * vg_to )
2007-03-23 15:43:17 +03:00
{
struct metadata_area * mda , * mda2 ;
struct list * mdas_from , * mdas_to ;
int common_mda = 0 ;
mdas_from = & vg_from - > fid - > metadata_areas ;
mdas_to = & vg_to - > fid - > metadata_areas ;
list_iterate_items_safe ( mda , mda2 , mdas_from ) {
if ( ! mda - > ops - > mda_in_vg ) {
common_mda = 1 ;
continue ;
}
if ( ! mda - > ops - > mda_in_vg ( vg_from - > fid , vg_from , mda ) ) {
list_del ( & mda - > list ) ;
list_add ( mdas_to , & mda - > list ) ;
}
}
if ( list_empty ( mdas_from ) | | list_empty ( mdas_to ) )
return common_mda ;
return 1 ;
}
2007-06-13 02:41:27 +04:00
/**
* pv_create - initialize a physical volume for use with a volume group
* @ fmt : format type
* @ dev : PV device to initialize
* @ id : PV UUID to use for initialization
* @ size : size of the PV in sectors
* @ pe_start : physical extent start
* @ existing_extent_count
* @ existing_extent_size
* @ pvmetadatacopies
* @ pvmetadatasize
* @ mdas
*
* Returns :
* PV handle - physical volume initialized successfully
* NULL - invalid parameter or problem initializing the physical volume
*
* Note :
* FIXME - liblvm todo - tidy up arguments for external use ( fmt , mdas , etc )
*/
2007-06-14 00:55:56 +04:00
pv_t * pv_create ( const struct format_type * fmt ,
2007-06-13 02:41:27 +04:00
struct device * dev ,
struct id * id , uint64_t size ,
uint64_t pe_start ,
uint32_t existing_extent_count ,
uint32_t existing_extent_size ,
int pvmetadatacopies ,
uint64_t pvmetadatasize , struct list * mdas )
2007-06-11 22:29:30 +04:00
{
2007-06-14 01:14:07 +04:00
return _pv_create ( fmt , dev , id , size , pe_start ,
existing_extent_count ,
existing_extent_size ,
pvmetadatacopies ,
pvmetadatasize , mdas ) ;
2007-06-11 22:29:30 +04:00
}
2007-10-12 22:37:19 +04:00
static void _free_pv ( struct dm_pool * mem , struct physical_volume * pv )
{
dm_pool_free ( mem , pv ) ;
}
static struct physical_volume * _alloc_pv ( struct dm_pool * mem )
{
struct physical_volume * pv = dm_pool_zalloc ( mem , sizeof ( * pv ) ) ;
if ( ! pv ) {
stack ;
return NULL ;
}
if ( ! ( pv - > vg_name = dm_pool_zalloc ( mem , NAME_LEN ) ) ) {
dm_pool_free ( mem , pv ) ;
return NULL ;
}
pv - > pe_size = 0 ;
pv - > pe_start = 0 ;
pv - > pe_count = 0 ;
pv - > pe_alloc_count = 0 ;
pv - > fmt = NULL ;
pv - > status = ALLOCATABLE_PV ;
list_init ( & pv - > tags ) ;
list_init ( & pv - > segments ) ;
return pv ;
}
2007-06-11 22:29:30 +04:00
/* Sizes in sectors */
static struct physical_volume * _pv_create ( const struct format_type * fmt ,
struct device * dev ,
struct id * id , uint64_t size ,
uint64_t pe_start ,
uint32_t existing_extent_count ,
uint32_t existing_extent_size ,
int pvmetadatacopies ,
uint64_t pvmetadatasize , struct list * mdas )
2001-09-25 16:49:28 +04:00
{
2005-10-17 03:03:59 +04:00
struct dm_pool * mem = fmt - > cmd - > mem ;
2007-10-12 22:37:19 +04:00
struct physical_volume * pv = _alloc_pv ( mem ) ;
2001-10-12 14:32:06 +04:00
2007-10-12 22:37:19 +04:00
if ( ! pv )
2001-10-12 14:32:06 +04:00
return NULL ;
2005-01-20 21:11:53 +03:00
if ( id )
2002-01-16 21:10:08 +03:00
memcpy ( & pv - > id , id , sizeof ( * id ) ) ;
2005-01-20 21:11:53 +03:00
else if ( ! id_create ( & pv - > id ) ) {
log_error ( " Failed to create random uuid for %s. " ,
dev_name ( dev ) ) ;
2007-10-12 22:37:19 +04:00
goto bad ;
2005-01-20 21:11:53 +03:00
}
2002-01-16 21:10:08 +03:00
2002-11-18 17:04:08 +03:00
pv - > dev = dev ;
2001-10-12 14:32:06 +04:00
2002-02-20 21:29:30 +03:00
if ( ! dev_get_size ( pv - > dev , & pv - > size ) ) {
2007-10-12 18:29:32 +04:00
log_error ( " %s: Couldn't get size. " , pv_dev_name ( pv ) ) ;
2002-02-20 21:29:30 +03:00
goto bad ;
}
if ( size ) {
if ( size > pv - > size )
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: %s: Overriding real size. "
2007-10-12 18:29:32 +04:00
" You could lose data. " , pv_dev_name ( pv ) ) ;
2002-04-24 22:20:51 +04:00
log_verbose ( " %s: Pretending size is % " PRIu64 " sectors. " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) , size ) ;
2002-02-20 21:29:30 +03:00
pv - > size = size ;
}
2002-04-24 22:20:51 +04:00
2002-02-20 21:29:30 +03:00
if ( pv - > size < PV_MIN_SIZE ) {
2002-11-18 17:04:08 +03:00
log_error ( " %s: Size must exceed minimum of %ld sectors. " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) , PV_MIN_SIZE ) ;
2001-10-12 14:32:06 +04:00
goto bad ;
}
2002-11-18 17:04:08 +03:00
pv - > fmt = fmt ;
2002-02-15 17:33:59 +03:00
2002-11-18 17:04:08 +03:00
if ( ! fmt - > ops - > pv_setup ( fmt , pe_start , existing_extent_count ,
existing_extent_size ,
pvmetadatacopies , pvmetadatasize , mdas ,
pv , NULL ) ) {
2002-02-20 21:29:30 +03:00
log_error ( " %s: Format-specific setup of physical volume "
2007-10-12 18:29:32 +04:00
" failed. " , pv_dev_name ( pv ) ) ;
2002-02-15 17:33:59 +03:00
goto bad ;
}
2001-10-12 14:32:06 +04:00
return pv ;
2001-10-15 22:39:40 +04:00
bad :
2007-10-12 22:37:19 +04:00
_free_pv ( mem , pv ) ;
2001-10-12 14:32:06 +04:00
return NULL ;
2001-09-25 16:49:28 +04:00
}
2007-06-11 22:29:30 +04:00
/* FIXME: liblvm todo - make into function that returns handle */
2002-01-21 17:28:12 +03:00
struct pv_list * find_pv_in_vg ( struct volume_group * vg , const char * pv_name )
2007-06-11 22:29:30 +04:00
{
return _find_pv_in_vg ( vg , pv_name ) ;
}
static struct pv_list * _find_pv_in_vg ( struct volume_group * vg , const char * pv_name )
2001-10-15 22:39:40 +04:00
{
2002-01-21 17:28:12 +03:00
struct pv_list * pvl ;
2001-10-25 18:04:18 +04:00
2005-06-01 20:51:55 +04:00
list_iterate_items ( pvl , & vg - > pvs )
2002-01-25 01:37:24 +03:00
if ( pvl - > pv - > dev = = dev_cache_get ( pv_name , vg - > cmd - > filter ) )
2002-01-21 17:28:12 +03:00
return pvl ;
2001-09-25 16:49:28 +04:00
2001-10-15 22:39:40 +04:00
return NULL ;
2002-11-18 17:04:08 +03:00
}
2003-01-18 00:04:26 +03:00
int pv_is_in_vg ( struct volume_group * vg , struct physical_volume * pv )
{
2005-06-01 20:51:55 +04:00
struct pv_list * pvl ;
2003-01-18 00:04:26 +03:00
2005-06-01 20:51:55 +04:00
list_iterate_items ( pvl , & vg - > pvs )
if ( pv = = pvl - > pv )
2003-01-18 00:04:26 +03:00
return 1 ;
return 0 ;
}
2007-06-13 02:41:27 +04:00
/**
* find_pv_in_vg_by_uuid - Find PV in VG by PV UUID
* @ vg : volume group to search
* @ id : UUID of the PV to match
*
* Returns :
* PV handle - if UUID of PV found in VG
* NULL - invalid parameter or UUID of PV not found in VG
*
* Note
* FIXME - liblvm todo - make into function that takes VG handle
*/
2007-06-14 00:55:56 +04:00
pv_t * find_pv_in_vg_by_uuid ( struct volume_group * vg , struct id * id )
2007-06-11 22:29:30 +04:00
{
2007-06-14 01:14:07 +04:00
return _find_pv_in_vg_by_uuid ( vg , id ) ;
2007-06-11 22:29:30 +04:00
}
static struct physical_volume * _find_pv_in_vg_by_uuid ( struct volume_group * vg ,
struct id * id )
2002-11-18 17:04:08 +03:00
{
struct pv_list * pvl ;
2001-10-12 14:32:06 +04:00
2005-06-01 20:51:55 +04:00
list_iterate_items ( pvl , & vg - > pvs )
2002-11-18 17:04:08 +03:00
if ( id_equal ( & pvl - > pv - > id , id ) )
return pvl - > pv ;
return NULL ;
2001-10-15 22:39:40 +04:00
}
2001-10-29 16:52:23 +03:00
2002-01-21 17:28:12 +03:00
struct lv_list * find_lv_in_vg ( struct volume_group * vg , const char * lv_name )
2001-10-29 16:52:23 +03:00
{
2002-01-21 17:28:12 +03:00
struct lv_list * lvl ;
2001-10-29 16:52:23 +03:00
const char * ptr ;
/* Use last component */
if ( ( ptr = strrchr ( lv_name , ' / ' ) ) )
ptr + + ;
else
ptr = lv_name ;
2001-10-31 15:47:01 +03:00
2005-06-01 20:51:55 +04:00
list_iterate_items ( lvl , & vg - > lvs )
2002-01-21 19:49:32 +03:00
if ( ! strcmp ( lvl - > lv - > name , ptr ) )
2002-01-21 17:28:12 +03:00
return lvl ;
2001-10-29 16:52:23 +03:00
2001-11-10 01:01:04 +03:00
return NULL ;
2001-10-29 16:52:23 +03:00
}
2002-12-20 02:25:55 +03:00
struct lv_list * find_lv_in_vg_by_lvid ( struct volume_group * vg ,
const union lvid * lvid )
2002-02-25 15:56:16 +03:00
{
struct lv_list * lvl ;
2005-05-19 20:48:51 +04:00
list_iterate_items ( lvl , & vg - > lvs )
2002-03-05 23:03:09 +03:00
if ( ! strncmp ( lvl - > lv - > lvid . s , lvid - > s , sizeof ( * lvid ) ) )
2002-02-25 15:56:16 +03:00
return lvl ;
return NULL ;
}
2001-10-29 16:52:23 +03:00
struct logical_volume * find_lv ( struct volume_group * vg , const char * lv_name )
{
2002-01-21 17:28:12 +03:00
struct lv_list * lvl = find_lv_in_vg ( vg , lv_name ) ;
2002-01-21 19:49:32 +03:00
return lvl ? lvl - > lv : NULL ;
2001-10-29 16:52:23 +03:00
}
2001-11-28 16:45:50 +03:00
struct physical_volume * find_pv ( struct volume_group * vg , struct device * dev )
2001-10-29 16:52:23 +03:00
{
2005-06-01 20:51:55 +04:00
struct pv_list * pvl ;
2001-11-10 01:01:04 +03:00
2005-06-01 20:51:55 +04:00
list_iterate_items ( pvl , & vg - > pvs )
if ( dev = = pvl - > pv - > dev )
return pvl - > pv ;
2002-01-21 19:05:23 +03:00
2001-11-10 01:01:04 +03:00
return NULL ;
2001-10-29 16:52:23 +03:00
}
2002-02-25 15:56:16 +03:00
2007-06-11 22:29:30 +04:00
/* FIXME: liblvm todo - make into function that returns handle */
2004-05-05 15:04:28 +04:00
struct physical_volume * find_pv_by_name ( struct cmd_context * cmd ,
const char * pv_name )
2007-06-11 22:29:30 +04:00
{
return _find_pv_by_name ( cmd , pv_name ) ;
}
static struct physical_volume * _find_pv_by_name ( struct cmd_context * cmd ,
const char * pv_name )
2004-05-05 15:04:28 +04:00
{
struct physical_volume * pv ;
2007-06-11 22:29:30 +04:00
if ( ! ( pv = _pv_read ( cmd , pv_name , NULL , NULL , 1 ) ) ) {
2004-05-05 15:04:28 +04:00
log_error ( " Physical volume %s not found " , pv_name ) ;
return NULL ;
}
2008-01-16 21:15:26 +03:00
if ( is_orphan_vg ( pv - > vg_name ) ) {
/* If a PV has no MDAs - need to search all VGs for it */
if ( ! scan_vgs_for_pvs ( cmd ) )
return_NULL ;
if ( ! ( pv = _pv_read ( cmd , pv_name , NULL , NULL , 1 ) ) ) {
log_error ( " Physical volume %s not found " , pv_name ) ;
return NULL ;
}
}
2007-11-02 16:06:42 +03:00
if ( is_orphan_vg ( pv - > vg_name ) ) {
2004-05-05 15:04:28 +04:00
log_error ( " Physical volume %s not in a volume group " , pv_name ) ;
return NULL ;
}
return pv ;
}
2003-04-25 02:23:24 +04:00
/* Find segment at a given logical extent in an LV */
2007-12-20 21:55:46 +03:00
struct lv_segment * find_seg_by_le ( const struct logical_volume * lv , uint32_t le )
2003-04-25 02:23:24 +04:00
{
struct lv_segment * seg ;
2005-06-01 20:51:55 +04:00
list_iterate_items ( seg , & lv - > segments )
2003-04-25 02:23:24 +04:00
if ( le > = seg - > le & & le < seg - > le + seg - > len )
return seg ;
return NULL ;
}
2007-12-20 21:55:46 +03:00
struct lv_segment * first_seg ( const struct logical_volume * lv )
2005-10-28 16:48:50 +04:00
{
struct lv_segment * seg = NULL ;
list_iterate_items ( seg , & lv - > segments )
break ;
return seg ;
}
2005-05-03 21:28:23 +04:00
/* Find segment at a given physical extent in a PV */
2007-12-20 21:55:46 +03:00
struct pv_segment * find_peg_by_pe ( const struct physical_volume * pv , uint32_t pe )
2005-05-03 21:28:23 +04:00
{
struct pv_segment * peg ;
2005-06-01 20:51:55 +04:00
list_iterate_items ( peg , & pv - > segments )
2005-05-03 21:28:23 +04:00
if ( pe > = peg - > pe & & pe < peg - > pe + peg - > len )
return peg ;
return NULL ;
}
2002-04-24 22:20:51 +04:00
int vg_remove ( struct volume_group * vg )
{
2002-11-18 17:04:08 +03:00
struct metadata_area * mda ;
2002-04-24 22:20:51 +04:00
/* FIXME Improve recovery situation? */
/* Remove each copy of the metadata */
2005-06-01 20:51:55 +04:00
list_iterate_items ( mda , & vg - > fid - > metadata_areas ) {
2002-11-18 17:04:08 +03:00
if ( mda - > ops - > vg_remove & &
! mda - > ops - > vg_remove ( vg - > fid , vg , mda ) ) {
2002-04-24 22:20:51 +04:00
stack ;
return 0 ;
}
}
return 1 ;
}
2008-01-16 22:54:39 +03:00
/*
* Determine whether two vgs are compatible for merging .
*/
int vgs_are_compatible ( struct cmd_context * cmd ,
struct volume_group * vg_from ,
struct volume_group * vg_to )
{
struct lv_list * lvl1 , * lvl2 ;
struct pv_list * pvl ;
if ( lvs_in_vg_activated ( vg_from ) ) {
log_error ( " Logical volumes in \" %s \" must be inactive " ,
vg_from - > name ) ;
goto error ;
}
/* Check compatibility */
if ( vg_to - > extent_size ! = vg_from - > extent_size ) {
log_error ( " Extent sizes differ: %d (%s) and %d (%s) " ,
vg_to - > extent_size , vg_to - > name ,
vg_from - > extent_size , vg_from - > name ) ;
goto error ;
}
if ( vg_to - > max_pv & &
( vg_to - > max_pv < vg_to - > pv_count + vg_from - > pv_count ) ) {
log_error ( " Maximum number of physical volumes (%d) exceeded "
" for \" %s \" and \" %s \" " , vg_to - > max_pv , vg_to - > name ,
vg_from - > name ) ;
goto error ;
}
if ( vg_to - > max_lv & &
( vg_to - > max_lv < vg_to - > lv_count + vg_from - > lv_count ) ) {
log_error ( " Maximum number of logical volumes (%d) exceeded "
" for \" %s \" and \" %s \" " , vg_to - > max_lv , vg_to - > name ,
vg_from - > name ) ;
goto error ;
}
/* Check no conflicts with LV names */
list_iterate_items ( lvl1 , & vg_to - > lvs ) {
char * name1 = lvl1 - > lv - > name ;
list_iterate_items ( lvl2 , & vg_from - > lvs ) {
char * name2 = lvl2 - > lv - > name ;
if ( ! strcmp ( name1 , name2 ) ) {
log_error ( " Duplicate logical volume "
" name \" %s \" "
" in \" %s \" and \" %s \" " ,
name1 , vg_to - > name , vg_from - > name ) ;
goto error ;
}
}
}
/* Check no PVs are constructed from either VG */
list_iterate_items ( pvl , & vg_to - > pvs ) {
if ( pv_uses_vg ( pvl - > pv , vg_from ) ) {
log_error ( " Physical volume %s might be constructed "
" from same volume group %s. " ,
pv_dev_name ( pvl - > pv ) , vg_from - > name ) ;
goto error ;
}
}
list_iterate_items ( pvl , & vg_from - > pvs ) {
if ( pv_uses_vg ( pvl - > pv , vg_to ) ) {
log_error ( " Physical volume %s might be constructed "
" from same volume group %s. " ,
pv_dev_name ( pvl - > pv ) , vg_to - > name ) ;
goto error ;
}
}
return 1 ;
error :
return 0 ;
}
2005-07-12 23:40:59 +04:00
int vg_validate ( struct volume_group * vg )
2002-04-24 22:20:51 +04:00
{
2006-08-09 23:33:25 +04:00
struct pv_list * pvl , * pvl2 ;
struct lv_list * lvl , * lvl2 ;
2006-12-01 02:11:42 +03:00
char uuid [ 64 ] __attribute ( ( aligned ( 8 ) ) ) ;
2006-08-09 23:33:25 +04:00
int r = 1 ;
2006-10-06 02:02:52 +04:00
/* FIXME Also check there's no data/metadata overlap */
2006-08-09 23:33:25 +04:00
list_iterate_items ( pvl , & vg - > pvs ) {
list_iterate_items ( pvl2 , & vg - > pvs ) {
if ( pvl = = pvl2 )
break ;
if ( id_equal ( & pvl - > pv - > id ,
& pvl2 - > pv - > id ) ) {
if ( ! id_write_format ( & pvl - > pv - > id , uuid ,
sizeof ( uuid ) ) )
stack ;
log_error ( " Internal error: Duplicate PV id "
" %s detected for %s in %s. " ,
2007-10-12 18:29:32 +04:00
uuid , pv_dev_name ( pvl - > pv ) ,
2006-08-09 23:33:25 +04:00
vg - > name ) ;
r = 0 ;
}
}
2007-03-23 15:43:17 +03:00
if ( strcmp ( pvl - > pv - > vg_name , vg - > name ) ) {
log_error ( " Internal error: VG name for PV %s is corrupted " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pvl - > pv ) ) ;
2007-03-23 15:43:17 +03:00
r = 0 ;
}
2006-08-09 23:33:25 +04:00
}
2002-04-24 22:20:51 +04:00
2005-05-03 21:28:23 +04:00
if ( ! check_pv_segments ( vg ) ) {
log_error ( " Internal error: PV segments corrupted in %s. " ,
vg - > name ) ;
2006-08-09 23:33:25 +04:00
r = 0 ;
}
list_iterate_items ( lvl , & vg - > lvs ) {
list_iterate_items ( lvl2 , & vg - > lvs ) {
if ( lvl = = lvl2 )
break ;
if ( ! strcmp ( lvl - > lv - > name , lvl2 - > lv - > name ) ) {
log_error ( " Internal error: Duplicate LV name "
" %s detected in %s. " , lvl - > lv - > name ,
vg - > name ) ;
r = 0 ;
}
if ( id_equal ( & lvl - > lv - > lvid . id [ 1 ] ,
& lvl2 - > lv - > lvid . id [ 1 ] ) ) {
if ( ! id_write_format ( & lvl - > lv - > lvid . id [ 1 ] , uuid ,
sizeof ( uuid ) ) )
stack ;
log_error ( " Internal error: Duplicate LV id "
" %s detected for %s and %s in %s. " ,
uuid , lvl - > lv - > name , lvl2 - > lv - > name ,
vg - > name ) ;
r = 0 ;
}
}
2005-05-03 21:28:23 +04:00
}
2005-06-01 20:51:55 +04:00
list_iterate_items ( lvl , & vg - > lvs ) {
2005-10-28 01:51:28 +04:00
if ( ! check_lv_segments ( lvl - > lv , 1 ) ) {
2005-06-01 20:51:55 +04:00
log_error ( " Internal error: LV segments corrupted in %s. " ,
lvl - > lv - > name ) ;
2006-08-09 23:33:25 +04:00
r = 0 ;
2005-06-01 20:51:55 +04:00
}
}
2006-08-09 23:33:25 +04:00
return r ;
2005-07-12 23:40:59 +04:00
}
/*
* After vg_write ( ) returns success ,
* caller MUST call either vg_commit ( ) or vg_revert ( )
*/
int vg_write ( struct volume_group * vg )
{
struct list * mdah ;
struct metadata_area * mda ;
if ( ! vg_validate ( vg ) ) {
stack ;
return 0 ;
}
2002-04-30 21:12:37 +04:00
if ( vg - > status & PARTIAL_VG ) {
log_error ( " Cannot change metadata for partial volume group %s " ,
vg - > name ) ;
return 0 ;
}
2002-11-18 17:04:08 +03:00
if ( list_empty ( & vg - > fid - > metadata_areas ) ) {
log_error ( " Aborting vg_write: No metadata areas to write to! " ) ;
return 0 ;
}
2002-04-24 22:20:51 +04:00
vg - > seqno + + ;
/* Write to each copy of the metadata area */
2005-06-01 20:51:55 +04:00
list_iterate_items ( mda , & vg - > fid - > metadata_areas ) {
2004-03-27 00:07:30 +03:00
if ( ! mda - > ops - > vg_write ) {
2003-08-27 01:12:06 +04:00
log_error ( " Format does not support writing volume "
" group metadata areas " ) ;
/* Revert */
2005-06-01 20:51:55 +04:00
list_uniterate ( mdah , & vg - > fid - > metadata_areas , & mda - > list ) {
mda = list_item ( mdah , struct metadata_area ) ;
2005-04-06 22:59:55 +04:00
2003-08-27 01:12:06 +04:00
if ( mda - > ops - > vg_revert & &
! mda - > ops - > vg_revert ( vg - > fid , vg , mda ) ) {
stack ;
}
}
return 0 ;
}
2002-11-18 17:04:08 +03:00
if ( ! mda - > ops - > vg_write ( vg - > fid , vg , mda ) ) {
2002-04-24 22:20:51 +04:00
stack ;
2003-07-05 02:34:56 +04:00
/* Revert */
2005-06-01 20:51:55 +04:00
list_uniterate ( mdah , & vg - > fid - > metadata_areas , & mda - > list ) {
mda = list_item ( mdah , struct metadata_area ) ;
2003-07-05 02:34:56 +04:00
if ( mda - > ops - > vg_revert & &
! mda - > ops - > vg_revert ( vg - > fid , vg , mda ) ) {
stack ;
}
}
2002-04-24 22:20:51 +04:00
return 0 ;
}
}
2005-04-06 22:59:55 +04:00
/* Now pre-commit each copy of the new metadata */
2005-06-01 20:51:55 +04:00
list_iterate_items ( mda , & vg - > fid - > metadata_areas ) {
2005-04-06 22:59:55 +04:00
if ( mda - > ops - > vg_precommit & &
! mda - > ops - > vg_precommit ( vg - > fid , vg , mda ) ) {
stack ;
/* Revert */
2005-06-01 20:51:55 +04:00
list_iterate_items ( mda , & vg - > fid - > metadata_areas ) {
2005-04-06 22:59:55 +04:00
if ( mda - > ops - > vg_revert & &
! mda - > ops - > vg_revert ( vg - > fid , vg , mda ) ) {
stack ;
}
}
return 0 ;
}
}
2003-07-05 02:34:56 +04:00
return 1 ;
}
/* Commit pending changes */
int vg_commit ( struct volume_group * vg )
{
struct metadata_area * mda ;
int cache_updated = 0 ;
int failed = 0 ;
2002-04-24 22:20:51 +04:00
/* Commit to each copy of the metadata area */
2005-06-01 20:51:55 +04:00
list_iterate_items ( mda , & vg - > fid - > metadata_areas ) {
2003-07-05 02:34:56 +04:00
failed = 0 ;
2002-11-18 17:04:08 +03:00
if ( mda - > ops - > vg_commit & &
! mda - > ops - > vg_commit ( vg - > fid , vg , mda ) ) {
2002-04-24 22:20:51 +04:00
stack ;
2003-07-05 02:34:56 +04:00
failed = 1 ;
}
/* Update cache first time we succeed */
if ( ! failed & & ! cache_updated ) {
lvmcache_update_vg ( vg ) ;
cache_updated = 1 ;
}
}
/* If at least one mda commit succeeded, it was committed */
return cache_updated ;
}
/* Don't commit any pending changes */
int vg_revert ( struct volume_group * vg )
{
struct metadata_area * mda ;
2005-06-01 20:51:55 +04:00
list_iterate_items ( mda , & vg - > fid - > metadata_areas ) {
2003-07-05 02:34:56 +04:00
if ( mda - > ops - > vg_revert & &
! mda - > ops - > vg_revert ( vg - > fid , vg , mda ) ) {
stack ;
2002-04-24 22:20:51 +04:00
}
}
return 1 ;
}
2002-11-18 17:04:08 +03:00
/* Make orphan PVs look like a VG */
2002-12-20 02:25:55 +03:00
static struct volume_group * _vg_read_orphans ( struct cmd_context * cmd )
2002-11-18 17:04:08 +03:00
{
2003-07-05 02:34:56 +04:00
struct lvmcache_vginfo * vginfo ;
2005-06-01 20:51:55 +04:00
struct lvmcache_info * info ;
2002-11-18 17:04:08 +03:00
struct pv_list * pvl ;
struct volume_group * vg ;
struct physical_volume * pv ;
2006-04-12 21:54:11 +04:00
if ( ! ( vginfo = vginfo_from_vgname ( ORPHAN , NULL ) ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return NULL ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( vg = dm_pool_zalloc ( cmd - > mem , sizeof ( * vg ) ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " vg allocation failed " ) ;
return NULL ;
}
list_init ( & vg - > pvs ) ;
list_init ( & vg - > lvs ) ;
2004-03-08 20:19:15 +03:00
list_init ( & vg - > tags ) ;
2002-11-18 17:04:08 +03:00
vg - > cmd = cmd ;
2005-10-17 03:03:59 +04:00
if ( ! ( vg - > name = dm_pool_strdup ( cmd - > mem , ORPHAN ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " vg name allocation failed " ) ;
return NULL ;
}
2005-06-01 20:51:55 +04:00
list_iterate_items ( info , & vginfo - > infos ) {
2007-06-11 22:29:30 +04:00
if ( ! ( pv = _pv_read ( cmd , dev_name ( info - > dev ) , NULL , NULL , 1 ) ) ) {
2002-11-18 17:04:08 +03:00
continue ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( pvl = dm_pool_zalloc ( cmd - > mem , sizeof ( * pvl ) ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " pv_list allocation failed " ) ;
return NULL ;
}
pvl - > pv = pv ;
list_add ( & vg - > pvs , & pvl - > list ) ;
vg - > pv_count + + ;
}
return vg ;
}
2007-02-07 16:29:52 +03:00
static int _update_pv_list ( struct list * all_pvs , struct volume_group * vg )
{
struct pv_list * pvl , * pvl2 ;
list_iterate_items ( pvl , & vg - > pvs ) {
list_iterate_items ( pvl2 , all_pvs ) {
if ( pvl - > pv - > dev = = pvl2 - > pv - > dev )
goto next_pv ;
}
/* PV is not on list so add it. Note that we don't copy it. */
if ( ! ( pvl2 = dm_pool_zalloc ( vg - > cmd - > mem , sizeof ( * pvl2 ) ) ) ) {
log_error ( " pv_list allocation for '%s' failed " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pvl - > pv ) ) ;
2007-02-07 16:29:52 +03:00
return 0 ;
}
pvl2 - > pv = pvl - > pv ;
list_add ( all_pvs , & pvl2 - > list ) ;
next_pv :
;
}
return 1 ;
}
2002-11-18 17:04:08 +03:00
/* Caller sets consistent to 1 if it's safe for vg_read to correct
* inconsistent metadata on disk ( i . e . the VG write lock is held ) .
* This guarantees only consistent metadata is returned unless PARTIAL_VG .
* If consistent is 0 , caller must check whether consistent = = 1 on return
* and take appropriate action if it isn ' t ( e . g . abort ; get write lock
* and call vg_read again ) .
2005-10-31 23:15:28 +03:00
*
* If precommitted is set , use precommitted metadata if present .
2002-11-18 17:04:08 +03:00
*/
2005-04-06 22:59:55 +04:00
static struct volume_group * _vg_read ( struct cmd_context * cmd ,
const char * vgname ,
2006-04-13 01:23:04 +04:00
const char * vgid ,
2005-04-06 22:59:55 +04:00
int * consistent , int precommitted )
2002-04-24 22:20:51 +04:00
{
struct format_instance * fid ;
2002-12-20 02:25:55 +03:00
const struct format_type * fmt ;
struct volume_group * vg , * correct_vg = NULL ;
2002-11-18 17:04:08 +03:00
struct metadata_area * mda ;
2002-12-20 02:25:55 +03:00
int inconsistent = 0 ;
2007-02-07 16:29:52 +03:00
int inconsistent_vgid = 0 ;
2005-10-31 23:15:28 +03:00
int use_precommitted = precommitted ;
2006-04-21 23:12:41 +04:00
struct list * pvids ;
2007-02-07 16:29:52 +03:00
struct pv_list * pvl , * pvl2 ;
struct list all_pvs ;
char uuid [ 64 ] __attribute ( ( aligned ( 8 ) ) ) ;
2002-04-24 22:20:51 +04:00
2007-11-02 16:06:42 +03:00
if ( is_orphan_vg ( vgname ) ) {
2005-10-31 23:15:28 +03:00
if ( use_precommitted ) {
2005-04-06 22:59:55 +04:00
log_error ( " Internal error: vg_read requires vgname "
" with pre-commit. " ) ;
return NULL ;
}
2002-11-18 17:04:08 +03:00
* consistent = 1 ;
return _vg_read_orphans ( cmd ) ;
}
/* Find the vgname in the cache */
/* If it's not there we must do full scan to be completely sure */
2006-04-13 01:23:04 +04:00
if ( ! ( fmt = fmt_from_vgname ( vgname , vgid ) ) ) {
2003-07-05 02:34:56 +04:00
lvmcache_label_scan ( cmd , 0 ) ;
2006-04-13 01:23:04 +04:00
if ( ! ( fmt = fmt_from_vgname ( vgname , vgid ) ) ) {
2003-07-05 02:34:56 +04:00
if ( memlock ( ) ) {
stack ;
return NULL ;
}
2005-03-08 16:46:17 +03:00
lvmcache_label_scan ( cmd , 2 ) ;
2006-04-13 01:23:04 +04:00
if ( ! ( fmt = fmt_from_vgname ( vgname , vgid ) ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return NULL ;
}
2002-04-24 22:20:51 +04:00
}
}
2005-10-31 23:15:28 +03:00
if ( use_precommitted & & ! ( fmt - > features & FMT_PRECOMMIT ) )
use_precommitted = 0 ;
2005-04-06 22:59:55 +04:00
2006-04-21 23:12:41 +04:00
/* Store pvids for later so we can check if any are missing */
if ( ! ( pvids = lvmcache_get_pvids ( cmd , vgname , vgid ) ) ) {
stack ;
return NULL ;
}
2002-11-18 17:04:08 +03:00
/* create format instance with appropriate metadata area */
2006-04-13 01:23:04 +04:00
if ( ! ( fid = fmt - > ops - > create_instance ( fmt , vgname , vgid , NULL ) ) ) {
2002-04-24 22:20:51 +04:00
log_error ( " Failed to create format instance " ) ;
return NULL ;
}
/* Ensure contents of all metadata areas match - else do recovery */
2005-06-01 20:51:55 +04:00
list_iterate_items ( mda , & fid - > metadata_areas ) {
2005-10-31 23:15:28 +03:00
if ( ( use_precommitted & &
2005-04-06 22:59:55 +04:00
! ( vg = mda - > ops - > vg_read_precommit ( fid , vgname , mda ) ) ) | |
2005-10-31 23:15:28 +03:00
( ! use_precommitted & &
2005-04-06 22:59:55 +04:00
! ( vg = mda - > ops - > vg_read ( fid , vgname , mda ) ) ) ) {
2002-11-18 17:04:08 +03:00
inconsistent = 1 ;
continue ;
2002-04-24 22:20:51 +04:00
}
2002-12-20 02:25:55 +03:00
if ( ! correct_vg ) {
2002-04-24 22:20:51 +04:00
correct_vg = vg ;
continue ;
}
2002-11-18 17:04:08 +03:00
/* FIXME Also ensure contents same - checksum compare? */
2002-04-24 22:20:51 +04:00
if ( correct_vg - > seqno ! = vg - > seqno ) {
inconsistent = 1 ;
if ( vg - > seqno > correct_vg - > seqno )
correct_vg = vg ;
}
}
2006-04-21 23:12:41 +04:00
/* Ensure every PV in the VG was in the cache */
if ( correct_vg ) {
if ( list_size ( & correct_vg - > pvs ) ! = list_size ( pvids ) ) {
log_debug ( " Cached VG %s had incorrect PV list " ,
2006-09-22 00:25:54 +04:00
vgname ) ;
2006-07-04 23:36:49 +04:00
if ( memlock ( ) )
inconsistent = 1 ;
else
correct_vg = NULL ;
2006-04-21 23:12:41 +04:00
} else list_iterate_items ( pvl , & correct_vg - > pvs ) {
if ( ! str_list_match_item ( pvids , pvl - > pv - > dev - > pvid ) ) {
log_debug ( " Cached VG %s had incorrect PV list " ,
2006-09-22 00:25:54 +04:00
vgname ) ;
2006-04-21 23:12:41 +04:00
correct_vg = NULL ;
break ;
}
}
}
2007-02-07 16:29:52 +03:00
list_init ( & all_pvs ) ;
2005-03-22 01:40:35 +03:00
/* Failed to find VG where we expected it - full scan and retry */
2002-12-20 02:25:55 +03:00
if ( ! correct_vg ) {
2005-03-22 01:40:35 +03:00
inconsistent = 0 ;
2006-07-04 23:36:49 +04:00
if ( memlock ( ) ) {
stack ;
return NULL ;
}
2005-03-22 01:40:35 +03:00
lvmcache_label_scan ( cmd , 2 ) ;
2006-04-13 01:23:04 +04:00
if ( ! ( fmt = fmt_from_vgname ( vgname , vgid ) ) ) {
2005-03-22 01:40:35 +03:00
stack ;
return NULL ;
}
2005-10-31 23:15:28 +03:00
if ( precommitted & & ! ( fmt - > features & FMT_PRECOMMIT ) )
use_precommitted = 0 ;
2005-04-06 22:59:55 +04:00
2005-03-22 01:40:35 +03:00
/* create format instance with appropriate metadata area */
2006-04-13 01:23:04 +04:00
if ( ! ( fid = fmt - > ops - > create_instance ( fmt , vgname , vgid , NULL ) ) ) {
2005-03-22 01:40:35 +03:00
log_error ( " Failed to create format instance " ) ;
return NULL ;
}
/* Ensure contents of all metadata areas match - else recover */
2005-06-01 20:51:55 +04:00
list_iterate_items ( mda , & fid - > metadata_areas ) {
2005-10-31 23:15:28 +03:00
if ( ( use_precommitted & &
2005-04-06 22:59:55 +04:00
! ( vg = mda - > ops - > vg_read_precommit ( fid , vgname ,
mda ) ) ) | |
2005-10-31 23:15:28 +03:00
( ! use_precommitted & &
2005-04-06 22:59:55 +04:00
! ( vg = mda - > ops - > vg_read ( fid , vgname , mda ) ) ) ) {
2005-03-22 01:40:35 +03:00
inconsistent = 1 ;
continue ;
}
if ( ! correct_vg ) {
correct_vg = vg ;
2007-02-07 16:29:52 +03:00
if ( ! _update_pv_list ( & all_pvs , correct_vg ) )
return_NULL ;
2005-03-22 01:40:35 +03:00
continue ;
}
2007-02-07 16:29:52 +03:00
if ( strncmp ( ( char * ) vg - > id . uuid ,
( char * ) correct_vg - > id . uuid , ID_LEN ) ) {
inconsistent = 1 ;
inconsistent_vgid = 1 ;
}
2005-03-22 01:40:35 +03:00
/* FIXME Also ensure contents same - checksums same? */
if ( correct_vg - > seqno ! = vg - > seqno ) {
inconsistent = 1 ;
2007-02-07 16:29:52 +03:00
if ( vg - > seqno > correct_vg - > seqno ) {
if ( ! _update_pv_list ( & all_pvs , vg ) )
return_NULL ;
2005-03-22 01:40:35 +03:00
correct_vg = vg ;
2007-02-07 16:29:52 +03:00
}
2005-03-22 01:40:35 +03:00
}
}
/* Give up looking */
if ( ! correct_vg ) {
stack ;
return NULL ;
}
2002-05-13 16:38:54 +04:00
}
2003-07-05 02:34:56 +04:00
lvmcache_update_vg ( correct_vg ) ;
2002-11-18 17:04:08 +03:00
2002-04-24 22:20:51 +04:00
if ( inconsistent ) {
2005-10-31 23:15:28 +03:00
/* FIXME Test should be if we're *using* precommitted metadata not if we were searching for it */
if ( use_precommitted ) {
2005-04-06 22:59:55 +04:00
log_error ( " Inconsistent pre-commit metadata copies "
" for volume group %s " , vgname ) ;
return NULL ;
}
2002-11-18 17:04:08 +03:00
if ( ! * consistent )
return correct_vg ;
/* Don't touch partial volume group metadata */
/* Should be fixed manually with vgcfgbackup/restore etc. */
if ( ( correct_vg - > status & PARTIAL_VG ) ) {
log_error ( " Inconsistent metadata copies found for "
" partial volume group %s " , vgname ) ;
* consistent = 0 ;
return correct_vg ;
}
2007-02-07 16:29:52 +03:00
/* Don't touch if vgids didn't match */
if ( inconsistent_vgid ) {
log_error ( " Inconsistent metadata UUIDs found for "
" volume group %s " , vgname ) ;
* consistent = 0 ;
return correct_vg ;
}
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: Inconsistent metadata found for VG %s - updating "
" to use version %u " , vgname , correct_vg - > seqno ) ;
2007-02-07 16:29:52 +03:00
2002-04-24 22:20:51 +04:00
if ( ! vg_write ( correct_vg ) ) {
log_error ( " Automatic metadata correction failed " ) ;
return NULL ;
}
2007-02-07 16:29:52 +03:00
2005-01-17 21:24:28 +03:00
if ( ! vg_commit ( correct_vg ) ) {
log_error ( " Automatic metadata correction commit "
" failed " ) ;
return NULL ;
}
2007-02-07 16:29:52 +03:00
list_iterate_items ( pvl , & all_pvs ) {
list_iterate_items ( pvl2 , & correct_vg - > pvs ) {
if ( pvl - > pv - > dev = = pvl2 - > pv - > dev )
goto next_pv ;
}
if ( ! id_write_format ( & pvl - > pv - > id , uuid , sizeof ( uuid ) ) )
return_NULL ;
log_error ( " Removing PV %s (%s) that no longer belongs to VG %s " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pvl - > pv ) , uuid , correct_vg - > name ) ;
2007-02-07 16:29:52 +03:00
if ( ! pv_write_orphan ( cmd , pvl - > pv ) )
return_NULL ;
next_pv :
;
}
2002-04-24 22:20:51 +04:00
}
2003-05-06 16:06:02 +04:00
if ( ( correct_vg - > status & PVMOVE ) & & ! pvmove_mode ( ) ) {
2003-04-30 19:23:43 +04:00
log_error ( " WARNING: Interrupted pvmove detected in "
2003-07-15 05:26:24 +04:00
" volume group %s " , correct_vg - > name ) ;
2003-04-30 19:23:43 +04:00
log_error ( " Please restore the metadata by running "
" vgcfgrestore. " ) ;
return NULL ;
}
2002-04-24 22:20:51 +04:00
2003-04-30 19:23:43 +04:00
* consistent = 1 ;
2002-05-13 16:38:54 +04:00
return correct_vg ;
2002-04-24 22:20:51 +04:00
}
2005-04-06 22:59:55 +04:00
struct volume_group * vg_read ( struct cmd_context * cmd , const char * vgname ,
2006-04-13 01:23:04 +04:00
const char * vgid , int * consistent )
2005-04-06 22:59:55 +04:00
{
2005-06-14 21:54:48 +04:00
struct volume_group * vg ;
struct lv_list * lvl ;
2006-04-13 01:23:04 +04:00
if ( ! ( vg = _vg_read ( cmd , vgname , vgid , consistent , 0 ) ) )
2005-06-14 21:54:48 +04:00
return NULL ;
if ( ! check_pv_segments ( vg ) ) {
log_error ( " Internal error: PV segments corrupted in %s. " ,
vg - > name ) ;
return NULL ;
}
list_iterate_items ( lvl , & vg - > lvs ) {
2005-10-28 01:51:28 +04:00
if ( ! check_lv_segments ( lvl - > lv , 1 ) ) {
2005-06-14 21:54:48 +04:00
log_error ( " Internal error: LV segments corrupted in %s. " ,
lvl - > lv - > name ) ;
return NULL ;
}
}
return vg ;
2005-04-06 22:59:55 +04:00
}
2002-11-18 17:04:08 +03:00
/* This is only called by lv_from_lvid, which is only called from
* activate . c so we know the appropriate VG lock is already held and
* the vg_read is therefore safe .
*/
2005-10-31 23:15:28 +03:00
static struct volume_group * _vg_read_by_vgid ( struct cmd_context * cmd ,
const char * vgid ,
int precommitted )
2002-04-24 22:20:51 +04:00
{
2003-10-16 00:10:11 +04:00
const char * vgname ;
2005-06-01 20:51:55 +04:00
struct list * vgnames ;
2002-04-24 22:20:51 +04:00
struct volume_group * vg ;
2003-07-05 02:34:56 +04:00
struct lvmcache_vginfo * vginfo ;
2005-06-01 20:51:55 +04:00
struct str_list * strl ;
2002-11-18 17:04:08 +03:00
int consistent = 0 ;
/* Is corresponding vgname already cached? */
if ( ( vginfo = vginfo_from_vgid ( vgid ) ) & &
2007-11-02 16:06:42 +03:00
vginfo - > vgname & & ! is_orphan_vg ( vginfo - > vgname ) ) {
2006-04-13 01:23:04 +04:00
if ( ( vg = _vg_read ( cmd , vginfo - > vgname , vgid ,
2005-10-31 23:15:28 +03:00
& consistent , precommitted ) ) & &
2006-05-10 01:23:51 +04:00
! strncmp ( ( char * ) vg - > id . uuid , vgid , ID_LEN ) ) {
2002-11-18 17:04:08 +03:00
if ( ! consistent ) {
log_error ( " Volume group %s metadata is "
" inconsistent " , vginfo - > vgname ) ;
2006-07-04 23:36:49 +04:00
if ( ! partial_mode ( ) )
return NULL ;
2002-11-18 17:04:08 +03:00
}
return vg ;
}
}
2002-04-24 22:20:51 +04:00
2003-10-16 00:10:11 +04:00
/* Mustn't scan if memory locked: ensure cache gets pre-populated! */
if ( memlock ( ) )
return NULL ;
2003-07-05 02:34:56 +04:00
/* FIXME Need a genuine read by ID here - don't vg_read by name! */
/* FIXME Disabled vgrenames while active for now because we aren't
* allowed to do a full scan here any more . */
// The slow way - full scan required to cope with vgrename
2005-03-08 16:46:17 +03:00
if ( ! ( vgnames = get_vgs ( cmd , 2 ) ) ) {
2002-04-24 22:20:51 +04:00
log_error ( " vg_read_by_vgid: get_vgs failed " ) ;
return NULL ;
}
2005-06-01 20:51:55 +04:00
list_iterate_items ( strl , vgnames ) {
vgname = strl - > str ;
2007-11-02 16:06:42 +03:00
if ( ! vgname | | is_orphan_vg ( vgname ) )
2003-07-05 02:34:56 +04:00
continue ; // FIXME Unnecessary?
2002-11-18 17:04:08 +03:00
consistent = 0 ;
2006-04-13 01:23:04 +04:00
if ( ( vg = _vg_read ( cmd , vgname , vgid , & consistent ,
2005-10-31 23:15:28 +03:00
precommitted ) ) & &
2006-05-10 01:23:51 +04:00
! strncmp ( ( char * ) vg - > id . uuid , vgid , ID_LEN ) ) {
2002-11-18 17:04:08 +03:00
if ( ! consistent ) {
log_error ( " Volume group %s metadata is "
" inconsistent " , vgname ) ;
return NULL ;
}
return vg ;
}
2002-04-24 22:20:51 +04:00
}
return NULL ;
}
2002-11-18 17:04:08 +03:00
/* Only called by activate.c */
2005-10-31 23:15:28 +03:00
struct logical_volume * lv_from_lvid ( struct cmd_context * cmd , const char * lvid_s ,
int precommitted )
2002-11-18 17:04:08 +03:00
{
struct lv_list * lvl ;
struct volume_group * vg ;
2002-12-20 02:25:55 +03:00
const union lvid * lvid ;
2002-11-18 17:04:08 +03:00
2002-12-20 02:25:55 +03:00
lvid = ( const union lvid * ) lvid_s ;
2002-11-18 17:04:08 +03:00
log_very_verbose ( " Finding volume group for uuid %s " , lvid_s ) ;
2006-05-10 01:23:51 +04:00
if ( ! ( vg = _vg_read_by_vgid ( cmd , ( char * ) lvid - > id [ 0 ] . uuid , precommitted ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Volume group for uuid not found: %s " , lvid_s ) ;
return NULL ;
}
log_verbose ( " Found volume group \" %s \" " , vg - > name ) ;
if ( vg - > status & EXPORTED_VG ) {
log_error ( " Volume group \" %s \" is exported " , vg - > name ) ;
return NULL ;
}
if ( ! ( lvl = find_lv_in_vg_by_lvid ( vg , lvid ) ) ) {
log_very_verbose ( " Can't find logical volume id %s " , lvid_s ) ;
return NULL ;
}
return lvl - > lv ;
}
2007-06-13 01:20:20 +04:00
/**
* pv_read - read and return a handle to a physical volume
* @ cmd : LVM command initiating the pv_read
* @ pv_name : full device name of the PV , including the path
* @ mdas : list of metadata areas of the PV
* @ label_sector : sector number where the PV label is stored on @ pv_name
* @ warnings :
*
* Returns :
* PV handle - valid pv_name and successful read of the PV , or
* NULL - invalid parameter or error in reading the PV
*
* Note :
* FIXME - liblvm todo - make into function that returns handle
*/
2002-11-18 17:04:08 +03:00
struct physical_volume * pv_read ( struct cmd_context * cmd , const char * pv_name ,
2004-06-19 23:27:00 +04:00
struct list * mdas , uint64_t * label_sector ,
int warnings )
2007-06-11 22:29:30 +04:00
{
return _pv_read ( cmd , pv_name , mdas , label_sector , warnings ) ;
}
/* FIXME Use label functions instead of PV functions */
static struct physical_volume * _pv_read ( struct cmd_context * cmd ,
const char * pv_name ,
struct list * mdas ,
uint64_t * label_sector ,
int warnings )
2002-04-24 22:20:51 +04:00
{
struct physical_volume * pv ;
2002-11-18 17:04:08 +03:00
struct label * label ;
2003-07-05 02:34:56 +04:00
struct lvmcache_info * info ;
2002-11-18 17:04:08 +03:00
struct device * dev ;
2002-04-24 22:20:51 +04:00
2002-11-18 17:04:08 +03:00
if ( ! ( dev = dev_cache_get ( pv_name , cmd - > filter ) ) ) {
stack ;
2005-04-20 00:52:35 +04:00
return NULL ;
2002-04-24 22:20:51 +04:00
}
2007-04-23 22:21:01 +04:00
if ( ! ( label_read ( dev , & label , UINT64_C ( 0 ) ) ) ) {
2004-06-19 23:27:00 +04:00
if ( warnings )
log_error ( " No physical volume label read from %s " ,
pv_name ) ;
2005-04-20 00:52:35 +04:00
return NULL ;
2002-04-24 22:20:51 +04:00
}
2003-07-05 02:34:56 +04:00
info = ( struct lvmcache_info * ) label - > info ;
2002-11-18 17:04:08 +03:00
if ( label_sector & & * label_sector )
* label_sector = label - > sector ;
2005-10-17 03:03:59 +04:00
if ( ! ( pv = dm_pool_zalloc ( cmd - > mem , sizeof ( * pv ) ) ) ) {
2003-04-25 02:23:24 +04:00
log_error ( " pv allocation for '%s' failed " , pv_name ) ;
2005-04-20 00:52:35 +04:00
return NULL ;
2002-11-18 17:04:08 +03:00
}
2004-03-08 20:19:15 +03:00
list_init ( & pv - > tags ) ;
2005-04-20 00:52:35 +04:00
list_init ( & pv - > segments ) ;
2004-03-08 20:19:15 +03:00
2002-11-18 17:04:08 +03:00
/* FIXME Move more common code up here */
if ( ! ( info - > fmt - > ops - > pv_read ( info - > fmt , pv_name , pv , mdas ) ) ) {
2002-04-24 22:20:51 +04:00
log_error ( " Failed to read existing physical volume '%s' " ,
pv_name ) ;
2005-04-20 00:52:35 +04:00
return NULL ;
2002-04-24 22:20:51 +04:00
}
if ( ! pv - > size )
return NULL ;
2005-04-20 00:52:35 +04:00
if ( ! alloc_pv_segment_whole_pv ( cmd - > mem , pv ) ) {
stack ;
return NULL ;
}
return pv ;
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:04:08 +03:00
/* May return empty list */
struct list * get_vgs ( struct cmd_context * cmd , int full_scan )
2002-04-24 22:20:51 +04:00
{
2003-07-05 02:34:56 +04:00
return lvmcache_get_vgnames ( cmd , full_scan ) ;
2002-04-24 22:20:51 +04:00
}
2006-04-13 01:23:04 +04:00
struct list * get_vgids ( struct cmd_context * cmd , int full_scan )
{
return lvmcache_get_vgids ( cmd , full_scan ) ;
}
2008-01-16 21:15:26 +03:00
static int _get_pvs ( struct cmd_context * cmd , struct list * * pvslist )
2002-04-24 22:20:51 +04:00
{
2005-06-01 20:51:55 +04:00
struct str_list * strl ;
2002-04-24 22:20:51 +04:00
struct list * results ;
2006-04-13 01:23:04 +04:00
const char * vgname , * vgid ;
2002-11-18 17:04:08 +03:00
struct list * pvh , * tmp ;
2006-04-13 01:23:04 +04:00
struct list * vgids ;
2002-11-18 17:04:08 +03:00
struct volume_group * vg ;
int consistent = 0 ;
2003-04-30 19:23:43 +04:00
int old_partial ;
int old_pvmove ;
2002-11-18 17:04:08 +03:00
2003-07-05 02:34:56 +04:00
lvmcache_label_scan ( cmd , 0 ) ;
2002-04-24 22:20:51 +04:00
2008-01-16 21:15:26 +03:00
if ( pvslist ) {
if ( ! ( results = dm_pool_alloc ( cmd - > mem , sizeof ( * results ) ) ) ) {
log_error ( " PV list allocation failed " ) ;
2008-01-17 01:52:46 +03:00
return 0 ;
2008-01-16 21:15:26 +03:00
}
2002-04-24 22:20:51 +04:00
2008-01-16 21:15:26 +03:00
list_init ( results ) ;
}
2002-04-24 22:20:51 +04:00
2002-11-18 17:04:08 +03:00
/* Get list of VGs */
2006-04-13 01:23:04 +04:00
if ( ! ( vgids = get_vgids ( cmd , 0 ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " get_pvs: get_vgs failed " ) ;
2008-01-16 21:15:26 +03:00
return 0 ;
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:04:08 +03:00
/* Read every VG to ensure cache consistency */
/* Orphan VG is last on list */
2003-04-30 19:23:43 +04:00
old_partial = partial_mode ( ) ;
old_pvmove = pvmove_mode ( ) ;
2002-11-18 17:04:08 +03:00
init_partial ( 1 ) ;
2003-04-30 19:23:43 +04:00
init_pvmove ( 1 ) ;
2006-04-13 01:23:04 +04:00
list_iterate_items ( strl , vgids ) {
vgid = strl - > str ;
if ( ! vgid )
2002-11-18 17:04:08 +03:00
continue ; /* FIXME Unnecessary? */
consistent = 0 ;
2006-04-14 01:08:29 +04:00
if ( ! ( vgname = vgname_from_vgid ( NULL , vgid ) ) ) {
2006-04-13 01:23:04 +04:00
stack ;
continue ;
}
if ( ! ( vg = vg_read ( cmd , vgname , vgid , & consistent ) ) ) {
2002-11-18 17:04:08 +03:00
stack ;
continue ;
}
if ( ! consistent )
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: Volume Group %s is not consistent " ,
vgname ) ;
2002-11-18 17:04:08 +03:00
/* Move PVs onto results list */
2008-01-16 21:15:26 +03:00
if ( pvslist )
list_iterate_safe ( pvh , tmp , & vg - > pvs )
list_add ( results , pvh ) ;
2002-11-18 17:04:08 +03:00
}
2003-04-30 19:23:43 +04:00
init_pvmove ( old_pvmove ) ;
init_partial ( old_partial ) ;
2002-11-18 17:04:08 +03:00
2008-01-16 21:15:26 +03:00
if ( pvslist )
* pvslist = results ;
else
dm_pool_free ( cmd - > mem , vgids ) ;
return 1 ;
}
struct list * get_pvs ( struct cmd_context * cmd )
{
struct list * results ;
if ( ! _get_pvs ( cmd , & results ) )
return NULL ;
2002-04-24 22:20:51 +04:00
return results ;
}
2008-01-16 21:15:26 +03:00
int scan_vgs_for_pvs ( struct cmd_context * cmd )
{
return _get_pvs ( cmd , NULL ) ;
}
2007-06-11 22:29:30 +04:00
/* FIXME: liblvm todo - make into function that takes handle */
int pv_write ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
struct physical_volume * pv ,
2002-11-18 17:04:08 +03:00
struct list * mdas , int64_t label_sector )
2007-06-11 22:29:30 +04:00
{
return _pv_write ( cmd , pv , mdas , label_sector ) ;
}
static int _pv_write ( struct cmd_context * cmd __attribute ( ( unused ) ) ,
struct physical_volume * pv ,
struct list * mdas , int64_t label_sector )
2002-04-24 22:20:51 +04:00
{
2003-08-27 01:12:06 +04:00
if ( ! pv - > fmt - > ops - > pv_write ) {
log_error ( " Format does not support writing physical volumes " ) ;
return 0 ;
}
2007-11-02 16:06:42 +03:00
if ( ! is_orphan_vg ( pv - > vg_name ) | | pv - > pe_alloc_count ) {
2002-11-18 17:04:08 +03:00
log_error ( " Assertion failed: can't _pv_write non-orphan PV "
" (in VG %s) " , pv - > vg_name ) ;
return 0 ;
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:04:08 +03:00
if ( ! pv - > fmt - > ops - > pv_write ( pv - > fmt , pv , mdas , label_sector ) ) {
stack ;
return 0 ;
2002-04-24 22:20:51 +04:00
}
return 1 ;
}
2007-02-07 16:29:52 +03:00
int pv_write_orphan ( struct cmd_context * cmd , struct physical_volume * pv )
{
const char * old_vg_name = pv - > vg_name ;
pv - > vg_name = ORPHAN ;
pv - > status = ALLOCATABLE_PV ;
if ( ! dev_get_size ( pv - > dev , & pv - > size ) ) {
2007-10-12 18:29:32 +04:00
log_error ( " %s: Couldn't get size. " , pv_dev_name ( pv ) ) ;
2007-02-07 16:29:52 +03:00
return 0 ;
}
2007-06-11 22:29:30 +04:00
if ( ! _pv_write ( cmd , pv , NULL , INT64_C ( - 1 ) ) ) {
2007-02-07 16:29:52 +03:00
log_error ( " Failed to clear metadata from physical "
" volume \" %s \" after removal from \" %s \" " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) , old_vg_name ) ;
2007-02-07 16:29:52 +03:00
return 0 ;
}
return 1 ;
}
2007-06-14 19:48:05 +04:00
2007-11-02 16:06:42 +03:00
/**
* is_orphan_vg - Determine whether a vg_name is an orphan
* @ vg_name : pointer to the vg_name
*/
int is_orphan_vg ( const char * vg_name )
{
2007-11-05 20:17:55 +03:00
return ( ! strcmp ( vg_name , ORPHAN ) ? 1 : 0 ) ;
2007-11-02 16:06:42 +03:00
}
2007-06-14 19:48:05 +04:00
/**
* is_orphan - Determine whether a pv is an orphan based on its vg_name
* @ pv : handle to the physical volume
*/
int is_orphan ( pv_t * pv )
{
2007-11-02 16:06:42 +03:00
return is_orphan_vg ( pv_field ( pv , vg_name ) ) ;
2007-06-14 19:48:05 +04:00
}
2008-01-07 23:42:57 +03:00
/**
* is_pv - Determine whether a pv is a real pv or dummy one
* @ pv : handle to device
*/
int is_pv ( pv_t * pv )
{
return ( pv_field ( pv , vg_name ) ? 1 : 0 ) ;
}
2007-04-26 00:03:16 +04:00
/*
* Returns :
* 0 - fail
* 1 - success
*/
int pv_analyze ( struct cmd_context * cmd , const char * pv_name ,
2007-08-22 18:38:18 +04:00
uint64_t label_sector )
2007-04-26 00:03:16 +04:00
{
struct label * label ;
struct device * dev ;
2007-04-26 01:10:55 +04:00
struct metadata_area * mda ;
struct lvmcache_info * info ;
2007-04-26 00:03:16 +04:00
dev = dev_cache_get ( pv_name , cmd - > filter ) ;
if ( ! dev ) {
log_error ( " Device %s not found (or ignored by filtering). " ,
pv_name ) ;
return 0 ;
}
/*
* First , scan for LVM labels .
*/
if ( ! label_read ( dev , & label , label_sector ) ) {
log_error ( " Could not find LVM label on %s " ,
pv_name ) ;
return 0 ;
}
log_print ( " Found label on %s, sector % " PRIu64 " , type=%s " ,
pv_name , label - > sector , label - > type ) ;
2007-04-26 01:10:55 +04:00
/*
* Next , loop through metadata areas
*/
info = label - > info ;
list_iterate_items ( mda , & info - > mdas )
mda - > ops - > pv_analyze_mda ( info - > fmt , mda ) ;
2007-04-26 00:03:16 +04:00
return 1 ;
}
2007-06-06 23:40:28 +04:00
/**
* vg_check_status - check volume group status flags and log error
* @ vg - volume group to check status flags
2007-06-19 08:36:12 +04:00
* @ status - specific status flags to check ( e . g . EXPORTED_VG )
2007-06-06 23:40:28 +04:00
*
* Returns :
* 0 - fail
* 1 - success
*/
2007-08-07 13:06:05 +04:00
int vg_check_status ( const struct volume_group * vg , uint32_t status )
2007-06-06 23:40:28 +04:00
{
2007-06-19 08:36:12 +04:00
if ( ( status & CLUSTERED ) & &
2007-06-06 23:40:28 +04:00
( vg - > status & CLUSTERED ) & & ! locking_is_clustered ( ) & &
! lockingfailed ( ) ) {
log_error ( " Skipping clustered volume group %s " , vg - > name ) ;
return 0 ;
}
2007-06-19 08:36:12 +04:00
if ( ( status & EXPORTED_VG ) & &
2007-06-06 23:40:28 +04:00
( vg - > status & EXPORTED_VG ) ) {
log_error ( " Volume group %s is exported " , vg - > name ) ;
return 0 ;
}
2007-06-19 08:36:12 +04:00
if ( ( status & LVM_WRITE ) & &
2007-06-06 23:40:28 +04:00
! ( vg - > status & LVM_WRITE ) ) {
log_error ( " Volume group %s is read-only " , vg - > name ) ;
return 0 ;
}
2007-06-19 08:36:12 +04:00
if ( ( status & RESIZEABLE_VG ) & &
2007-06-06 23:40:28 +04:00
! ( vg - > status & RESIZEABLE_VG ) ) {
log_error ( " Volume group %s is not resizeable. " , vg - > name ) ;
return 0 ;
}
return 1 ;
}
2007-06-13 01:20:20 +04:00
2007-08-07 01:11:27 +04:00
/*
* vg_lock_and_read - consolidate vg locking , reading , and status flag checking
2007-07-23 21:27:55 +04:00
*
* Returns :
* NULL - failure
* non - NULL - success ; volume group handle
*/
vg_t * vg_lock_and_read ( struct cmd_context * cmd , const char * vg_name ,
2007-11-15 05:20:03 +03:00
const char * vgid ,
2007-07-24 01:03:42 +04:00
uint32_t lock_flags , uint32_t status_flags ,
uint32_t misc_flags )
2007-07-23 21:27:55 +04:00
{
struct volume_group * vg ;
int consistent = 1 ;
2007-07-24 01:03:42 +04:00
if ( ! ( misc_flags & CORRECT_INCONSISTENT ) )
consistent = 0 ;
2007-11-02 23:40:05 +03:00
if ( ! validate_name ( vg_name ) ) {
log_error ( " Volume group name %s has invalid characters " ,
vg_name ) ;
return NULL ;
}
2007-07-23 21:27:55 +04:00
if ( ! lock_vol ( cmd , vg_name , lock_flags ) ) {
log_error ( " Can't get lock for %s " , vg_name ) ;
return NULL ;
}
2007-11-15 05:20:03 +03:00
if ( ! ( vg = vg_read ( cmd , vg_name , vgid , & consistent ) ) | |
2007-07-24 01:03:42 +04:00
( ( misc_flags & FAIL_INCONSISTENT ) & & ! consistent ) ) {
2007-07-23 21:27:55 +04:00
log_error ( " Volume group \" %s \" not found " , vg_name ) ;
unlock_vg ( cmd , vg_name ) ;
return NULL ;
}
if ( ! vg_check_status ( vg , status_flags ) ) {
unlock_vg ( cmd , vg_name ) ;
return NULL ;
}
2007-11-15 05:20:03 +03:00
2007-07-23 21:27:55 +04:00
return vg ;
}
2007-06-13 01:20:20 +04:00
/*
* Gets / Sets for external LVM library
*/
2007-10-12 18:08:10 +04:00
struct id pv_id ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , id ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:08:10 +04:00
const struct format_type * pv_format_type ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , fmt ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:08:10 +04:00
struct id pv_vgid ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , vgid ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:08:10 +04:00
struct device * pv_dev ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , dev ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:08:10 +04:00
const char * pv_vg_name ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , vg_name ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:29:32 +04:00
const char * pv_dev_name ( const pv_t * pv )
{
return dev_name ( pv_dev ( pv ) ) ;
}
2007-10-12 18:08:10 +04:00
uint64_t pv_size ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , size ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:08:10 +04:00
uint32_t pv_status ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , status ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:08:10 +04:00
uint32_t pv_pe_size ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , pe_size ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:08:10 +04:00
uint64_t pv_pe_start ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , pe_start ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:08:10 +04:00
uint32_t pv_pe_count ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , pe_count ) ;
2007-06-13 01:20:20 +04:00
}
2007-10-12 18:08:10 +04:00
uint32_t pv_pe_alloc_count ( const pv_t * pv )
2007-06-13 01:20:20 +04:00
{
2007-06-14 00:55:56 +04:00
return pv_field ( pv , pe_alloc_count ) ;
2007-06-13 01:20:20 +04:00
}
2007-06-19 08:23:32 +04:00
2007-10-12 18:08:10 +04:00
uint32_t vg_status ( const vg_t * vg )
2007-06-19 08:23:32 +04:00
{
return vg - > status ;
}
2007-07-12 03:33:12 +04:00
/**
2007-07-12 19:38:53 +04:00
* pv_by_path - Given a device path return a PV handle if it is a PV
2007-07-12 03:33:12 +04:00
* @ cmd - handle to the LVM command instance
* @ pv_name - device path to read for the PV
*
* Returns :
* NULL - device path does not contain a valid PV
* non - NULL - PV handle corresponding to device path
*
2007-07-12 19:38:53 +04:00
* FIXME : merge with find_pv_by_name ?
2007-07-12 03:33:12 +04:00
*/
2007-07-12 19:38:53 +04:00
pv_t * pv_by_path ( struct cmd_context * cmd , const char * pv_name )
2007-07-12 03:33:12 +04:00
{
struct list mdas ;
list_init ( & mdas ) ;
return _pv_read ( cmd , pv_name , & mdas , NULL , 1 ) ;
}