2001-10-10 13:25:04 +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-10 13:25:04 +04:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2001-10-10 13:25:04 +04:00
# include "disk-rep.h"
/*
* Only works with powers of 2.
*/
2003-04-15 17:24:42 +04:00
static inline uint32_t _round_up ( uint32_t n , uint32_t size )
2001-10-10 13:25:04 +04:00
{
size - - ;
return ( n + size ) & ~ size ;
}
2003-04-15 17:24:42 +04:00
static inline uint32_t _div_up ( uint32_t n , uint32_t size )
2001-10-10 13:25:04 +04:00
{
return _round_up ( n , size ) / size ;
}
/*
* Each chunk of metadata should be aligned to
* METADATA_ALIGN .
*/
static uint32_t _next_base ( struct data_area * area )
{
return _round_up ( area - > base + area - > size , METADATA_ALIGN ) ;
}
/*
* Quick calculation based on pe_start .
*/
static int _adjust_pe_on_disk ( struct pv_disk * pvd )
{
2002-11-18 17:01:16 +03:00
uint32_t pe_start = pvd - > pe_start < < SECTOR_SHIFT ;
2001-10-10 13:25:04 +04:00
if ( pe_start < pvd - > pe_on_disk . base + pvd - > pe_on_disk . size )
return 0 ;
pvd - > pe_on_disk . size = pe_start - pvd - > pe_on_disk . base ;
return 1 ;
}
2001-10-10 14:55:55 +04:00
static void _calc_simple_layout ( struct pv_disk * pvd )
2001-10-10 13:25:04 +04:00
{
pvd - > pv_on_disk . base = METADATA_BASE ;
pvd - > pv_on_disk . size = PV_SIZE ;
2002-04-24 22:20:51 +04:00
pvd - > vg_on_disk . base = _next_base ( & pvd - > pv_on_disk ) ;
pvd - > vg_on_disk . size = VG_SIZE ;
2001-10-10 13:25:04 +04:00
2002-04-24 22:20:51 +04:00
pvd - > pv_uuidlist_on_disk . base = _next_base ( & pvd - > vg_on_disk ) ;
pvd - > pv_uuidlist_on_disk . size = MAX_PV * NAME_LEN ;
2001-10-10 13:25:04 +04:00
2002-04-24 22:20:51 +04:00
pvd - > lv_on_disk . base = _next_base ( & pvd - > pv_uuidlist_on_disk ) ;
pvd - > lv_on_disk . size = MAX_LV * sizeof ( struct lv_disk ) ;
2001-10-10 13:25:04 +04:00
2002-04-24 22:20:51 +04:00
pvd - > pe_on_disk . base = _next_base ( & pvd - > lv_on_disk ) ;
pvd - > pe_on_disk . size = pvd - > pe_total * sizeof ( struct pe_disk ) ;
2001-10-10 14:55:55 +04:00
}
2001-10-10 13:25:04 +04:00
2002-12-20 02:25:55 +03:00
static int _check_vg_limits ( struct disk_list * dl )
2001-10-16 20:25:28 +04:00
{
2002-01-21 17:53:47 +03:00
if ( dl - > vgd . lv_max > MAX_LV ) {
2001-10-16 20:25:28 +04:00
log_error ( " MaxLogicalVolumes of %d exceeds format limit of %d "
2002-01-25 16:41:13 +03:00
" for VG '%s' " , dl - > vgd . lv_max , MAX_LV - 1 ,
2001-10-31 20:59:52 +03:00
dl - > pvd . vg_name ) ;
2001-10-16 20:25:28 +04:00
return 0 ;
}
2002-01-21 17:53:47 +03:00
if ( dl - > vgd . pv_max > MAX_PV ) {
2001-10-16 20:25:28 +04:00
log_error ( " MaxPhysicalVolumes of %d exceeds format limit of %d "
2002-01-25 16:41:13 +03:00
" for VG '%s' " , dl - > vgd . pv_max , MAX_PV - 1 ,
2001-10-31 20:59:52 +03:00
dl - > pvd . vg_name ) ;
2001-10-16 20:25:28 +04:00
return 0 ;
}
return 1 ;
}
2001-10-10 14:55:55 +04:00
/*
* This assumes pe_count and pe_start have already
* been calculated correctly .
*/
int calculate_layout ( struct disk_list * dl )
{
2001-10-31 20:59:52 +03:00
struct pv_disk * pvd = & dl - > pvd ;
2001-10-10 14:55:55 +04:00
_calc_simple_layout ( pvd ) ;
2001-10-10 13:25:04 +04:00
if ( ! _adjust_pe_on_disk ( pvd ) ) {
2001-10-16 20:25:28 +04:00
log_error ( " Insufficient space for metadata and PE's. " ) ;
2001-10-10 13:25:04 +04:00
return 0 ;
}
2001-10-16 20:25:28 +04:00
if ( ! _check_vg_limits ( dl ) )
return 0 ;
2001-10-10 13:25:04 +04:00
return 1 ;
}
2001-10-10 14:55:55 +04:00
/*
2002-11-18 17:01:16 +03:00
* The number of extents that can fit on a disk is metadata format dependant .
2001-10-10 14:55:55 +04:00
*/
2002-11-18 17:01:16 +03:00
int calculate_extent_count ( struct physical_volume * pv , uint32_t extent_size ,
uint32_t max_extent_count )
2001-10-10 14:55:55 +04:00
{
struct pv_disk * pvd = dbg_malloc ( sizeof ( * pvd ) ) ;
uint32_t end ;
if ( ! pvd ) {
stack ;
return 0 ;
}
/*
2002-01-31 18:28:30 +03:00
* Guess how many extents will fit , bearing in mind that
* one is going to be knocked off at the start of the
* next loop .
2001-10-10 14:55:55 +04:00
*/
2002-11-18 17:01:16 +03:00
if ( max_extent_count )
pvd - > pe_total = max_extent_count + 1 ;
else
pvd - > pe_total = ( pv - > size / extent_size ) ;
2001-10-10 14:55:55 +04:00
2001-10-16 00:29:15 +04:00
if ( pvd - > pe_total < PE_SIZE_PV_SIZE_REL ) {
2002-11-18 17:01:16 +03:00
log_error ( " Too few extents on %s. Try smaller extent size. " ,
2001-10-25 18:04:18 +04:00
dev_name ( pv - > dev ) ) ;
2002-01-24 20:24:32 +03:00
dbg_free ( pvd ) ;
2001-10-16 00:29:15 +04:00
return 0 ;
}
2001-10-10 14:55:55 +04:00
do {
pvd - > pe_total - - ;
_calc_simple_layout ( pvd ) ;
2002-04-24 22:20:51 +04:00
end = ( ( pvd - > pe_on_disk . base + pvd - > pe_on_disk . size +
2002-11-18 17:01:16 +03:00
SECTOR_SIZE - 1 ) > > SECTOR_SHIFT ) ;
2001-10-10 14:55:55 +04:00
pvd - > pe_start = _round_up ( end , PE_ALIGN ) ;
2002-11-18 17:01:16 +03:00
} while ( ( pvd - > pe_start + ( pvd - > pe_total * extent_size ) )
> pv - > size ) ;
2001-10-10 14:55:55 +04:00
2002-01-25 02:35:56 +03:00
if ( pvd - > pe_total > MAX_PE_TOTAL ) {
log_error ( " Metadata extent limit (%u) exceeded for %s - "
" %u required " , MAX_PE_TOTAL , dev_name ( pv - > dev ) ,
pvd - > pe_total ) ;
dbg_free ( pvd ) ;
return 0 ;
}
2001-10-10 14:55:55 +04:00
pv - > pe_count = pvd - > pe_total ;
pv - > pe_start = pvd - > pe_start ;
2002-11-18 17:01:16 +03:00
/* We can't set pe_size here without breaking LVM1 compatibility */
2001-10-10 14:55:55 +04:00
dbg_free ( pvd ) ;
return 1 ;
}