2001-09-25 16:49:28 +04:00
/*
2001-10-12 14:32:06 +04:00
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
2001-09-25 16:49:28 +04:00
*
2001-10-31 15:47:01 +03:00
* This file is released under the LGPL .
2001-09-25 16:49:28 +04:00
*/
2001-10-01 19:14:39 +04:00
# include "log.h"
2001-10-12 14:32:06 +04:00
# include "pool.h"
# include "device.h"
# include "dev-cache.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"
# include "uuid.h"
2001-09-25 16:49:28 +04:00
2001-10-12 14:32:06 +04:00
# include <string.h>
2001-09-25 16:49:28 +04:00
2001-11-12 15:16:57 +03:00
int _add_pv_to_vg ( struct format_instance * fi , struct volume_group * vg ,
2001-10-15 22:39:40 +04:00
const char * pv_name )
2001-10-12 18:25:53 +04:00
{
2001-10-15 22:39:40 +04:00
struct pv_list * pvl ;
struct physical_volume * pv ;
2001-11-12 15:16:57 +03:00
struct pool * mem = fi - > 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
2001-11-12 15:16:57 +03:00
if ( ! ( pvl = pool_alloc ( 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 ;
}
2001-11-12 15:16:57 +03:00
if ( ! ( pv = fi - > ops - > pv_read ( fi , pv_name ) ) ) {
2001-10-15 22:39:40 +04:00
log_error ( " Failed to read existing physical volume '%s' " ,
pv_name ) ;
return 0 ;
}
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
if ( * pv - > vg_name ) {
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
2001-11-12 15:16:57 +03:00
if ( ! ( pv - > vg_name = 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 ;
}
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 ;
/*
* The next two fields should be corrected
2001-11-12 15:16:57 +03:00
* by fi - > pv_setup .
2001-10-12 18:25:53 +04:00
*/
pv - > pe_start = 0 ;
pv - > pe_count = pv - > size / pv - > pe_size ;
pv - > pe_allocated = 0 ;
2001-11-12 15:16:57 +03:00
if ( ! fi - > ops - > pv_setup ( fi , 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 ;
}
if ( find_pv_in_vg ( vg , pv_name ) ) {
log_error ( " Physical volume '%s' listed more than once. " ,
pv_name ) ;
2001-10-12 18:25:53 +04:00
return 0 ;
}
2001-10-15 22:39:40 +04:00
if ( vg - > pv_count = = vg - > max_pv ) {
log_error ( " No space for '%s' - volume group '%s' "
" holds max %d physical volume(s). " , pv_name ,
vg - > name , vg - > max_pv ) ;
return 0 ;
}
2002-01-21 19:05:23 +03:00
pvl - > pv = pv ;
2001-10-15 22:39:40 +04:00
2001-10-31 15:47:01 +03:00
list_add ( & vg - > pvs , & pvl - > list ) ;
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 ;
}
2001-11-12 15:16:57 +03:00
int vg_extend ( struct format_instance * fi ,
struct volume_group * vg , int pv_count , char * * pv_names )
2001-10-16 02:04:27 +04:00
{
int i ;
/* attach each pv */
for ( i = 0 ; i < pv_count ; i + + )
2001-11-12 15:16:57 +03:00
if ( ! _add_pv_to_vg ( fi , vg , pv_names [ i ] ) ) {
2001-10-16 02:04:27 +04:00
log_error ( " Unable to add physical volume '%s' to "
" volume group '%s'. " , pv_names [ i ] , vg - > name ) ;
return 0 ;
}
return 1 ;
}
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
{
int len = strlen ( dev_dir ) ;
if ( ! strncmp ( vg_name , dev_dir , len ) )
vg_name + = len ;
return vg_name ;
}
struct volume_group * vg_create ( struct format_instance * fi , const char * vg_name ,
2001-11-06 22:02:26 +03:00
uint32_t extent_size , int max_pv , int max_lv ,
2001-10-12 18:25:53 +04:00
int pv_count , char * * pv_names )
{
struct volume_group * vg ;
2001-11-12 15:16:57 +03:00
struct pool * mem = fi - > cmd - > mem ;
2001-10-12 18:25:53 +04:00
2001-11-12 15:16:57 +03:00
if ( ! ( vg = pool_alloc ( mem , sizeof ( * vg ) ) ) ) {
2001-10-12 18:25:53 +04:00
stack ;
return NULL ;
}
/* is this vg name already in use ? */
2002-01-29 20:23:33 +03:00
init_partial ( 1 ) ;
2001-11-12 15:16:57 +03:00
if ( fi - > ops - > vg_read ( fi , vg_name ) ) {
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 ;
}
2002-01-29 20:23:33 +03:00
init_partial ( 0 ) ;
2001-10-12 18:25:53 +04:00
if ( ! id_create ( & vg - > id ) ) {
2001-11-12 15:16:57 +03: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 */
2001-11-12 15:16:57 +03:00
vg_name = strip_dir ( vg_name , fi - > cmd - > dev_dir ) ;
2001-10-15 22:39:40 +04:00
2002-01-07 18:27:55 +03:00
vg - > cmd = fi - > cmd ;
2001-11-12 15:16:57 +03:00
if ( ! ( vg - > name = pool_strdup ( mem , vg_name ) ) ) {
2001-10-12 18:25:53 +04:00
stack ;
goto bad ;
}
2002-01-11 02:21:07 +03:00
vg - > status = ( RESIZEABLE_VG | LVM_READ | LVM_WRITE ) ;
2002-01-30 15:47:29 +03:00
vg - > system_id = pool_alloc ( mem , NAME_LEN ) ;
* 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
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 ;
list_init ( & vg - > snapshots ) ;
2001-11-12 15:16:57 +03:00
if ( ! fi - > ops - > vg_setup ( fi , 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 */
2001-11-12 15:16:57 +03:00
if ( ! vg_extend ( fi , vg , pv_count , pv_names ) )
2001-10-16 02:04:27 +04:00
goto bad ;
2001-10-12 18:25:53 +04:00
return vg ;
2001-11-12 15:16:57 +03:00
bad :
pool_free ( mem , vg ) ;
2001-10-12 18:25:53 +04:00
return NULL ;
}
2002-01-16 21:10:08 +03:00
struct physical_volume * pv_create ( struct format_instance * fi ,
const char * name ,
2002-02-15 04:26:16 +03:00
struct id * id ,
uint64_t size )
2001-09-25 16:49:28 +04:00
{
2001-11-12 15:16:57 +03:00
struct pool * mem = fi - > cmd - > mem ;
struct physical_volume * pv = pool_alloc ( mem , sizeof ( * pv ) ) ;
2001-10-12 14:32:06 +04:00
if ( ! pv ) {
stack ;
return NULL ;
}
2002-01-16 21:10:08 +03:00
if ( ! id )
id_create ( & pv - > id ) ;
else
memcpy ( & pv - > id , id , sizeof ( * id ) ) ;
2001-11-12 15:16:57 +03:00
if ( ! ( pv - > dev = dev_cache_get ( name , fi - > cmd - > filter ) ) ) {
2002-02-20 21:29:30 +03:00
log_error ( " %s: Couldn't find device. " , name ) ;
2001-10-12 14:32:06 +04:00
goto bad ;
}
2001-11-12 15:16:57 +03:00
if ( ! ( pv - > vg_name = pool_alloc ( mem , NAME_LEN ) ) ) {
2001-10-12 16:21:43 +04:00
stack ;
goto bad ;
}
* pv - > vg_name = 0 ;
2002-01-10 18:09:51 +03:00
pv - > status = ALLOCATABLE_PV ;
2001-10-12 14:32:06 +04:00
2002-02-20 21:29:30 +03:00
if ( ! dev_get_size ( pv - > dev , & pv - > size ) ) {
log_error ( " %s: Couldn't get size. " , name ) ;
goto bad ;
}
if ( size ) {
if ( size > pv - > size )
log_print ( " WARNING: %s: Overriding real size. "
" You could lose data. " , name ) ;
log_verbose ( " %s: Pretending size is % " PRIu64 " sectors. " ,
name , size ) ;
pv - > size = size ;
}
if ( pv - > size < PV_MIN_SIZE ) {
log_error ( " %s: Size must exceed minimum of %lu sectors. " ,
name , PV_MIN_SIZE ) ;
2001-10-12 14:32:06 +04:00
goto bad ;
}
2001-10-15 22:39:40 +04:00
pv - > pe_size = 0 ;
pv - > pe_start = 0 ;
pv - > pe_count = 0 ;
pv - > pe_allocated = 0 ;
2002-02-15 17:33:59 +03:00
if ( ! fi - > ops - > pv_setup ( fi , pv , NULL ) ) {
2002-02-20 21:29:30 +03:00
log_error ( " %s: Format-specific setup of physical volume "
2002-02-15 17:33:59 +03:00
" failed. " , name ) ;
goto bad ;
}
2001-10-12 14:32:06 +04:00
return pv ;
2001-10-15 22:39:40 +04:00
bad :
2001-11-12 15:16:57 +03:00
pool_free ( mem , pv ) ;
2001-10-12 14:32:06 +04:00
return NULL ;
2001-09-25 16:49:28 +04:00
}
2002-01-21 17:28:12 +03:00
struct pv_list * find_pv_in_vg ( struct volume_group * vg , const char * pv_name )
2001-10-15 22:39:40 +04:00
{
2001-10-31 15:47:01 +03:00
struct list * pvh ;
2002-01-21 17:28:12 +03:00
struct pv_list * pvl ;
2001-10-25 18:04:18 +04:00
2001-10-31 15:47:01 +03:00
list_iterate ( pvh , & vg - > pvs ) {
2002-01-21 17:28:12 +03:00
pvl = list_item ( pvh , struct pv_list ) ;
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-10-15 22:39:40 +04:00
}
2001-09-25 16:49:28 +04:00
2001-10-15 22:39:40 +04:00
return NULL ;
2001-10-12 14:32:06 +04:00
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
{
2001-10-31 15:47:01 +03:00
struct list * lvh ;
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
2002-01-21 17:28:12 +03:00
list_iterate ( lvh , & vg - > lvs ) {
lvl = list_item ( lvh , struct lv_list ) ;
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-03-05 23:03:09 +03:00
struct lv_list * find_lv_in_vg_by_lvid ( struct volume_group * vg , union lvid * lvid )
2002-02-25 15:56:16 +03:00
{
struct list * lvh ;
struct lv_list * lvl ;
list_iterate ( lvh , & vg - > lvs ) {
lvl = list_item ( lvh , struct lv_list ) ;
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
{
2001-10-31 15:47:01 +03:00
struct list * pvh ;
2001-11-10 01:01:04 +03:00
struct physical_volume * pv ;
list_iterate ( pvh , & vg - > pvs ) {
2002-01-21 19:05:23 +03:00
pv = list_item ( pvh , struct pv_list ) - > pv ;
2001-11-10 01:01:04 +03:00
if ( dev = = pv - > dev )
return pv ;
}
return NULL ;
2001-10-29 16:52:23 +03:00
}
2002-02-25 15:56:16 +03:00