2001-11-21 12:20:05 +03:00
/*
2008-01-30 17:00:02 +03: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-11-21 12:20:05 +03: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-11-21 12:20:05 +03:00
*/
2002-11-18 17:04:08 +03:00
# include "lib.h"
2001-11-21 12:20:05 +03:00
# include "format-text.h"
2002-01-07 12:16:20 +03:00
# include "import-export.h"
2002-11-18 17:04:08 +03:00
# include "device.h"
2002-01-09 22:16:48 +03:00
# include "lvm-file.h"
2001-11-21 12:20:05 +03:00
# include "config.h"
2002-02-22 14:44:56 +03:00
# include "display.h"
2002-02-11 23:50:53 +03:00
# include "toolcontext.h"
2002-04-24 22:20:51 +04:00
# include "lvm-string.h"
2002-11-18 17:04:08 +03:00
# include "uuid.h"
# include "layout.h"
# include "crc.h"
# include "xlate.h"
# include "label.h"
2003-07-05 02:34:56 +04:00
# include "memlock.h"
2004-05-05 01:25:57 +04:00
# include "lvmcache.h"
2001-11-21 12:20:05 +03:00
2002-01-09 22:16:48 +03:00
# include <unistd.h>
# include <sys/file.h>
2009-02-22 22:00:26 +03:00
# include <sys/param.h>
2002-01-09 22:16:48 +03:00
# include <limits.h>
2002-04-24 22:20:51 +04:00
# include <dirent.h>
2002-11-18 17:04:08 +03:00
# include <ctype.h>
2002-01-09 22:16:48 +03:00
2007-04-26 01:10:55 +04:00
static struct mda_header * _raw_read_mda_header ( const struct format_type * fmt ,
struct device_area * dev_area ) ;
2006-04-19 19:33:07 +04:00
static struct format_instance * _text_create_text_instance ( const struct format_type
2002-12-20 02:25:55 +03:00
* fmt , const char * vgname ,
2006-04-13 01:23:04 +04:00
const char * vgid ,
2002-11-18 17:04:08 +03:00
void * context ) ;
2002-02-22 14:44:56 +03:00
2005-10-23 04:14:48 +04:00
struct text_fid_context {
char * raw_metadata_buf ;
uint32_t raw_metadata_buf_size ;
} ;
2002-04-24 22:20:51 +04:00
struct dir_list {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2002-04-24 22:20:51 +04:00
char dir [ 0 ] ;
} ;
2002-11-18 17:04:08 +03:00
struct raw_list {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2002-11-18 17:04:08 +03:00
struct device_area dev_area ;
} ;
2002-04-24 22:20:51 +04:00
struct text_context {
char * path_live ; /* Path to file holding live metadata */
char * path_edit ; /* Path to file holding edited metadata */
char * desc ; /* Description placed inside file */
} ;
2001-11-21 12:20:05 +03:00
/*
2002-12-20 02:25:55 +03:00
* NOTE : Currently there can be only one vg per text file .
2001-11-21 12:20:05 +03:00
*/
2006-05-11 21:58:58 +04:00
static int _text_vg_setup ( struct format_instance * fid __attribute ( ( unused ) ) ,
struct volume_group * vg )
2001-11-21 12:20:05 +03:00
{
2002-04-24 22:20:51 +04:00
if ( vg - > extent_size & ( vg - > extent_size - 1 ) ) {
log_error ( " Extent size must be power of 2 " ) ;
return 0 ;
}
2002-02-22 14:44:56 +03:00
return 1 ;
2001-11-21 12:20:05 +03:00
}
2007-11-05 20:17:55 +03:00
static uint64_t _mda_free_sectors_raw ( struct metadata_area * mda )
{
struct mda_context * mdac = ( struct mda_context * ) mda - > metadata_locn ;
return mdac - > free_sectors ;
}
2009-01-10 01:44:33 +03:00
static uint64_t _mda_total_sectors_raw ( struct metadata_area * mda )
{
struct mda_context * mdac = ( struct mda_context * ) mda - > metadata_locn ;
return mdac - > area . size > > SECTOR_SHIFT ;
}
2007-03-23 15:43:17 +03:00
/*
* Check if metadata area belongs to vg
*/
static int _mda_in_vg_raw ( struct format_instance * fid __attribute ( ( unused ) ) ,
struct volume_group * vg , struct metadata_area * mda )
{
struct mda_context * mdac = ( struct mda_context * ) mda - > metadata_locn ;
struct pv_list * pvl ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , & vg - > pvs )
2007-03-23 15:43:17 +03:00
if ( pvl - > pv - > dev = = mdac - > area . dev )
return 1 ;
return 0 ;
}
2007-04-26 01:10:55 +04:00
/*
* For circular region between region_start and region_start + region_size ,
* back up one SECTOR_SIZE from ' region_ptr ' and return the value .
* This allows reverse traversal through text metadata area to find old
* metadata .
*
* Parameters :
* region_start : start of the region ( bytes )
* region_size : size of the region ( bytes )
* region_ptr : pointer within the region ( bytes )
* NOTE : region_start < = region_ptr < = region_start + region_size
*/
static uint64_t _get_prev_sector_circular ( uint64_t region_start ,
uint64_t region_size ,
uint64_t region_ptr )
{
if ( region_ptr > = region_start + SECTOR_SIZE )
return region_ptr - SECTOR_SIZE ;
else
return ( region_start + region_size - SECTOR_SIZE ) ;
}
/*
* Analyze a metadata area for old metadata records in the circular buffer .
* This function just looks through and makes a first pass at the data in
* the sectors for particular things .
* FIXME : do something with each metadata area ( try to extract vg , write
* raw data to file , etc )
*/
static int _pv_analyze_mda_raw ( const struct format_type * fmt ,
struct metadata_area * mda )
{
struct mda_header * mdah ;
struct raw_locn * rlocn ;
uint64_t area_start ;
uint64_t area_size ;
2008-07-31 17:07:01 +04:00
uint64_t prev_sector , prev_sector2 ;
2007-04-26 01:10:55 +04:00
uint64_t latest_mrec_offset ;
int i ;
uint64_t offset ;
uint64_t offset2 ;
2007-08-22 18:38:18 +04:00
size_t size ;
size_t size2 ;
2007-04-26 01:10:55 +04:00
char * buf = NULL ;
struct device_area * area ;
struct mda_context * mdac ;
int r = 0 ;
mdac = ( struct mda_context * ) mda - > metadata_locn ;
2007-08-22 18:38:18 +04:00
log_print ( " Found text metadata area: offset=% " PRIu64 " , size=% "
PRIu64 , mdac - > area . start , mdac - > area . size ) ;
2007-04-26 01:10:55 +04:00
area = & mdac - > area ;
if ( ! dev_open ( area - > dev ) )
return_0 ;
if ( ! ( mdah = _raw_read_mda_header ( fmt , area ) ) )
goto_out ;
rlocn = mdah - > raw_locns ;
/*
* The device area includes the metadata header as well as the
* records , so remove the metadata header from the start and size
*/
area_start = area - > start + MDA_HEADER_SIZE ;
area_size = area - > size - MDA_HEADER_SIZE ;
latest_mrec_offset = rlocn - > offset + area - > start ;
/*
* Start searching at rlocn ( point of live metadata ) and go
* backwards .
*/
prev_sector = _get_prev_sector_circular ( area_start , area_size ,
latest_mrec_offset ) ;
offset = prev_sector ;
size = SECTOR_SIZE ;
offset2 = size2 = 0 ;
i = 0 ;
while ( prev_sector ! = latest_mrec_offset ) {
2008-07-31 17:07:01 +04:00
prev_sector2 = prev_sector ;
2007-04-26 01:10:55 +04:00
prev_sector = _get_prev_sector_circular ( area_start , area_size ,
prev_sector ) ;
2008-07-31 17:07:01 +04:00
if ( prev_sector > prev_sector2 )
goto_out ;
2007-04-26 01:10:55 +04:00
/*
* FIXME : for some reason , the whole metadata region from
* area - > start to area - > start + area - > size is not used .
* Only ~ 32 KB seems to contain valid metadata records
* ( LVM2 format - format_text ) . As a result , I end up with
* " maybe_config_section " returning true when there ' s no valid
* metadata in a sector ( sectors with all nulls ) .
*/
if ( ! ( buf = dm_pool_alloc ( fmt - > cmd - > mem , size + size2 ) ) )
goto_out ;
if ( ! dev_read_circular ( area - > dev , offset , size ,
offset2 , size2 , buf ) )
goto_out ;
/*
* FIXME : We could add more sophisticated metadata detection
*/
2007-08-22 18:38:18 +04:00
if ( maybe_config_section ( buf , size + size2 ) ) {
2007-04-26 01:10:55 +04:00
/* FIXME: Validate region, pull out timestamp?, etc */
/* FIXME: Do something with this region */
log_verbose ( " Found LVM2 metadata record at "
2007-08-22 18:38:18 +04:00
" offset=% " PRIu64 " , size=% " PRIsize_t " , "
" offset2=% " PRIu64 " size2=% " PRIsize_t ,
2007-04-26 01:10:55 +04:00
offset , size , offset2 , size2 ) ;
offset = prev_sector ;
size = SECTOR_SIZE ;
offset2 = size2 = 0 ;
} else {
/*
* Not a complete metadata record , assume we have
* metadata and just increase the size and offset .
* Start the second region if the previous sector is
* wrapping around towards the end of the disk .
*/
if ( prev_sector > offset ) {
offset2 = prev_sector ;
size2 + = SECTOR_SIZE ;
} else {
offset = prev_sector ;
size + = SECTOR_SIZE ;
}
}
dm_pool_free ( fmt - > cmd - > mem , buf ) ;
buf = NULL ;
}
r = 1 ;
out :
if ( buf )
dm_pool_free ( fmt - > cmd - > mem , buf ) ;
if ( ! dev_close ( area - > dev ) )
stack ;
return r ;
}
2006-05-11 21:58:58 +04:00
static int _text_lv_setup ( struct format_instance * fid __attribute ( ( unused ) ) ,
struct logical_volume * lv )
2001-11-21 12:20:05 +03:00
{
2008-01-30 17:00:02 +03:00
/******** FIXME Any LV size restriction?
2002-02-22 14:44:56 +03:00
uint64_t max_size = UINT_MAX ;
2001-11-21 12:20:05 +03:00
2002-02-22 14:44:56 +03:00
if ( lv - > size > max_size ) {
2006-05-10 01:23:51 +04:00
char * dummy = display_size ( max_size ) ;
2002-02-22 14:44:56 +03:00
log_error ( " logical volumes cannot be larger than %s " , dummy ) ;
2005-10-17 03:03:59 +04:00
dm_free ( dummy ) ;
2002-02-22 14:44:56 +03:00
return 0 ;
}
2002-11-18 19:21:00 +03:00
*/
2005-01-20 21:11:53 +03:00
if ( ! * lv - > lvid . s & & ! lvid_create ( & lv - > lvid , & lv - > vg - > id ) ) {
log_error ( " Random lvid creation failed for %s/%s. " ,
lv - > vg - > name , lv - > name ) ;
return 0 ;
}
2002-02-22 14:44:56 +03:00
return 1 ;
2001-11-21 12:20:05 +03:00
}
2002-11-18 17:04:08 +03:00
static void _xlate_mdah ( struct mda_header * mdah )
{
struct raw_locn * rl ;
mdah - > version = xlate32 ( mdah - > version ) ;
mdah - > start = xlate64 ( mdah - > start ) ;
mdah - > size = xlate64 ( mdah - > size ) ;
rl = & mdah - > raw_locns [ 0 ] ;
while ( rl - > offset ) {
rl - > checksum = xlate32 ( rl - > checksum ) ;
rl - > offset = xlate64 ( rl - > offset ) ;
rl - > size = xlate64 ( rl - > size ) ;
rl + + ;
}
}
2002-12-20 02:25:55 +03:00
static struct mda_header * _raw_read_mda_header ( const struct format_type * fmt ,
2002-11-18 17:04:08 +03:00
struct device_area * dev_area )
{
struct mda_header * mdah ;
2005-10-17 03:03:59 +04:00
if ( ! ( mdah = dm_pool_alloc ( fmt - > cmd - > mem , MDA_HEADER_SIZE ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " struct mda_header allocation failed " ) ;
return NULL ;
}
2008-01-30 16:19:47 +03:00
if ( ! dev_read ( dev_area - > dev , dev_area - > start , MDA_HEADER_SIZE , mdah ) )
goto_bad ;
2002-11-18 17:04:08 +03:00
if ( mdah - > checksum_xl ! = xlate32 ( calc_crc ( INITIAL_CRC , mdah - > magic ,
MDA_HEADER_SIZE -
sizeof ( mdah - > checksum_xl ) ) ) ) {
log_error ( " Incorrect metadata area header checksum " ) ;
2008-01-30 16:19:47 +03:00
goto bad ;
2002-11-18 17:04:08 +03:00
}
_xlate_mdah ( mdah ) ;
2006-05-10 01:23:51 +04:00
if ( strncmp ( ( char * ) mdah - > magic , FMTT_MAGIC , sizeof ( mdah - > magic ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Wrong magic number in metadata area header " ) ;
2008-01-30 16:19:47 +03:00
goto bad ;
2002-11-18 17:04:08 +03:00
}
if ( mdah - > version ! = FMTT_VERSION ) {
log_error ( " Incompatible metadata area header version: %d " ,
mdah - > version ) ;
2008-01-30 16:19:47 +03:00
goto bad ;
2002-11-18 17:04:08 +03:00
}
if ( mdah - > start ! = dev_area - > start ) {
log_error ( " Incorrect start sector in metadata area header: % "
PRIu64 , mdah - > start ) ;
2008-01-30 16:19:47 +03:00
goto bad ;
2002-11-18 17:04:08 +03:00
}
return mdah ;
2007-01-10 00:12:41 +03:00
2008-01-30 16:19:47 +03:00
bad :
2007-01-10 00:12:41 +03:00
dm_pool_free ( fmt - > cmd - > mem , mdah ) ;
return NULL ;
2002-11-18 17:04:08 +03:00
}
2002-12-20 02:25:55 +03:00
static int _raw_write_mda_header ( const struct format_type * fmt ,
2002-11-18 17:04:08 +03:00
struct device * dev ,
uint64_t start_byte , struct mda_header * mdah )
{
2006-05-10 01:23:51 +04:00
strncpy ( ( char * ) mdah - > magic , FMTT_MAGIC , sizeof ( mdah - > magic ) ) ;
2002-11-18 17:04:08 +03:00
mdah - > version = FMTT_VERSION ;
mdah - > start = start_byte ;
_xlate_mdah ( mdah ) ;
mdah - > checksum_xl = xlate32 ( calc_crc ( INITIAL_CRC , mdah - > magic ,
MDA_HEADER_SIZE -
sizeof ( mdah - > checksum_xl ) ) ) ;
2008-08-16 13:46:55 +04:00
if ( ! dev_write ( dev , start_byte , MDA_HEADER_SIZE , mdah ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2002-11-18 17:04:08 +03:00
return 1 ;
}
static struct raw_locn * _find_vg_rlocn ( struct device_area * dev_area ,
struct mda_header * mdah ,
2005-04-06 22:59:55 +04:00
const char * vgname ,
2005-10-31 23:15:28 +03:00
int * precommitted )
2002-11-18 17:04:08 +03:00
{
2002-12-20 02:25:55 +03:00
size_t len ;
2006-12-01 02:11:42 +03:00
char vgnamebuf [ NAME_LEN + 2 ] __attribute ( ( aligned ( 8 ) ) ) ;
2005-10-31 23:15:28 +03:00
struct raw_locn * rlocn , * rlocn_precommitted ;
2005-03-22 01:40:35 +03:00
struct lvmcache_info * info ;
2002-11-18 17:04:08 +03:00
2005-04-06 22:59:55 +04:00
rlocn = mdah - > raw_locns ; /* Slot 0 */
2005-10-31 23:15:28 +03:00
rlocn_precommitted = rlocn + 1 ; /* Slot 1 */
2005-04-06 22:59:55 +04:00
2005-10-31 23:15:28 +03:00
/* Should we use precommitted metadata? */
if ( * precommitted & & rlocn_precommitted - > size & &
( rlocn_precommitted - > offset ! = rlocn - > offset ) ) {
rlocn = rlocn_precommitted ;
} else
* precommitted = 0 ;
2002-11-18 17:04:08 +03:00
2005-04-06 22:59:55 +04:00
/* FIXME Loop through rlocns two-at-a-time. List null-terminated. */
2002-11-18 17:04:08 +03:00
/* FIXME Ignore if checksum incorrect!!! */
2005-04-06 22:59:55 +04:00
if ( ! dev_read ( dev_area - > dev , dev_area - > start + rlocn - > offset ,
2008-01-30 16:19:47 +03:00
sizeof ( vgnamebuf ) , vgnamebuf ) )
goto_bad ;
2005-04-06 22:59:55 +04:00
if ( ! strncmp ( vgnamebuf , vgname , len = strlen ( vgname ) ) & &
( isspace ( vgnamebuf [ len ] ) | | vgnamebuf [ len ] = = ' { ' ) ) {
return rlocn ;
2002-11-18 17:04:08 +03:00
}
2008-01-30 16:19:47 +03:00
bad :
2008-01-30 02:45:48 +03:00
if ( ( info = info_from_pvid ( dev_area - > dev - > pvid , 0 ) ) )
2008-02-06 18:47:28 +03:00
lvmcache_update_vgname_and_id ( info , FMT_TEXT_ORPHAN_VG_NAME ,
FMT_TEXT_ORPHAN_VG_NAME , 0 , NULL ) ;
2005-03-22 01:40:35 +03:00
2002-11-18 17:04:08 +03:00
return NULL ;
}
2005-04-06 20:35:33 +04:00
/*
* Determine offset for uncommitted metadata
*/
static uint64_t _next_rlocn_offset ( struct raw_locn * rlocn ,
struct mda_header * mdah )
2002-11-18 17:04:08 +03:00
{
2005-04-06 20:35:33 +04:00
if ( ! rlocn )
/* Find an empty slot */
/* FIXME Assume only one VG per mdah for now */
return MDA_HEADER_SIZE ;
2002-11-18 17:04:08 +03:00
2005-04-06 20:35:33 +04:00
/* Start of free space - round up to next sector; circular */
return ( ( rlocn - > offset + rlocn - > size +
( SECTOR_SIZE - rlocn - > size % SECTOR_SIZE ) -
MDA_HEADER_SIZE ) % ( mdah - > size - MDA_HEADER_SIZE ) )
+ MDA_HEADER_SIZE ;
2002-11-18 17:04:08 +03:00
}
static int _raw_holds_vgname ( struct format_instance * fid ,
struct device_area * dev_area , const char * vgname )
{
int r = 0 ;
2005-10-31 23:15:28 +03:00
int noprecommit = 0 ;
2005-04-06 20:35:33 +04:00
struct mda_header * mdah ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! dev_open ( dev_area - > dev ) )
return_0 ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , dev_area ) ) )
return_0 ;
2005-04-06 20:35:33 +04:00
2005-10-31 23:15:28 +03:00
if ( _find_vg_rlocn ( dev_area , mdah , vgname , & noprecommit ) )
2002-11-18 17:04:08 +03:00
r = 1 ;
if ( ! dev_close ( dev_area - > dev ) )
stack ;
return r ;
}
static struct volume_group * _vg_read_raw_area ( struct format_instance * fid ,
const char * vgname ,
2005-04-06 22:59:55 +04:00
struct device_area * area ,
2005-10-31 23:15:28 +03:00
int precommitted )
2002-11-18 17:04:08 +03:00
{
struct volume_group * vg = NULL ;
struct raw_locn * rlocn ;
struct mda_header * mdah ;
time_t when ;
char * desc ;
2002-12-20 02:25:55 +03:00
uint32_t wrap = 0 ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! dev_open ( area - > dev ) )
return_NULL ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , area ) ) )
goto_out ;
2002-11-18 17:04:08 +03:00
2005-10-31 23:15:28 +03:00
if ( ! ( rlocn = _find_vg_rlocn ( area , mdah , vgname , & precommitted ) ) ) {
2005-03-22 01:40:35 +03:00
log_debug ( " VG %s not found on %s " , vgname , dev_name ( area - > dev ) ) ;
2002-11-18 17:04:08 +03:00
goto out ;
}
if ( rlocn - > offset + rlocn - > size > mdah - > size )
2002-12-20 02:25:55 +03:00
wrap = ( uint32_t ) ( ( rlocn - > offset + rlocn - > size ) - mdah - > size ) ;
2002-11-18 17:04:08 +03:00
if ( wrap > rlocn - > offset ) {
log_error ( " VG %s metadata too large for circular buffer " ,
vg - > name ) ;
goto out ;
}
2002-12-20 02:25:55 +03:00
/* FIXME 64-bit */
2003-07-05 02:34:56 +04:00
if ( ! ( vg = text_vg_import_fd ( fid , NULL , area - > dev ,
2002-12-20 02:25:55 +03:00
( off_t ) ( area - > start + rlocn - > offset ) ,
( uint32_t ) ( rlocn - > size - wrap ) ,
( off_t ) ( area - > start + MDA_HEADER_SIZE ) ,
wrap , calc_crc , rlocn - > checksum , & when ,
2008-01-30 16:19:47 +03:00
& desc ) ) )
goto_out ;
2005-04-06 22:59:55 +04:00
log_debug ( " Read %s %smetadata (%u) from %s at % " PRIu64 " size % "
2005-10-31 23:15:28 +03:00
PRIu64 , vg - > name , precommitted ? " pre-commit " : " " ,
2005-04-06 22:59:55 +04:00
vg - > seqno , dev_name ( area - > dev ) ,
2003-04-28 16:18:53 +04:00
area - > start + rlocn - > offset , rlocn - > size ) ;
2002-11-18 17:04:08 +03:00
2005-10-31 23:15:28 +03:00
if ( precommitted )
vg - > status | = PRECOMMITTED ;
2002-11-18 17:04:08 +03:00
out :
if ( ! dev_close ( area - > dev ) )
stack ;
return vg ;
}
static struct volume_group * _vg_read_raw ( struct format_instance * fid ,
const char * vgname ,
struct metadata_area * mda )
{
struct mda_context * mdac = ( struct mda_context * ) mda - > metadata_locn ;
2005-04-06 22:59:55 +04:00
return _vg_read_raw_area ( fid , vgname , & mdac - > area , 0 ) ;
}
static struct volume_group * _vg_read_precommit_raw ( struct format_instance * fid ,
const char * vgname ,
struct metadata_area * mda )
{
struct mda_context * mdac = ( struct mda_context * ) mda - > metadata_locn ;
return _vg_read_raw_area ( fid , vgname , & mdac - > area , 1 ) ;
2002-11-18 17:04:08 +03:00
}
static int _vg_write_raw ( struct format_instance * fid , struct volume_group * vg ,
struct metadata_area * mda )
{
struct mda_context * mdac = ( struct mda_context * ) mda - > metadata_locn ;
2005-10-23 04:14:48 +04:00
struct text_fid_context * fidtc = ( struct text_fid_context * ) fid - > private ;
2002-11-18 17:04:08 +03:00
struct raw_locn * rlocn ;
struct mda_header * mdah ;
2005-06-01 20:51:55 +04:00
struct pv_list * pvl ;
2002-11-18 17:04:08 +03:00
int r = 0 ;
2008-10-17 04:55:46 +04:00
uint64_t new_wrap = 0 , old_wrap = 0 , new_end ;
2002-11-18 17:04:08 +03:00
int found = 0 ;
2005-10-31 23:15:28 +03:00
int noprecommit = 0 ;
2002-11-18 17:04:08 +03:00
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2005-06-01 20:51:55 +04:00
if ( pvl - > pv - > dev = = mdac - > area . dev ) {
2002-11-18 17:04:08 +03:00
found = 1 ;
break ;
}
}
if ( ! found )
return 1 ;
2008-01-30 16:19:47 +03:00
if ( ! dev_open ( mdac - > area . dev ) )
return_0 ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , & mdac - > area ) ) )
goto_out ;
2002-11-18 17:04:08 +03:00
2005-10-31 23:15:28 +03:00
rlocn = _find_vg_rlocn ( & mdac - > area , mdah , vg - > name , & noprecommit ) ;
2005-04-06 20:35:33 +04:00
mdac - > rlocn . offset = _next_rlocn_offset ( rlocn , mdah ) ;
2002-11-18 17:04:08 +03:00
2005-10-23 04:14:48 +04:00
if ( ! fidtc - > raw_metadata_buf & &
! ( fidtc - > raw_metadata_buf_size =
text_vg_export_raw ( vg , " " , & fidtc - > raw_metadata_buf ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " VG %s metadata writing failed " , vg - > name ) ;
goto out ;
}
2005-10-23 04:14:48 +04:00
mdac - > rlocn . size = fidtc - > raw_metadata_buf_size ;
2002-11-18 17:04:08 +03:00
if ( mdac - > rlocn . offset + mdac - > rlocn . size > mdah - > size )
new_wrap = ( mdac - > rlocn . offset + mdac - > rlocn . size ) - mdah - > size ;
if ( rlocn & & ( rlocn - > offset + rlocn - > size > mdah - > size ) )
old_wrap = ( rlocn - > offset + rlocn - > size ) - mdah - > size ;
2008-10-17 04:55:46 +04:00
new_end = new_wrap ? new_wrap + MDA_HEADER_SIZE :
mdac - > rlocn . offset + mdac - > rlocn . size ;
2002-11-18 17:04:08 +03:00
if ( ( new_wrap & & old_wrap ) | |
2008-10-17 04:55:46 +04:00
( rlocn & & ( new_wrap | | old_wrap ) & & ( new_end > rlocn - > offset ) ) | |
2002-11-18 17:04:08 +03:00
( mdac - > rlocn . size > = mdah - > size ) ) {
log_error ( " VG %s metadata too large for circular buffer " ,
vg - > name ) ;
goto out ;
}
log_debug ( " Writing %s metadata to %s at % " PRIu64 " len % " PRIu64 ,
vg - > name , dev_name ( mdac - > area . dev ) , mdac - > area . start +
mdac - > rlocn . offset , mdac - > rlocn . size - new_wrap ) ;
/* Write text out, circularly */
2003-07-05 02:34:56 +04:00
if ( ! dev_write ( mdac - > area . dev , mdac - > area . start + mdac - > rlocn . offset ,
2005-10-23 04:14:48 +04:00
( size_t ) ( mdac - > rlocn . size - new_wrap ) ,
2008-01-30 16:19:47 +03:00
fidtc - > raw_metadata_buf ) )
goto_out ;
2002-11-18 17:04:08 +03:00
if ( new_wrap ) {
2008-10-17 04:55:46 +04:00
log_debug ( " Writing metadata to %s at % " PRIu64 " len % " PRIu64 ,
2002-11-18 17:04:08 +03:00
dev_name ( mdac - > area . dev ) , mdac - > area . start +
MDA_HEADER_SIZE , new_wrap ) ;
2003-07-05 02:34:56 +04:00
if ( ! dev_write ( mdac - > area . dev ,
mdac - > area . start + MDA_HEADER_SIZE ,
( size_t ) new_wrap ,
2008-01-30 17:00:02 +03:00
fidtc - > raw_metadata_buf +
2008-01-30 16:19:47 +03:00
mdac - > rlocn . size - new_wrap ) )
goto_out ;
2002-11-18 17:04:08 +03:00
}
2005-10-23 04:14:48 +04:00
mdac - > rlocn . checksum = calc_crc ( INITIAL_CRC , fidtc - > raw_metadata_buf ,
2002-12-20 02:25:55 +03:00
( uint32_t ) ( mdac - > rlocn . size -
new_wrap ) ) ;
2002-11-18 17:04:08 +03:00
if ( new_wrap )
mdac - > rlocn . checksum = calc_crc ( mdac - > rlocn . checksum ,
2005-10-23 04:14:48 +04:00
fidtc - > raw_metadata_buf +
mdac - > rlocn . size -
2008-10-17 04:55:46 +04:00
new_wrap , ( uint32_t ) new_wrap ) ;
2002-11-18 17:04:08 +03:00
r = 1 ;
out :
2008-10-01 00:37:52 +04:00
if ( ! r ) {
if ( ! dev_close ( mdac - > area . dev ) )
stack ;
2008-10-17 04:55:46 +04:00
if ( fidtc - > raw_metadata_buf ) {
dm_free ( fidtc - > raw_metadata_buf ) ;
fidtc - > raw_metadata_buf = NULL ;
}
2008-10-01 00:37:52 +04:00
}
2002-11-18 17:04:08 +03:00
return r ;
}
2005-04-06 22:59:55 +04:00
static int _vg_commit_raw_rlocn ( struct format_instance * fid ,
struct volume_group * vg ,
struct metadata_area * mda ,
int precommit )
2002-11-18 17:04:08 +03:00
{
struct mda_context * mdac = ( struct mda_context * ) mda - > metadata_locn ;
2005-10-23 04:14:48 +04:00
struct text_fid_context * fidtc = ( struct text_fid_context * ) fid - > private ;
2002-11-18 17:04:08 +03:00
struct mda_header * mdah ;
struct raw_locn * rlocn ;
2005-06-01 20:51:55 +04:00
struct pv_list * pvl ;
2002-11-18 17:04:08 +03:00
int r = 0 ;
int found = 0 ;
2005-10-31 23:15:28 +03:00
int noprecommit = 0 ;
2002-11-18 17:04:08 +03:00
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2005-06-01 20:51:55 +04:00
if ( pvl - > pv - > dev = = mdac - > area . dev ) {
2002-11-18 17:04:08 +03:00
found = 1 ;
break ;
}
}
if ( ! found )
return 1 ;
2008-01-30 16:19:47 +03:00
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , & mdac - > area ) ) )
goto_out ;
2002-11-18 17:04:08 +03:00
2005-10-31 23:15:28 +03:00
if ( ! ( rlocn = _find_vg_rlocn ( & mdac - > area , mdah , vg - > name , & noprecommit ) ) ) {
2005-04-06 22:59:55 +04:00
mdah - > raw_locns [ 0 ] . offset = 0 ;
2005-10-31 23:15:28 +03:00
mdah - > raw_locns [ 0 ] . size = 0 ;
mdah - > raw_locns [ 0 ] . checksum = 0 ;
2002-11-18 17:04:08 +03:00
mdah - > raw_locns [ 1 ] . offset = 0 ;
2005-10-31 23:15:28 +03:00
mdah - > raw_locns [ 1 ] . size = 0 ;
mdah - > raw_locns [ 1 ] . checksum = 0 ;
2005-04-06 22:59:55 +04:00
mdah - > raw_locns [ 2 ] . offset = 0 ;
2005-10-31 23:15:28 +03:00
mdah - > raw_locns [ 2 ] . size = 0 ;
mdah - > raw_locns [ 2 ] . checksum = 0 ;
2005-04-06 22:59:55 +04:00
rlocn = & mdah - > raw_locns [ 0 ] ;
2002-11-18 17:04:08 +03:00
}
2005-04-06 22:59:55 +04:00
if ( precommit )
rlocn + + ;
2005-10-31 23:15:28 +03:00
else {
/* If not precommitting, wipe the precommitted rlocn */
mdah - > raw_locns [ 1 ] . offset = 0 ;
mdah - > raw_locns [ 1 ] . size = 0 ;
mdah - > raw_locns [ 1 ] . checksum = 0 ;
}
/* Is there new metadata to commit? */
if ( mdac - > rlocn . size ) {
rlocn - > offset = mdac - > rlocn . offset ;
rlocn - > size = mdac - > rlocn . size ;
rlocn - > checksum = mdac - > rlocn . checksum ;
log_debug ( " %sCommitting %s metadata (%u) to %s header at % "
PRIu64 , precommit ? " Pre- " : " " , vg - > name , vg - > seqno ,
dev_name ( mdac - > area . dev ) , mdac - > area . start ) ;
} else
log_debug ( " Wiping pre-committed %s metadata from %s "
" header at % " PRIu64 , vg - > name ,
dev_name ( mdac - > area . dev ) , mdac - > area . start ) ;
2005-04-06 22:59:55 +04:00
2002-11-18 17:04:08 +03:00
if ( ! _raw_write_mda_header ( fid - > fmt , mdac - > area . dev , mdac - > area . start ,
mdah ) ) {
2008-08-16 13:46:55 +04:00
dm_pool_free ( fid - > fmt - > cmd - > mem , mdah ) ;
2002-11-18 17:04:08 +03:00
log_error ( " Failed to write metadata area header " ) ;
goto out ;
}
r = 1 ;
out :
2005-10-23 04:14:48 +04:00
if ( ! precommit ) {
if ( ! dev_close ( mdac - > area . dev ) )
stack ;
if ( fidtc - > raw_metadata_buf ) {
dm_free ( fidtc - > raw_metadata_buf ) ;
fidtc - > raw_metadata_buf = NULL ;
}
}
2002-11-18 17:04:08 +03:00
return r ;
}
2005-04-06 22:59:55 +04:00
static int _vg_commit_raw ( struct format_instance * fid , struct volume_group * vg ,
struct metadata_area * mda )
{
return _vg_commit_raw_rlocn ( fid , vg , mda , 0 ) ;
}
static int _vg_precommit_raw ( struct format_instance * fid ,
struct volume_group * vg ,
struct metadata_area * mda )
{
return _vg_commit_raw_rlocn ( fid , vg , mda , 1 ) ;
}
2003-07-05 02:34:56 +04:00
/* Close metadata area devices */
static int _vg_revert_raw ( struct format_instance * fid , struct volume_group * vg ,
struct metadata_area * mda )
{
struct mda_context * mdac = ( struct mda_context * ) mda - > metadata_locn ;
2005-06-01 20:51:55 +04:00
struct pv_list * pvl ;
2003-07-05 02:34:56 +04:00
int found = 0 ;
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2005-06-01 20:51:55 +04:00
if ( pvl - > pv - > dev = = mdac - > area . dev ) {
2003-07-05 02:34:56 +04:00
found = 1 ;
break ;
}
}
if ( ! found )
return 1 ;
2005-10-31 23:15:28 +03:00
/* Wipe pre-committed metadata */
mdac - > rlocn . size = 0 ;
return _vg_commit_raw_rlocn ( fid , vg , mda , 0 ) ;
2003-07-05 02:34:56 +04:00
}
2002-11-18 17:04:08 +03:00
static int _vg_remove_raw ( struct format_instance * fid , struct volume_group * vg ,
struct metadata_area * mda )
{
struct mda_context * mdac = ( struct mda_context * ) mda - > metadata_locn ;
struct mda_header * mdah ;
struct raw_locn * rlocn ;
int r = 0 ;
2005-10-31 23:15:28 +03:00
int noprecommit = 0 ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! dev_open ( mdac - > area . dev ) )
return_0 ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , & mdac - > area ) ) )
goto_out ;
2002-11-18 17:04:08 +03:00
2005-10-31 23:15:28 +03:00
if ( ! ( rlocn = _find_vg_rlocn ( & mdac - > area , mdah , vg - > name , & noprecommit ) ) ) {
2002-11-18 17:04:08 +03:00
rlocn = & mdah - > raw_locns [ 0 ] ;
mdah - > raw_locns [ 1 ] . offset = 0 ;
}
rlocn - > offset = 0 ;
rlocn - > size = 0 ;
rlocn - > checksum = 0 ;
if ( ! _raw_write_mda_header ( fid - > fmt , mdac - > area . dev , mdac - > area . start ,
mdah ) ) {
2008-08-16 13:46:55 +04:00
dm_pool_free ( fid - > fmt - > cmd - > mem , mdah ) ;
2002-11-18 17:04:08 +03:00
log_error ( " Failed to write metadata area header " ) ;
goto out ;
}
r = 1 ;
out :
if ( ! dev_close ( mdac - > area . dev ) )
stack ;
return r ;
}
static struct volume_group * _vg_read_file_name ( struct format_instance * fid ,
const char * vgname ,
2005-04-06 22:59:55 +04:00
const char * read_path )
2001-11-21 12:20:05 +03:00
{
2002-01-10 17:27:47 +03:00
struct volume_group * vg ;
2002-02-11 14:43:17 +03:00
time_t when ;
char * desc ;
2002-01-10 17:27:47 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( vg = text_vg_import_file ( fid , read_path , & when , & desc ) ) )
return_NULL ;
2002-01-10 17:27:47 +03:00
/*
* Currently you can only have a single volume group per
* text file ( this restriction may remain ) . We need to
* check that it contains the correct volume group .
*/
2002-11-18 17:04:08 +03:00
if ( vgname & & strcmp ( vgname , vg - > name ) ) {
2005-10-17 03:03:59 +04:00
dm_pool_free ( fid - > fmt - > cmd - > mem , vg ) ;
2009-07-16 00:02:46 +04:00
log_error ( " '%s' does not contain volume group '%s'. " ,
read_path , vgname ) ;
2002-01-10 17:27:47 +03:00
return NULL ;
2002-11-18 17:04:08 +03:00
} else
2005-04-06 22:59:55 +04:00
log_debug ( " Read volume group %s from %s " , vg - > name , read_path ) ;
2002-01-10 17:27:47 +03:00
return vg ;
2001-11-21 12:20:05 +03:00
}
2002-11-18 17:04:08 +03:00
static struct volume_group * _vg_read_file ( struct format_instance * fid ,
const char * vgname ,
struct metadata_area * mda )
{
struct text_context * tc = ( struct text_context * ) mda - > metadata_locn ;
return _vg_read_file_name ( fid , vgname , tc - > path_live ) ;
}
2005-04-06 22:59:55 +04:00
static struct volume_group * _vg_read_precommit_file ( struct format_instance * fid ,
const char * vgname ,
struct metadata_area * mda )
{
struct text_context * tc = ( struct text_context * ) mda - > metadata_locn ;
2005-10-31 23:15:28 +03:00
struct volume_group * vg ;
2005-04-06 22:59:55 +04:00
2005-10-31 23:15:28 +03:00
if ( ( vg = _vg_read_file_name ( fid , vgname , tc - > path_edit ) ) )
vg - > status | = PRECOMMITTED ;
else
vg = _vg_read_file_name ( fid , vgname , tc - > path_live ) ;
return vg ;
2005-04-06 22:59:55 +04:00
}
2007-08-22 18:38:18 +04:00
static int _vg_write_file ( struct format_instance * fid __attribute ( ( unused ) ) ,
struct volume_group * vg , struct metadata_area * mda )
2001-11-21 12:20:05 +03:00
{
2002-11-18 17:04:08 +03:00
struct text_context * tc = ( struct text_context * ) mda - > metadata_locn ;
2002-01-15 20:37:23 +03:00
2002-01-07 12:05:31 +03:00
FILE * fp ;
2002-01-10 17:27:47 +03:00
int fd ;
2002-01-09 22:16:48 +03:00
char * slash ;
char temp_file [ PATH_MAX ] , temp_dir [ PATH_MAX ] ;
2007-07-02 15:17:21 +04:00
slash = strrchr ( tc - > path_edit , ' / ' ) ;
2001-11-21 12:20:05 +03:00
2002-01-09 22:16:48 +03:00
if ( slash = = 0 )
strcpy ( temp_dir , " . " ) ;
2002-04-24 22:20:51 +04:00
else if ( slash - tc - > path_edit < PATH_MAX ) {
2002-12-20 02:25:55 +03:00
strncpy ( temp_dir , tc - > path_edit ,
( size_t ) ( slash - tc - > path_edit ) ) ;
2002-04-24 22:20:51 +04:00
temp_dir [ slash - tc - > path_edit ] = ' \0 ' ;
2002-01-10 17:27:47 +03:00
2002-01-09 22:16:48 +03:00
} else {
log_error ( " Text format failed to determine directory. " ) ;
return 0 ;
}
2008-12-07 07:27:56 +03:00
if ( ! create_temp_name ( temp_dir , temp_file , sizeof ( temp_file ) , & fd ,
& vg - > cmd - > rand_seed ) ) {
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't create temporary text file name. " ) ;
2002-02-25 01:31:55 +03:00
return 0 ;
}
2002-01-09 22:16:48 +03:00
if ( ! ( fp = fdopen ( fd , " w " ) ) ) {
log_sys_error ( " fdopen " , temp_file ) ;
2007-01-25 17:37:48 +03:00
if ( close ( fd ) )
log_sys_error ( " fclose " , temp_file ) ;
2002-01-07 12:05:31 +03:00
return 0 ;
}
2001-11-21 12:20:05 +03:00
2002-11-18 17:04:08 +03:00
log_debug ( " Writing %s metadata to %s " , vg - > name , temp_file ) ;
if ( ! text_vg_export_file ( vg , tc - > desc , fp ) ) {
2002-01-09 22:16:48 +03:00
log_error ( " Failed to write metadata to %s. " , temp_file ) ;
2007-01-25 17:37:48 +03:00
if ( fclose ( fp ) )
log_sys_error ( " fclose " , temp_file ) ;
2002-01-09 16:07:03 +03:00
return 0 ;
}
2005-09-01 22:37:22 +04:00
if ( fsync ( fd ) & & ( errno ! = EROFS ) & & ( errno ! = EINVAL ) ) {
2002-04-24 22:20:51 +04:00
log_sys_error ( " fsync " , tc - > path_edit ) ;
2007-01-25 17:37:48 +03:00
if ( fclose ( fp ) )
log_sys_error ( " fclose " , tc - > path_edit ) ;
2002-04-24 22:20:51 +04:00
return 0 ;
}
2007-07-24 21:48:08 +04:00
if ( lvm_fclose ( fp , tc - > path_edit ) )
return_0 ;
2002-04-24 22:20:51 +04:00
if ( rename ( temp_file , tc - > path_edit ) ) {
2002-11-18 17:04:08 +03:00
log_debug ( " Renaming %s to %s " , temp_file , tc - > path_edit ) ;
2002-04-24 22:20:51 +04:00
log_error ( " %s: rename to %s failed: %s " , temp_file ,
tc - > path_edit , strerror ( errno ) ) ;
return 0 ;
}
return 1 ;
}
2007-08-22 18:38:18 +04:00
static int _vg_commit_file_backup ( struct format_instance * fid __attribute ( ( unused ) ) ,
2002-11-18 17:04:08 +03:00
struct volume_group * vg ,
struct metadata_area * mda )
2002-04-24 22:20:51 +04:00
{
2002-11-18 17:04:08 +03:00
struct text_context * tc = ( struct text_context * ) mda - > metadata_locn ;
if ( test_mode ( ) ) {
log_verbose ( " Test mode: Skipping committing %s metadata (%u) " ,
vg - > name , vg - > seqno ) ;
if ( unlink ( tc - > path_edit ) ) {
log_debug ( " Unlinking %s " , tc - > path_edit ) ;
log_sys_error ( " unlink " , tc - > path_edit ) ;
return 0 ;
}
} else {
log_debug ( " Committing %s metadata (%u) " , vg - > name , vg - > seqno ) ;
log_debug ( " Renaming %s to %s " , tc - > path_edit , tc - > path_live ) ;
if ( rename ( tc - > path_edit , tc - > path_live ) ) {
log_error ( " %s: rename to %s failed: %s " , tc - > path_edit ,
2002-12-06 01:56:22 +03:00
tc - > path_live , strerror ( errno ) ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
}
2002-12-06 01:56:22 +03:00
sync_dir ( tc - > path_edit ) ;
2002-04-24 22:20:51 +04:00
return 1 ;
}
2002-11-18 17:04:08 +03:00
static int _vg_commit_file ( struct format_instance * fid , struct volume_group * vg ,
struct metadata_area * mda )
2002-04-24 22:20:51 +04:00
{
2002-11-18 17:04:08 +03:00
struct text_context * tc = ( struct text_context * ) mda - > metadata_locn ;
char * slash ;
2007-08-06 18:57:48 +04:00
char new_name [ PATH_MAX ] ;
2002-12-20 02:25:55 +03:00
size_t len ;
2002-04-24 22:20:51 +04:00
2002-11-18 17:04:08 +03:00
if ( ! _vg_commit_file_backup ( fid , vg , mda ) )
2002-01-07 12:05:31 +03:00
return 0 ;
2001-11-21 12:20:05 +03:00
2002-11-18 17:04:08 +03:00
/* vgrename? */
2007-07-02 15:17:21 +04:00
if ( ( slash = strrchr ( tc - > path_live , ' / ' ) ) )
2002-11-18 17:04:08 +03:00
slash = slash + 1 ;
else
slash = tc - > path_live ;
if ( strcmp ( slash , vg - > name ) ) {
len = slash - tc - > path_live ;
2007-08-06 18:57:48 +04:00
strncpy ( new_name , tc - > path_live , len ) ;
strcpy ( new_name + len , vg - > name ) ;
log_debug ( " Renaming %s to %s " , tc - > path_live , new_name ) ;
2002-11-18 17:04:08 +03:00
if ( test_mode ( ) )
log_verbose ( " Test mode: Skipping rename " ) ;
else {
2007-08-06 18:57:48 +04:00
if ( rename ( tc - > path_live , new_name ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " %s: rename to %s failed: %s " ,
2007-08-06 18:57:48 +04:00
tc - > path_live , new_name ,
2002-11-18 17:04:08 +03:00
strerror ( errno ) ) ;
2007-08-06 18:57:48 +04:00
sync_dir ( new_name ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
}
}
2002-04-24 22:20:51 +04:00
return 1 ;
}
2007-08-22 18:38:18 +04:00
static int _vg_remove_file ( struct format_instance * fid __attribute ( ( unused ) ) ,
struct volume_group * vg __attribute ( ( unused ) ) ,
2002-11-18 17:04:08 +03:00
struct metadata_area * mda )
2002-04-24 22:20:51 +04:00
{
2002-11-18 17:04:08 +03:00
struct text_context * tc = ( struct text_context * ) mda - > metadata_locn ;
2002-04-24 22:20:51 +04:00
if ( path_exists ( tc - > path_edit ) & & unlink ( tc - > path_edit ) ) {
log_sys_error ( " unlink " , tc - > path_edit ) ;
2002-01-09 22:16:48 +03:00
return 0 ;
}
2002-04-24 22:20:51 +04:00
if ( path_exists ( tc - > path_live ) & & unlink ( tc - > path_live ) ) {
log_sys_error ( " unlink " , tc - > path_live ) ;
return 0 ;
}
2002-12-06 01:56:22 +03:00
sync_dir ( tc - > path_live ) ;
2002-04-24 22:20:51 +04:00
2002-01-07 12:05:31 +03:00
return 1 ;
2001-11-21 12:20:05 +03:00
}
2002-12-20 02:25:55 +03:00
static int _scan_file ( const struct format_type * fmt )
2002-04-24 22:20:51 +04:00
{
struct dirent * dirent ;
struct dir_list * dl ;
2008-11-04 01:14:30 +03:00
struct dm_list * dir_list ;
2002-04-24 22:20:51 +04:00
char * tmp ;
DIR * d ;
2002-11-18 17:04:08 +03:00
struct volume_group * vg ;
struct format_instance * fid ;
char path [ PATH_MAX ] ;
char * vgname ;
2002-04-24 22:20:51 +04:00
2002-11-18 17:04:08 +03:00
dir_list = & ( ( struct mda_lists * ) fmt - > private ) - > dirs ;
2002-04-24 22:20:51 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( dl , dir_list ) {
2002-04-24 22:20:51 +04:00
if ( ! ( d = opendir ( dl - > dir ) ) ) {
log_sys_error ( " opendir " , dl - > dir ) ;
continue ;
}
while ( ( dirent = readdir ( d ) ) )
if ( strcmp ( dirent - > d_name , " . " ) & &
strcmp ( dirent - > d_name , " .. " ) & &
( ! ( tmp = strstr ( dirent - > d_name , " .tmp " ) ) | |
tmp ! = dirent - > d_name + strlen ( dirent - > d_name )
2002-11-18 17:04:08 +03:00
- 4 ) ) {
vgname = dirent - > d_name ;
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( path , PATH_MAX , " %s/%s " ,
2002-11-18 17:04:08 +03:00
dl - > dir , vgname ) < 0 ) {
log_error ( " Name too long %s/%s " ,
dl - > dir , vgname ) ;
break ;
}
/* FIXME stat file to see if it's changed */
2006-04-19 19:33:07 +04:00
fid = _text_create_text_instance ( fmt , NULL , NULL ,
2006-04-13 01:23:04 +04:00
NULL ) ;
2002-11-18 17:04:08 +03:00
if ( ( vg = _vg_read_file_name ( fid , vgname ,
path ) ) )
2006-04-13 21:32:24 +04:00
/* FIXME Store creation host in vg */
2008-03-17 19:51:31 +03:00
lvmcache_update_vg ( vg , 0 ) ;
2002-11-18 17:04:08 +03:00
}
2002-04-24 22:20:51 +04:00
if ( closedir ( d ) )
log_sys_error ( " closedir " , dl - > dir ) ;
2002-02-22 14:44:56 +03:00
}
2002-11-18 17:04:08 +03:00
return 1 ;
2002-02-22 14:44:56 +03:00
}
2006-04-11 17:55:59 +04:00
const char * vgname_from_mda ( const struct format_type * fmt ,
2006-04-11 21:42:15 +04:00
struct device_area * dev_area , struct id * vgid ,
2009-11-25 01:55:55 +03:00
uint64_t * vgstatus , char * * creation_host ,
2007-11-05 20:17:55 +03:00
uint64_t * mda_free_sectors )
2002-02-22 14:44:56 +03:00
{
2002-11-18 17:04:08 +03:00
struct raw_locn * rlocn ;
struct mda_header * mdah ;
2006-04-11 17:55:59 +04:00
uint32_t wrap = 0 ;
const char * vgname = NULL ;
2006-04-12 21:54:11 +04:00
unsigned int len = 0 ;
2006-12-01 02:11:42 +03:00
char buf [ NAME_LEN + 1 ] __attribute ( ( aligned ( 8 ) ) ) ;
char uuid [ 64 ] __attribute ( ( aligned ( 8 ) ) ) ;
2007-11-05 20:17:55 +03:00
uint64_t buffer_size , current_usage ;
if ( mda_free_sectors )
* mda_free_sectors = ( ( dev_area - > size - MDA_HEADER_SIZE ) / 2 ) > > SECTOR_SHIFT ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! dev_open ( dev_area - > dev ) )
return_NULL ;
2002-02-22 14:44:56 +03:00
2006-04-11 17:55:59 +04:00
if ( ! ( mdah = _raw_read_mda_header ( fmt , dev_area ) ) )
goto_out ;
2002-02-25 01:31:55 +03:00
2006-04-11 17:55:59 +04:00
/* FIXME Cope with returning a list */
2002-11-18 17:04:08 +03:00
rlocn = mdah - > raw_locns ;
2009-03-03 19:35:32 +03:00
/*
* If no valid offset , do not try to search for vgname
*/
if ( ! rlocn - > offset )
goto out ;
2006-04-12 21:54:11 +04:00
/* Do quick check for a vgname */
if ( ! dev_read ( dev_area - > dev , dev_area - > start + rlocn - > offset ,
NAME_LEN , buf ) )
goto_out ;
while ( buf [ len ] & & ! isspace ( buf [ len ] ) & & buf [ len ] ! = ' { ' & &
len < ( NAME_LEN - 1 ) )
len + + ;
buf [ len ] = ' \0 ' ;
/* Ignore this entry if the characters aren't permissible */
if ( ! validate_name ( buf ) )
goto_out ;
/* We found a VG - now check the metadata */
2006-04-11 17:55:59 +04:00
if ( rlocn - > offset + rlocn - > size > mdah - > size )
wrap = ( uint32_t ) ( ( rlocn - > offset + rlocn - > size ) - mdah - > size ) ;
2002-11-18 17:04:08 +03:00
2006-04-11 17:55:59 +04:00
if ( wrap > rlocn - > offset ) {
log_error ( " %s: metadata too large for circular buffer " ,
dev_name ( dev_area - > dev ) ) ;
goto out ;
}
2002-11-18 17:04:08 +03:00
2006-04-11 17:55:59 +04:00
/* FIXME 64-bit */
if ( ! ( vgname = text_vgname_import ( fmt , dev_area - > dev ,
( off_t ) ( dev_area - > start +
rlocn - > offset ) ,
( uint32_t ) ( rlocn - > size - wrap ) ,
( off_t ) ( dev_area - > start +
MDA_HEADER_SIZE ) ,
wrap , calc_crc , rlocn - > checksum ,
2006-04-13 21:32:24 +04:00
vgid , vgstatus , creation_host ) ) )
2006-04-11 17:55:59 +04:00
goto_out ;
/* Ignore this entry if the characters aren't permissible */
if ( ! validate_name ( vgname ) ) {
vgname = NULL ;
2008-01-30 16:19:47 +03:00
goto_out ;
2002-02-22 14:44:56 +03:00
}
2006-04-21 19:37:08 +04:00
if ( ! id_write_format ( vgid , uuid , sizeof ( uuid ) ) ) {
vgname = NULL ;
2008-01-30 16:19:47 +03:00
goto_out ;
2006-04-21 19:37:08 +04:00
}
2006-04-11 17:55:59 +04:00
log_debug ( " %s: Found metadata at % " PRIu64 " size % " PRIu64
2007-11-05 20:17:55 +03:00
" (in area at % " PRIu64 " size % " PRIu64
2008-01-30 17:00:02 +03:00
" ) for %s (%s) " ,
2006-04-11 17:55:59 +04:00
dev_name ( dev_area - > dev ) , dev_area - > start + rlocn - > offset ,
2007-11-05 20:17:55 +03:00
rlocn - > size , dev_area - > start , dev_area - > size , vgname , uuid ) ;
if ( mda_free_sectors ) {
current_usage = ( rlocn - > size + SECTOR_SIZE - UINT64_C ( 1 ) ) -
( rlocn - > size + SECTOR_SIZE - UINT64_C ( 1 ) ) % SECTOR_SIZE ;
buffer_size = mdah - > size - MDA_HEADER_SIZE ;
if ( current_usage * 2 > = buffer_size )
* mda_free_sectors = UINT64_C ( 0 ) ;
else
* mda_free_sectors = ( ( buffer_size - 2 * current_usage ) / 2 ) > > SECTOR_SHIFT ;
}
2006-04-11 17:55:59 +04:00
2002-11-18 17:04:08 +03:00
out :
2003-07-05 02:34:56 +04:00
if ( ! dev_close ( dev_area - > dev ) )
2002-11-18 17:04:08 +03:00
stack ;
2006-04-11 17:55:59 +04:00
return vgname ;
2002-02-22 14:44:56 +03:00
}
2002-12-20 02:25:55 +03:00
static int _scan_raw ( const struct format_type * fmt )
2002-02-22 14:44:56 +03:00
{
2002-11-18 17:04:08 +03:00
struct raw_list * rl ;
2008-11-04 01:14:30 +03:00
struct dm_list * raw_list ;
2006-04-11 17:55:59 +04:00
const char * vgname ;
2002-11-18 17:04:08 +03:00
struct volume_group * vg ;
struct format_instance fid ;
2006-04-11 17:55:59 +04:00
struct id vgid ;
2009-11-25 01:55:55 +03:00
uint64_t vgstatus ;
2002-11-18 17:04:08 +03:00
raw_list = & ( ( struct mda_lists * ) fmt - > private ) - > raws ;
fid . fmt = fmt ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & fid . metadata_areas ) ;
2002-11-18 17:04:08 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( rl , raw_list ) {
2002-11-18 17:04:08 +03:00
/* FIXME We're reading mdah twice here... */
2006-04-13 21:32:24 +04:00
if ( ( vgname = vgname_from_mda ( fmt , & rl - > dev_area , & vgid , & vgstatus ,
2007-11-05 20:17:55 +03:00
NULL , NULL ) ) ) {
2006-04-11 17:55:59 +04:00
if ( ( vg = _vg_read_raw_area ( & fid , vgname ,
2005-04-06 22:59:55 +04:00
& rl - > dev_area , 0 ) ) )
2008-03-17 19:51:31 +03:00
lvmcache_update_vg ( vg , 0 ) ;
2002-11-18 17:04:08 +03:00
}
}
2002-04-24 22:20:51 +04:00
return 1 ;
2002-11-18 17:04:08 +03:00
}
2006-04-19 19:33:07 +04:00
static int _text_scan ( const struct format_type * fmt )
2002-11-18 17:04:08 +03:00
{
return ( _scan_file ( fmt ) & _scan_raw ( fmt ) ) ;
}
/* For orphan, creates new mdas according to policy.
2006-08-17 23:30:59 +04:00
Always have an mda between end - of - label and pe_align ( ) boundary */
2002-12-20 02:25:55 +03:00
static int _mda_setup ( const struct format_type * fmt ,
2002-11-18 17:04:08 +03:00
uint64_t pe_start , uint64_t pe_end ,
int pvmetadatacopies ,
2008-11-04 01:14:30 +03:00
uint64_t pvmetadatasize , struct dm_list * mdas ,
2007-08-22 18:38:18 +04:00
struct physical_volume * pv ,
struct volume_group * vg __attribute ( ( unused ) ) )
2002-11-18 17:04:08 +03:00
{
2009-07-30 21:45:28 +04:00
uint64_t mda_adjustment , disk_size , alignment , alignment_offset ;
2002-11-18 17:04:08 +03:00
uint64_t start1 , mda_size1 ; /* First area - start of disk */
uint64_t start2 , mda_size2 ; /* Second area - end of disk */
uint64_t wipe_size = 8 < < SECTOR_SHIFT ;
2006-08-17 22:23:44 +04:00
size_t pagesize = lvm_getpagesize ( ) ;
2002-11-18 17:04:08 +03:00
2006-10-06 02:02:52 +04:00
if ( ! pvmetadatacopies )
2002-11-18 17:04:08 +03:00
return 1 ;
2009-02-22 22:00:26 +03:00
alignment = pv - > pe_align < < SECTOR_SHIFT ;
2009-07-30 21:45:28 +04:00
alignment_offset = pv - > pe_align_offset < < SECTOR_SHIFT ;
2002-11-18 17:04:08 +03:00
disk_size = pv - > size < < SECTOR_SHIFT ;
pe_start < < = SECTOR_SHIFT ;
pe_end < < = SECTOR_SHIFT ;
if ( pe_end > disk_size ) {
log_error ( " Physical extents end beyond end of device %s! " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
/* Requested metadatasize */
mda_size1 = pvmetadatasize < < SECTOR_SHIFT ;
/* Place mda straight after label area at start of disk */
start1 = LABEL_SCAN_SIZE ;
2005-06-01 20:51:55 +04:00
/* Unless the space available is tiny, round to PAGE_SIZE boundary */
if ( ( ! pe_start & & ! pe_end ) | |
( ( pe_start > start1 ) & & ( pe_start - start1 > = MDA_SIZE_MIN ) ) ) {
mda_adjustment = start1 % pagesize ;
2006-10-06 02:02:52 +04:00
if ( mda_adjustment )
2005-06-01 20:51:55 +04:00
start1 + = ( pagesize - mda_adjustment ) ;
}
2009-07-30 21:19:31 +04:00
/* Round up to pe_align boundary */
mda_adjustment = ( mda_size1 + start1 ) % alignment ;
if ( mda_adjustment ) {
mda_size1 + = ( alignment - mda_adjustment ) ;
/* Revert if it's now too large */
if ( start1 + mda_size1 > disk_size )
mda_size1 - = ( alignment - mda_adjustment ) ;
}
2009-07-30 21:45:28 +04:00
/* Add pe_align_offset if on pe_align boundary */
if ( alignment_offset & &
( ( ( start1 + mda_size1 ) % alignment ) = = 0 ) ) {
mda_size1 + = alignment_offset ;
/* Revert if it's now too large */
if ( start1 + mda_size1 > disk_size )
mda_size1 - = alignment_offset ;
}
2003-10-16 00:06:37 +04:00
/* Ensure it's not going to be bigger than the disk! */
2005-06-01 20:51:55 +04:00
if ( start1 + mda_size1 > disk_size ) {
2007-06-28 21:33:44 +04:00
log_warn ( " WARNING: metadata area fills disk leaving no "
2007-10-12 18:29:32 +04:00
" space for data on %s. " , pv_dev_name ( pv ) ) ;
2003-10-16 00:06:37 +04:00
/* Leave some free space for rounding */
/* Avoid empty data area as could cause tools problems */
mda_size1 = disk_size - start1 - alignment * 2 ;
2009-07-30 21:19:31 +04:00
if ( start1 + mda_size1 > disk_size ) {
log_error ( " Insufficient space for first mda on %s " ,
pv_dev_name ( pv ) ) ;
return 0 ;
}
/* Round up to pe_align boundary */
mda_adjustment = ( mda_size1 + start1 ) % alignment ;
if ( mda_adjustment )
mda_size1 + = ( alignment - mda_adjustment ) ;
2003-10-16 00:06:37 +04:00
/* Only have 1 mda in this case */
pvmetadatacopies = 1 ;
}
2002-11-18 17:04:08 +03:00
/* If we already have PEs, avoid overlap */
if ( pe_start | | pe_end ) {
if ( pe_start < = start1 )
mda_size1 = 0 ;
else if ( start1 + mda_size1 > pe_start )
mda_size1 = pe_start - start1 ;
}
/* FIXME If creating new mdas, wipe them! */
if ( mda_size1 ) {
if ( ! add_mda ( fmt , fmt - > cmd - > mem , mdas , pv - > dev , start1 ,
2006-10-06 02:02:52 +04:00
mda_size1 ) )
return 0 ;
2002-11-18 17:04:08 +03:00
2006-05-11 22:39:24 +04:00
if ( ! dev_set ( ( struct device * ) pv - > dev , start1 ,
( size_t ) ( mda_size1 >
wipe_size ? : mda_size1 ) , 0 ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Failed to wipe new metadata area " ) ;
return 0 ;
}
if ( pvmetadatacopies = = 1 )
return 1 ;
} else
start1 = 0 ;
/* A second copy at end of disk */
mda_size2 = pvmetadatasize < < SECTOR_SHIFT ;
/* Ensure it's not going to be bigger than the disk! */
if ( mda_size2 > disk_size )
mda_size2 = disk_size - start1 - mda_size1 ;
mda_adjustment = ( disk_size - mda_size2 ) % alignment ;
if ( mda_adjustment )
mda_size2 + = mda_adjustment ;
start2 = disk_size - mda_size2 ;
/* If we already have PEs, avoid overlap */
if ( pe_start | | pe_end ) {
if ( start2 < pe_end ) {
mda_size2 - = ( pe_end - start2 ) ;
start2 = pe_end ;
}
}
/* If we already have a first mda, avoid overlap */
if ( mda_size1 ) {
if ( start2 < start1 + mda_size1 ) {
mda_size2 - = ( start1 + mda_size1 - start2 ) ;
start2 = start1 + mda_size1 ;
}
/* No room for any PEs here now! */
}
if ( mda_size2 ) {
if ( ! add_mda ( fmt , fmt - > cmd - > mem , mdas , pv - > dev , start2 ,
2004-05-05 01:25:57 +04:00
mda_size2 ) ) return 0 ;
2006-05-11 22:39:24 +04:00
if ( ! dev_set ( pv - > dev , start2 ,
( size_t ) ( mda_size1 >
wipe_size ? : mda_size1 ) , 0 ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Failed to wipe new metadata area " ) ;
return 0 ;
}
} else
return 0 ;
return 1 ;
}
/* Only for orphans */
/* Set label_sector to -1 if rewriting existing label into same sector */
2009-02-22 22:00:26 +03:00
/* If mdas is supplied it overwrites existing mdas e.g. used with pvcreate */
2006-04-19 19:33:07 +04:00
static int _text_pv_write ( const struct format_type * fmt , struct physical_volume * pv ,
2008-11-04 01:14:30 +03:00
struct dm_list * mdas , int64_t label_sector )
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 mda_context * mdac ;
struct metadata_area * mda ;
2006-12-01 02:11:42 +03:00
char buf [ MDA_HEADER_SIZE ] __attribute ( ( aligned ( 8 ) ) ) ;
2002-11-18 17:04:08 +03:00
struct mda_header * mdah = ( struct mda_header * ) buf ;
uint64_t adjustment ;
2009-07-31 01:15:17 +04:00
struct data_area_list * da ;
2002-11-18 17:04:08 +03:00
2002-12-20 02:25:55 +03:00
/* FIXME Test mode don't update cache? */
2003-07-05 02:34:56 +04:00
if ( ! ( info = lvmcache_add ( fmt - > labeller , ( char * ) & pv - > id , pv - > dev ,
2008-02-06 18:47:28 +03:00
FMT_TEXT_ORPHAN_VG_NAME , NULL , 0 ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2002-11-18 17:04:08 +03:00
label = info - > label ;
if ( label_sector ! = - 1 )
label - > sector = label_sector ;
info - > device_size = pv - > size < < SECTOR_SHIFT ;
info - > fmt = fmt ;
/* If mdas supplied, use them regardless of existing ones, */
/* otherwise retain existing ones */
if ( mdas ) {
if ( info - > mdas . n )
del_mdas ( & info - > mdas ) ;
else
2008-11-04 01:14:30 +03:00
dm_list_init ( & info - > mdas ) ;
dm_list_iterate_items ( mda , mdas ) {
2002-11-18 17:04:08 +03:00
mdac = mda - > metadata_locn ;
log_debug ( " Creating metadata area on %s at sector % "
PRIu64 " size % " PRIu64 " sectors " ,
dev_name ( mdac - > area . dev ) ,
mdac - > area . start > > SECTOR_SHIFT ,
mdac - > area . size > > SECTOR_SHIFT ) ;
add_mda ( fmt , NULL , & info - > mdas , mdac - > area . dev ,
mdac - > area . start , mdac - > area . size ) ;
}
/* FIXME Temporary until mda creation supported by tools */
} else if ( ! info - > mdas . n ) {
2008-11-04 01:14:30 +03:00
dm_list_init ( & info - > mdas ) ;
2002-11-18 17:04:08 +03:00
}
2009-07-31 01:15:17 +04:00
/*
* If no pe_start supplied but PV already exists ,
* get existing value ; use - cases include :
* - pvcreate on PV without prior pvremove
* - vgremove on VG with PV ( s ) that have pe_start = 0 ( hacked cfg )
*/
if ( info - > das . n ) {
if ( ! pv - > pe_start )
dm_list_iterate_items ( da , & info - > das )
pv - > pe_start = da - > disk_locn . offset > > SECTOR_SHIFT ;
2002-11-18 17:04:08 +03:00
del_das ( & info - > das ) ;
2009-07-31 01:15:17 +04:00
} else
2008-11-04 01:14:30 +03:00
dm_list_init ( & info - > das ) ;
2002-11-18 17:04:08 +03:00
2009-07-31 01:15:17 +04:00
#if 0
/*
* FIXME : ideally a pre - existing pe_start seen in . pv_write
* would always be preserved BUT ' pvcreate on PV without prior pvremove '
* could easily cause the pe_start to overlap with the first mda !
*/
2009-07-30 21:42:33 +04:00
if ( pv - > pe_start ) {
log_very_verbose ( " %s: preserving pe_start=%lu " ,
pv_dev_name ( pv ) , pv - > pe_start ) ;
goto preserve_pe_start ;
}
2009-07-31 01:15:17 +04:00
# endif
2009-07-30 21:42:33 +04:00
2009-02-22 22:00:26 +03:00
/*
* If pe_start is still unset , set it to first aligned
* sector after any metadata areas that begin before pe_start .
*/
2009-07-31 01:15:17 +04:00
if ( ! pv - > pe_start ) {
pv - > pe_start = pv - > pe_align ;
if ( pv - > pe_align_offset )
pv - > pe_start + = pv - > pe_align_offset ;
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( mda , & info - > mdas ) {
2002-11-18 17:04:08 +03:00
mdac = ( struct mda_context * ) mda - > metadata_locn ;
if ( pv - > dev = = mdac - > area . dev & &
2009-05-07 16:11:50 +04:00
( ( mdac - > area . start < = ( pv - > pe_start < < SECTOR_SHIFT ) ) | |
( mdac - > area . start < = lvm_getpagesize ( ) & &
pv - > pe_start < ( lvm_getpagesize ( ) > > SECTOR_SHIFT ) ) ) & &
2002-11-18 17:04:08 +03:00
( mdac - > area . start + mdac - > area . size >
( pv - > pe_start < < SECTOR_SHIFT ) ) ) {
pv - > pe_start = ( mdac - > area . start + mdac - > area . size )
> > SECTOR_SHIFT ;
2009-07-30 21:45:28 +04:00
/* Adjust pe_start to: (N * pe_align) + pe_align_offset */
2009-07-31 01:15:17 +04:00
if ( pv - > pe_align ) {
adjustment =
2009-07-30 21:45:28 +04:00
( pv - > pe_start - pv - > pe_align_offset ) % pv - > pe_align ;
2009-07-31 01:15:17 +04:00
if ( adjustment )
pv - > pe_start + = pv - > pe_align - adjustment ;
2009-07-31 18:23:06 +04:00
log_very_verbose ( " %s: setting pe_start=% " PRIu64
" (orig_pe_start=% " PRIu64 " , "
2009-07-30 21:45:28 +04:00
" pe_align=%lu, pe_align_offset=%lu, "
" adjustment=% " PRIu64 " ) " ,
pv_dev_name ( pv ) , pv - > pe_start ,
( adjustment ?
pv - > pe_start - = pv - > pe_align - adjustment :
pv - > pe_start ) ,
pv - > pe_align , pv - > pe_align_offset , adjustment ) ;
2009-07-31 01:15:17 +04:00
}
2002-11-18 17:04:08 +03:00
}
}
2009-07-30 21:45:28 +04:00
if ( pv - > pe_start > = pv - > size ) {
log_error ( " Data area is beyond end of device %s! " ,
pv_dev_name ( pv ) ) ;
return 0 ;
}
2009-07-30 21:42:33 +04:00
2009-07-31 01:15:17 +04:00
/* FIXME: preserve_pe_start: */
2002-12-20 02:25:55 +03:00
if ( ! add_da
2008-01-30 16:19:47 +03:00
( NULL , & info - > das , pv - > pe_start < < SECTOR_SHIFT , UINT64_C ( 0 ) ) )
return_0 ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! dev_open ( pv - > dev ) )
return_0 ;
2002-11-18 17:04:08 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( mda , & info - > mdas ) {
2002-11-18 17:04:08 +03:00
mdac = mda - > metadata_locn ;
memset ( & buf , 0 , sizeof ( buf ) ) ;
mdah - > size = mdac - > area . size ;
if ( ! _raw_write_mda_header ( fmt , mdac - > area . dev ,
mdac - > area . start , mdah ) ) {
if ( ! dev_close ( pv - > dev ) )
stack ;
2008-01-30 16:19:47 +03:00
return_0 ;
2002-11-18 17:04:08 +03:00
}
}
2008-07-17 01:32:38 +04:00
if ( ! label_write ( pv - > dev , label ) ) {
dev_close ( pv - > dev ) ;
return_0 ;
}
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! dev_close ( pv - > dev ) )
return_0 ;
2002-11-18 17:04:08 +03:00
return 1 ;
}
2008-11-04 01:14:30 +03:00
static int _add_raw ( struct dm_list * raw_list , struct device_area * dev_area )
2002-02-22 14:44:56 +03:00
{
2002-11-18 17:04:08 +03:00
struct raw_list * rl ;
/* Already present? */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( rl , raw_list ) {
2002-11-18 17:04:08 +03:00
/* FIXME Check size/overlap consistency too */
if ( rl - > dev_area . dev = = dev_area - > dev & &
2005-06-01 20:51:55 +04:00
rl - > dev_area . start = = dev_area - > start )
return 1 ;
2002-11-18 17:04:08 +03:00
}
2002-04-24 22:20:51 +04:00
2005-10-17 03:03:59 +04:00
if ( ! ( rl = dm_malloc ( sizeof ( struct raw_list ) ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " _add_raw allocation failed " ) ;
return 0 ;
}
memcpy ( & rl - > dev_area , dev_area , sizeof ( * dev_area ) ) ;
2008-11-04 01:14:30 +03:00
dm_list_add ( raw_list , & rl - > list ) ;
2002-11-18 17:04:08 +03:00
return 1 ;
}
2008-07-31 14:50:18 +04:00
static int _get_pv_if_in_vg ( struct lvmcache_info * info ,
struct physical_volume * pv )
2002-11-18 17:04:08 +03:00
{
2008-07-31 14:50:18 +04:00
if ( info - > vginfo & & info - > vginfo - > vgname & &
! is_orphan_vg ( info - > vginfo - > vgname ) & &
get_pv_from_vg_by_id ( info - > fmt , info - > vginfo - > vgname ,
info - > vginfo - > vgid , info - > dev - > pvid , pv ) )
return 1 ;
2002-11-18 17:04:08 +03:00
2008-07-31 14:50:18 +04:00
return 0 ;
}
2002-04-24 22:20:51 +04:00
2008-07-31 14:50:18 +04:00
static int _populate_pv_fields ( struct lvmcache_info * info ,
2009-02-26 02:29:06 +03:00
struct physical_volume * pv ,
int scan_label_only )
2008-07-31 14:50:18 +04:00
{
struct data_area_list * da ;
2002-11-18 17:04:08 +03:00
/* Have we already cached vgname? */
2009-02-26 02:29:06 +03:00
if ( ! scan_label_only & & _get_pv_if_in_vg ( info , pv ) )
2002-11-18 17:04:08 +03:00
return 1 ;
2005-03-22 01:40:35 +03:00
/* Perform full scan (just the first time) and try again */
2009-02-26 02:29:06 +03:00
if ( ! scan_label_only & & ! memlock ( ) & & ! full_scan_done ( ) ) {
2008-07-31 14:50:18 +04:00
lvmcache_label_scan ( info - > fmt - > cmd , 2 ) ;
2002-11-18 17:04:08 +03:00
2008-07-31 14:50:18 +04:00
if ( _get_pv_if_in_vg ( info , pv ) )
2003-07-05 02:34:56 +04:00
return 1 ;
2002-11-18 17:04:08 +03:00
}
/* Orphan */
pv - > dev = info - > dev ;
pv - > fmt = info - > fmt ;
pv - > size = info - > device_size > > SECTOR_SHIFT ;
2008-02-06 18:47:28 +03:00
pv - > vg_name = FMT_TEXT_ORPHAN_VG_NAME ;
2002-11-18 17:04:08 +03:00
memcpy ( & pv - > id , & info - > dev - > pvid , sizeof ( pv - > id ) ) ;
/* Currently only support exactly one data area */
2008-11-04 01:14:30 +03:00
if ( dm_list_size ( & info - > das ) ! = 1 ) {
2002-11-18 17:04:08 +03:00
log_error ( " Must be exactly one data area (found %d) on PV %s " ,
2008-11-04 01:14:30 +03:00
dm_list_size ( & info - > das ) , dev_name ( info - > dev ) ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
2005-06-01 20:51:55 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( da , & info - > das )
2002-11-18 17:04:08 +03:00
pv - > pe_start = da - > disk_locn . offset > > SECTOR_SHIFT ;
2002-02-22 14:44:56 +03:00
2008-07-31 14:50:18 +04:00
return 1 ;
}
2010-02-02 19:26:34 +03:00
/*
* Copy constructor for a metadata_area .
*/
static struct metadata_area * _mda_copy ( struct dm_pool * mem ,
struct metadata_area * mda )
{
struct metadata_area * mda_new ;
struct mda_context * mdac , * mdac_new ;
if ( ! ( mda_new = dm_pool_alloc ( mem , sizeof ( * mda_new ) ) ) ) {
log_error ( " metadata_area allocation failed " ) ;
return NULL ;
}
/* FIXME: Should have a per-format constructor here */
mdac = ( struct mda_context * ) mda - > metadata_locn ;
if ( ! ( mdac_new = dm_pool_alloc ( mem , sizeof ( * mdac_new ) ) ) ) {
log_error ( " mda_context allocation failed " ) ;
dm_pool_free ( mem , mda_new ) ;
return NULL ;
}
memcpy ( mda_new , mda , sizeof ( * mda ) ) ;
memcpy ( mdac_new , mdac , sizeof ( * mdac ) ) ;
mda_new - > metadata_locn = mdac_new ;
2010-02-16 02:53:15 +03:00
/* FIXME mda 'list' left invalid here */
2010-02-02 19:26:34 +03:00
return mda_new ;
}
2008-07-31 14:50:18 +04:00
static int _text_pv_read ( const struct format_type * fmt , const char * pv_name ,
2009-02-26 02:29:06 +03:00
struct physical_volume * pv , struct dm_list * mdas ,
int scan_label_only )
2008-07-31 14:50:18 +04:00
{
2010-02-02 19:26:34 +03:00
struct metadata_area * mda , * mda_new ;
2008-07-31 14:50:18 +04:00
struct label * label ;
struct device * dev ;
struct lvmcache_info * info ;
if ( ! ( dev = dev_cache_get ( pv_name , fmt - > cmd - > filter ) ) )
return_0 ;
if ( ! ( label_read ( dev , & label , UINT64_C ( 0 ) ) ) )
return_0 ;
info = ( struct lvmcache_info * ) label - > info ;
2009-02-26 02:29:06 +03:00
if ( ! _populate_pv_fields ( info , pv , scan_label_only ) )
2008-07-31 14:50:18 +04:00
return 0 ;
2002-11-18 17:04:08 +03:00
if ( ! mdas )
return 1 ;
2002-02-25 01:31:55 +03:00
2002-11-18 17:04:08 +03:00
/* Add copy of mdas to supplied list */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( mda , & info - > mdas ) {
2010-02-02 19:26:34 +03:00
mda_new = _mda_copy ( fmt - > cmd - > mem , mda ) ;
if ( ! mda_new )
2002-11-18 17:04:08 +03:00
return 0 ;
2008-11-04 01:14:30 +03:00
dm_list_add ( mdas , & mda_new - > list ) ;
2002-02-22 14:44:56 +03:00
}
2002-04-24 22:20:51 +04:00
return 1 ;
2002-02-22 14:44:56 +03:00
}
2006-05-11 21:58:58 +04:00
static void _text_destroy_instance ( struct format_instance * fid __attribute ( ( unused ) ) )
2001-11-21 12:20:05 +03:00
{
2002-04-24 22:20:51 +04:00
}
2008-11-04 01:14:30 +03:00
static void _free_dirs ( struct dm_list * dir_list )
2002-04-24 22:20:51 +04:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * dl , * tmp ;
2002-04-24 22:20:51 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_safe ( dl , tmp , dir_list ) {
dm_list_del ( dl ) ;
2005-10-17 03:03:59 +04:00
dm_free ( dl ) ;
2002-04-24 22:20:51 +04:00
}
}
2008-11-04 01:14:30 +03:00
static void _free_raws ( struct dm_list * raw_list )
2002-11-18 17:04:08 +03:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * rl , * tmp ;
2002-11-18 17:04:08 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_safe ( rl , tmp , raw_list ) {
dm_list_del ( rl ) ;
2005-10-17 03:03:59 +04:00
dm_free ( rl ) ;
2002-11-18 17:04:08 +03:00
}
}
2006-04-19 19:33:07 +04:00
static void _text_destroy ( const struct format_type * fmt )
2002-04-24 22:20:51 +04:00
{
if ( fmt - > private ) {
2002-11-18 17:04:08 +03:00
_free_dirs ( & ( ( struct mda_lists * ) fmt - > private ) - > dirs ) ;
_free_raws ( & ( ( struct mda_lists * ) fmt - > private ) - > raws ) ;
2005-10-17 03:03:59 +04:00
dm_free ( fmt - > private ) ;
2002-04-24 22:20:51 +04:00
}
2006-05-11 21:58:58 +04:00
dm_free ( ( void * ) fmt ) ;
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:04:08 +03:00
static struct metadata_area_ops _metadata_text_file_ops = {
2006-05-10 01:23:51 +04:00
. vg_read = _vg_read_file ,
. vg_read_precommit = _vg_read_precommit_file ,
. vg_write = _vg_write_file ,
. vg_remove = _vg_remove_file ,
. vg_commit = _vg_commit_file
2002-11-18 17:04:08 +03:00
} ;
static struct metadata_area_ops _metadata_text_file_backup_ops = {
2006-05-10 01:23:51 +04:00
. vg_read = _vg_read_file ,
. vg_write = _vg_write_file ,
. vg_remove = _vg_remove_file ,
. vg_commit = _vg_commit_file_backup
2002-11-18 17:04:08 +03:00
} ;
static struct metadata_area_ops _metadata_text_raw_ops = {
2006-05-10 01:23:51 +04:00
. vg_read = _vg_read_raw ,
. vg_read_precommit = _vg_read_precommit_raw ,
. vg_write = _vg_write_raw ,
. vg_remove = _vg_remove_raw ,
. vg_precommit = _vg_precommit_raw ,
. vg_commit = _vg_commit_raw ,
2007-03-23 15:43:17 +03:00
. vg_revert = _vg_revert_raw ,
2007-11-05 20:17:55 +03:00
. mda_free_sectors = _mda_free_sectors_raw ,
2009-01-10 01:44:33 +03:00
. mda_total_sectors = _mda_total_sectors_raw ,
2007-03-23 15:43:17 +03:00
. mda_in_vg = _mda_in_vg_raw ,
2007-04-26 01:10:55 +04:00
. pv_analyze_mda = _pv_analyze_mda_raw ,
2002-11-18 17:04:08 +03:00
} ;
/* pvmetadatasize in sectors */
2009-07-30 21:18:03 +04:00
/*
2009-07-31 01:15:17 +04:00
* pe_start goal : FIXME - - reality of . pv_write complexity undermines this goal
2009-07-30 21:18:03 +04:00
* - In cases where a pre - existing pe_start is provided ( pvcreate - - restorefile
* and vgconvert ) : pe_start must not be changed ( so pv - > pe_start = pe_start ) .
* - In cases where pe_start is 0 : leave pv - > pe_start as 0 and defer the
* setting of pv - > pe_start to . pv_write
*/
2006-04-19 19:33:07 +04:00
static int _text_pv_setup ( const struct format_type * fmt ,
2002-11-18 17:04:08 +03:00
uint64_t pe_start , uint32_t extent_count ,
2009-02-22 22:00:26 +03:00
uint32_t extent_size , unsigned long data_alignment ,
2009-07-30 21:45:28 +04:00
unsigned long data_alignment_offset ,
2002-11-18 17:04:08 +03:00
int pvmetadatacopies ,
2008-11-04 01:14:30 +03:00
uint64_t pvmetadatasize , struct dm_list * mdas ,
2002-11-18 17:04:08 +03:00
struct physical_volume * pv , struct volume_group * vg )
{
struct metadata_area * mda , * mda_new , * mda2 ;
2010-02-02 19:26:34 +03:00
struct mda_context * mdac , * mdac2 ;
2008-11-04 01:14:30 +03:00
struct dm_list * pvmdas ;
2003-07-05 02:34:56 +04:00
struct lvmcache_info * info ;
2002-11-18 17:04:08 +03:00
int found ;
uint64_t pe_end = 0 ;
2006-10-06 02:02:52 +04:00
unsigned mda_count = 0 ;
uint64_t mda_size2 = 0 ;
2006-11-10 21:24:11 +03:00
uint64_t pe_count ;
2002-11-18 17:04:08 +03:00
/* FIXME Cope with pvchange */
2006-04-19 19:33:07 +04:00
/* FIXME Merge code with _text_create_text_instance */
2002-11-18 17:04:08 +03:00
/* If new vg, add any further mdas on this PV to the fid's mda list */
if ( vg ) {
/* Iterate through all mdas on this PV */
2008-01-30 02:45:48 +03:00
if ( ( info = info_from_pvid ( pv - > dev - > pvid , 0 ) ) ) {
2002-11-18 17:04:08 +03:00
pvmdas = & info - > mdas ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( mda , pvmdas ) {
2006-10-06 02:02:52 +04:00
mda_count + + ;
2002-11-18 17:04:08 +03:00
mdac =
( struct mda_context * ) mda - > metadata_locn ;
/* FIXME Check it isn't already in use */
2006-10-06 02:02:52 +04:00
/* Reduce usable device size */
if ( mda_count > 1 )
mda_size2 = mdac - > area . size > > SECTOR_SHIFT ;
2002-11-18 17:04:08 +03:00
/* Ensure it isn't already on list */
found = 0 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( mda2 , mdas ) {
2002-11-18 17:04:08 +03:00
if ( mda2 - > ops ! =
2004-05-05 01:25:57 +04:00
& _metadata_text_raw_ops ) continue ;
2002-11-18 17:04:08 +03:00
mdac2 =
2004-05-05 01:25:57 +04:00
( struct mda_context * )
mda2 - > metadata_locn ;
2002-11-18 17:04:08 +03:00
if ( ! memcmp
( & mdac2 - > area , & mdac - > area ,
sizeof ( mdac - > area ) ) ) {
found = 1 ;
break ;
}
}
if ( found )
continue ;
2010-02-02 19:26:34 +03:00
mda_new = _mda_copy ( fmt - > cmd - > mem , mda ) ;
if ( ! mda_new )
2008-01-30 16:19:47 +03:00
return_0 ;
2008-11-04 01:14:30 +03:00
dm_list_add ( mdas , & mda_new - > list ) ;
2010-02-02 19:26:34 +03:00
/* FIXME multiple dev_areas inside area */
2002-11-18 17:04:08 +03:00
}
}
2006-10-08 03:17:17 +04:00
/* FIXME Cope with genuine pe_count 0 */
/* If missing, estimate pv->size from file-based metadata */
if ( ! pv - > size & & pv - > pe_count )
pv - > size = pv - > pe_count * ( uint64_t ) vg - > extent_size +
pv - > pe_start + mda_size2 ;
2006-10-06 02:02:52 +04:00
/* Recalculate number of extents that will fit */
2006-11-10 21:24:11 +03:00
if ( ! pv - > pe_count ) {
pe_count = ( pv - > size - pv - > pe_start - mda_size2 ) /
vg - > extent_size ;
if ( pe_count > UINT32_MAX ) {
log_error ( " PV %s too large for extent size %s. " ,
2007-10-12 18:29:32 +04:00
pv_dev_name ( pv ) ,
2006-11-10 21:24:11 +03:00
display_size ( vg - > cmd , ( uint64_t ) vg - > extent_size ) ) ;
return 0 ;
}
pv - > pe_count = ( uint32_t ) pe_count ;
}
2006-10-06 02:02:52 +04:00
2002-11-18 17:04:08 +03:00
/* Unlike LVM1, we don't store this outside a VG */
/* FIXME Default from config file? vgextend cmdline flag? */
pv - > status | = ALLOCATABLE_PV ;
} else {
2009-07-30 22:40:22 +04:00
if ( pe_start )
2009-02-22 22:00:26 +03:00
pv - > pe_start = pe_start ;
if ( ! data_alignment )
data_alignment = find_config_tree_int ( pv - > fmt - > cmd ,
" devices/data_alignment " ,
0 ) * 2 ;
if ( set_pe_align ( pv , data_alignment ) ! = data_alignment & &
data_alignment )
log_warn ( " WARNING: %s: Overriding data alignment to "
" %lu sectors (requested %lu sectors) " ,
pv_dev_name ( pv ) , pv - > pe_align , data_alignment ) ;
2009-08-01 21:07:36 +04:00
if ( set_pe_align_offset ( pv , data_alignment_offset ) ! = data_alignment_offset & &
data_alignment_offset )
log_warn ( " WARNING: %s: Overriding data alignment offset to "
" %lu sectors (requested %lu sectors) " ,
pv_dev_name ( pv ) , pv - > pe_align_offset , data_alignment_offset ) ;
2009-07-30 21:45:28 +04:00
if ( pv - > pe_align < pv - > pe_align_offset ) {
log_error ( " %s: pe_align (%lu sectors) must not be less "
" than pe_align_offset (%lu sectors) " ,
pv_dev_name ( pv ) , pv - > pe_align , pv - > pe_align_offset ) ;
return 0 ;
}
2009-07-31 01:15:17 +04:00
/*
* This initialization has a side - effect of allowing
* orphaned PVs to be created with the proper alignment .
* Setting pv - > pe_start here circumvents . pv_write ' s
* " pvcreate on PV without prior pvremove " retreival of
* the PV ' s previous pe_start .
* - Without this you get actual ! = expected pe_start
* failures in the testsuite .
*/
if ( ! pe_start & & pv - > pe_start < pv - > pe_align )
pv - > pe_start = pv - > pe_align ;
2002-11-18 17:04:08 +03:00
if ( extent_count )
pe_end = pe_start + extent_count * extent_size - 1 ;
if ( ! _mda_setup ( fmt , pe_start , pe_end , pvmetadatacopies ,
2008-01-30 16:19:47 +03:00
pvmetadatasize , mdas , pv , vg ) )
return_0 ;
2002-11-18 17:04:08 +03:00
}
return 1 ;
}
/* NULL vgname means use only the supplied context e.g. an archive file */
2006-04-19 19:33:07 +04:00
static struct format_instance * _text_create_text_instance ( const struct format_type
2002-12-20 02:25:55 +03:00
* fmt , const char * vgname ,
2006-04-13 01:23:04 +04:00
const char * vgid ,
2002-04-24 22:20:51 +04:00
void * context )
{
struct format_instance * fid ;
2005-10-23 04:14:48 +04:00
struct text_fid_context * fidtc ;
2002-11-18 17:04:08 +03:00
struct metadata_area * mda , * mda_new ;
2010-02-02 19:26:34 +03:00
struct mda_context * mdac ;
2002-04-24 22:20:51 +04:00
struct dir_list * dl ;
2002-11-18 17:04:08 +03:00
struct raw_list * rl ;
2008-11-04 01:14:30 +03:00
struct dm_list * dir_list , * raw_list , * mdas ;
2002-04-24 22:20:51 +04:00
char path [ PATH_MAX ] ;
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-04-24 22:20:51 +04:00
2005-10-17 03:03:59 +04:00
if ( ! ( fid = dm_pool_alloc ( fmt - > cmd - > mem , sizeof ( * fid ) ) ) ) {
2002-04-24 22:20:51 +04:00
log_error ( " Couldn't allocate format instance object. " ) ;
return NULL ;
}
2005-10-23 04:14:48 +04:00
if ( ! ( fidtc = ( struct text_fid_context * )
dm_pool_zalloc ( fmt - > cmd - > mem , sizeof ( * fidtc ) ) ) ) {
log_error ( " Couldn't allocate text_fid_context. " ) ;
return NULL ;
}
fidtc - > raw_metadata_buf = NULL ;
fid - > private = ( void * ) fidtc ;
2002-04-24 22:20:51 +04:00
2005-10-23 04:14:48 +04:00
fid - > fmt = fmt ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & fid - > metadata_areas ) ;
2002-04-24 22:20:51 +04:00
if ( ! vgname ) {
2008-01-30 16:19:47 +03:00
if ( ! ( mda = dm_pool_alloc ( fmt - > cmd - > mem , sizeof ( * mda ) ) ) )
return_NULL ;
2002-11-18 17:04:08 +03:00
mda - > ops = & _metadata_text_file_backup_ops ;
2002-04-24 22:20:51 +04:00
mda - > metadata_locn = context ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & fid - > metadata_areas , & mda - > list ) ;
2002-04-24 22:20:51 +04:00
} else {
2002-11-18 17:04:08 +03:00
dir_list = & ( ( struct mda_lists * ) fmt - > private ) - > dirs ;
2002-04-24 22:20:51 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( dl , dir_list ) {
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( path , PATH_MAX , " %s/%s " ,
2002-04-24 22:20:51 +04:00
dl - > dir , vgname ) < 0 ) {
log_error ( " Name too long %s/%s " , dl - > dir ,
vgname ) ;
return NULL ;
}
2002-11-18 17:04:08 +03:00
context = create_text_context ( fmt - > cmd , path , NULL ) ;
2008-01-30 16:19:47 +03:00
if ( ! ( mda = dm_pool_alloc ( fmt - > cmd - > mem , sizeof ( * mda ) ) ) )
return_NULL ;
2002-11-18 17:04:08 +03:00
mda - > ops = & _metadata_text_file_ops ;
2002-04-24 22:20:51 +04:00
mda - > metadata_locn = context ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & fid - > metadata_areas , & mda - > list ) ;
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:04:08 +03:00
raw_list = & ( ( struct mda_lists * ) fmt - > private ) - > raws ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( rl , raw_list ) {
2002-11-18 17:04:08 +03:00
/* FIXME Cache this; rescan below if some missing */
if ( ! _raw_holds_vgname ( fid , & rl - > dev_area , vgname ) )
continue ;
2008-01-30 16:19:47 +03:00
if ( ! ( mda = dm_pool_alloc ( fmt - > cmd - > mem , sizeof ( * mda ) ) ) )
return_NULL ;
2002-11-18 17:04:08 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( mdac = dm_pool_alloc ( fmt - > cmd - > mem , sizeof ( * mdac ) ) ) )
return_NULL ;
2002-11-18 17:04:08 +03:00
mda - > metadata_locn = mdac ;
/* FIXME Allow multiple dev_areas inside area */
memcpy ( & mdac - > area , & rl - > dev_area , sizeof ( mdac - > area ) ) ;
mda - > ops = & _metadata_text_raw_ops ;
2002-12-20 02:25:55 +03:00
/* FIXME MISTAKE? mda->metadata_locn = context; */
2008-11-04 01:14:30 +03:00
dm_list_add ( & fid - > metadata_areas , & mda - > list ) ;
2002-11-18 17:04:08 +03:00
}
/* Scan PVs in VG for any further MDAs */
2003-07-05 02:34:56 +04:00
lvmcache_label_scan ( fmt - > cmd , 0 ) ;
2008-01-30 16:19:47 +03:00
if ( ! ( vginfo = vginfo_from_vgname ( vgname , vgid ) ) )
goto_out ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( info , & vginfo - > infos ) {
2005-06-01 20:51:55 +04:00
mdas = & info - > mdas ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( mda , mdas ) {
2002-11-18 17:04:08 +03:00
/* FIXME Check it holds this VG */
2010-02-02 19:26:34 +03:00
mda_new = _mda_copy ( fmt - > cmd - > mem , mda ) ;
if ( ! mda_new )
2008-01-30 16:19:47 +03:00
return_NULL ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & fid - > metadata_areas , & mda_new - > list ) ;
2002-11-18 17:04:08 +03:00
}
}
/* FIXME Check raw metadata area count - rescan if required */
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:04:08 +03:00
out :
2002-04-24 22:20:51 +04:00
return fid ;
}
2002-11-18 17:04:08 +03:00
void * create_text_context ( struct cmd_context * cmd , const char * path ,
2002-04-24 22:20:51 +04:00
const char * desc )
{
struct text_context * tc ;
char * tmp ;
if ( ( tmp = strstr ( path , " .tmp " ) ) & & ( tmp = = path + strlen ( path ) - 4 ) ) {
log_error ( " %s: Volume group filename may not end in .tmp " ,
path ) ;
return NULL ;
}
2008-01-30 16:19:47 +03:00
if ( ! ( tc = dm_pool_alloc ( cmd - > mem , sizeof ( * tc ) ) ) )
return_NULL ;
2002-04-24 22:20:51 +04:00
2008-01-30 16:19:47 +03:00
if ( ! ( tc - > path_live = dm_pool_strdup ( cmd - > mem , path ) ) )
goto_bad ;
if ( ! ( tc - > path_edit = dm_pool_alloc ( cmd - > mem , strlen ( path ) + 5 ) ) )
goto_bad ;
2002-04-24 22:20:51 +04:00
sprintf ( tc - > path_edit , " %s.tmp " , path ) ;
if ( ! desc )
desc = " " ;
2008-01-30 16:19:47 +03:00
if ( ! ( tc - > desc = dm_pool_strdup ( cmd - > mem , desc ) ) )
goto_bad ;
2002-04-24 22:20:51 +04:00
return ( void * ) tc ;
2008-01-30 16:19:47 +03:00
bad :
2005-10-17 03:03:59 +04:00
dm_pool_free ( cmd - > mem , tc ) ;
2002-04-24 22:20:51 +04:00
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't allocate text format context object. " ) ;
2002-04-24 22:20:51 +04:00
return NULL ;
2001-11-21 12:20:05 +03:00
}
static struct format_handler _text_handler = {
2006-05-10 01:23:51 +04:00
. scan = _text_scan ,
. pv_read = _text_pv_read ,
. pv_setup = _text_pv_setup ,
. pv_write = _text_pv_write ,
. vg_setup = _text_vg_setup ,
. lv_setup = _text_lv_setup ,
. create_instance = _text_create_text_instance ,
. destroy_instance = _text_destroy_instance ,
. destroy = _text_destroy
2001-11-21 12:20:05 +03:00
} ;
2008-11-04 01:14:30 +03:00
static int _add_dir ( const char * dir , struct dm_list * dir_list )
2001-11-21 12:20:05 +03:00
{
2002-04-24 22:20:51 +04:00
struct dir_list * dl ;
2001-11-21 12:20:05 +03:00
2007-07-28 16:26:21 +04:00
if ( dm_create_dir ( dir ) ) {
2008-11-04 01:14:30 +03:00
if ( ! ( dl = dm_malloc ( sizeof ( struct dm_list ) + strlen ( dir ) + 1 ) ) ) {
2002-04-24 22:20:51 +04:00
log_error ( " _add_dir allocation failed " ) ;
return 0 ;
}
2002-11-18 17:04:08 +03:00
log_very_verbose ( " Adding text format metadata dir: %s " , dir ) ;
2002-04-24 22:20:51 +04:00
strcpy ( dl - > dir , dir ) ;
2008-11-04 01:14:30 +03:00
dm_list_add ( dir_list , & dl - > list ) ;
2002-04-24 22:20:51 +04:00
return 1 ;
2001-11-21 12:20:05 +03:00
}
2002-04-24 22:20:51 +04:00
return 0 ;
}
2002-02-08 14:13:47 +03:00
2002-11-18 17:04:08 +03:00
static int _get_config_disk_area ( struct cmd_context * cmd ,
2008-11-04 01:14:30 +03:00
struct config_node * cn , struct dm_list * raw_list )
2002-11-18 17:04:08 +03:00
{
struct device_area dev_area ;
char * id_str ;
struct id id ;
if ( ! ( cn = cn - > child ) ) {
log_error ( " Empty metadata disk_area section of config file " ) ;
return 0 ;
}
2004-03-08 21:28:45 +03:00
if ( ! get_config_uint64 ( cn , " start_sector " , & dev_area . start ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Missing start_sector in metadata disk_area section "
" of config file " ) ;
return 0 ;
}
dev_area . start < < = SECTOR_SHIFT ;
2004-03-08 21:28:45 +03:00
if ( ! get_config_uint64 ( cn , " size " , & dev_area . size ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Missing size in metadata disk_area section "
" of config file " ) ;
return 0 ;
}
dev_area . size < < = SECTOR_SHIFT ;
2004-03-08 21:28:45 +03:00
if ( ! get_config_str ( cn , " id " , & id_str ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Missing uuid in metadata disk_area section "
" of config file " ) ;
return 0 ;
}
if ( ! id_read_format ( & id , id_str ) ) {
log_error ( " Invalid uuid in metadata disk_area section "
" of config file: %s " , id_str ) ;
return 0 ;
}
if ( ! ( dev_area . dev = device_from_pvid ( cmd , & id ) ) ) {
2006-12-01 02:11:42 +03:00
char buffer [ 64 ] __attribute ( ( aligned ( 8 ) ) ) ;
2002-11-18 17:04:08 +03:00
if ( ! id_write_format ( & id , buffer , sizeof ( buffer ) ) )
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't find device. " ) ;
2002-11-18 17:04:08 +03:00
else
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't find device with uuid '%s'. " ,
buffer ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
return _add_raw ( raw_list , & dev_area ) ;
}
2002-04-24 22:20:51 +04:00
struct format_type * create_text_format ( struct cmd_context * cmd )
{
struct format_type * fmt ;
struct config_node * cn ;
struct config_value * cv ;
2002-11-18 17:04:08 +03:00
struct mda_lists * mda_lists ;
2002-04-24 22:20:51 +04:00
2008-01-30 16:19:47 +03:00
if ( ! ( fmt = dm_malloc ( sizeof ( * fmt ) ) ) )
return_NULL ;
2001-11-21 12:20:05 +03:00
2002-04-24 22:20:51 +04:00
fmt - > cmd = cmd ;
fmt - > ops = & _text_handler ;
fmt - > name = FMT_TEXT_NAME ;
2002-11-18 17:04:08 +03:00
fmt - > alias = FMT_TEXT_ALIAS ;
2008-02-06 18:47:28 +03:00
fmt - > orphan_vg_name = ORPHAN_VG_NAME ( FMT_TEXT_NAME ) ;
2005-04-06 22:59:55 +04:00
fmt - > features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS | FMT_PRECOMMIT |
2006-04-30 02:08:43 +04:00
FMT_UNLIMITED_VOLS | FMT_RESIZE_PV |
FMT_UNLIMITED_STRIPESIZE ;
2002-04-24 22:20:51 +04:00
2005-10-17 03:03:59 +04:00
if ( ! ( mda_lists = dm_malloc ( sizeof ( struct mda_lists ) ) ) ) {
2002-04-24 22:20:51 +04:00
log_error ( " Failed to allocate dir_list " ) ;
2006-05-10 01:23:51 +04:00
dm_free ( fmt ) ;
2002-04-24 22:20:51 +04:00
return NULL ;
2002-01-15 20:37:23 +03:00
}
2008-11-04 01:14:30 +03:00
dm_list_init ( & mda_lists - > dirs ) ;
dm_list_init ( & mda_lists - > raws ) ;
2002-11-18 17:04:08 +03:00
mda_lists - > file_ops = & _metadata_text_file_ops ;
mda_lists - > raw_ops = & _metadata_text_raw_ops ;
fmt - > private = ( void * ) mda_lists ;
2002-01-15 20:37:23 +03:00
2002-11-18 17:04:08 +03:00
if ( ! ( fmt - > labeller = text_labeller_create ( fmt ) ) ) {
log_error ( " Couldn't create text label handler. " ) ;
2006-05-10 01:23:51 +04:00
dm_free ( fmt ) ;
2002-11-18 17:04:08 +03:00
return NULL ;
2002-04-24 22:20:51 +04:00
}
2001-11-21 12:20:05 +03:00
2002-11-18 17:04:08 +03:00
if ( ! ( label_register_handler ( FMT_TEXT_NAME , fmt - > labeller ) ) ) {
log_error ( " Couldn't register text label handler. " ) ;
2006-05-10 01:23:51 +04:00
dm_free ( fmt ) ;
2002-11-18 17:04:08 +03:00
return NULL ;
}
2006-05-16 20:48:31 +04:00
if ( ( cn = find_config_tree_node ( cmd , " metadata/dirs " ) ) ) {
2002-11-18 17:04:08 +03:00
for ( cv = cn - > v ; cv ; cv = cv - > next ) {
if ( cv - > type ! = CFG_STRING ) {
log_error ( " Invalid string in config file: "
" metadata/dirs " ) ;
goto err ;
}
if ( ! _add_dir ( cv - > v . str , & mda_lists - > dirs ) ) {
2009-03-24 00:13:37 +03:00
log_error ( " Failed to add %s to text format "
" metadata directory list " , cv - > v . str ) ;
2002-11-18 17:04:08 +03:00
goto err ;
}
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:04:08 +03:00
}
2002-02-08 14:13:47 +03:00
2006-05-16 20:48:31 +04:00
if ( ( cn = find_config_tree_node ( cmd , " metadata/disk_areas " ) ) ) {
2004-09-14 21:37:51 +04:00
for ( cn = cn - > child ; cn ; cn = cn - > sib ) {
if ( ! _get_config_disk_area ( cmd , cn , & mda_lists - > raws ) )
goto err ;
}
2002-04-24 22:20:51 +04:00
}
2002-02-08 14:13:47 +03:00
2004-09-14 21:37:51 +04:00
log_very_verbose ( " Initialised format: %s " , fmt - > name ) ;
2002-04-24 22:20:51 +04:00
return fmt ;
2002-02-08 14:13:47 +03:00
2002-04-24 22:20:51 +04:00
err :
2002-11-18 17:04:08 +03:00
_free_dirs ( & mda_lists - > dirs ) ;
2002-02-08 14:13:47 +03:00
2005-10-17 03:03:59 +04:00
dm_free ( fmt ) ;
2002-02-08 14:13:47 +03:00
return NULL ;
2001-11-21 12:20:05 +03:00
}