2001-10-04 21:48:55 +04:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
*
2001-10-31 15:47:01 +03:00
* This file is released under the LGPL .
2001-10-04 21:48:55 +04:00
*/
# include "disk-rep.h"
# include "dbg_malloc.h"
# include "pool.h"
# include "hash.h"
# include "list.h"
2001-10-08 13:45:16 +04:00
# include "log.h"
2001-10-16 00:29:15 +04:00
# include "display.h"
2001-10-04 21:48:55 +04:00
2001-10-16 20:25:28 +04:00
/* VG consistency checks */
2001-10-31 15:47:01 +03:00
static int _check_vgs ( struct list * pvs )
2001-10-04 21:48:55 +04:00
{
2001-10-31 15:47:01 +03:00
struct list * pvh ;
2001-10-25 17:08:29 +04:00
struct disk_list * dl = NULL ;
2001-10-16 20:25:28 +04:00
struct disk_list * first = NULL ;
int pv_count = 0 ;
2001-10-04 21:48:55 +04:00
/* check all the vg's are the same */
2001-10-31 15:47:01 +03:00
list_iterate ( pvh , pvs ) {
dl = list_item ( pvh , struct disk_list ) ;
2001-10-04 21:48:55 +04:00
2001-10-09 18:26:45 +04:00
if ( ! first )
2001-10-16 20:25:28 +04:00
first = dl ;
2001-11-12 15:16:57 +03:00
2001-10-31 20:59:52 +03:00
else if ( memcmp ( & first - > vgd , & dl - > vgd , sizeof ( first - > vgd ) ) ) {
2001-10-16 20:25:28 +04:00
log_err ( " VG data differs between PVs %s and %s " ,
2001-10-25 18:04:18 +04:00
dev_name ( first - > dev ) , dev_name ( dl - > dev ) ) ;
2001-10-04 21:48:55 +04:00
return 0 ;
}
2001-10-16 20:25:28 +04:00
pv_count + + ;
}
/* On entry to fn, list known to be non-empty */
2001-10-31 20:59:52 +03:00
if ( ! ( pv_count = = dl - > vgd . pv_cur ) ) {
2001-10-16 20:25:28 +04:00
log_error ( " Only %d out of %d PV(s) found for VG %s " ,
2001-10-31 20:59:52 +03:00
pv_count , dl - > vgd . pv_cur , dl - > pvd . vg_name ) ;
2001-10-16 20:25:28 +04:00
return 0 ;
2001-10-04 21:48:55 +04:00
}
return 1 ;
}
2001-10-31 15:47:01 +03:00
static struct volume_group * _build_vg ( struct pool * mem , struct list * pvs )
2001-10-04 21:48:55 +04:00
{
struct volume_group * vg = pool_alloc ( mem , sizeof ( * vg ) ) ;
2001-10-09 21:09:46 +04:00
struct disk_list * dl ;
2001-10-15 22:39:40 +04:00
if ( ! vg )
goto bad ;
2001-10-04 21:48:55 +04:00
2001-10-15 22:39:40 +04:00
if ( list_empty ( pvs ) )
goto bad ;
2001-10-09 21:09:46 +04:00
2001-10-31 15:47:01 +03:00
dl = list_item ( pvs - > n , struct disk_list ) ;
2001-10-04 21:48:55 +04:00
memset ( vg , 0 , sizeof ( * vg ) ) ;
2001-10-31 15:47:01 +03:00
list_init ( & vg - > pvs ) ;
list_init ( & vg - > lvs ) ;
2001-10-08 20:08:16 +04:00
2001-10-15 22:39:40 +04:00
if ( ! _check_vgs ( pvs ) )
goto bad ;
2001-10-09 18:26:45 +04:00
if ( ! import_vg ( mem , vg , dl ) )
2001-10-04 21:48:55 +04:00
goto bad ;
2001-10-09 18:26:45 +04:00
if ( ! import_pvs ( mem , pvs , & vg - > pvs , & vg - > pv_count ) )
2001-10-04 21:48:55 +04:00
goto bad ;
2001-10-09 18:26:45 +04:00
if ( ! import_lvs ( mem , vg , pvs ) )
2001-10-04 21:48:55 +04:00
goto bad ;
2001-10-09 18:26:45 +04:00
if ( ! import_extents ( mem , vg , pvs ) )
2001-10-08 13:45:16 +04:00
goto bad ;
2001-10-04 21:48:55 +04:00
return vg ;
bad :
stack ;
pool_free ( mem , vg ) ;
return NULL ;
}
2001-11-12 15:16:57 +03:00
static struct volume_group * _vg_read ( struct format_instance * fi ,
const char * vg_name )
2001-10-04 21:48:55 +04:00
{
struct pool * mem = pool_create ( 1024 * 10 ) ;
2001-10-31 15:47:01 +03:00
struct list pvs ;
2001-11-12 18:10:01 +03:00
struct volume_group * vg = NULL ;
2001-10-31 15:47:01 +03:00
list_init ( & pvs ) ;
2001-10-04 21:48:55 +04:00
if ( ! mem ) {
stack ;
return NULL ;
}
2001-10-12 01:35:55 +04:00
/* Strip prefix if present */
2001-11-12 15:16:57 +03:00
vg_name = strip_dir ( vg_name , fi - > cmd - > dev_dir ) ;
2001-10-12 01:35:55 +04:00
2001-11-12 15:16:57 +03:00
if ( ! read_pvs_in_vg ( vg_name , fi - > cmd - > filter , mem , & pvs ) ) {
2001-10-04 21:48:55 +04:00
stack ;
2001-11-12 18:10:01 +03:00
goto bad ;
2001-10-04 21:48:55 +04:00
}
2001-11-12 18:10:01 +03:00
if ( ! ( vg = _build_vg ( fi - > cmd - > mem , & pvs ) ) ) {
2001-10-04 21:48:55 +04:00
stack ;
2001-11-12 18:10:01 +03:00
goto bad ;
}
2001-11-12 15:23:10 +03:00
vg - > cmd = fi - > cmd ;
2001-10-04 21:48:55 +04:00
2001-11-12 18:10:01 +03:00
bad :
2001-10-04 21:48:55 +04:00
pool_destroy ( mem ) ;
return vg ;
}
2001-10-08 13:45:16 +04:00
static struct disk_list * _flatten_pv ( struct pool * mem , struct volume_group * vg ,
2001-10-09 18:26:45 +04:00
struct physical_volume * pv ,
const char * prefix )
2001-10-05 20:36:53 +04:00
{
2001-10-09 14:47:52 +04:00
struct disk_list * dl = pool_alloc ( mem , sizeof ( * dl ) ) ;
2001-10-08 16:11:33 +04:00
2001-10-09 14:47:52 +04:00
if ( ! dl ) {
stack ;
return NULL ;
}
dl - > mem = mem ;
dl - > dev = pv - > dev ;
2001-10-31 15:47:01 +03:00
list_init ( & dl - > uuids ) ;
2001-10-31 20:59:52 +03:00
list_init ( & dl - > lvds ) ;
2001-10-09 14:47:52 +04:00
2001-10-31 20:59:52 +03:00
if ( ! export_pv ( & dl - > pvd , pv ) | |
! export_vg ( & dl - > vgd , vg ) | |
2001-10-09 18:26:45 +04:00
! export_uuids ( dl , vg ) | |
2001-10-10 13:25:04 +04:00
! export_lvs ( dl , vg , pv , prefix ) | |
! calculate_layout ( dl ) ) {
2001-10-09 14:47:52 +04:00
stack ;
2001-10-15 22:39:40 +04:00
pool_free ( mem , dl ) ;
2001-10-09 14:47:52 +04:00
return NULL ;
}
return dl ;
2001-10-05 20:36:53 +04:00
}
static int _flatten_vg ( struct pool * mem , struct volume_group * vg ,
2001-10-31 15:47:01 +03:00
struct list * pvs , const char * prefix ,
2001-10-11 18:10:18 +04:00
struct dev_filter * filter )
2001-10-05 20:36:53 +04:00
{
2001-10-31 15:47:01 +03:00
struct list * pvh ;
2001-10-09 14:47:52 +04:00
struct pv_list * pvl ;
2001-10-05 20:36:53 +04:00
struct disk_list * data ;
2001-10-31 15:47:01 +03:00
list_iterate ( pvh , & vg - > pvs ) {
pvl = list_item ( pvh , struct pv_list ) ;
2001-10-05 20:36:53 +04:00
2001-10-09 18:26:45 +04:00
if ( ! ( data = _flatten_pv ( mem , vg , & pvl - > pv , prefix ) ) ) {
2001-10-05 20:36:53 +04:00
stack ;
return 0 ;
}
2001-10-31 15:47:01 +03:00
list_add ( pvs , & data - > list ) ;
2001-10-05 20:36:53 +04:00
}
2001-10-11 14:55:19 +04:00
export_numbers ( pvs , vg ) ;
2001-10-11 17:05:55 +04:00
export_pv_act ( pvs ) ;
2001-10-11 18:10:18 +04:00
if ( ! export_vg_number ( pvs , vg - > name , filter ) ) {
stack ;
return 0 ;
}
2001-10-05 20:36:53 +04:00
return 1 ;
}
2001-11-12 15:16:57 +03:00
static int _vg_write ( struct format_instance * fi , struct volume_group * vg )
2001-10-05 20:36:53 +04:00
{
struct pool * mem = pool_create ( 1024 * 10 ) ;
2001-10-31 15:47:01 +03:00
struct list pvs ;
2001-10-05 20:36:53 +04:00
int r = 0 ;
if ( ! mem ) {
stack ;
return 0 ;
}
2001-10-31 15:47:01 +03:00
list_init ( & pvs ) ;
2001-10-10 17:09:40 +04:00
2001-11-12 15:16:57 +03:00
r = ( _flatten_vg ( mem , vg , & pvs , fi - > cmd - > dev_dir , fi - > cmd - > filter ) & &
2001-11-14 13:01:52 +03:00
write_disks ( & pvs ) ) ;
2001-10-05 20:36:53 +04:00
pool_destroy ( mem ) ;
return r ;
}
2001-10-04 21:48:55 +04:00
2001-11-12 15:16:57 +03:00
static struct physical_volume * _pv_read ( struct format_instance * fi ,
2001-10-09 20:05:34 +04:00
const char * name )
2001-10-09 12:58:52 +04:00
{
struct pool * mem = pool_create ( 1024 ) ;
2001-11-12 15:16:57 +03:00
struct physical_volume * pv = NULL ;
2001-10-09 12:58:52 +04:00
struct disk_list * dl ;
2001-10-09 20:05:34 +04:00
struct device * dev ;
2001-10-09 12:58:52 +04:00
2001-10-31 15:47:01 +03:00
log_very_verbose ( " Reading physical volume data %s from disk " , name ) ;
2001-10-17 19:29:31 +04:00
2001-10-09 12:58:52 +04:00
if ( ! mem ) {
stack ;
return NULL ;
}
2001-11-12 15:16:57 +03:00
if ( ! ( dev = dev_cache_get ( name , fi - > cmd - > filter ) ) ) {
2001-10-09 20:05:34 +04:00
stack ;
2001-11-12 15:16:57 +03:00
goto out ;
2001-10-09 20:05:34 +04:00
}
2001-11-02 19:28:04 +03:00
if ( ! ( dl = read_disk ( dev , mem , NULL ) ) ) {
2001-10-09 12:58:52 +04:00
stack ;
2001-11-12 15:16:57 +03:00
goto out ;
2001-10-09 12:58:52 +04:00
}
2001-11-12 15:16:57 +03:00
if ( ! ( pv = pool_alloc ( fi - > cmd - > mem , sizeof ( * pv ) ) ) ) {
2001-10-09 12:58:52 +04:00
stack ;
2001-11-12 15:16:57 +03:00
goto out ;
2001-10-09 12:58:52 +04:00
}
2001-11-12 15:16:57 +03:00
if ( ! import_pv ( fi - > cmd - > mem , dl - > dev , pv , & dl - > pvd ) ) {
2001-10-09 12:58:52 +04:00
stack ;
2001-11-12 15:16:57 +03:00
pool_free ( fi - > cmd - > mem , pv ) ;
pv = NULL ;
2001-10-09 12:58:52 +04:00
}
2001-11-12 15:16:57 +03:00
out :
2001-10-09 12:58:52 +04:00
pool_destroy ( mem ) ;
return pv ;
}
2001-11-12 15:16:57 +03:00
static struct list * _get_pvs ( struct format_instance * fi )
2001-10-08 21:53:43 +04:00
{
struct pool * mem = pool_create ( 1024 * 10 ) ;
2001-10-31 15:47:01 +03:00
struct list pvs , * results ;
2001-10-08 21:53:43 +04:00
uint32_t count ;
if ( ! mem ) {
stack ;
return NULL ;
}
2001-11-12 15:16:57 +03:00
if ( ! ( results = pool_alloc ( fi - > cmd - > mem , sizeof ( * results ) ) ) ) {
2001-10-08 21:53:43 +04:00
stack ;
2001-10-15 22:39:40 +04:00
pool_destroy ( mem ) ;
2001-10-08 21:53:43 +04:00
return NULL ;
}
2001-10-31 15:47:01 +03:00
list_init ( & pvs ) ;
list_init ( results ) ;
2001-10-08 21:53:43 +04:00
2001-11-12 15:16:57 +03:00
if ( ! read_pvs_in_vg ( NULL , fi - > cmd - > filter , mem , & pvs ) ) {
2001-10-08 21:53:43 +04:00
stack ;
goto bad ;
}
2001-11-12 15:16:57 +03:00
if ( ! import_pvs ( fi - > cmd - > mem , & pvs , results , & count ) ) {
2001-10-08 21:53:43 +04:00
stack ;
goto bad ;
}
pool_destroy ( mem ) ;
return results ;
bad :
2001-11-12 15:16:57 +03:00
pool_free ( fi - > cmd - > mem , results ) ;
2001-10-15 22:39:40 +04:00
pool_destroy ( mem ) ;
2001-10-08 21:53:43 +04:00
return NULL ;
}
2001-10-31 15:47:01 +03:00
static int _find_vg_name ( struct list * names , const char * vg )
2001-10-09 13:22:50 +04:00
{
2001-10-31 15:47:01 +03:00
struct list * nh ;
2001-10-09 13:22:50 +04:00
struct name_list * nl ;
2001-10-31 15:47:01 +03:00
list_iterate ( nh , names ) {
nl = list_item ( nh , struct name_list ) ;
2001-10-09 13:22:50 +04:00
if ( ! strcmp ( nl - > name , vg ) )
return 1 ;
}
return 0 ;
}
2001-11-12 15:16:57 +03:00
static struct list * _get_vgs ( struct format_instance * fi )
2001-10-09 13:22:50 +04:00
{
2001-10-31 15:47:01 +03:00
struct list * pvh ;
2001-11-12 15:16:57 +03:00
struct list * pvs , * names = pool_alloc ( fi - > cmd - > mem , sizeof ( * names ) ) ;
2001-10-09 13:22:50 +04:00
struct name_list * nl ;
if ( ! names ) {
stack ;
return NULL ;
}
2001-10-31 15:47:01 +03:00
list_init ( names ) ;
2001-10-09 13:22:50 +04:00
2001-11-12 15:16:57 +03:00
if ( ! ( pvs = _get_pvs ( fi ) ) ) {
2001-10-09 13:22:50 +04:00
stack ;
goto bad ;
}
2001-10-31 15:47:01 +03:00
list_iterate ( pvh , pvs ) {
struct pv_list * pvl = list_item ( pvh , struct pv_list ) ;
2001-10-09 13:22:50 +04:00
2001-10-31 15:47:01 +03:00
if ( ! ( * pvl - > pv . vg_name ) | |
2001-10-12 01:35:55 +04:00
_find_vg_name ( names , pvl - > pv . vg_name ) )
2001-10-09 13:22:50 +04:00
continue ;
2001-11-12 15:16:57 +03:00
if ( ! ( nl = pool_alloc ( fi - > cmd - > mem , sizeof ( * nl ) ) ) ) {
2001-10-09 13:22:50 +04:00
stack ;
goto bad ;
}
2001-11-12 15:16:57 +03:00
if ( ! ( nl - > name = pool_strdup ( fi - > cmd - > mem , pvl - > pv . vg_name ) ) ) {
2001-10-09 13:22:50 +04:00
stack ;
goto bad ;
}
2001-10-31 15:47:01 +03:00
list_add ( names , & nl - > list ) ;
2001-10-09 13:22:50 +04:00
}
2001-10-16 20:25:28 +04:00
if ( list_empty ( names ) )
goto bad ;
2001-10-09 13:22:50 +04:00
return names ;
bad :
2001-11-12 15:16:57 +03:00
pool_free ( fi - > cmd - > mem , names ) ;
2001-10-09 13:22:50 +04:00
return NULL ;
}
2001-11-12 15:16:57 +03:00
static int _pv_setup ( struct format_instance * fi , struct physical_volume * pv ,
2001-10-10 13:25:04 +04:00
struct volume_group * vg )
{
2001-10-10 14:55:55 +04:00
/*
* This works out pe_start and pe_count .
*/
if ( ! calculate_extent_count ( pv ) ) {
stack ;
return 0 ;
}
2001-10-10 13:25:04 +04:00
return 1 ;
}
2001-11-12 15:16:57 +03:00
static int _pv_write ( struct format_instance * fi , struct physical_volume * pv )
2001-10-09 21:44:58 +04:00
{
2001-10-10 14:05:29 +04:00
struct pool * mem ;
struct disk_list * dl ;
2001-10-31 15:47:01 +03:00
struct list pvs ;
2001-10-10 14:05:29 +04:00
2001-10-31 15:47:01 +03:00
list_init ( & pvs ) ;
2001-10-10 14:05:29 +04:00
2001-10-18 20:55:19 +04:00
if ( * pv - > vg_name | | pv - > pe_allocated ) {
2001-10-31 15:47:01 +03:00
log_error ( " Assertion failed: can't _pv_write non-orphan PV "
2001-10-12 01:35:55 +04:00
" (in VG %s) " , pv - > vg_name ) ;
2001-10-10 14:05:29 +04:00
return 0 ;
}
2001-10-18 20:55:19 +04:00
/* Ensure any residual PE structure is gone */
pv - > pe_size = pv - > pe_count = pv - > pe_start = 0 ;
pv - > status & = ~ ALLOCATED_PV ;
2001-10-10 14:05:29 +04:00
if ( ! ( mem = pool_create ( 1024 ) ) ) {
stack ;
return 0 ;
}
if ( ! ( dl = pool_alloc ( mem , sizeof ( * dl ) ) ) ) {
stack ;
2001-10-15 22:39:40 +04:00
goto bad ;
2001-10-10 14:05:29 +04:00
}
dl - > mem = mem ;
dl - > dev = pv - > dev ;
2001-10-31 20:59:52 +03:00
if ( ! export_pv ( & dl - > pvd , pv ) ) {
2001-10-10 14:05:29 +04:00
stack ;
goto bad ;
}
2001-10-31 15:47:01 +03:00
list_add ( & pvs , & dl - > list ) ;
2001-11-14 13:01:52 +03:00
if ( ! write_disks ( & pvs ) ) {
2001-10-10 14:05:29 +04:00
stack ;
goto bad ;
}
pool_destroy ( mem ) ;
2001-10-09 21:44:58 +04:00
return 1 ;
2001-10-10 14:05:29 +04:00
bad :
pool_destroy ( mem ) ;
return 0 ;
2001-10-09 21:44:58 +04:00
}
2001-11-12 15:16:57 +03:00
int _vg_setup ( struct format_instance * fi , struct volume_group * vg )
2001-10-12 18:25:53 +04:00
{
/* just check max_pv and max_lv */
2001-10-15 22:39:40 +04:00
if ( vg - > max_lv > = MAX_LV )
vg - > max_lv = MAX_LV - 1 ;
2001-10-12 18:25:53 +04:00
2001-10-15 22:39:40 +04:00
if ( vg - > max_pv > = MAX_PV )
vg - > max_pv = MAX_PV - 1 ;
2001-10-12 18:25:53 +04:00
2001-10-16 00:29:15 +04:00
if ( vg - > extent_size > MAX_PE_SIZE | | vg - > extent_size < MIN_PE_SIZE ) {
char * dummy , * dummy2 ;
log_error ( " Extent size must be between %s and %s " ,
2001-10-31 15:47:01 +03:00
( dummy = display_size ( MIN_PE_SIZE / 2 , SIZE_SHORT ) ) ,
2001-10-16 00:29:15 +04:00
( dummy2 = display_size ( MAX_PE_SIZE / 2 , SIZE_SHORT ) ) ) ;
dbg_free ( dummy ) ;
dbg_free ( dummy2 ) ;
return 0 ;
}
if ( vg - > extent_size % MIN_PE_SIZE ) {
char * dummy ;
log_error ( " Extent size must be multiple of %s " ,
( dummy = display_size ( MIN_PE_SIZE / 2 , SIZE_SHORT ) ) ) ;
dbg_free ( dummy ) ;
return 0 ;
}
/* Redundant? */
if ( vg - > extent_size & ( vg - > extent_size - 1 ) ) {
log_error ( " Extent size must be power of 2 " ) ;
return 0 ;
}
2001-10-12 18:25:53 +04:00
return 1 ;
}
2001-10-09 21:44:58 +04:00
2001-11-12 15:16:57 +03:00
void _destroy ( struct format_instance * fi )
2001-10-04 21:48:55 +04:00
{
2001-11-12 15:16:57 +03:00
dbg_free ( fi ) ;
2001-10-08 16:11:33 +04:00
}
2001-11-12 15:16:57 +03:00
static struct format_handler _format1_ops = {
get_vgs : _get_vgs ,
get_pvs : _get_pvs ,
pv_read : _pv_read ,
pv_setup : _pv_setup ,
pv_write : _pv_write ,
vg_read : _vg_read ,
vg_setup : _vg_setup ,
vg_write : _vg_write ,
destroy : _destroy ,
} ;
2001-10-30 20:53:21 +03:00
2001-11-12 15:16:57 +03:00
struct format_instance * create_lvm1_format ( struct cmd_context * cmd )
{
struct format_instance * fi = dbg_malloc ( sizeof ( * fi ) ) ;
2001-10-08 16:11:33 +04:00
2001-11-12 15:16:57 +03:00
if ( ! fi ) {
2001-10-08 16:11:33 +04:00
stack ;
2001-11-12 15:16:57 +03:00
return NULL ;
2001-10-08 16:11:33 +04:00
}
2001-11-12 15:16:57 +03:00
fi - > cmd = cmd ;
fi - > ops = & _format1_ops ;
fi - > private = NULL ;
2001-10-08 16:11:33 +04:00
2001-11-12 15:16:57 +03:00
return fi ;
2001-10-04 21:48:55 +04:00
}