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
2011-02-21 15:05:49 +03:00
static struct format_instance * _text_create_text_instance ( const struct format_type * fmt ,
const struct format_instance_ctx * fic ) ;
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 ;
} ;
2011-02-21 15:05:49 +03:00
struct text_fid_pv_context {
int64_t label_sector ;
} ;
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 */
} ;
2010-06-29 00:29:57 +04:00
int rlocn_is_ignored ( const struct raw_locn * rlocn )
{
return ( rlocn - > flags & RAW_LOCN_IGNORED ? 1 : 0 ) ;
}
2010-06-30 21:13:05 +04:00
void rlocn_set_ignored ( struct raw_locn * rlocn , unsigned mda_ignored )
2010-06-29 00:29:57 +04:00
{
2010-06-30 21:13:05 +04:00
if ( mda_ignored )
2010-06-29 00:29:57 +04:00
rlocn - > flags | = RAW_LOCN_IGNORED ;
else
rlocn - > flags & = ~ RAW_LOCN_IGNORED ;
}
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
*/
2010-07-09 19:34:40 +04:00
static int _text_vg_setup ( struct format_instance * fid __attribute__ ( ( unused ) ) ,
2006-05-11 21:58:58 +04:00
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
*/
2010-07-09 19:34:40 +04:00
static int _mda_in_vg_raw ( struct format_instance * fid __attribute__ ( ( unused ) ) ,
2007-03-23 15:43:17 +03:00
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 ;
}
2010-06-29 00:31:38 +04:00
static unsigned _mda_locns_match_raw ( struct metadata_area * mda1 ,
struct metadata_area * mda2 )
{
struct mda_context * mda1c = ( struct mda_context * ) mda1 - > metadata_locn ;
struct mda_context * mda2c = ( struct mda_context * ) mda2 - > metadata_locn ;
if ( ( mda1c - > area . dev = = mda2c - > area . dev ) & &
( mda1c - > area . start = = mda2c - > area . start ) & &
( mda1c - > area . size = = mda2c - > area . size ) )
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 ;
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 ;
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
if ( ! ( mdah = raw_read_mda_header ( fmt , area ) ) )
2007-04-26 01:10:55 +04:00
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 ;
2010-11-29 14:16:58 +03:00
2007-04-26 01:10:55 +04:00
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 ;
}
2010-07-09 19:34:40 +04:00
static int _text_lv_setup ( struct format_instance * fid __attribute__ ( ( unused ) ) ,
2006-05-11 21:58:58 +04:00
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 + + ;
}
}
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
struct mda_header * raw_read_mda_header ( const struct format_type * fmt ,
struct device_area * dev_area )
2002-11-18 17:04:08 +03:00
{
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
2010-09-27 23:09:34 +04:00
if ( mdah - > checksum_xl ! = xlate32 ( calc_crc ( INITIAL_CRC , ( uint8_t * ) mdah - > magic ,
2002-11-18 17:04:08 +03:00
MDA_HEADER_SIZE -
sizeof ( mdah - > checksum_xl ) ) ) ) {
Add device name to output of error messages in raw_read_mda_header().
It would be helpful if we had the device name when something like
a mda_header checksum error occurs.
Before:
./tools/lvm pvs -opv_name,vg_name,uuid,mda_count,pv_mda_count_ignored,vg_mda_count,vg_mda_count_ignored,vg_mda_copies
Incorrect metadata area header checksum
PV VG PV UUID #PMda #PMdaIgn #VMda #VMdaIgn #VMdaCps
/dev/loop0 vgtest2 sVv26t-gjpb-Rcau-uBDO-Cx04-GbRR-6Ssq7e 2 0 4 0 4
/dev/loop1 vgtest2 zXWStT-qE8F-mbkc-RfgH-aytv-mptF-Y5Ce09 2 0 4 0 4
/dev/loop2 riCpK9-9G8r-LlIp-i2oh-mb3N-CUzk-u5YpuR 1 0 0 0 0
/dev/loop3 vgtest tQCUjm-rmyd-i92d-4eeE-UYBW-v1vQ-kRaA17 2 0 4 2 0
/dev/loop4 vgtest ZRvpeI-p8F1-ccVW-BBac-xhl1-aGXU-CbP0oo 2 2 4 2 0
After:
./tools/lvm pvs -opv_name,vg_name,uuid,mda_count,pv_mda_count_ignored,vg_mda_count,vg_mda_count_ignored,vg_mda_copies
Incorrect metadata area header checksum on /dev/loop2 at offset 4096
PV VG PV UUID #PMda #PMdaIgn #VMda #VMdaIgn #VMdaCps
/dev/loop0 vgtest2 sVv26t-gjpb-Rcau-uBDO-Cx04-GbRR-6Ssq7e 2 0 4 0 4
/dev/loop1 vgtest2 zXWStT-qE8F-mbkc-RfgH-aytv-mptF-Y5Ce09 2 0 4 0 4
/dev/loop2 riCpK9-9G8r-LlIp-i2oh-mb3N-CUzk-u5YpuR 1 0 0 0 0
/dev/loop3 vgtest tQCUjm-rmyd-i92d-4eeE-UYBW-v1vQ-kRaA17 2 0 4 2 0
/dev/loop4 vgtest ZRvpeI-p8F1-ccVW-BBac-xhl1-aGXU-CbP0oo 2 2 4 2 0
2010-06-22 23:18:27 +04:00
log_error ( " Incorrect metadata area header checksum on %s "
" at offset % " PRIu64 , dev_name ( dev_area - > dev ) ,
dev_area - > start ) ;
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 ) ) ) {
Add device name to output of error messages in raw_read_mda_header().
It would be helpful if we had the device name when something like
a mda_header checksum error occurs.
Before:
./tools/lvm pvs -opv_name,vg_name,uuid,mda_count,pv_mda_count_ignored,vg_mda_count,vg_mda_count_ignored,vg_mda_copies
Incorrect metadata area header checksum
PV VG PV UUID #PMda #PMdaIgn #VMda #VMdaIgn #VMdaCps
/dev/loop0 vgtest2 sVv26t-gjpb-Rcau-uBDO-Cx04-GbRR-6Ssq7e 2 0 4 0 4
/dev/loop1 vgtest2 zXWStT-qE8F-mbkc-RfgH-aytv-mptF-Y5Ce09 2 0 4 0 4
/dev/loop2 riCpK9-9G8r-LlIp-i2oh-mb3N-CUzk-u5YpuR 1 0 0 0 0
/dev/loop3 vgtest tQCUjm-rmyd-i92d-4eeE-UYBW-v1vQ-kRaA17 2 0 4 2 0
/dev/loop4 vgtest ZRvpeI-p8F1-ccVW-BBac-xhl1-aGXU-CbP0oo 2 2 4 2 0
After:
./tools/lvm pvs -opv_name,vg_name,uuid,mda_count,pv_mda_count_ignored,vg_mda_count,vg_mda_count_ignored,vg_mda_copies
Incorrect metadata area header checksum on /dev/loop2 at offset 4096
PV VG PV UUID #PMda #PMdaIgn #VMda #VMdaIgn #VMdaCps
/dev/loop0 vgtest2 sVv26t-gjpb-Rcau-uBDO-Cx04-GbRR-6Ssq7e 2 0 4 0 4
/dev/loop1 vgtest2 zXWStT-qE8F-mbkc-RfgH-aytv-mptF-Y5Ce09 2 0 4 0 4
/dev/loop2 riCpK9-9G8r-LlIp-i2oh-mb3N-CUzk-u5YpuR 1 0 0 0 0
/dev/loop3 vgtest tQCUjm-rmyd-i92d-4eeE-UYBW-v1vQ-kRaA17 2 0 4 2 0
/dev/loop4 vgtest ZRvpeI-p8F1-ccVW-BBac-xhl1-aGXU-CbP0oo 2 2 4 2 0
2010-06-22 23:18:27 +04:00
log_error ( " Wrong magic number in metadata area header on %s "
" at offset % " PRIu64 , dev_name ( dev_area - > dev ) ,
dev_area - > start ) ;
2008-01-30 16:19:47 +03:00
goto bad ;
2002-11-18 17:04:08 +03:00
}
if ( mdah - > version ! = FMTT_VERSION ) {
Add device name to output of error messages in raw_read_mda_header().
It would be helpful if we had the device name when something like
a mda_header checksum error occurs.
Before:
./tools/lvm pvs -opv_name,vg_name,uuid,mda_count,pv_mda_count_ignored,vg_mda_count,vg_mda_count_ignored,vg_mda_copies
Incorrect metadata area header checksum
PV VG PV UUID #PMda #PMdaIgn #VMda #VMdaIgn #VMdaCps
/dev/loop0 vgtest2 sVv26t-gjpb-Rcau-uBDO-Cx04-GbRR-6Ssq7e 2 0 4 0 4
/dev/loop1 vgtest2 zXWStT-qE8F-mbkc-RfgH-aytv-mptF-Y5Ce09 2 0 4 0 4
/dev/loop2 riCpK9-9G8r-LlIp-i2oh-mb3N-CUzk-u5YpuR 1 0 0 0 0
/dev/loop3 vgtest tQCUjm-rmyd-i92d-4eeE-UYBW-v1vQ-kRaA17 2 0 4 2 0
/dev/loop4 vgtest ZRvpeI-p8F1-ccVW-BBac-xhl1-aGXU-CbP0oo 2 2 4 2 0
After:
./tools/lvm pvs -opv_name,vg_name,uuid,mda_count,pv_mda_count_ignored,vg_mda_count,vg_mda_count_ignored,vg_mda_copies
Incorrect metadata area header checksum on /dev/loop2 at offset 4096
PV VG PV UUID #PMda #PMdaIgn #VMda #VMdaIgn #VMdaCps
/dev/loop0 vgtest2 sVv26t-gjpb-Rcau-uBDO-Cx04-GbRR-6Ssq7e 2 0 4 0 4
/dev/loop1 vgtest2 zXWStT-qE8F-mbkc-RfgH-aytv-mptF-Y5Ce09 2 0 4 0 4
/dev/loop2 riCpK9-9G8r-LlIp-i2oh-mb3N-CUzk-u5YpuR 1 0 0 0 0
/dev/loop3 vgtest tQCUjm-rmyd-i92d-4eeE-UYBW-v1vQ-kRaA17 2 0 4 2 0
/dev/loop4 vgtest ZRvpeI-p8F1-ccVW-BBac-xhl1-aGXU-CbP0oo 2 2 4 2 0
2010-06-22 23:18:27 +04:00
log_error ( " Incompatible metadata area header version: %d on %s "
" at offset % " PRIu64 , mdah - > version ,
dev_name ( dev_area - > dev ) , dev_area - > start ) ;
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: % "
Add device name to output of error messages in raw_read_mda_header().
It would be helpful if we had the device name when something like
a mda_header checksum error occurs.
Before:
./tools/lvm pvs -opv_name,vg_name,uuid,mda_count,pv_mda_count_ignored,vg_mda_count,vg_mda_count_ignored,vg_mda_copies
Incorrect metadata area header checksum
PV VG PV UUID #PMda #PMdaIgn #VMda #VMdaIgn #VMdaCps
/dev/loop0 vgtest2 sVv26t-gjpb-Rcau-uBDO-Cx04-GbRR-6Ssq7e 2 0 4 0 4
/dev/loop1 vgtest2 zXWStT-qE8F-mbkc-RfgH-aytv-mptF-Y5Ce09 2 0 4 0 4
/dev/loop2 riCpK9-9G8r-LlIp-i2oh-mb3N-CUzk-u5YpuR 1 0 0 0 0
/dev/loop3 vgtest tQCUjm-rmyd-i92d-4eeE-UYBW-v1vQ-kRaA17 2 0 4 2 0
/dev/loop4 vgtest ZRvpeI-p8F1-ccVW-BBac-xhl1-aGXU-CbP0oo 2 2 4 2 0
After:
./tools/lvm pvs -opv_name,vg_name,uuid,mda_count,pv_mda_count_ignored,vg_mda_count,vg_mda_count_ignored,vg_mda_copies
Incorrect metadata area header checksum on /dev/loop2 at offset 4096
PV VG PV UUID #PMda #PMdaIgn #VMda #VMdaIgn #VMdaCps
/dev/loop0 vgtest2 sVv26t-gjpb-Rcau-uBDO-Cx04-GbRR-6Ssq7e 2 0 4 0 4
/dev/loop1 vgtest2 zXWStT-qE8F-mbkc-RfgH-aytv-mptF-Y5Ce09 2 0 4 0 4
/dev/loop2 riCpK9-9G8r-LlIp-i2oh-mb3N-CUzk-u5YpuR 1 0 0 0 0
/dev/loop3 vgtest tQCUjm-rmyd-i92d-4eeE-UYBW-v1vQ-kRaA17 2 0 4 2 0
/dev/loop4 vgtest ZRvpeI-p8F1-ccVW-BBac-xhl1-aGXU-CbP0oo 2 2 4 2 0
2010-06-22 23:18:27 +04:00
PRIu64 " on %s at offset % " PRIu64 , mdah - > start ,
dev_name ( dev_area - > dev ) , dev_area - > 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 ) ;
2010-09-27 23:09:34 +04:00
mdah - > checksum_xl = xlate32 ( calc_crc ( INITIAL_CRC , ( uint8_t * ) mdah - > magic ,
2002-11-18 17:04:08 +03:00
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 ;
2010-07-09 19:34:40 +04: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
2010-04-14 17:09:16 +04:00
/* Do not check non-existent metadata. */
if ( ! rlocn - > offset & & ! rlocn - > size )
return NULL ;
/*
* Don ' t try to check existing metadata
* if given vgname is an empty string .
*/
if ( ! * vgname )
return rlocn ;
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 ) ) & &
2010-04-14 17:09:16 +04:00
( isspace ( vgnamebuf [ len ] ) | | vgnamebuf [ len ] = = ' { ' ) )
2005-04-06 22:59:55 +04:00
return rlocn ;
2010-04-14 17:09:16 +04:00
else
log_debug ( " Volume group name found in metadata does "
" not match expected name %s. " , vgname ) ;
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
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
if ( ! ( mdah = raw_read_mda_header ( fid - > fmt , dev_area ) ) )
2008-01-30 16:19:47 +03:00
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
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
if ( ! ( mdah = raw_read_mda_header ( fid - > fmt , area ) ) )
2008-01-30 16:19:47 +03:00
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 " ,
2010-10-26 13:13:13 +04:00
vgname ) ;
2002-11-18 17:04:08 +03:00
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 :
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 ;
2010-06-29 00:30:30 +04:00
struct volume_group * vg ;
if ( ! dev_open ( mdac - > area . dev ) )
return_NULL ;
vg = _vg_read_raw_area ( fid , vgname , & mdac - > area , 0 ) ;
if ( ! dev_close ( mdac - > area . dev ) )
stack ;
2002-11-18 17:04:08 +03:00
2010-06-29 00:30:30 +04:00
return vg ;
2005-04-06 22:59:55 +04:00
}
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 ;
2010-06-29 00:30:30 +04:00
struct volume_group * vg ;
2005-04-06 22:59:55 +04:00
2010-06-29 00:30:30 +04:00
if ( ! dev_open ( mdac - > area . dev ) )
return_NULL ;
vg = _vg_read_raw_area ( fid , vgname , & mdac - > area , 1 ) ;
if ( ! dev_close ( mdac - > area . dev ) )
stack ;
return vg ;
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
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
if ( ! ( mdah = raw_read_mda_header ( fid - > fmt , & mdac - > area ) ) )
2008-01-30 16:19:47 +03:00
goto_out ;
2002-11-18 17:04:08 +03:00
2010-04-14 17:09:16 +04:00
rlocn = _find_vg_rlocn ( & mdac - > area , mdah ,
vg - > old_name ? vg - > old_name : 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
}
2010-09-27 23:09:34 +04:00
mdac - > rlocn . checksum = calc_crc ( INITIAL_CRC , ( uint8_t * ) 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 ,
2010-09-27 23:09:34 +04:00
( uint8_t * ) fidtc - > raw_metadata_buf +
2005-10-23 04:14:48 +04:00
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 ;
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
if ( ! ( mdah = raw_read_mda_header ( fid - > fmt , & mdac - > area ) ) )
2008-01-30 16:19:47 +03:00
goto_out ;
2002-11-18 17:04:08 +03:00
2010-04-14 17:09:16 +04:00
if ( ! ( rlocn = _find_vg_rlocn ( & mdac - > area , mdah ,
vg - > old_name ? vg - > old_name : 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
2010-06-29 00:31:18 +04:00
rlocn_set_ignored ( mdah - > raw_locns , mda_is_ignored ( mda ) ) ;
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
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
if ( ! ( mdah = raw_read_mda_header ( fid - > fmt , & mdac - > area ) ) )
2008-01-30 16:19:47 +03:00
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 ;
2010-06-29 00:31:18 +04:00
rlocn_set_ignored ( mdah - > raw_locns , mda_is_ignored ( mda ) ) ;
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 :
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 ) ) {
2010-12-08 23:50:48 +03:00
free_vg ( 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
}
2010-07-09 19:34:40 +04:00
static int _vg_write_file ( struct format_instance * fid __attribute__ ( ( unused ) ) ,
2007-08-22 18:38:18 +04:00
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 ;
}
2010-07-09 19:34:40 +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 ;
}
2010-07-09 19:34:40 +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
}
2010-12-11 01:39:52 +03:00
static int _scan_file ( const struct format_type * fmt , const char * vgname )
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 ;
2011-02-21 15:07:03 +03:00
struct format_instance_ctx fic ;
2002-11-18 17:04:08 +03:00
char path [ PATH_MAX ] ;
2010-12-11 01:39:52 +03:00
char * scanned_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 ) ) {
2010-12-11 01:39:52 +03:00
scanned_vgname = dirent - > d_name ;
/* If vgname supplied, only scan that one VG */
if ( vgname & & strcmp ( vgname , scanned_vgname ) )
continue ;
2006-08-21 16:54:53 +04:00
if ( dm_snprintf ( path , PATH_MAX , " %s/%s " ,
2010-12-11 01:39:52 +03:00
dl - > dir , scanned_vgname ) < 0 ) {
2002-11-18 17:04:08 +03:00
log_error ( " Name too long %s/%s " ,
2010-12-11 01:39:52 +03:00
dl - > dir , scanned_vgname ) ;
2002-11-18 17:04:08 +03:00
break ;
}
/* FIXME stat file to see if it's changed */
2011-02-21 15:07:03 +03:00
/* FIXME: Check this fid is OK! */
fic . type = FMT_INSTANCE_VG | FMT_INSTANCE_PRIVATE_MDAS ;
fic . context . private = NULL ;
fid = _text_create_text_instance ( fmt , & fic ) ;
2010-12-11 01:39:52 +03:00
if ( ( vg = _vg_read_file_name ( fid , scanned_vgname ,
2010-09-30 18:12:14 +04:00
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 ) ;
2010-12-08 23:50:48 +03:00
free_vg ( vg ) ;
2010-09-30 18:12:14 +04:00
}
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 ,
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
struct mda_header * mdah ,
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 ;
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 ;
2010-07-09 19:34:40 +04: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
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
if ( ! mdah ) {
log_error ( INTERNAL_ERROR " vgname_from_mda called with NULL pointer for mda_header " ) ;
2006-04-11 17:55:59 +04:00
goto_out ;
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
}
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 :
2006-04-11 17:55:59 +04:00
return vgname ;
2002-02-22 14:44:56 +03:00
}
2010-12-11 01:39:52 +03:00
static int _scan_raw ( const struct format_type * fmt , const char * vgname __attribute__ ( ( unused ) ) )
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 ;
2010-12-11 01:39:52 +03:00
const char * scanned_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 ;
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
struct mda_header * mdah ;
2002-11-18 17:04:08 +03:00
raw_list = & ( ( struct mda_lists * ) fmt - > private ) - > raws ;
fid . fmt = fmt ;
2010-06-29 00:32:44 +04:00
dm_list_init ( & fid . metadata_areas_in_use ) ;
2010-06-29 00:33:22 +04:00
dm_list_init ( & fid . metadata_areas_ignored ) ;
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... */
2010-06-29 00:30:46 +04:00
if ( ! dev_open ( rl - > dev_area . dev ) ) {
stack ;
continue ;
}
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
if ( ! ( mdah = raw_read_mda_header ( fmt , & rl - > dev_area ) ) ) {
stack ;
goto close_dev ;
}
2010-12-11 01:39:52 +03:00
if ( ( scanned_vgname = vgname_from_mda ( fmt , mdah ,
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
& rl - > dev_area , & vgid , & vgstatus ,
2007-11-05 20:17:55 +03:00
NULL , NULL ) ) ) {
2010-12-11 01:39:52 +03:00
vg = _vg_read_raw_area ( & fid , scanned_vgname , & rl - > dev_area , 0 ) ;
2010-06-29 00:30:30 +04:00
if ( vg )
2008-03-17 19:51:31 +03:00
lvmcache_update_vg ( vg , 0 ) ;
2010-06-29 00:30:30 +04:00
2002-11-18 17:04:08 +03:00
}
Allow raw_read_mda_header to be called from text_label.c.
We'd like to pass in mda_header to vgname_from_mda(). In order to
do this, we need to call raw_read_mda_header() from text_label.c,
_text_read(), which gets called from the label_read() path, and
peers into the metadata and update vginfo cache. We should check
the disable bit here, and if set, not peer into the vg metadata,
thus reducing the I/O to disk.
In the process, move vgname_from_mda() to layout.h, since the fn
only gets called from format_text code, and we need the mda_header
definition from the private layout.h.
Signed-off-by: Dave Wysochanski <dwysocha@redhat.com>
2010-06-29 00:31:01 +04:00
close_dev :
2010-06-29 00:30:46 +04:00
if ( ! dev_close ( rl - > dev_area . dev ) )
stack ;
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
}
2010-12-11 01:39:52 +03:00
static int _text_scan ( const struct format_type * fmt , const char * vgname )
2002-11-18 17:04:08 +03:00
{
2010-12-11 01:39:52 +03:00
return ( _scan_file ( fmt , vgname ) & _scan_raw ( fmt , vgname ) ) ;
2002-11-18 17:04:08 +03:00
}
/* Only for orphans */
2011-02-21 15:26:27 +03:00
static int _text_pv_write ( const struct format_type * fmt , struct physical_volume * pv )
2002-11-18 17:04:08 +03:00
{
2011-02-21 15:26:27 +03:00
struct text_fid_pv_context * fid_pv_tc ;
struct format_instance * fid = pv - > fid ;
2011-02-21 15:31:28 +03:00
const char * pvid = ( const char * ) ( * pv - > old_id . uuid ? & pv - > old_id : & pv - > id ) ;
2002-11-18 17:04:08 +03:00
struct label * label ;
2011-02-21 15:26:27 +03:00
int64_t label_sector ;
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 ;
2011-02-21 15:26:27 +03:00
unsigned mda_index ;
2010-07-09 19:34:40 +04: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 ;
2009-07-31 01:15:17 +04:00
struct data_area_list * da ;
2002-11-18 17:04:08 +03:00
2011-02-21 15:26:27 +03:00
/* Add a new cache entry with PV info or update existing one. */
if ( ! ( info = lvmcache_add ( fmt - > labeller , ( const char * ) & pv - > id ,
2011-02-28 20:05:48 +03:00
pv - > dev , pv - > vg_name , NULL , 0 ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2011-02-21 15:26:27 +03:00
2002-11-18 17:04:08 +03:00
label = info - > label ;
2011-02-21 15:26:27 +03:00
/*
* We can change the label sector for a
* plain PV that is not part of a VG only !
*/
if ( fid & & ( ! fid - > type & FMT_INSTANCE_VG ) & &
( fid_pv_tc = ( struct text_fid_pv_context * ) pv - > fid - > private ) & &
( ( label_sector = fid_pv_tc - > label_sector ) ! = - 1 ) )
2002-11-18 17:04:08 +03:00
label - > sector = label_sector ;
info - > device_size = pv - > size < < SECTOR_SHIFT ;
info - > fmt = fmt ;
2011-02-21 15:26:27 +03:00
/* Flush all cached metadata areas, we will reenter new/modified ones. */
if ( info - > mdas . n )
del_mdas ( & info - > mdas ) ;
else
2008-11-04 01:14:30 +03:00
dm_list_init ( & info - > mdas ) ;
2011-02-21 15:26:27 +03:00
/*
* Add all new or modified metadata areas for this PV stored in
* its format instance . If this PV is not part of a VG yet ,
* pv - > fid will be used . Otherwise pv - > vg - > fid will be used .
* The fid_get_mda_indexed fn can handle that transparently ,
* just pass the right format_instance in .
*/
for ( mda_index = 0 ; mda_index < FMT_TEXT_MAX_MDAS_PER_PV ; mda_index + + ) {
2011-02-21 15:31:28 +03:00
if ( ! ( mda = fid_get_mda_indexed ( fid , pvid , ID_LEN , mda_index ) ) )
2011-02-21 15:26:27 +03:00
continue ;
mdac = ( struct mda_context * ) 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 , mda_is_ignored ( mda ) ) ;
2002-11-18 17:04:08 +03:00
}
2009-07-31 01:15:17 +04:00
/*
2011-02-21 15:26:27 +03:00
* FIXME : Allow writing zero offset / size data area to disk .
* This requires defining a special value since we can ' t
* write offset / size that is 0 / 0 - this is already reserved
* as a delimiter in data / metadata area area list in PV header
* ( needs exploring compatibility with older lvm2 ) .
*/
/*
* We can ' t actually write pe_start = 0 ( a data area offset )
* in PV header now . We need to replace this value here . This can
* happen with vgcfgrestore with redefined pe_start or
* pvcreate - - restorefile . However , we can can have this value in
* metadata which will override the value in the PV header .
2009-07-31 01:15:17 +04:00
*/
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
2011-02-21 15:26:27 +03:00
if ( ! add_da ( NULL , & info - > das , pv - > pe_start < < SECTOR_SHIFT , UINT64_C ( 0 ) ) )
2008-01-30 16:19:47 +03:00
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 ;
2010-06-29 00:31:18 +04:00
rlocn_set_ignored ( mdah - > raw_locns , mda_is_ignored ( mda ) ) ;
2002-11-18 17:04:08 +03:00
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
}
}
2011-02-21 15:26:27 +03:00
if ( ! label_write ( pv - > dev , info - > label ) ) {
2008-07-17 01:32:38 +04:00
dev_close ( pv - > dev ) ;
return_0 ;
}
2002-11-18 17:04:08 +03:00
2011-02-21 15:26:27 +03:00
/*
* FIXME : We should probably use the format instance ' s metadata
* areas for label_write and only if it ' s successful ,
* update the cache afterwards ?
*/
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 */
2011-02-18 17:16:11 +03:00
if ( ! scan_label_only & & ! critical_section ( ) & & ! 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
/*
2010-06-29 00:31:59 +04:00
* Copy constructor for a metadata_locn .
2010-02-02 19:26:34 +03:00
*/
2010-06-29 00:31:59 +04:00
static void * _metadata_locn_copy_raw ( struct dm_pool * mem , void * metadata_locn )
2010-02-02 19:26:34 +03:00
{
struct mda_context * mdac , * mdac_new ;
2010-06-29 00:31:59 +04:00
mdac = ( struct mda_context * ) metadata_locn ;
2010-02-02 19:26:34 +03:00
if ( ! ( mdac_new = dm_pool_alloc ( mem , sizeof ( * mdac_new ) ) ) ) {
log_error ( " mda_context allocation failed " ) ;
return NULL ;
}
memcpy ( mdac_new , mdac , sizeof ( * mdac ) ) ;
2010-02-16 02:53:15 +03:00
2010-06-29 00:31:59 +04:00
return mdac_new ;
2010-02-02 19:26:34 +03:00
}
2010-06-30 02:37:32 +04:00
/*
* Return a string description of the metadata location .
*/
2010-06-30 17:51:11 +04:00
static const char * _metadata_locn_name_raw ( void * metadata_locn )
2010-06-30 02:37:32 +04:00
{
2010-06-30 17:51:11 +04:00
struct mda_context * mdac = ( struct mda_context * ) metadata_locn ;
2010-06-30 02:37:32 +04:00
return dev_name ( mdac - > area . dev ) ;
}
2010-08-26 16:22:05 +04:00
static uint64_t _metadata_locn_offset_raw ( void * metadata_locn )
2010-06-30 17:51:11 +04:00
{
struct mda_context * mdac = ( struct mda_context * ) metadata_locn ;
return mdac - > area . start ;
}
2010-02-02 19:26:34 +03:00
2008-07-31 14:50:18 +04:00
static int _text_pv_read ( const struct format_type * fmt , const char * pv_name ,
2011-02-21 15:15:59 +03:00
struct physical_volume * pv , int scan_label_only )
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-04-24 22:20:51 +04:00
return 1 ;
2002-02-22 14:44:56 +03:00
}
2011-02-21 15:20:18 +03:00
static int _text_pv_initialise ( const struct format_type * fmt ,
const int64_t label_sector ,
uint64_t pe_start ,
uint32_t extent_count ,
uint32_t extent_size ,
unsigned long data_alignment ,
unsigned long data_alignment_offset ,
struct physical_volume * pv )
{
struct text_fid_pv_context * fid_pv_tc ;
/*
* Try to keep the value of PE start set to a firm value if requested .
* This is usefull when restoring existing PE start value ( backups etc . ) .
*/
if ( pe_start ! = PV_PE_START_CALC )
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_error ( " %s: invalid data alignment of "
" %lu sectors (requested %lu sectors) " ,
pv_dev_name ( pv ) , pv - > pe_align , data_alignment ) ;
return 0 ;
}
if ( set_pe_align_offset ( pv , data_alignment_offset ) ! = data_alignment_offset & &
data_alignment_offset ) {
log_error ( " %s: invalid data alignment offset of "
" %lu sectors (requested %lu sectors) " ,
pv_dev_name ( pv ) , pv - > pe_align_offset , data_alignment_offset ) ;
return 0 ;
}
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 ;
}
if ( pe_start = = PV_PE_START_CALC & & pv - > pe_start < pv - > pe_align )
pv - > pe_start = pv - > pe_align ;
if ( extent_size )
pv - > pe_size = extent_size ;
if ( extent_count )
pv - > pe_count = extent_count ;
if ( ( pv - > pe_start + pv - > pe_count * pv - > pe_size - 1 ) > ( pv - > size < < SECTOR_SHIFT ) ) {
log_error ( " Physical extents end beyond end of device %s. " ,
pv_dev_name ( pv ) ) ;
return 0 ;
}
if ( label_sector ! = - 1 ) {
fid_pv_tc = ( struct text_fid_pv_context * ) pv - > fid - > private ;
fid_pv_tc - > label_sector = label_sector ;
}
return 1 ;
}
2011-03-11 17:38:38 +03:00
static void _text_destroy_instance ( struct format_instance * fid )
2001-11-21 12:20:05 +03:00
{
2011-03-11 17:38:38 +03:00
if ( - - fid - > ref_count < = 1 ) {
if ( fid - > type & FMT_INSTANCE_VG & & fid - > metadata_areas_index . hash )
dm_hash_destroy ( fid - > metadata_areas_index . hash ) ;
dm_pool_destroy ( fid - > mem ) ;
}
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
}
}
2010-12-20 16:32:49 +03:00
static void _text_destroy ( 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
}
2010-12-20 16:32:49 +03:00
dm_free ( 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 ,
2010-06-29 00:31:59 +04:00
. mda_metadata_locn_copy = _metadata_locn_copy_raw ,
2010-06-30 17:51:11 +04:00
. mda_metadata_locn_name = _metadata_locn_name_raw ,
. mda_metadata_locn_offset = _metadata_locn_offset_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 ,
2010-06-29 00:31:38 +04:00
. mda_locns_match = _mda_locns_match_raw
2002-11-18 17:04:08 +03:00
} ;
2006-04-19 19:33:07 +04:00
static int _text_pv_setup ( const struct format_type * fmt ,
2011-02-21 15:24:15 +03:00
struct physical_volume * pv ,
struct volume_group * vg )
2002-11-18 17:04:08 +03:00
{
2011-02-21 15:24:15 +03:00
struct format_instance * fid = pv - > fid ;
2011-02-21 15:31:28 +03:00
const char * pvid = ( const char * ) ( * pv - > old_id . uuid ? & pv - > old_id : & pv - > id ) ;
2011-02-25 16:59:47 +03:00
struct lvmcache_info * info ;
2011-02-21 15:24:15 +03:00
unsigned mda_index ;
2011-03-02 13:23:29 +03:00
struct metadata_area * pv_mda , * pv_mda_copy ;
2011-02-21 15:24:15 +03:00
struct mda_context * pv_mdac ;
2006-11-10 21:24:11 +03:00
uint64_t pe_count ;
2011-02-21 15:24:15 +03:00
uint64_t size_reduction = 0 ;
2002-11-18 17:04:08 +03:00
2011-02-25 16:59:47 +03:00
/* If PV has its own format instance, add mdas from pv->fid to vg->fid. */
if ( pv - > fid ! = vg - > fid ) {
for ( mda_index = 0 ; mda_index < FMT_TEXT_MAX_MDAS_PER_PV ; mda_index + + ) {
if ( ! ( pv_mda = fid_get_mda_indexed ( fid , pvid , ID_LEN , mda_index ) ) )
continue ;
2002-11-18 17:04:08 +03:00
2011-02-25 16:59:47 +03:00
/* Be sure it's not already in VG's format instance! */
2011-03-02 13:23:29 +03:00
if ( ! fid_get_mda_indexed ( vg - > fid , pvid , ID_LEN , mda_index ) ) {
pv_mda_copy = mda_copy ( vg - > fid - > fmt - > cmd - > mem , pv_mda ) ;
fid_add_mda ( vg - > fid , pv_mda_copy , pvid , ID_LEN , mda_index ) ;
}
2011-02-25 16:59:47 +03:00
}
}
/*
* Otherwise , if the PV is already a part of the VG ( pv - > fid = = vg - > fid ) ,
* reread PV mda information from the cache and add it to vg - > fid .
*/
else {
if ( ! ( info = info_from_pvid ( pv - > dev - > pvid , 0 ) ) ) {
log_error ( " PV %s missing from cache " , pv_dev_name ( pv ) ) ;
return 0 ;
}
if ( fmt ! = info - > fmt ) {
log_error ( " PV %s is a different format (seqno %s) " ,
pv_dev_name ( pv ) , info - > fmt - > name ) ;
return 0 ;
}
if ( ! fid_add_mdas ( vg - > fid , & info - > mdas , pvid , ID_LEN ) )
return_0 ;
2011-02-21 15:24:15 +03:00
}
2002-11-18 17:04:08 +03:00
2011-02-21 15:24:15 +03:00
/* If there's the 2nd mda, we need to reduce
* usable size for further pe_count calculation ! */
if ( ( pv_mda = fid_get_mda_indexed ( fid , pvid , ID_LEN , 1 ) ) & &
( pv_mdac = pv_mda - > metadata_locn ) )
size_reduction = pv_mdac - > area . size > > SECTOR_SHIFT ;
2006-10-06 02:02:52 +04:00
2011-02-21 15:24:15 +03:00
/* Destroy old PV-based format instance if it exists. */
if ( ! ( pv - > fid - > type & FMT_INSTANCE_VG ) )
pv - > fmt - > ops - > destroy_instance ( pv - > fid ) ;
2009-02-22 22:00:26 +03:00
2011-02-21 15:24:15 +03:00
/* From now on, VG format instance will be used. */
pv - > fid = vg - > fid ;
2009-07-30 21:45:28 +04:00
2011-02-21 15:24:15 +03:00
/* FIXME Cope with genuine pe_count 0 */
2009-07-30 21:45:28 +04:00
2011-02-21 15:24:15 +03:00
/* 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 + size_reduction ;
2009-07-31 01:15:17 +04:00
2011-02-21 15:24:15 +03:00
/* Recalculate number of extents that will fit */
if ( ! pv - > pe_count ) {
pe_count = ( pv - > size - pv - > pe_start - size_reduction ) /
vg - > extent_size ;
if ( pe_count > UINT32_MAX ) {
log_error ( " PV %s too large for extent size %s. " ,
pv_dev_name ( pv ) ,
display_size ( vg - > cmd , ( uint64_t ) vg - > extent_size ) ) ;
return 0 ;
}
pv - > pe_count = ( uint32_t ) pe_count ;
2002-11-18 17:04:08 +03:00
}
2011-02-21 15:24:15 +03:00
/* Unlike LVM1, we don't store this outside a VG */
/* FIXME Default from config file? vgextend cmdline flag? */
pv - > status | = ALLOCATABLE_PV ;
2002-11-18 17:04:08 +03:00
return 1 ;
}
2011-02-21 15:05:49 +03:00
static int _create_pv_text_instance ( struct format_instance * fid ,
const struct format_instance_ctx * fic )
2002-04-24 22:20:51 +04:00
{
2011-02-21 15:05:49 +03:00
struct text_fid_pv_context * fid_pv_tc ;
struct lvmcache_info * info ;
if ( ! ( fid_pv_tc = ( struct text_fid_pv_context * )
dm_pool_zalloc ( fid - > fmt - > cmd - > mem , sizeof ( * fid_pv_tc ) ) ) ) {
log_error ( " Couldn't allocate text_fid_pv_context. " ) ;
return 0 ;
}
fid_pv_tc - > label_sector = - 1 ;
fid - > private = ( void * ) fid_pv_tc ;
if ( ! ( fid - > metadata_areas_index . array = dm_pool_zalloc ( fid - > fmt - > cmd - > mem ,
FMT_TEXT_MAX_MDAS_PER_PV *
sizeof ( struct metadata_area * ) ) ) ) {
log_error ( " Couldn't allocate format instance metadata index. " ) ;
return 0 ;
}
if ( fic - > type & FMT_INSTANCE_MDAS & &
( info = info_from_pvid ( fic - > context . pv_id , 0 ) ) )
fid_add_mdas ( fid , & info - > mdas , fic - > context . pv_id , ID_LEN ) ;
return 1 ;
}
static int _create_vg_text_instance ( struct format_instance * fid ,
const struct format_instance_ctx * fic )
{
uint32_t type = fic - > type ;
2005-10-23 04:14:48 +04:00
struct text_fid_context * fidtc ;
2010-06-29 00:35:17 +04:00
struct metadata_area * mda ;
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 ;
2010-06-29 00:35:17 +04:00
struct dm_list * dir_list , * raw_list ;
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 ;
2011-02-21 15:05:49 +03:00
const char * vg_name , * vg_id ;
2002-04-24 22:20:51 +04:00
2005-10-23 04:14:48 +04:00
if ( ! ( fidtc = ( struct text_fid_context * )
2011-02-21 15:05:49 +03:00
dm_pool_zalloc ( fid - > fmt - > cmd - > mem , sizeof ( * fidtc ) ) ) ) {
2005-10-23 04:14:48 +04:00
log_error ( " Couldn't allocate text_fid_context. " ) ;
2011-02-21 15:05:49 +03:00
return 0 ;
2005-10-23 04:14:48 +04:00
}
fidtc - > raw_metadata_buf = NULL ;
fid - > private = ( void * ) fidtc ;
2002-04-24 22:20:51 +04:00
2011-02-21 15:05:49 +03:00
if ( type & FMT_INSTANCE_PRIVATE_MDAS ) {
if ( ! ( mda = dm_pool_zalloc ( fid - > fmt - > cmd - > mem , sizeof ( * mda ) ) ) )
return_0 ;
2002-11-18 17:04:08 +03:00
mda - > ops = & _metadata_text_file_backup_ops ;
2011-02-21 15:05:49 +03:00
mda - > metadata_locn = fic - > context . private ;
2010-10-05 21:34:05 +04:00
mda - > status = 0 ;
2011-02-21 15:05:49 +03:00
fid - > metadata_areas_index . hash = NULL ;
fid_add_mda ( fid , mda , NULL , 0 , 0 ) ;
2002-04-24 22:20:51 +04:00
} else {
2011-02-21 15:05:49 +03:00
vg_name = fic - > context . vg_ref . vg_name ;
vg_id = fic - > context . vg_ref . vg_id ;
2002-04-24 22:20:51 +04:00
2011-02-21 15:05:49 +03:00
if ( ! ( fid - > metadata_areas_index . hash = dm_hash_create ( 128 ) ) ) {
log_error ( " Couldn't create metadata index for format "
" instance of VG %s. " , vg_name ) ;
return 0 ;
2002-04-24 22:20:51 +04:00
}
2002-11-18 17:04:08 +03:00
2011-02-21 15:05:49 +03:00
if ( type & FMT_INSTANCE_AUX_MDAS ) {
dir_list = & ( ( struct mda_lists * ) fid - > fmt - > private ) - > dirs ;
dm_list_iterate_items ( dl , dir_list ) {
if ( dm_snprintf ( path , PATH_MAX , " %s/%s " , dl - > dir , vg_name ) < 0 ) {
log_error ( " Name too long %s/%s " , dl - > dir , vg_name ) ;
return 0 ;
}
if ( ! ( mda = dm_pool_zalloc ( fid - > fmt - > cmd - > mem , sizeof ( * mda ) ) ) )
return_0 ;
mda - > ops = & _metadata_text_file_ops ;
mda - > metadata_locn = create_text_context ( fid - > fmt - > cmd , path , NULL ) ;
mda - > status = 0 ;
fid_add_mda ( fid , mda , NULL , 0 , 0 ) ;
}
raw_list = & ( ( struct mda_lists * ) fid - > fmt - > private ) - > raws ;
dm_list_iterate_items ( rl , raw_list ) {
/* FIXME Cache this; rescan below if some missing */
if ( ! _raw_holds_vgname ( fid , & rl - > dev_area , vg_name ) )
continue ;
if ( ! ( mda = dm_pool_zalloc ( fid - > fmt - > cmd - > mem , sizeof ( * mda ) ) ) )
return_0 ;
if ( ! ( mdac = dm_pool_zalloc ( fid - > fmt - > cmd - > mem , sizeof ( * mdac ) ) ) )
return_0 ;
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 ;
mda - > status = 0 ;
/* FIXME MISTAKE? mda->metadata_locn = context; */
fid_add_mda ( fid , mda , NULL , 0 , 0 ) ;
}
2002-11-18 17:04:08 +03:00
}
2011-02-21 15:05:49 +03:00
if ( type & FMT_INSTANCE_MDAS ) {
/* Scan PVs in VG for any further MDAs */
lvmcache_label_scan ( fid - > fmt - > cmd , 0 ) ;
if ( ! ( vginfo = vginfo_from_vgname ( vg_name , vg_id ) ) )
goto_out ;
dm_list_iterate_items ( info , & vginfo - > infos ) {
if ( ! fid_add_mdas ( fid , & info - > mdas , info - > dev - > pvid , ID_LEN ) )
return_0 ;
}
2002-11-18 17:04:08 +03:00
}
2011-02-21 15:05:49 +03:00
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
}
2011-02-21 15:05:49 +03:00
out :
return 1 ;
}
2011-03-02 13:19:14 +03:00
static int _add_metadata_area_to_pv ( struct physical_volume * pv ,
unsigned mda_index ,
uint64_t mda_start ,
uint64_t mda_size ,
unsigned mda_ignored )
2011-02-21 15:17:26 +03:00
{
struct metadata_area * mda ;
struct mda_context * mdac ;
struct mda_lists * mda_lists = ( struct mda_lists * ) pv - > fmt - > private ;
if ( mda_index > = FMT_TEXT_MAX_MDAS_PER_PV ) {
log_error ( INTERNAL_ERROR " can't add metadata area with "
" index %u to PV %s. Metadata "
" layout not supported by %s format. " ,
mda_index , dev_name ( pv - > dev ) ,
pv - > fmt - > name ) ;
}
if ( ! ( mda = dm_malloc ( sizeof ( struct metadata_area ) ) ) ) {
log_error ( " struct metadata_area allocation failed " ) ;
return 0 ;
}
if ( ! ( mdac = dm_malloc ( sizeof ( struct mda_context ) ) ) ) {
log_error ( " struct mda_context allocation failed " ) ;
dm_free ( mda ) ;
return 0 ;
}
mda - > ops = mda_lists - > raw_ops ;
mda - > metadata_locn = mdac ;
mda - > status = 0 ;
mdac - > area . dev = pv - > dev ;
mdac - > area . start = mda_start ;
mdac - > area . size = mda_size ;
mdac - > free_sectors = UINT64_C ( 0 ) ;
memset ( & mdac - > rlocn , 0 , sizeof ( mdac - > rlocn ) ) ;
mda_set_ignored ( mda , mda_ignored ) ;
fid_add_mda ( pv - > fid , mda , ( char * ) & pv - > id , ID_LEN , mda_index ) ;
return 1 ;
}
static int _text_pv_add_metadata_area ( const struct format_type * fmt ,
struct physical_volume * pv ,
int pe_start_locked ,
unsigned mda_index ,
uint64_t mda_size ,
unsigned mda_ignored )
{
struct format_instance * fid = pv - > fid ;
2011-02-21 15:31:28 +03:00
const char * pvid = ( const char * ) ( * pv - > old_id . uuid ? & pv - > old_id : & pv - > id ) ;
2011-02-21 15:17:26 +03:00
uint64_t pe_start , pe_end ;
uint64_t alignment , alignment_offset ;
uint64_t disk_size ;
uint64_t mda_start ;
2011-02-25 16:50:02 +03:00
uint64_t adjustment , limit , tmp_mda_size ;
2011-02-21 15:17:26 +03:00
uint64_t wipe_size = 8 < < SECTOR_SHIFT ;
size_t page_size = lvm_getpagesize ( ) ;
struct metadata_area * mda ;
struct mda_context * mdac ;
2011-02-25 16:50:02 +03:00
const char * limit_name ;
int limit_applied = 0 ;
2011-02-21 15:17:26 +03:00
if ( mda_index > = FMT_TEXT_MAX_MDAS_PER_PV ) {
log_error ( INTERNAL_ERROR " invalid index of value %u used "
" while trying to add metadata area on PV %s. "
" Metadata layout not supported by %s format. " ,
mda_index , pv_dev_name ( pv ) , fmt - > name ) ;
return 0 ;
}
pe_start = pv - > pe_start < < SECTOR_SHIFT ;
alignment = pv - > pe_align < < SECTOR_SHIFT ;
alignment_offset = pv - > pe_align_offset < < SECTOR_SHIFT ;
disk_size = pv - > size < < SECTOR_SHIFT ;
mda_size = mda_size < < SECTOR_SHIFT ;
if ( fid_get_mda_indexed ( fid , pvid , ID_LEN , mda_index ) ) {
log_error ( INTERNAL_ERROR " metadata area with index %u already "
" exists on PV %s. " , mda_index , pv_dev_name ( pv ) ) ;
return 0 ;
}
/* First metadata area at the start of the device. */
if ( mda_index = = 0 ) {
/*
* Try to fit MDA0 end within given pe_start limit if its value
* is locked . If it ' s not locked , count with any existing MDA1 .
* If there ' s no MDA1 , just use disk size as the limit .
*/
2011-02-25 16:50:02 +03:00
if ( pe_start_locked ) {
2011-02-21 15:17:26 +03:00
limit = pe_start ;
2011-02-25 16:50:02 +03:00
limit_name = " pe_start " ;
}
2011-02-21 15:17:26 +03:00
else if ( ( mda = fid_get_mda_indexed ( fid , pvid , ID_LEN , 1 ) ) & &
2011-02-25 16:50:02 +03:00
( mdac = mda - > metadata_locn ) ) {
2011-02-21 15:17:26 +03:00
limit = mdac - > area . start ;
2011-02-25 16:50:02 +03:00
limit_name = " MDA1 start " ;
}
else {
2011-02-21 15:17:26 +03:00
limit = disk_size ;
2011-02-25 16:50:02 +03:00
limit_name = " disk size " ;
}
2011-02-21 15:17:26 +03:00
if ( limit > disk_size )
goto bad ;
mda_start = LABEL_SCAN_SIZE ;
/* Align MDA0 start with page size if possible. */
if ( limit - mda_start > = MDA_SIZE_MIN ) {
if ( ( adjustment = mda_start % page_size ) )
mda_start + = ( page_size - adjustment ) ;
}
/* Align MDA0 end position with given alignment if possible. */
2011-02-25 16:50:02 +03:00
if ( alignment & &
( adjustment = ( mda_start + mda_size ) % alignment ) ) {
tmp_mda_size = mda_size + alignment - adjustment ;
if ( mda_start + tmp_mda_size < = limit )
mda_size = tmp_mda_size ;
2011-02-21 15:17:26 +03:00
}
/* Align MDA0 end position with given alignment offset if possible. */
if ( alignment_offset & &
( ( ( mda_start + mda_size ) % alignment ) = = 0 ) ) {
2011-02-25 16:50:02 +03:00
tmp_mda_size = mda_size + alignment_offset ;
if ( mda_start + tmp_mda_size < = limit )
mda_size = tmp_mda_size ;
2011-02-21 15:17:26 +03:00
}
if ( mda_start + mda_size > limit ) {
/*
* Try to decrease the MDA0 size with twice the
* alignment and then align with given alignment .
* If pe_start is locked , skip this type of
* alignment since it would be useless .
* Check first whether we can apply that !
*/
if ( ! pe_start_locked & &
( ( limit - mda_start ) > alignment * 2 ) ) {
mda_size = limit - mda_start - alignment * 2 ;
if ( ( adjustment = ( mda_start + mda_size ) % alignment ) )
mda_size + = ( alignment - adjustment ) ;
/* Still too much? Then there's nothing else to do. */
if ( mda_start + mda_size > limit )
goto bad ;
}
/* Otherwise, give up and take any usable space. */
/* FIXME: We should probably check for some minimum MDA size here. */
else
mda_size = limit - mda_start ;
2011-02-25 16:50:02 +03:00
limit_applied = 1 ;
2011-02-21 15:17:26 +03:00
}
/*
* If PV ' s pe_start is not locked , update pe_start value with the
* start of the area that follows the MDA0 we ' ve just calculated .
*/
if ( ! pe_start_locked ) {
pe_start = mda_start + mda_size ;
pv - > pe_start = pe_start > > SECTOR_SHIFT ;
}
}
/* Second metadata area at the end of the device. */
else {
/*
* Try to fit MDA1 start within given pe_end or pe_start limit
2011-02-25 16:50:02 +03:00
* if defined or locked . If pe_start is not defined yet , count
* with any existing MDA0 . If MDA0 does not exist , just use
* LABEL_SCAN_SIZE .
2011-02-21 15:17:26 +03:00
*/
pe_end = pv - > pe_count ? ( pv - > pe_start +
pv - > pe_count * pv - > pe_size - 1 ) < < SECTOR_SHIFT
: 0 ;
2011-02-25 16:50:02 +03:00
if ( pe_start | | pe_start_locked ) {
2011-02-21 15:17:26 +03:00
limit = pe_end ? pe_end : pe_start ;
2011-02-25 16:50:02 +03:00
limit_name = pe_end ? " pe_end " : " pe_start " ;
}
2011-02-21 15:17:26 +03:00
else if ( ( mda = fid_get_mda_indexed ( fid , pvid , ID_LEN , 0 ) ) & &
2011-02-25 16:50:02 +03:00
( mdac = mda - > metadata_locn ) ) {
2011-02-21 15:17:26 +03:00
limit = mdac - > area . start + mdac - > area . size ;
2011-02-25 16:50:02 +03:00
limit_name = " MDA0 end " ;
}
else {
2011-02-21 15:17:26 +03:00
limit = LABEL_SCAN_SIZE ;
2011-02-25 16:50:02 +03:00
limit_name = " label scan size " ;
}
2011-02-21 15:17:26 +03:00
2011-02-25 16:50:02 +03:00
if ( limit > disk_size )
2011-02-21 15:17:26 +03:00
goto bad ;
2011-02-25 16:50:02 +03:00
if ( mda_size > disk_size ) {
mda_size = disk_size - limit ;
limit_applied = 1 ;
2011-02-21 15:17:26 +03:00
}
2011-02-25 16:50:02 +03:00
mda_start = disk_size - mda_size ;
/* If MDA1 size is too big, just take any usable space. */
if ( disk_size - mda_size < limit ) {
2011-02-21 15:17:26 +03:00
mda_size = disk_size - limit ;
2011-02-25 16:50:02 +03:00
mda_start = disk_size - mda_size ;
limit_applied = 1 ;
}
/* Otherwise, try to align MDA1 start if possible. */
else if ( alignment & &
( adjustment = mda_start % alignment ) ) {
tmp_mda_size = mda_size + adjustment ;
if ( tmp_mda_size < disk_size & &
disk_size - tmp_mda_size > = limit ) {
mda_size = tmp_mda_size ;
mda_start = disk_size - mda_size ;
}
}
2011-02-21 15:17:26 +03:00
/*
* If PV ' s pe_end not set yet , set it to the end of the
* area that precedes the MDA1 we ' ve just calculated .
* FIXME : do we need to set this ? Isn ' t it always set before ?
*/
/*if (!pe_end) {
pe_end = mda_start ;
pv - > pe_end = pe_end > > SECTOR_SHIFT ;
} */
}
2011-02-25 16:50:02 +03:00
if ( limit_applied )
log_very_verbose ( " Using limited metadata area size on %s "
" with value % " PRIu64 " (limited by %s of "
" % " PRIu64 " ). " , pv_dev_name ( pv ) ,
mda_size , limit_name , limit ) ;
2011-02-21 15:17:26 +03:00
if ( mda_size ) {
/* Wipe metadata area with zeroes. */
if ( ! dev_set ( ( struct device * ) pv - > dev , mda_start ,
( size_t ) ( ( mda_size > wipe_size ) ?
wipe_size : mda_size ) , 0 ) ) {
log_error ( " Failed to wipe new metadata area "
" at the %s of the %s " ,
mda_index ? " end " : " start " ,
pv_dev_name ( pv ) ) ;
return 0 ;
}
/* Finally, add new metadata area to PV's format instance. */
2011-03-02 13:19:14 +03:00
if ( ! _add_metadata_area_to_pv ( pv , mda_index , mda_start ,
mda_size , mda_ignored ) )
2011-02-21 15:17:26 +03:00
return_0 ;
}
return 1 ;
bad :
log_error ( " Not enough space available for metadata area "
" with index %u on PV %s. " , mda_index , pv_dev_name ( pv ) ) ;
return 0 ;
}
2011-03-02 13:19:14 +03:00
static int _remove_metadata_area_from_pv ( struct physical_volume * pv ,
unsigned mda_index )
2011-02-21 15:17:54 +03:00
{
if ( mda_index > = FMT_TEXT_MAX_MDAS_PER_PV ) {
log_error ( INTERNAL_ERROR " can't remove metadata area with "
" index %u from PV %s. Metadata "
" layou not supported by %s format. " ,
mda_index , dev_name ( pv - > dev ) ,
pv - > fmt - > name ) ;
return 0 ;
}
return fid_remove_mda ( pv - > fid , NULL , ( const char * ) & pv - > id ,
ID_LEN , mda_index ) ;
}
static int _text_pv_remove_metadata_area ( const struct format_type * fmt ,
struct physical_volume * pv ,
unsigned mda_index )
{
2011-03-02 13:19:14 +03:00
return _remove_metadata_area_from_pv ( pv , mda_index ) ;
2011-02-21 15:17:54 +03:00
}
2011-02-21 15:27:26 +03:00
static int _text_pv_resize ( const struct format_type * fmt ,
struct physical_volume * pv ,
struct volume_group * vg ,
uint64_t size )
{
struct format_instance * fid = pv - > fid ;
2011-02-21 15:31:28 +03:00
const char * pvid = ( const char * ) ( * pv - > old_id . uuid ? & pv - > old_id : & pv - > id ) ;
2011-02-21 15:27:26 +03:00
struct metadata_area * mda ;
struct mda_context * mdac ;
uint64_t size_reduction ;
uint64_t mda_size ;
unsigned mda_ignored ;
/*
* First , set the new size and update the cache and reset pe_count .
* ( pe_count must be reset otherwise it would be considered as
* a limiting factor while moving the mda ! )
*/
pv - > size = size ;
pv - > pe_count = 0 ;
/* If there's an mda at the end, move it to a new position. */
if ( ( mda = fid_get_mda_indexed ( fid , pvid , ID_LEN , 1 ) ) & &
( mdac = mda - > metadata_locn ) ) {
/* FIXME: Maybe MDA0 size would be better? */
mda_size = mdac - > area . size > > SECTOR_SHIFT ;
mda_ignored = mda_is_ignored ( mda ) ;
if ( ! _text_pv_remove_metadata_area ( fmt , pv , 1 ) | |
! _text_pv_add_metadata_area ( fmt , pv , 1 , 1 , mda_size ,
mda_ignored ) ) {
log_error ( " Failed to move metadata area with index 1 "
" while resizing PV %s. " , pv_dev_name ( pv ) ) ;
return 0 ;
}
}
/* If there's a VG, reduce size by counting in pe_start and metadata areas. */
if ( vg ) {
size_reduction = pv_pe_start ( pv ) ;
if ( ( mda = fid_get_mda_indexed ( fid , pvid , ID_LEN , 1 ) ) & &
( mdac = mda - > metadata_locn ) )
size_reduction + = mdac - > area . size > > SECTOR_SHIFT ;
pv - > size - = size_reduction ;
}
return 1 ;
}
2011-02-21 15:05:49 +03:00
static struct format_instance * _text_create_text_instance ( const struct format_type * fmt ,
2011-03-11 17:30:27 +03:00
const struct format_instance_ctx * fic )
2011-02-21 15:05:49 +03:00
{
struct format_instance * fid ;
2011-03-11 17:30:27 +03:00
if ( ! ( fid = alloc_fid ( fmt , fic ) ) )
return_NULL ;
2011-02-21 15:05:49 +03:00
2011-03-11 17:38:38 +03:00
if ( fid - > type & FMT_INSTANCE_VG ? _create_vg_text_instance ( fid , fic ) :
_create_pv_text_instance ( fid , fic ) )
2011-02-21 15:05:49 +03:00
return fid ;
2011-03-11 17:38:38 +03:00
dm_pool_free ( fmt - > cmd - > mem , fid ) ;
dm_pool_destroy ( fid - > mem ) ;
return NULL ;
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 ;
}
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 ,
2011-02-21 15:20:18 +03:00
. pv_initialise = _text_pv_initialise ,
2006-05-10 01:23:51 +04:00
. pv_setup = _text_pv_setup ,
2011-02-21 15:17:26 +03:00
. pv_add_metadata_area = _text_pv_add_metadata_area ,
2011-02-21 15:17:54 +03:00
. pv_remove_metadata_area = _text_pv_remove_metadata_area ,
2011-02-21 15:27:26 +03:00
. pv_resize = _text_pv_resize ,
2006-05-10 01:23:51 +04:00
. 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 ,
2010-12-20 16:12:55 +03:00
const struct config_node * cn , struct dm_list * raw_list )
2002-11-18 17:04:08 +03:00
{
struct device_area dev_area ;
2010-12-20 16:12:55 +03:00
const char * id_str ;
2002-11-18 17:04:08 +03:00
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 ;
}
2010-03-16 20:30:00 +03:00
if ( ! ( dev_area . dev = device_from_pvid ( cmd , & id , NULL ) ) ) {
2010-07-09 19:34:40 +04: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 ;
2010-12-20 16:12:55 +03:00
const struct config_node * cn ;
const 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 ;
}
2010-12-11 01:39:52 +03:00
cmd - > independent_metadata_areas = 1 ;
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 ;
2010-12-11 01:39:52 +03:00
cmd - > independent_metadata_areas = 1 ;
2004-09-14 21:37:51 +04:00
}
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
}