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
*/
# include "disk-rep.h"
# include "log.h"
2001-10-10 14:55:55 +04:00
# include "dbg_malloc.h"
2001-10-10 13:25:04 +04:00
/*
* Only works with powers of 2.
*/
static inline ulong _round_up ( ulong n , ulong size )
{
size - - ;
return ( n + size ) & ~ size ;
}
static inline ulong _div_up ( ulong n , ulong size )
{
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 )
{
uint32_t pe_start = pvd - > pe_start * SECTOR_SIZE ;
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 ;
pvd - > vg_on_disk . base = _next_base ( & pvd - > pv_on_disk ) ;
pvd - > vg_on_disk . size = VG_SIZE ;
pvd - > pv_uuidlist_on_disk . base = _next_base ( & pvd - > vg_on_disk ) ;
2001-10-11 14:08:44 +04:00
pvd - > pv_uuidlist_on_disk . size = MAX_PV * NAME_LEN ;
2001-10-10 13:25:04 +04:00
pvd - > lv_on_disk . base = _next_base ( & pvd - > pv_uuidlist_on_disk ) ;
2001-10-11 14:08:44 +04:00
pvd - > lv_on_disk . size = MAX_LV * sizeof ( struct lv_disk ) ;
2001-10-10 13:25:04 +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
2001-10-16 20:25:28 +04:00
int _check_vg_limits ( struct disk_list * dl )
{
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-01-31 18:28:30 +03:00
* It may seem strange to have a struct physical_volume in here ,
* but the number of extents that can fit on a disk * is * metadata
2001-10-10 14:55:55 +04:00
* format dependant .
*/
int calculate_extent_count ( struct physical_volume * pv )
{
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
*/
pvd - > pe_total = ( pv - > size / pv - > pe_size ) ;
2001-10-16 00:29:15 +04:00
if ( pvd - > pe_total < PE_SIZE_PV_SIZE_REL ) {
log_error ( " Insufficient space for extents on %s " ,
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 ;
}
2002-01-24 20:24:32 +03:00
2001-10-10 14:55:55 +04:00
do {
pvd - > pe_total - - ;
_calc_simple_layout ( pvd ) ;
2002-01-29 18:43:04 +03:00
end = ( ( pvd - > pe_on_disk . base + pvd - > pe_on_disk . size + \
SECTOR_SIZE - 1 ) / SECTOR_SIZE ) ;
2001-10-10 14:55:55 +04:00
pvd - > pe_start = _round_up ( end , PE_ALIGN ) ;
} while ( ( pvd - > pe_start + ( pvd - > pe_total * pv - > pe_size ) ) > pv - > size ) ;
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 ;
dbg_free ( pvd ) ;
return 1 ;
}