2001-11-21 12:20:05 +03:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
* Copyright ( C ) 2004 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
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU General Public License
* 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 "pool.h"
# include "config.h"
# include "hash.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"
2001-11-21 12:20:05 +03:00
2002-01-09 22:16:48 +03:00
# include <unistd.h>
# include <sys/file.h>
# 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
2003-08-20 19:48:27 +04:00
# define FMT_TEXT_NAME "lvm2"
# define FMT_TEXT_ALIAS "text"
2002-12-20 02:25:55 +03:00
static struct format_instance * _create_text_instance ( const struct format_type
* fmt , const char * vgname ,
2002-11-18 17:04:08 +03:00
void * context ) ;
2002-02-22 14:44:56 +03:00
2002-04-24 22:20:51 +04:00
struct dir_list {
struct list list ;
char dir [ 0 ] ;
} ;
2002-11-18 17:04:08 +03:00
struct raw_list {
struct list list ;
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
*/
2002-11-18 17:04:08 +03:00
static int _vg_setup ( struct format_instance * fid , 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
}
2002-11-18 17:04:08 +03:00
static int _lv_setup ( struct format_instance * fid , struct logical_volume * lv )
2001-11-21 12:20:05 +03:00
{
2002-11-18 19:21:00 +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 ) {
2002-11-18 19:21:00 +03:00
char * dummy = display_size ( max_size / 2 , SIZE_SHORT ) ;
2002-02-22 14:44:56 +03:00
log_error ( " logical volumes cannot be larger than %s " , dummy ) ;
dbg_free ( dummy ) ;
return 0 ;
}
2002-11-18 19:21:00 +03:00
*/
if ( ! * lv - > lvid . s )
lvid_create ( & lv - > lvid , & lv - > vg - > id ) ;
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 ;
if ( ! ( mdah = pool_alloc ( fmt - > cmd - > mem , MDA_HEADER_SIZE ) ) ) {
log_error ( " struct mda_header allocation failed " ) ;
return NULL ;
}
2003-07-05 02:34:56 +04:00
if ( ! dev_read ( dev_area - > dev , dev_area - > start , MDA_HEADER_SIZE , mdah ) ) {
2002-11-18 17:04:08 +03:00
stack ;
pool_free ( fmt - > cmd - > mem , mdah ) ;
return NULL ;
}
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 " ) ;
return NULL ;
}
_xlate_mdah ( mdah ) ;
if ( strncmp ( mdah - > magic , FMTT_MAGIC , sizeof ( mdah - > magic ) ) ) {
log_error ( " Wrong magic number in metadata area header " ) ;
return NULL ;
}
if ( mdah - > version ! = FMTT_VERSION ) {
log_error ( " Incompatible metadata area header version: %d " ,
mdah - > version ) ;
return NULL ;
}
if ( mdah - > start ! = dev_area - > start ) {
log_error ( " Incorrect start sector in metadata area header: % "
PRIu64 , mdah - > start ) ;
return NULL ;
}
return mdah ;
}
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 )
{
strncpy ( mdah - > magic , FMTT_MAGIC , sizeof ( mdah - > magic ) ) ;
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 ) ) ) ;
2003-07-05 02:34:56 +04:00
if ( ! dev_write ( dev , start_byte , MDA_HEADER_SIZE , mdah ) ) {
2002-11-18 17:04:08 +03:00
stack ;
pool_free ( fmt - > cmd - > mem , mdah ) ;
return 0 ;
}
return 1 ;
}
static struct raw_locn * _find_vg_rlocn ( struct device_area * dev_area ,
struct mda_header * mdah ,
const char * vgname )
{
2002-12-20 02:25:55 +03:00
size_t len ;
2002-11-18 17:04:08 +03:00
char vgnamebuf [ NAME_LEN + 2 ] ;
struct raw_locn * rlocn ;
rlocn = mdah - > raw_locns ;
/* FIXME Ignore if checksum incorrect!!! */
while ( rlocn - > offset ) {
2003-07-05 02:34:56 +04:00
if ( ! dev_read ( dev_area - > dev , dev_area - > start + rlocn - > offset ,
sizeof ( vgnamebuf ) , vgnamebuf ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return NULL ;
}
if ( ! strncmp ( vgnamebuf , vgname , len = strlen ( vgname ) ) & &
( isspace ( vgnamebuf [ len ] ) | | vgnamebuf [ len ] = = ' { ' ) ) {
return rlocn ;
}
rlocn + + ;
}
return NULL ;
}
static struct raw_locn * _vg_posn ( struct format_instance * fid ,
struct device_area * dev_area ,
const char * vgname )
{
struct mda_header * mdah ;
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , dev_area ) ) ) {
stack ;
return NULL ;
}
return _find_vg_rlocn ( dev_area , mdah , vgname ) ;
}
static int _raw_holds_vgname ( struct format_instance * fid ,
struct device_area * dev_area , const char * vgname )
{
int r = 0 ;
2003-07-05 02:34:56 +04:00
if ( ! dev_open ( dev_area - > dev ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return 0 ;
}
if ( _vg_posn ( fid , dev_area , vgname ) )
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 ,
struct device_area * area )
{
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
2003-07-05 02:34:56 +04:00
if ( ! dev_open ( area - > dev ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return NULL ;
}
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , area ) ) ) {
stack ;
goto out ;
}
if ( ! ( rlocn = _vg_posn ( fid , area , vgname ) ) ) {
stack ;
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 ,
2002-11-18 17:04:08 +03:00
& desc ) ) ) {
stack ;
goto out ;
}
2003-04-28 16:18:53 +04:00
log_debug ( " Read %s metadata (%u) from %s at % " PRIu64 " size % " PRIu64 ,
vg - > name , vg - > seqno , dev_name ( area - > dev ) ,
area - > start + rlocn - > offset , rlocn - > size ) ;
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 ;
return _vg_read_raw_area ( fid , vgname , & mdac - > area ) ;
}
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 ;
struct raw_locn * rlocn ;
struct mda_header * mdah ;
struct physical_volume * pv ;
struct list * pvh ;
int r = 0 ;
2002-12-20 02:25:55 +03:00
uint32_t new_wrap = 0 , old_wrap = 0 ;
2002-11-18 17:04:08 +03:00
/* FIXME Essential fix! Make dynamic (realloc? pool?) */
char buf [ 65536 ] ;
int found = 0 ;
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
list_iterate ( pvh , & vg - > pvs ) {
pv = list_item ( pvh , struct pv_list ) - > pv ;
if ( pv - > dev = = mdac - > area . dev ) {
found = 1 ;
break ;
}
}
if ( ! found )
return 1 ;
2003-07-05 02:34:56 +04:00
if ( ! dev_open ( mdac - > area . dev ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return 0 ;
}
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , & mdac - > area ) ) ) {
stack ;
goto out ;
}
if ( ( rlocn = _find_vg_rlocn ( & mdac - > area , mdah , vg - > name ) ) ) {
/* Start of free space - round up to next sector; circular */
mdac - > rlocn . offset =
( ( rlocn - > offset + rlocn - > size +
( SECTOR_SIZE - rlocn - > size % SECTOR_SIZE ) -
MDA_HEADER_SIZE ) % ( mdah - > size - MDA_HEADER_SIZE ) )
+ MDA_HEADER_SIZE ;
} else {
/* Find an empty slot */
/* FIXME Assume only one VG per mdah for now */
mdac - > rlocn . offset = MDA_HEADER_SIZE ;
}
if ( ! ( mdac - > rlocn . size = text_vg_export_raw ( vg , " " , buf , sizeof ( buf ) ) ) ) {
log_error ( " VG %s metadata writing failed " , vg - > name ) ;
goto out ;
}
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 ;
if ( ( new_wrap & & old_wrap ) | |
( rlocn & & ( ( new_wrap > rlocn - > offset ) | |
( old_wrap & & ( mdac - > rlocn . offset + mdac - > rlocn . size >
rlocn - > offset ) ) ) ) | |
( 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 ,
( size_t ) ( mdac - > rlocn . size - new_wrap ) , buf ) ) {
2002-11-18 17:04:08 +03:00
stack ;
goto out ;
}
if ( new_wrap ) {
2002-12-20 02:25:55 +03:00
log_debug ( " Writing metadata to %s at % " PRIu64 " len % " PRIu32 ,
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 ,
buf + mdac - > rlocn . size - new_wrap ) ) {
2002-11-18 17:04:08 +03:00
stack ;
goto out ;
}
}
mdac - > rlocn . checksum = calc_crc ( INITIAL_CRC , 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 ,
buf + mdac - > rlocn . size -
new_wrap , new_wrap ) ;
r = 1 ;
out :
2003-07-05 02:34:56 +04:00
if ( ! r & & ! dev_close ( mdac - > area . dev ) )
2002-11-18 17:04:08 +03:00
stack ;
return r ;
}
static int _vg_commit_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 ;
struct physical_volume * pv ;
struct list * pvh ;
int r = 0 ;
int found = 0 ;
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
list_iterate ( pvh , & vg - > pvs ) {
pv = list_item ( pvh , struct pv_list ) - > pv ;
if ( pv - > dev = = mdac - > area . dev ) {
found = 1 ;
break ;
}
}
if ( ! found )
return 1 ;
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , & mdac - > area ) ) ) {
stack ;
goto out ;
}
if ( ! ( rlocn = _find_vg_rlocn ( & mdac - > area , mdah , vg - > name ) ) ) {
rlocn = & mdah - > raw_locns [ 0 ] ;
mdah - > raw_locns [ 1 ] . offset = 0 ;
}
rlocn - > offset = mdac - > rlocn . offset ;
rlocn - > size = mdac - > rlocn . size ;
rlocn - > checksum = mdac - > rlocn . checksum ;
log_debug ( " Committing %s metadata (%u) to %s header at % " PRIu64 ,
vg - > name , vg - > seqno , dev_name ( mdac - > area . dev ) ,
mdac - > area . start ) ;
if ( ! _raw_write_mda_header ( fid - > fmt , mdac - > area . dev , mdac - > area . start ,
mdah ) ) {
log_error ( " Failed to write metadata area header " ) ;
goto out ;
}
r = 1 ;
out :
if ( ! dev_close ( mdac - > area . dev ) )
stack ;
return r ;
}
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 ;
struct physical_volume * pv ;
struct list * pvh ;
int found = 0 ;
/* Ignore any mda on a PV outside the VG. vgsplit relies on this */
list_iterate ( pvh , & vg - > pvs ) {
pv = list_item ( pvh , struct pv_list ) - > pv ;
if ( pv - > dev = = mdac - > area . dev ) {
found = 1 ;
break ;
}
}
if ( ! found )
return 1 ;
if ( ! dev_close ( mdac - > area . dev ) )
stack ;
return 1 ;
}
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 ;
2003-07-05 02:34:56 +04:00
if ( ! dev_open ( mdac - > area . dev ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return 0 ;
}
if ( ! ( mdah = _raw_read_mda_header ( fid - > fmt , & mdac - > area ) ) ) {
stack ;
goto out ;
}
if ( ! ( rlocn = _find_vg_rlocn ( & mdac - > area , mdah , vg - > name ) ) ) {
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 ) ) {
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 ,
const char * path_live )
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
2002-11-18 17:04:08 +03:00
if ( ! ( vg = text_vg_import_file ( fid , path_live , & when , & desc ) ) ) {
2002-01-10 17:27:47 +03:00
stack ;
return NULL ;
}
/*
* 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 ) ) {
pool_free ( fid - > fmt - > cmd - > mem , vg ) ;
2002-01-10 17:27:47 +03:00
log_err ( " '%s' does not contain volume group '%s'. " ,
2002-11-18 17:04:08 +03:00
path_live , vgname ) ;
2002-01-10 17:27:47 +03:00
return NULL ;
2002-11-18 17:04:08 +03:00
} else
log_debug ( " Read volume group %s from %s " , vg - > name , path_live ) ;
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 ) ;
}
static int _vg_write_file ( struct format_instance * fid , 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 ] ;
2002-04-24 22:20:51 +04:00
slash = rindex ( 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 ;
}
2002-02-25 01:31:55 +03:00
if ( ! create_temp_name ( temp_dir , temp_file , sizeof ( temp_file ) , & fd ) ) {
log_err ( " Couldn't create temporary text file name. " ) ;
return 0 ;
}
2002-01-09 22:16:48 +03:00
if ( ! ( fp = fdopen ( fd , " w " ) ) ) {
log_sys_error ( " fdopen " , temp_file ) ;
close ( fd ) ;
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 ) ;
2002-01-09 16:07:03 +03:00
fclose ( fp ) ;
return 0 ;
}
2002-04-24 22:20:51 +04:00
if ( fsync ( fd ) ) {
log_sys_error ( " fsync " , tc - > path_edit ) ;
fclose ( fp ) ;
return 0 ;
}
2002-01-09 22:16:48 +03:00
if ( fclose ( fp ) ) {
2002-04-24 22:20:51 +04:00
log_sys_error ( " fclose " , tc - > path_edit ) ;
return 0 ;
}
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 ;
}
2002-11-18 17:04:08 +03:00
static int _vg_commit_file_backup ( 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 ;
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 ;
char newname [ 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? */
if ( ( slash = rindex ( tc - > path_live , ' / ' ) ) )
slash = slash + 1 ;
else
slash = tc - > path_live ;
if ( strcmp ( slash , vg - > name ) ) {
len = slash - tc - > path_live ;
strncpy ( newname , tc - > path_live , len ) ;
strcpy ( newname + len , vg - > name ) ;
log_debug ( " Renaming %s to %s " , tc - > path_live , newname ) ;
if ( test_mode ( ) )
log_verbose ( " Test mode: Skipping rename " ) ;
else {
if ( rename ( tc - > path_live , newname ) ) {
log_error ( " %s: rename to %s failed: %s " ,
tc - > path_live , newname ,
strerror ( errno ) ) ;
2002-12-06 01:56:22 +03:00
sync_dir ( newname ) ;
2002-11-18 17:04:08 +03:00
return 0 ;
}
}
}
2002-04-24 22:20:51 +04:00
return 1 ;
}
2002-11-18 17:04:08 +03:00
static int _vg_remove_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 ;
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 ;
struct list * dlh , * dir_list ;
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
list_iterate ( dlh , dir_list ) {
dl = list_item ( dlh , struct dir_list ) ;
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 ;
if ( lvm_snprintf ( path , PATH_MAX , " %s/%s " ,
dl - > dir , vgname ) < 0 ) {
log_error ( " Name too long %s/%s " ,
dl - > dir , vgname ) ;
break ;
}
/* FIXME stat file to see if it's changed */
fid = _create_text_instance ( fmt , NULL , NULL ) ;
if ( ( vg = _vg_read_file_name ( fid , vgname ,
path ) ) )
2003-07-05 02:34:56 +04:00
lvmcache_update_vg ( vg ) ;
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
}
2002-12-20 02:25:55 +03:00
int vgname_from_mda ( const struct format_type * fmt , struct device_area * dev_area ,
2002-11-18 17:04:08 +03:00
char * buf , uint32_t size )
2002-02-22 14:44:56 +03:00
{
2002-11-18 17:04:08 +03:00
struct raw_locn * rlocn ;
struct mda_header * mdah ;
2002-12-20 02:25:55 +03:00
unsigned int len ;
2002-11-18 17:04:08 +03:00
int r = 0 ;
2003-07-05 02:34:56 +04:00
if ( ! dev_open ( dev_area - > dev ) ) {
2002-04-24 22:20:51 +04:00
stack ;
2002-11-18 17:04:08 +03:00
return 0 ;
2002-04-24 22:20:51 +04:00
}
2002-02-22 14:44:56 +03:00
2002-11-18 17:04:08 +03:00
if ( ! ( mdah = _raw_read_mda_header ( fmt , dev_area ) ) ) {
stack ;
goto out ;
}
2002-02-25 01:31:55 +03:00
2002-11-18 17:04:08 +03:00
rlocn = mdah - > raw_locns ;
while ( rlocn - > offset ) {
2003-07-05 02:34:56 +04:00
if ( ! dev_read ( dev_area - > dev , dev_area - > start + rlocn - > offset ,
size , buf ) ) {
2002-11-18 17:04:08 +03:00
stack ;
goto out ;
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:04:08 +03:00
len = 0 ;
while ( buf [ len ] & & ! isspace ( buf [ len ] ) & & buf [ len ] ! = ' { ' & &
2002-12-20 02:25:55 +03:00
len < ( size - 1 ) )
2002-11-18 17:04:08 +03:00
len + + ;
buf [ len ] = ' \0 ' ;
/* Ignore this entry if the characters aren't permissible */
2003-02-03 23:09:58 +03:00
if ( ! validate_name ( buf ) ) {
2002-11-18 17:04:08 +03:00
stack ;
goto out ;
2002-02-22 14:44:56 +03:00
}
2002-11-18 17:04:08 +03:00
r = 1 ;
break ;
/* FIXME Cope with returning a list */
rlocn + + ;
2002-02-22 14:44:56 +03: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 ;
return r ;
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 ;
struct list * rlh , * raw_list ;
char vgnamebuf [ NAME_LEN + 2 ] ;
struct volume_group * vg ;
struct format_instance fid ;
raw_list = & ( ( struct mda_lists * ) fmt - > private ) - > raws ;
fid . fmt = fmt ;
list_init ( & fid . metadata_areas ) ;
list_iterate ( rlh , raw_list ) {
rl = list_item ( rlh , struct raw_list ) ;
/* FIXME We're reading mdah twice here... */
if ( vgname_from_mda ( fmt , & rl - > dev_area , vgnamebuf ,
sizeof ( vgnamebuf ) ) ) {
if ( ( vg = _vg_read_raw_area ( & fid , vgnamebuf ,
& rl - > dev_area ) ) )
2003-07-05 02:34:56 +04:00
lvmcache_update_vg ( vg ) ;
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
}
2002-12-20 02:25:55 +03:00
static int _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.
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 ,
uint64_t pvmetadatasize , struct list * mdas ,
struct physical_volume * pv , struct volume_group * vg )
{
uint64_t mda_adjustment , disk_size , alignment ;
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 ;
if ( ! pvmetadatacopies ) {
/* Space available for PEs */
pv - > size - = PE_ALIGN ;
return 1 ;
}
alignment = PE_ALIGN < < SECTOR_SHIFT ;
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! " ,
dev_name ( pv - > dev ) ) ;
return 0 ;
}
/* Requested metadatasize */
mda_size1 = pvmetadatasize < < SECTOR_SHIFT ;
/* Space available for PEs (before any mdas created) */
pv - > size - = LABEL_SCAN_SECTORS ;
/* Place mda straight after label area at start of disk */
start1 = LABEL_SCAN_SIZE ;
2003-10-16 00:06:37 +04:00
/* Ensure it's not going to be bigger than the disk! */
if ( mda_size1 > disk_size ) {
log_print ( " Warning: metadata area fills disk %s " ,
dev_name ( pv - > dev ) ) ;
/* Leave some free space for rounding */
/* Avoid empty data area as could cause tools problems */
mda_size1 = disk_size - start1 - alignment * 2 ;
/* Only have 1 mda in this case */
pvmetadatacopies = 1 ;
}
2002-11-18 17:04:08 +03:00
/* Round up to PE_ALIGN boundary */
mda_adjustment = ( mda_size1 + start1 ) % alignment ;
if ( mda_adjustment )
mda_size1 + = ( alignment - mda_adjustment ) ;
/* 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 ,
mda_size1 ) )
return 0 ;
2002-12-20 02:25:55 +03:00
if ( ! dev_zero ( ( struct device * ) pv - > dev , start1 ,
( size_t ) ( mda_size1 >
wipe_size ? wipe_size : mda_size1 ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Failed to wipe new metadata area " ) ;
return 0 ;
}
pv - > size - = mda_size1 > > SECTOR_SHIFT ;
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 ,
mda_size2 ) )
return 0 ;
if ( ! dev_zero ( pv - > dev , start2 ,
2002-12-20 02:25:55 +03:00
( size_t ) ( mda_size1 >
wipe_size ? wipe_size : mda_size1 ) ) ) {
2002-11-18 17:04:08 +03:00
log_error ( " Failed to wipe new metadata area " ) ;
return 0 ;
}
pv - > size - = mda_size2 > > SECTOR_SHIFT ;
} else
return 0 ;
return 1 ;
}
/* Only for orphans */
/* Set label_sector to -1 if rewriting existing label into same sector */
2002-12-20 02:25:55 +03:00
static int _pv_write ( const struct format_type * fmt , struct physical_volume * pv ,
2002-11-18 17:04:08 +03:00
struct list * mdas , int64_t label_sector )
{
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 list * mdash ;
struct metadata_area * mda ;
char buf [ MDA_HEADER_SIZE ] ;
struct mda_header * mdah = ( struct mda_header * ) buf ;
uint64_t adjustment ;
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 ,
ORPHAN , NULL ) ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return 0 ;
}
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
list_init ( & info - > mdas ) ;
list_iterate ( mdash , mdas ) {
mda = list_item ( mdash , struct metadata_area ) ;
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 ) {
list_init ( & info - > mdas ) ;
}
if ( info - > das . n )
del_das ( & info - > das ) ;
else
list_init ( & info - > das ) ;
/* Set pe_start to first aligned sector after any metadata
* areas that begin before pe_start */
pv - > pe_start = PE_ALIGN ;
list_iterate ( mdash , & info - > mdas ) {
mda = list_item ( mdash , struct metadata_area ) ;
mdac = ( struct mda_context * ) mda - > metadata_locn ;
if ( pv - > dev = = mdac - > area . dev & &
( mdac - > area . start < ( pv - > pe_start < < SECTOR_SHIFT ) ) & &
( mdac - > area . start + mdac - > area . size >
( pv - > pe_start < < SECTOR_SHIFT ) ) ) {
pv - > pe_start = ( mdac - > area . start + mdac - > area . size )
> > SECTOR_SHIFT ;
adjustment = pv - > pe_start % PE_ALIGN ;
if ( adjustment )
pv - > pe_start + = ( PE_ALIGN - adjustment ) ;
}
}
2002-12-20 02:25:55 +03:00
if ( ! add_da
( fmt , NULL , & info - > das , pv - > pe_start < < SECTOR_SHIFT ,
2003-03-24 21:08:53 +03:00
UINT64_C ( 0 ) ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return 0 ;
}
2003-07-05 02:34:56 +04:00
if ( ! dev_open ( pv - > dev ) ) {
2002-11-18 17:04:08 +03:00
stack ;
return 0 ;
}
list_iterate ( mdash , & info - > mdas ) {
mda = list_item ( mdash , struct metadata_area ) ;
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 ) ) {
stack ;
if ( ! dev_close ( pv - > dev ) )
stack ;
return 0 ;
}
}
label_write ( pv - > dev , label ) ;
if ( ! dev_close ( pv - > dev ) ) {
stack ;
return 0 ;
}
return 1 ;
}
2002-12-20 02:25:55 +03:00
static int _get_pv_from_vg ( const struct format_type * fmt , const char * vg_name ,
2002-11-18 17:04:08 +03:00
const char * id , struct physical_volume * pv )
{
2002-02-25 01:31:55 +03:00
struct volume_group * vg ;
2002-02-22 14:44:56 +03:00
struct list * pvh ;
2002-11-18 17:04:08 +03:00
struct pv_list * pvl ;
int consistent = 0 ;
2002-02-22 14:44:56 +03:00
2002-11-18 17:04:08 +03:00
if ( ! ( vg = vg_read ( fmt - > cmd , vg_name , & consistent ) ) ) {
log_error ( " format_text: _vg_read failed to read VG %s " ,
vg_name ) ;
return 0 ;
}
2002-02-22 14:44:56 +03:00
2002-11-18 17:04:08 +03:00
if ( ! consistent )
log_error ( " Warning: Volume group %s is not consistent " ,
vg_name ) ;
list_iterate ( pvh , & vg - > pvs ) {
pvl = list_item ( pvh , struct pv_list ) ;
2002-12-20 02:25:55 +03:00
if ( id_equal ( & pvl - > pv - > id , ( const struct id * ) id ) ) {
2002-11-18 17:04:08 +03:00
memcpy ( pv , pvl - > pv , sizeof ( * pv ) ) ;
return 1 ;
2002-02-22 14:44:56 +03:00
}
}
return 0 ;
}
2002-11-18 17:04:08 +03:00
static int _add_raw ( struct 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 ;
struct list * rlh ;
/* Already present? */
list_iterate ( rlh , raw_list ) {
rl = list_item ( rlh , struct raw_list ) ;
/* FIXME Check size/overlap consistency too */
if ( rl - > dev_area . dev = = dev_area - > dev & &
rl - > dev_area . start = = dev_area - > start )
return 1 ;
}
2002-04-24 22:20:51 +04:00
2002-11-18 17:04:08 +03:00
if ( ! ( rl = dbg_malloc ( sizeof ( struct raw_list ) ) ) ) {
log_error ( " _add_raw allocation failed " ) ;
return 0 ;
}
memcpy ( & rl - > dev_area , dev_area , sizeof ( * dev_area ) ) ;
list_add ( raw_list , & rl - > list ) ;
return 1 ;
}
2002-12-20 02:25:55 +03:00
static int _pv_read ( const struct format_type * fmt , const char * pv_name ,
2002-11-18 17:04:08 +03:00
struct physical_volume * pv , struct list * mdas )
{
struct label * label ;
struct device * dev ;
2003-07-05 02:34:56 +04:00
struct lvmcache_info * info ;
2002-11-18 17:04:08 +03:00
struct metadata_area * mda , * mda_new ;
struct mda_context * mdac , * mdac_new ;
struct list * mdah , * dah ;
struct data_area_list * da ;
if ( ! ( dev = dev_cache_get ( pv_name , fmt - > cmd - > filter ) ) ) {
2002-04-24 22:20:51 +04:00
stack ;
return 0 ;
}
2002-12-20 02:25:55 +03:00
/* FIXME Optimise out repeated reading when cache lock held */
2002-11-18 17:04:08 +03:00
if ( ! ( label_read ( dev , & label ) ) ) {
2002-04-24 22:20:51 +04:00
stack ;
return 0 ;
}
2003-07-05 02:34:56 +04:00
info = ( struct lvmcache_info * ) label - > info ;
2002-11-18 17:04:08 +03:00
/* Have we already cached vgname? */
if ( info - > vginfo & & info - > vginfo - > vgname & & * info - > vginfo - > vgname & &
_get_pv_from_vg ( info - > fmt , info - > vginfo - > vgname , info - > dev - > pvid ,
pv ) ) {
return 1 ;
}
/* Perform full scan and try again */
2003-07-05 02:34:56 +04:00
if ( ! memlock ( ) ) {
lvmcache_label_scan ( fmt - > cmd , 1 ) ;
2002-11-18 17:04:08 +03:00
2003-07-05 02:34:56 +04:00
if ( info - > vginfo & & info - > vginfo - > vgname & &
* info - > vginfo - > vgname & &
_get_pv_from_vg ( info - > fmt , info - > vginfo - > vgname ,
info - > dev - > pvid , pv ) ) {
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 ;
pv - > vg_name = ORPHAN ;
memcpy ( & pv - > id , & info - > dev - > pvid , sizeof ( pv - > id ) ) ;
/* Currently only support exactly one data area */
if ( list_size ( & info - > das ) ! = 1 ) {
log_error ( " Must be exactly one data area (found %d) on PV %s " ,
list_size ( & info - > das ) , dev_name ( dev ) ) ;
return 0 ;
}
list_iterate ( dah , & info - > das ) {
da = list_item ( dah , struct data_area_list ) ;
pv - > pe_start = da - > disk_locn . offset > > SECTOR_SHIFT ;
}
2002-02-22 14:44:56 +03:00
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 */
list_iterate ( mdah , & info - > mdas ) {
mda = list_item ( mdah , struct metadata_area ) ;
mdac = ( struct mda_context * ) mda - > metadata_locn ;
if ( ! ( mda_new = pool_alloc ( fmt - > cmd - > mem , sizeof ( * mda_new ) ) ) ) {
log_error ( " metadata_area allocation failed " ) ;
2002-04-24 22:20:51 +04:00
return 0 ;
}
2002-11-18 17:04:08 +03:00
if ( ! ( mdac_new = pool_alloc ( fmt - > cmd - > mem , sizeof ( * mdac_new ) ) ) ) {
log_error ( " metadata_area allocation failed " ) ;
return 0 ;
2002-02-22 14:44:56 +03:00
}
2002-11-18 17:04:08 +03:00
memcpy ( mda_new , mda , sizeof ( * mda ) ) ;
memcpy ( mdac_new , mdac , sizeof ( * mdac ) ) ;
mda_new - > metadata_locn = mdac_new ;
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
}
2002-04-24 22:20:51 +04:00
static void _destroy_instance ( struct format_instance * fid )
2001-11-21 12:20:05 +03:00
{
2002-04-24 22:20:51 +04:00
return ;
}
static void _free_dirs ( struct list * dir_list )
{
struct list * dl , * tmp ;
list_iterate_safe ( dl , tmp , dir_list ) {
list_del ( dl ) ;
dbg_free ( dl ) ;
}
}
2002-11-18 17:04:08 +03:00
static void _free_raws ( struct list * raw_list )
{
struct list * rl , * tmp ;
list_iterate_safe ( rl , tmp , raw_list ) {
list_del ( rl ) ;
dbg_free ( rl ) ;
}
}
2002-12-20 02:25:55 +03:00
static void _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 ) ;
2002-04-24 22:20:51 +04:00
dbg_free ( fmt - > private ) ;
}
2002-12-20 02:25:55 +03:00
dbg_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 = {
vg_read : _vg_read_file ,
vg_write : _vg_write_file ,
vg_remove : _vg_remove_file ,
vg_commit : _vg_commit_file
} ;
static struct metadata_area_ops _metadata_text_file_backup_ops = {
vg_read : _vg_read_file ,
vg_write : _vg_write_file ,
vg_remove : _vg_remove_file ,
vg_commit : _vg_commit_file_backup
} ;
static struct metadata_area_ops _metadata_text_raw_ops = {
vg_read : _vg_read_raw ,
vg_write : _vg_write_raw ,
vg_remove : _vg_remove_raw ,
2003-07-05 02:34:56 +04:00
vg_commit : _vg_commit_raw ,
vg_revert : _vg_revert_raw
2002-11-18 17:04:08 +03:00
} ;
/* pvmetadatasize in sectors */
2002-12-20 02:25:55 +03:00
static int _pv_setup ( const struct format_type * fmt ,
2002-11-18 17:04:08 +03:00
uint64_t pe_start , uint32_t extent_count ,
uint32_t extent_size ,
int pvmetadatacopies ,
uint64_t pvmetadatasize , struct list * mdas ,
struct physical_volume * pv , struct volume_group * vg )
{
struct metadata_area * mda , * mda_new , * mda2 ;
struct mda_context * mdac , * mdac_new , * mdac2 ;
struct list * pvmdas , * pvmdash , * mdash ;
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 ;
/* FIXME if vg, adjust start/end of pe area to avoid mdas! */
/* FIXME Cope with pvchange */
/* FIXME Merge code with _create_text_instance */
/* 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 */
if ( ( info = info_from_pvid ( pv - > dev - > pvid ) ) ) {
pvmdas = & info - > mdas ;
list_iterate ( pvmdash , pvmdas ) {
mda = list_item ( pvmdash , struct metadata_area ) ;
mdac =
( struct mda_context * ) mda - > metadata_locn ;
/* FIXME Check it isn't already in use */
/* Ensure it isn't already on list */
found = 0 ;
list_iterate ( mdash , mdas ) {
mda2 =
list_item ( mdash ,
struct metadata_area ) ;
if ( mda2 - > ops ! =
& _metadata_text_raw_ops )
continue ;
mdac2 =
( struct mda_context * ) mda2 - >
metadata_locn ;
if ( ! memcmp
( & mdac2 - > area , & mdac - > area ,
sizeof ( mdac - > area ) ) ) {
found = 1 ;
break ;
}
}
if ( found )
continue ;
if ( ! ( mda_new = pool_alloc ( fmt - > cmd - > mem ,
sizeof ( * mda_new ) ) ) ) {
stack ;
return 0 ;
}
if ( ! ( mdac_new = pool_alloc ( fmt - > cmd - > mem ,
sizeof ( * mdac_new ) ) ) )
{
stack ;
return 0 ;
}
/* FIXME multiple dev_areas inside area */
memcpy ( mda_new , mda , sizeof ( * mda ) ) ;
memcpy ( mdac_new , mdac , sizeof ( * mdac ) ) ;
mda_new - > metadata_locn = mdac_new ;
list_add ( mdas , & mda_new - > list ) ;
}
}
/* Unlike LVM1, we don't store this outside a VG */
/* FIXME Default from config file? vgextend cmdline flag? */
pv - > status | = ALLOCATABLE_PV ;
} else {
if ( extent_count )
pe_end = pe_start + extent_count * extent_size - 1 ;
if ( ! _mda_setup ( fmt , pe_start , pe_end , pvmetadatacopies ,
pvmetadatasize , mdas , pv , vg ) ) {
stack ;
return 0 ;
}
}
return 1 ;
}
/* NULL vgname means use only the supplied context e.g. an archive file */
2002-12-20 02:25:55 +03:00
static struct format_instance * _create_text_instance ( const struct format_type
* fmt , const char * vgname ,
2002-04-24 22:20:51 +04:00
void * context )
{
struct format_instance * fid ;
2002-11-18 17:04:08 +03:00
struct metadata_area * mda , * mda_new ;
struct mda_context * mdac , * mdac_new ;
2002-04-24 22:20:51 +04:00
struct dir_list * dl ;
2002-11-18 17:04:08 +03:00
struct raw_list * rl ;
struct list * dlh , * dir_list , * rlh , * raw_list , * mdas , * mdash , * infoh ;
2002-04-24 22:20:51 +04:00
char path [ PATH_MAX ] ;
2003-07-05 02:34:56 +04:00
struct lvmcache_vginfo * vginfo ;
2002-04-24 22:20:51 +04:00
if ( ! ( fid = pool_alloc ( fmt - > cmd - > mem , sizeof ( * fid ) ) ) ) {
log_error ( " Couldn't allocate format instance object. " ) ;
return NULL ;
}
fid - > fmt = fmt ;
list_init ( & fid - > metadata_areas ) ;
if ( ! vgname ) {
if ( ! ( mda = pool_alloc ( fmt - > cmd - > mem , sizeof ( * mda ) ) ) ) {
stack ;
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 ;
list_add ( & fid - > metadata_areas , & mda - > list ) ;
} 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
list_iterate ( dlh , dir_list ) {
dl = list_item ( dlh , struct dir_list ) ;
if ( lvm_snprintf ( path , PATH_MAX , " %s/%s " ,
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 ) ;
2002-04-24 22:20:51 +04:00
if ( ! ( mda = pool_alloc ( fmt - > cmd - > mem , sizeof ( * mda ) ) ) ) {
stack ;
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 ;
list_add ( & fid - > metadata_areas , & mda - > list ) ;
}
2002-11-18 17:04:08 +03:00
raw_list = & ( ( struct mda_lists * ) fmt - > private ) - > raws ;
list_iterate ( rlh , raw_list ) {
rl = list_item ( rlh , struct raw_list ) ;
/* FIXME Cache this; rescan below if some missing */
if ( ! _raw_holds_vgname ( fid , & rl - > dev_area , vgname ) )
continue ;
if ( ! ( mda = pool_alloc ( fmt - > cmd - > mem , sizeof ( * mda ) ) ) ) {
stack ;
return NULL ;
}
if ( ! ( mdac = pool_alloc ( fmt - > cmd - > mem , sizeof ( * mdac ) ) ) ) {
stack ;
return NULL ;
}
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; */
2002-11-18 17:04:08 +03:00
list_add ( & fid - > metadata_areas , & mda - > list ) ;
}
/* Scan PVs in VG for any further MDAs */
2003-07-05 02:34:56 +04:00
lvmcache_label_scan ( fmt - > cmd , 0 ) ;
2002-11-18 17:04:08 +03:00
if ( ! ( vginfo = vginfo_from_vgname ( vgname ) ) ) {
stack ;
goto out ;
}
list_iterate ( infoh , & vginfo - > infos ) {
2003-07-05 02:34:56 +04:00
mdas = & ( list_item ( infoh , struct lvmcache_info ) - > mdas ) ;
2002-11-18 17:04:08 +03:00
list_iterate ( mdash , mdas ) {
mda = list_item ( mdash , struct metadata_area ) ;
mdac =
( struct mda_context * ) mda - > metadata_locn ;
/* FIXME Check it holds this VG */
if ( ! ( mda_new = pool_alloc ( fmt - > cmd - > mem ,
sizeof ( * mda_new ) ) ) ) {
stack ;
return NULL ;
}
if ( ! ( mdac_new = pool_alloc ( fmt - > cmd - > mem ,
sizeof ( * mdac_new ) ) ) )
{
stack ;
return NULL ;
}
/* FIXME multiple dev_areas inside area */
memcpy ( mda_new , mda , sizeof ( * mda ) ) ;
memcpy ( mdac_new , mdac , sizeof ( * mdac ) ) ;
mda_new - > metadata_locn = mdac_new ;
list_add ( & fid - > metadata_areas , & mda_new - > list ) ;
}
}
/* 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-01-15 20:37:23 +03:00
2002-04-24 22:20:51 +04:00
}
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 ;
}
2002-11-18 17:04:08 +03:00
if ( ! ( tc = pool_alloc ( cmd - > mem , sizeof ( * tc ) ) ) ) {
2002-04-24 22:20:51 +04:00
stack ;
return NULL ;
}
2002-11-18 17:04:08 +03:00
if ( ! ( tc - > path_live = pool_strdup ( cmd - > mem , path ) ) ) {
2002-04-24 22:20:51 +04:00
stack ;
goto no_mem ;
}
2002-11-18 17:04:08 +03:00
if ( ! ( tc - > path_edit = pool_alloc ( cmd - > mem , strlen ( path ) + 5 ) ) ) {
2002-04-24 22:20:51 +04:00
stack ;
goto no_mem ;
}
sprintf ( tc - > path_edit , " %s.tmp " , path ) ;
if ( ! desc )
desc = " " ;
2002-11-18 17:04:08 +03:00
if ( ! ( tc - > desc = pool_strdup ( cmd - > mem , desc ) ) ) {
2002-04-24 22:20:51 +04:00
stack ;
goto no_mem ;
}
return ( void * ) tc ;
no_mem :
2002-11-18 17:04:08 +03:00
pool_free ( cmd - > mem , tc ) ;
2002-04-24 22:20:51 +04:00
log_err ( " Couldn't allocate text format context object. " ) ;
return NULL ;
2001-11-21 12:20:05 +03:00
}
static struct format_handler _text_handler = {
2002-11-18 17:04:08 +03:00
scan : _scan ,
pv_read : _pv_read ,
pv_setup : _pv_setup ,
pv_write : _pv_write ,
vg_setup : _vg_setup ,
lv_setup : _lv_setup ,
2002-04-24 22:20:51 +04:00
create_instance : _create_text_instance ,
destroy_instance : _destroy_instance ,
2002-11-18 17:04:08 +03:00
destroy : _destroy
2001-11-21 12:20:05 +03:00
} ;
2002-04-24 22:20:51 +04:00
static int _add_dir ( const char * dir , struct 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
2002-04-24 22:20:51 +04:00
if ( create_dir ( dir ) ) {
if ( ! ( dl = dbg_malloc ( sizeof ( struct list ) + strlen ( dir ) + 1 ) ) ) {
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 ) ;
list_add ( dir_list , & dl - > list ) ;
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 ,
struct config_node * cn , struct list * raw_list )
{
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 ) ) ) {
char buffer [ 64 ] ;
if ( ! id_write_format ( & id , buffer , sizeof ( buffer ) ) )
log_err ( " Couldn't find device. " ) ;
else
log_err ( " Couldn't find device with uuid '%s'. " , buffer ) ;
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
if ( ! ( fmt = dbg_malloc ( sizeof ( * fmt ) ) ) ) {
2002-02-08 14:13:47 +03:00
stack ;
2002-04-24 22:20:51 +04:00
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 ;
2004-03-08 20:19:15 +03:00
fmt - > features = FMT_SEGMENTS | FMT_MDAS | FMT_TAGS ;
2002-04-24 22:20:51 +04:00
2002-11-18 17:04:08 +03:00
if ( ! ( mda_lists = dbg_malloc ( sizeof ( struct mda_lists ) ) ) ) {
2002-04-24 22:20:51 +04:00
log_error ( " Failed to allocate dir_list " ) ;
return NULL ;
2002-01-15 20:37:23 +03:00
}
2002-11-18 17:04:08 +03:00
list_init ( & mda_lists - > dirs ) ;
list_init ( & mda_lists - > raws ) ;
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. " ) ;
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. " ) ;
return NULL ;
}
2004-03-08 21:28:45 +03:00
if ( ( cn = find_config_node ( cmd - > cft - > root , " 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 ) ) {
log_error ( " Failed to add %s to internal device "
" cache " , cv - > v . str ) ;
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
2004-03-08 21:28:45 +03:00
if ( ! ( cn = find_config_node ( cmd - > cft - > root , " metadata/disk_areas " ) ) )
2002-11-18 17:04:08 +03:00
return fmt ;
for ( cn = cn - > child ; cn ; cn = cn - > sib ) {
if ( ! _get_config_disk_area ( cmd , cn , & mda_lists - > raws ) )
2002-04-24 22:20:51 +04:00
goto err ;
}
2002-02-08 14:13:47 +03:00
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
2002-04-24 22:20:51 +04:00
dbg_free ( fmt ) ;
2002-02-08 14:13:47 +03:00
return NULL ;
2001-11-21 12:20:05 +03:00
}