2001-10-04 21:48:55 +04: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-10-04 21:48:55 +04: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 ,
2016-01-21 13:49:46 +03:00
* Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2001-10-04 21:48:55 +04:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2001-10-04 21:48:55 +04:00
# include "disk-rep.h"
2001-10-08 13:45:16 +04:00
# include "xlate.h"
2003-07-05 02:34:56 +04:00
# include "lvmcache.h"
2013-06-12 14:08:56 +04:00
# include "metadata-exported.h"
2001-10-04 21:48:55 +04:00
2001-11-14 13:01:52 +03:00
# include <fcntl.h>
2001-10-04 21:48:55 +04:00
# define xx16(v) disk->v = xlate16(disk->v)
# define xx32(v) disk->v = xlate32(disk->v)
# define xx64(v) disk->v = xlate64(disk->v)
/*
* Functions to perform the endian conversion
* between disk and core . The same code works
* both ways of course .
*/
2001-10-31 20:59:52 +03:00
static void _xlate_pvd ( struct pv_disk * disk )
2001-10-04 21:48:55 +04:00
{
2001-12-13 03:07:29 +03:00
xx16 ( version ) ;
xx32 ( pv_on_disk . base ) ;
xx32 ( pv_on_disk . size ) ;
xx32 ( vg_on_disk . base ) ;
xx32 ( vg_on_disk . size ) ;
xx32 ( pv_uuidlist_on_disk . base ) ;
xx32 ( pv_uuidlist_on_disk . size ) ;
xx32 ( lv_on_disk . base ) ;
xx32 ( lv_on_disk . size ) ;
xx32 ( pe_on_disk . base ) ;
xx32 ( pe_on_disk . size ) ;
xx32 ( pv_major ) ;
xx32 ( pv_number ) ;
xx32 ( pv_status ) ;
xx32 ( pv_allocatable ) ;
xx32 ( pv_size ) ;
xx32 ( lv_cur ) ;
xx32 ( pe_size ) ;
xx32 ( pe_total ) ;
xx32 ( pe_allocated ) ;
2001-10-04 21:48:55 +04:00
xx32 ( pe_start ) ;
}
2001-10-31 20:59:52 +03:00
static void _xlate_lvd ( struct lv_disk * disk )
2001-10-04 21:48:55 +04:00
{
2001-12-13 03:07:29 +03:00
xx32 ( lv_access ) ;
xx32 ( lv_status ) ;
xx32 ( lv_open ) ;
xx32 ( lv_dev ) ;
xx32 ( lv_number ) ;
xx32 ( lv_mirror_copies ) ;
xx32 ( lv_recovery ) ;
xx32 ( lv_schedule ) ;
xx32 ( lv_size ) ;
xx32 ( lv_snapshot_minor ) ;
xx16 ( lv_chunk_size ) ;
xx16 ( dummy ) ;
xx32 ( lv_allocated_le ) ;
xx32 ( lv_stripes ) ;
xx32 ( lv_stripesize ) ;
xx32 ( lv_badblock ) ;
xx32 ( lv_allocation ) ;
xx32 ( lv_io_timeout ) ;
xx32 ( lv_read_ahead ) ;
2001-10-04 21:48:55 +04:00
}
2001-10-31 20:59:52 +03:00
static void _xlate_vgd ( struct vg_disk * disk )
2001-10-04 21:48:55 +04:00
{
2001-12-13 03:07:29 +03:00
xx32 ( vg_number ) ;
xx32 ( vg_access ) ;
xx32 ( vg_status ) ;
xx32 ( lv_max ) ;
xx32 ( lv_cur ) ;
xx32 ( lv_open ) ;
xx32 ( pv_max ) ;
xx32 ( pv_cur ) ;
xx32 ( pv_act ) ;
xx32 ( dummy ) ;
xx32 ( vgda ) ;
xx32 ( pe_size ) ;
xx32 ( pe_total ) ;
xx32 ( pe_allocated ) ;
xx32 ( pvg_total ) ;
2001-10-04 21:48:55 +04:00
}
2002-12-20 02:25:55 +03:00
static void _xlate_extents ( struct pe_disk * extents , uint32_t count )
2001-10-04 21:48:55 +04:00
{
2006-05-10 01:23:51 +04:00
unsigned i ;
2001-10-05 19:20:40 +04:00
for ( i = 0 ; i < count ; i + + ) {
extents [ i ] . lv_num = xlate16 ( extents [ i ] . lv_num ) ;
extents [ i ] . le_num = xlate16 ( extents [ i ] . le_num ) ;
2001-10-04 21:48:55 +04:00
}
2001-10-05 19:20:40 +04:00
}
2001-10-04 21:48:55 +04:00
2001-10-10 13:36:29 +04:00
/*
* Handle both minor metadata formats .
*/
static int _munge_formats ( struct pv_disk * pvd )
{
uint32_t pe_start ;
2006-05-10 01:23:51 +04:00
unsigned b , e ;
2001-10-10 13:36:29 +04:00
switch ( pvd - > version ) {
case 1 :
2001-10-11 14:08:44 +04:00
pvd - > pe_start = ( ( pvd - > pe_on_disk . base +
2002-11-18 17:01:16 +03:00
pvd - > pe_on_disk . size ) > > SECTOR_SHIFT ) ;
2001-10-10 13:36:29 +04:00
break ;
case 2 :
pvd - > version = 1 ;
2002-11-18 17:01:16 +03:00
pe_start = pvd - > pe_start < < SECTOR_SHIFT ;
2001-10-10 13:36:29 +04:00
pvd - > pe_on_disk . size = pe_start - pvd - > pe_on_disk . base ;
break ;
default :
return 0 ;
}
2008-01-30 17:00:02 +03:00
/* UUID too long? */
if ( pvd - > pv_uuid [ ID_LEN ] ) {
2004-05-04 22:38:11 +04:00
/* Retain ID_LEN chars from end */
2008-01-30 17:00:02 +03:00
for ( e = ID_LEN ; e < sizeof ( pvd - > pv_uuid ) ; e + + ) {
if ( ! pvd - > pv_uuid [ e ] ) {
e - - ;
break ;
}
}
2004-05-04 22:38:11 +04:00
for ( b = 0 ; b < ID_LEN ; b + + ) {
pvd - > pv_uuid [ b ] = pvd - > pv_uuid [ + + e - ID_LEN ] ;
/* FIXME Remove all invalid chars */
if ( pvd - > pv_uuid [ b ] = = ' / ' )
pvd - > pv_uuid [ b ] = ' # ' ;
}
memset ( & pvd - > pv_uuid [ ID_LEN ] , 0 , sizeof ( pvd - > pv_uuid ) - ID_LEN ) ;
2008-01-30 17:00:02 +03:00
}
2004-05-04 22:38:11 +04:00
2004-05-05 01:25:57 +04:00
/* If UUID is missing, create one */
2006-05-10 20:42:03 +04:00
if ( pvd - > pv_uuid [ 0 ] = = ' \0 ' ) {
2006-05-10 01:23:51 +04:00
uuid_from_num ( ( char * ) pvd - > pv_uuid , pvd - > pv_number ) ;
2006-05-10 20:42:03 +04:00
pvd - > pv_uuid [ ID_LEN ] = ' \0 ' ;
}
2004-05-05 01:25:57 +04:00
2001-10-10 13:36:29 +04:00
return 1 ;
}
2008-01-30 17:00:02 +03:00
/*
* If exported , remove " PV_EXP " from end of VG name
2004-05-04 22:38:11 +04:00
*/
static void _munge_exported_vg ( struct pv_disk * pvd )
2001-10-05 19:20:40 +04:00
{
2004-05-04 22:38:11 +04:00
int l ;
size_t s ;
2002-01-16 21:10:08 +03:00
2004-05-04 22:38:11 +04:00
/* Return if PV not in a VG */
if ( ( ! * pvd - > vg_name ) )
return ;
/* FIXME also check vgd->status & VG_EXPORTED? */
2006-05-10 01:23:51 +04:00
l = strlen ( ( char * ) pvd - > vg_name ) ;
2004-05-04 22:38:11 +04:00
s = sizeof ( EXPORTED_TAG ) ;
2006-05-10 01:23:51 +04:00
if ( ! strncmp ( ( char * ) pvd - > vg_name + l - s + 1 , EXPORTED_TAG , s ) ) {
2004-05-04 22:38:11 +04:00
pvd - > vg_name [ l - s + 1 ] = ' \0 ' ;
2008-01-30 17:00:02 +03:00
pvd - > pv_status | = VG_EXPORTED ;
}
2004-05-04 22:38:11 +04:00
}
int munge_pvd ( struct device * dev , struct pv_disk * pvd )
{
2001-10-31 20:59:52 +03:00
_xlate_pvd ( pvd ) ;
2001-10-10 13:36:29 +04:00
2002-01-16 21:10:08 +03:00
if ( pvd - > id [ 0 ] ! = ' H ' | | pvd - > id [ 1 ] ! = ' M ' ) {
2002-11-18 17:01:16 +03:00
log_very_verbose ( " %s does not have a valid LVM1 PV identifier " ,
2002-01-16 21:10:08 +03:00
dev_name ( dev ) ) ;
return 0 ;
}
if ( ! _munge_formats ( pvd ) ) {
2002-11-18 17:01:16 +03:00
log_very_verbose ( " format1: Unknown metadata version %d "
" found on %s " , pvd - > version , dev_name ( dev ) ) ;
2008-09-15 21:06:55 +04:00
return 0 ;
2002-01-16 21:10:08 +03:00
}
2004-05-04 22:38:11 +04:00
/* If VG is exported, set VG name back to the real name */
_munge_exported_vg ( pvd ) ;
2001-10-10 16:45:20 +04:00
return 1 ;
2001-10-04 21:48:55 +04:00
}
2004-05-04 22:38:11 +04:00
static int _read_pvd ( struct device * dev , struct pv_disk * pvd )
{
if ( ! dev_read ( dev , UINT64_C ( 0 ) , sizeof ( * pvd ) , pvd ) ) {
log_very_verbose ( " Failed to read PV data from %s " ,
dev_name ( dev ) ) ;
2008-09-15 21:06:55 +04:00
return 0 ;
2004-05-04 22:38:11 +04:00
}
return munge_pvd ( dev , pvd ) ;
}
2002-12-20 02:25:55 +03:00
static int _read_lvd ( struct device * dev , uint64_t pos , struct lv_disk * disk )
2001-10-04 21:48:55 +04:00
{
2003-07-05 02:34:56 +04:00
if ( ! dev_read ( dev , pos , sizeof ( * disk ) , disk ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-05 19:48:05 +04:00
2001-10-31 20:59:52 +03:00
_xlate_lvd ( disk ) ;
2001-10-05 19:20:40 +04:00
2001-10-04 21:48:55 +04:00
return 1 ;
}
2006-04-11 02:09:00 +04:00
int read_vgd ( struct device * dev , struct vg_disk * vgd , struct pv_disk * pvd )
2001-10-04 21:48:55 +04:00
{
2006-04-11 02:09:00 +04:00
uint64_t pos = pvd - > vg_on_disk . base ;
if ( ! dev_read ( dev , pos , sizeof ( * vgd ) , vgd ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-05 19:48:05 +04:00
2001-10-31 20:59:52 +03:00
_xlate_vgd ( vgd ) ;
2001-10-04 21:48:55 +04:00
2004-05-11 21:18:42 +04:00
if ( ( vgd - > lv_max > MAX_LV ) | | ( vgd - > pv_max > MAX_PV ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2004-05-11 21:18:42 +04:00
2004-01-09 22:18:20 +03:00
/* If UUID is missing, create one */
if ( vgd - > vg_uuid [ 0 ] = = ' \0 ' )
2006-05-10 01:23:51 +04:00
uuid_from_num ( ( char * ) vgd - > vg_uuid , vgd - > vg_number ) ;
2004-01-09 22:18:20 +03:00
2001-10-04 21:48:55 +04:00
return 1 ;
}
2001-10-05 19:20:40 +04:00
static int _read_uuids ( struct disk_list * data )
2001-10-04 21:48:55 +04:00
{
2006-05-10 01:23:51 +04:00
unsigned num_read = 0 ;
2001-10-04 21:48:55 +04:00
struct uuid_list * ul ;
2010-07-09 19:34:40 +04:00
char buffer [ NAME_LEN ] __attribute__ ( ( aligned ( 8 ) ) ) ;
2002-12-20 02:25:55 +03:00
uint64_t pos = data - > pvd . pv_uuidlist_on_disk . base ;
uint64_t end = pos + data - > pvd . pv_uuidlist_on_disk . size ;
2001-10-04 21:48:55 +04:00
2001-12-13 03:07:29 +03:00
while ( pos < end & & num_read < data - > vgd . pv_cur ) {
2003-07-05 02:34:56 +04:00
if ( ! dev_read ( data - > dev , pos , sizeof ( buffer ) , buffer ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-04 21:48:55 +04:00
2005-10-17 03:03:59 +04:00
if ( ! ( ul = dm_pool_alloc ( data - > mem , sizeof ( * ul ) ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-04 21:48:55 +04:00
memcpy ( ul - > uuid , buffer , NAME_LEN ) ;
2001-11-28 02:12:06 +03:00
ul - > uuid [ NAME_LEN - 1 ] = ' \0 ' ;
2001-10-04 21:48:55 +04:00
2008-11-04 01:14:30 +03:00
dm_list_add ( & data - > uuids , & ul - > list ) ;
2001-10-04 21:48:55 +04:00
pos + = NAME_LEN ;
num_read + + ;
}
2001-10-05 19:20:40 +04:00
2001-10-04 21:48:55 +04:00
return 1 ;
}
2006-04-19 19:33:07 +04:00
static int _check_lvd ( struct lv_disk * lvd )
2001-10-11 14:08:44 +04:00
{
2001-11-13 21:52:52 +03:00
return ! ( lvd - > lv_name [ 0 ] = = ' \0 ' ) ;
2001-10-11 14:08:44 +04:00
}
2001-10-05 19:20:40 +04:00
static int _read_lvs ( struct disk_list * data )
2001-10-04 21:48:55 +04:00
{
2008-11-03 19:26:27 +03:00
unsigned int i , lvs_read = 0 ;
2002-12-20 02:25:55 +03:00
uint64_t pos ;
2001-10-08 13:45:16 +04:00
struct lvd_list * ll ;
2001-11-13 21:52:52 +03:00
struct vg_disk * vgd = & data - > vgd ;
2001-10-04 21:48:55 +04:00
2008-11-03 19:26:27 +03:00
for ( i = 0 ; ( i < vgd - > lv_max ) & & ( lvs_read < vgd - > lv_cur ) ; i + + ) {
2001-10-31 20:59:52 +03:00
pos = data - > pvd . lv_on_disk . base + ( i * sizeof ( struct lv_disk ) ) ;
2005-10-17 03:03:59 +04:00
ll = dm_pool_alloc ( data - > mem , sizeof ( * ll ) ) ;
2001-10-04 21:48:55 +04:00
2001-10-05 19:48:05 +04:00
if ( ! ll )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-04 21:48:55 +04:00
2001-10-31 20:59:52 +03:00
if ( ! _read_lvd ( data - > dev , pos , & ll - > lvd ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-04 21:48:55 +04:00
2001-10-31 20:59:52 +03:00
if ( ! _check_lvd ( & ll - > lvd ) )
2001-11-13 21:52:52 +03:00
continue ;
2001-10-11 14:08:44 +04:00
2008-11-03 19:26:27 +03:00
lvs_read + + ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & data - > lvds , & ll - > list ) ;
2001-10-04 21:48:55 +04:00
}
return 1 ;
}
2001-10-05 19:20:40 +04:00
static int _read_extents ( struct disk_list * data )
2001-10-04 21:48:55 +04:00
{
2001-10-31 20:59:52 +03:00
size_t len = sizeof ( struct pe_disk ) * data - > pvd . pe_total ;
2005-10-17 03:03:59 +04:00
struct pe_disk * extents = dm_pool_alloc ( data - > mem , len ) ;
2002-12-20 02:25:55 +03:00
uint64_t pos = data - > pvd . pe_on_disk . base ;
2001-10-04 21:48:55 +04:00
2001-10-05 19:48:05 +04:00
if ( ! extents )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-05 19:48:05 +04:00
2003-07-05 02:34:56 +04:00
if ( ! dev_read ( data - > dev , pos , len , extents ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-04 21:48:55 +04:00
2001-10-31 20:59:52 +03:00
_xlate_extents ( extents , data - > pvd . pe_total ) ;
2001-10-04 21:48:55 +04:00
data - > extents = extents ;
2001-10-05 19:20:40 +04:00
2001-10-04 21:48:55 +04:00
return 1 ;
}
2006-04-11 02:09:00 +04:00
static void __update_lvmcache ( const struct format_type * fmt ,
struct disk_list * dl ,
2006-04-11 21:42:15 +04:00
struct device * dev , const char * vgid ,
2006-05-10 01:23:51 +04:00
unsigned exported )
2006-04-11 02:09:00 +04:00
{
struct lvmcache_info * info ;
2008-02-06 18:47:28 +03:00
const char * vgname = * ( ( char * ) dl - > pvd . vg_name ) ?
( char * ) dl - > pvd . vg_name : fmt - > orphan_vg_name ;
2006-04-11 02:09:00 +04:00
2006-05-10 01:23:51 +04:00
if ( ! ( info = lvmcache_add ( fmt - > labeller , ( char * ) dl - > pvd . pv_uuid , dev ,
2008-02-06 18:47:28 +03:00
vgname , vgid , exported ? EXPORTED_VG : 0 ) ) ) {
2006-04-11 02:09:00 +04:00
stack ;
return ;
}
2012-08-16 22:07:30 +04:00
lvmcache_set_device_size ( info , ( ( uint64_t ) xlate32 ( dl - > pvd . pv_size ) ) < < SECTOR_SHIFT ) ;
2012-02-10 05:28:27 +04:00
lvmcache_del_mdas ( info ) ;
lvmcache_make_valid ( info ) ;
2006-04-11 02:09:00 +04:00
}
2002-12-20 02:25:55 +03:00
static struct disk_list * __read_disk ( const struct format_type * fmt ,
2005-10-17 03:03:59 +04:00
struct device * dev , struct dm_pool * mem ,
2001-11-14 13:01:52 +03:00
const char * vg_name )
2001-10-04 21:48:55 +04:00
{
2006-04-11 02:09:00 +04:00
struct disk_list * dl = dm_pool_zalloc ( mem , sizeof ( * dl ) ) ;
2001-10-25 18:04:18 +04:00
const char * name = dev_name ( dev ) ;
2008-01-30 16:19:47 +03:00
if ( ! dl )
return_NULL ;
2001-11-12 19:00:52 +03:00
2002-04-24 22:20:51 +04:00
dl - > dev = dev ;
dl - > mem = mem ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & dl - > uuids ) ;
dm_list_init ( & dl - > lvds ) ;
2001-10-05 19:20:40 +04:00
2007-04-26 20:44:59 +04:00
if ( ! _read_pvd ( dev , & dl - > pvd ) )
2008-09-19 11:03:23 +04:00
goto_bad ;
2001-10-10 16:45:20 +04:00
2001-10-10 16:28:10 +04:00
/*
* is it an orphan ?
*/
2002-04-24 22:20:51 +04:00
if ( ! * dl - > pvd . vg_name ) {
log_very_verbose ( " %s is not a member of any format1 VG " , name ) ;
2002-01-29 20:23:33 +03:00
2008-02-06 18:47:28 +03:00
__update_lvmcache ( fmt , dl , dev , fmt - > orphan_vg_name , 0 ) ;
2002-04-24 22:20:51 +04:00
return ( vg_name ) ? NULL : dl ;
2001-10-10 16:45:20 +04:00
}
2001-10-10 16:28:10 +04:00
2006-04-11 02:09:00 +04:00
if ( ! read_vgd ( dl - > dev , & dl - > vgd , & dl - > pvd ) ) {
2002-01-29 20:23:33 +03:00
log_error ( " Failed to read VG data from PV (%s) " , name ) ;
2008-02-06 18:47:28 +03:00
__update_lvmcache ( fmt , dl , dev , fmt - > orphan_vg_name , 0 ) ;
2001-10-05 19:20:40 +04:00
goto bad ;
2001-10-04 21:48:55 +04:00
}
2006-05-10 01:23:51 +04:00
if ( vg_name & & strcmp ( vg_name , ( char * ) dl - > pvd . vg_name ) ) {
2002-01-29 20:23:33 +03:00
log_very_verbose ( " %s is not a member of the VG %s " ,
name , vg_name ) ;
2008-02-06 18:47:28 +03:00
__update_lvmcache ( fmt , dl , dev , fmt - > orphan_vg_name , 0 ) ;
2001-10-05 19:20:40 +04:00
goto bad ;
2001-10-04 21:48:55 +04:00
}
2006-05-10 01:23:51 +04:00
__update_lvmcache ( fmt , dl , dev , ( char * ) dl - > vgd . vg_uuid ,
2006-04-11 21:42:15 +04:00
dl - > vgd . vg_status & VG_EXPORTED ) ;
2006-04-11 02:09:00 +04:00
2002-04-24 22:20:51 +04:00
if ( ! _read_uuids ( dl ) ) {
2001-10-25 18:04:18 +04:00
log_error ( " Failed to read PV uuid list from %s " , name ) ;
2001-10-05 19:20:40 +04:00
goto bad ;
2001-10-04 21:48:55 +04:00
}
2002-04-24 22:20:51 +04:00
if ( ! _read_lvs ( dl ) ) {
2001-10-25 18:04:18 +04:00
log_error ( " Failed to read LV's from %s " , name ) ;
2001-10-05 19:20:40 +04:00
goto bad ;
2001-10-04 21:48:55 +04:00
}
2002-04-24 22:20:51 +04:00
if ( ! _read_extents ( dl ) ) {
2001-10-25 18:04:18 +04:00
log_error ( " Failed to read extents from %s " , name ) ;
2001-10-05 19:20:40 +04:00
goto bad ;
2001-10-04 21:48:55 +04:00
}
2002-04-24 22:20:51 +04:00
log_very_verbose ( " Found %s in %sVG %s " , name ,
( dl - > vgd . vg_status & VG_EXPORTED ) ? " exported " : " " ,
dl - > pvd . vg_name ) ;
2001-10-29 16:52:23 +03:00
2002-04-24 22:20:51 +04:00
return dl ;
2001-10-05 19:20:40 +04:00
2001-12-13 03:07:29 +03:00
bad :
2005-10-17 03:03:59 +04:00
dm_pool_free ( dl - > mem , dl ) ;
2001-10-05 19:20:40 +04:00
return NULL ;
2001-10-04 21:48:55 +04:00
}
2002-12-20 02:25:55 +03:00
struct disk_list * read_disk ( const struct format_type * fmt , struct device * dev ,
2005-10-17 03:03:59 +04:00
struct dm_pool * mem , const char * vg_name )
2001-11-14 13:01:52 +03:00
{
2007-11-02 23:40:05 +03:00
struct disk_list * dl ;
2001-11-14 13:01:52 +03:00
2011-05-28 13:48:14 +04:00
if ( ! dev_open_readonly ( dev ) )
2008-01-30 16:19:47 +03:00
return_NULL ;
2001-11-14 13:01:52 +03:00
2007-11-02 23:40:05 +03:00
dl = __read_disk ( fmt , dev , mem , vg_name ) ;
2001-11-14 13:01:52 +03:00
if ( ! dev_close ( dev ) )
stack ;
2007-11-02 23:40:05 +03:00
return dl ;
2001-11-14 13:01:52 +03:00
}
2013-06-12 14:08:56 +04:00
static void _add_pv_to_list ( struct cmd_context * cmd , struct dm_list * head , struct disk_list * data )
2002-01-24 16:36:33 +03:00
{
struct pv_disk * pvd ;
2005-06-01 20:51:55 +04:00
struct disk_list * diskl ;
2002-01-24 16:36:33 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( diskl , head ) {
2005-06-01 20:51:55 +04:00
pvd = & diskl - > pvd ;
2006-05-10 01:23:51 +04:00
if ( ! strncmp ( ( char * ) data - > pvd . pv_uuid , ( char * ) pvd - > pv_uuid ,
2002-01-24 16:36:33 +03:00
sizeof ( pvd - > pv_uuid ) ) ) {
2013-06-12 14:08:56 +04:00
if ( ! dev_subsystem_part_major ( cmd - > dev_types , data - > dev ) ) {
2002-01-28 00:30:47 +03:00
log_very_verbose ( " Ignoring duplicate PV %s on "
2002-04-24 22:20:51 +04:00
" %s " , pvd - > pv_uuid ,
2002-01-28 00:30:47 +03:00
dev_name ( data - > dev ) ) ;
2002-01-24 16:36:33 +03:00
return ;
}
2009-10-27 20:00:44 +03:00
log_very_verbose ( " Duplicate PV %s - using %s %s " ,
2013-06-12 14:08:56 +04:00
pvd - > pv_uuid , dev_subsystem_name ( cmd - > dev_types , data - > dev ) ,
2009-10-27 20:00:44 +03:00
dev_name ( data - > dev ) ) ;
2008-11-04 01:14:30 +03:00
dm_list_del ( & diskl - > list ) ;
2002-01-24 16:36:33 +03:00
break ;
}
}
2008-11-04 01:14:30 +03:00
dm_list_add ( head , & data - > list ) ;
2002-01-24 16:36:33 +03:00
}
2012-02-10 05:28:27 +04:00
struct _read_pvs_in_vg_baton {
const char * vg_name ;
struct dm_list * head ;
struct disk_list * data ;
struct dm_pool * mem ;
int empty ;
} ;
static int _read_pv_in_vg ( struct lvmcache_info * info , void * baton )
{
struct _read_pvs_in_vg_baton * b = baton ;
b - > empty = 0 ;
if ( ! lvmcache_device ( info ) | |
! ( b - > data = read_disk ( lvmcache_fmt ( info ) , lvmcache_device ( info ) , b - > mem , b - > vg_name ) ) )
return 0 ; /* stop here */
2013-06-12 14:08:56 +04:00
_add_pv_to_list ( lvmcache_fmt ( info ) - > cmd , b - > head , b - > data ) ;
2012-02-10 05:28:27 +04:00
return 1 ;
}
2001-10-04 21:48:55 +04:00
/*
2002-01-10 21:12:26 +03:00
* Build a list of pv_d ' s structures , allocated from mem .
2006-08-01 18:56:33 +04:00
* We keep track of the first object allocated from the pool
2001-12-13 03:07:29 +03:00
* so we can free off all the memory if something goes wrong .
2001-10-04 21:48:55 +04:00
*/
2002-12-20 02:25:55 +03:00
int read_pvs_in_vg ( const struct format_type * fmt , const char * vg_name ,
2005-10-17 03:03:59 +04:00
struct dev_filter * filter , struct dm_pool * mem ,
2008-11-04 01:14:30 +03:00
struct dm_list * head )
2001-10-04 21:48:55 +04:00
{
2001-12-13 18:08:58 +03:00
struct dev_iter * iter ;
2001-10-04 21:48:55 +04:00
struct device * dev ;
2003-07-05 02:34:56 +04:00
struct lvmcache_vginfo * vginfo ;
2012-02-10 05:28:27 +04:00
struct _read_pvs_in_vg_baton baton ;
baton . head = head ;
baton . empty = 1 ;
baton . data = NULL ;
baton . mem = mem ;
baton . vg_name = vg_name ;
2001-12-13 03:07:29 +03:00
/* Fast path if we already saw this VG and cached the list of PVs */
2012-02-10 05:28:27 +04:00
if ( vg_name & & ( vginfo = lvmcache_vginfo_from_vgname ( vg_name , NULL ) ) ) {
lvmcache_foreach_pv ( vginfo , _read_pv_in_vg , & baton ) ;
2001-12-13 03:07:29 +03:00
2012-02-10 05:28:27 +04:00
if ( ! baton . empty ) {
/* Did we find the whole VG? */
if ( ! vg_name | | is_orphan_vg ( vg_name ) | |
( baton . data & & * baton . data - > pvd . vg_name & &
dm_list_size ( head ) = = baton . data - > vgd . pv_cur ) )
return 1 ;
2001-12-13 03:07:29 +03:00
2012-02-10 05:28:27 +04:00
/* Failed */
dm_list_init ( head ) ;
/* vgcache_del(vg_name); */
}
2001-12-13 03:07:29 +03:00
}
2005-03-08 16:46:17 +03:00
if ( ! ( iter = dev_iter_create ( filter , 1 ) ) ) {
2001-12-13 18:08:58 +03:00
log_error ( " read_pvs_in_vg: dev_iter_create failed " ) ;
return 0 ;
}
2001-12-13 03:07:29 +03:00
/* Otherwise do a complete scan */
2001-10-04 21:48:55 +04:00
for ( dev = dev_iter_get ( iter ) ; dev ; dev = dev_iter_get ( iter ) ) {
2012-02-10 05:28:27 +04:00
if ( ( baton . data = read_disk ( fmt , dev , mem , vg_name ) ) ) {
2013-06-12 14:08:56 +04:00
_add_pv_to_list ( fmt - > cmd , head , baton . data ) ;
2001-12-13 03:07:29 +03:00
}
2001-10-05 19:20:40 +04:00
}
2001-10-08 13:45:16 +04:00
dev_iter_destroy ( iter ) ;
2008-11-04 01:14:30 +03:00
if ( dm_list_empty ( head ) )
2001-10-16 20:25:28 +04:00
return 0 ;
2001-10-05 19:20:40 +04:00
return 1 ;
}
2001-10-31 20:59:52 +03:00
static int _write_vgd ( struct disk_list * data )
2001-10-05 19:20:40 +04:00
{
2001-10-31 20:59:52 +03:00
struct vg_disk * vgd = & data - > vgd ;
2002-12-20 02:25:55 +03:00
uint64_t pos = data - > pvd . vg_on_disk . base ;
2001-10-05 19:20:40 +04:00
2013-01-08 02:30:29 +04:00
log_debug_metadata ( " Writing %s VG metadata to %s at % " PRIu64 " len % " PRIsize_t ,
data - > pvd . vg_name , dev_name ( data - > dev ) , pos , sizeof ( * vgd ) ) ;
2005-08-16 23:00:55 +04:00
2001-10-31 20:59:52 +03:00
_xlate_vgd ( vgd ) ;
2003-07-05 02:34:56 +04:00
if ( ! dev_write ( data - > dev , pos , sizeof ( * vgd ) , vgd ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-05 19:48:05 +04:00
2001-10-31 20:59:52 +03:00
_xlate_vgd ( vgd ) ;
2001-10-05 19:20:40 +04:00
return 1 ;
}
static int _write_uuids ( struct disk_list * data )
{
struct uuid_list * ul ;
2002-12-20 02:25:55 +03:00
uint64_t pos = data - > pvd . pv_uuidlist_on_disk . base ;
uint64_t end = pos + data - > pvd . pv_uuidlist_on_disk . size ;
2001-10-05 19:20:40 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( ul , & data - > uuids ) {
2001-10-05 19:20:40 +04:00
if ( pos > = end ) {
2001-10-10 16:45:20 +04:00
log_error ( " Too many uuids to fit on %s " ,
2001-10-25 18:04:18 +04:00
dev_name ( data - > dev ) ) ;
2001-10-05 19:20:40 +04:00
return 0 ;
}
2013-01-08 02:30:29 +04:00
log_debug_metadata ( " Writing %s uuidlist to %s at % " PRIu64 " len %d " ,
data - > pvd . vg_name , dev_name ( data - > dev ) ,
pos , NAME_LEN ) ;
2005-08-16 23:00:55 +04:00
2003-07-05 02:34:56 +04:00
if ( ! dev_write ( data - > dev , pos , NAME_LEN , ul - > uuid ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-05 19:48:05 +04:00
2001-10-05 19:20:40 +04:00
pos + = NAME_LEN ;
}
2001-10-04 21:48:55 +04:00
2001-10-05 19:20:40 +04:00
return 1 ;
}
2001-10-04 21:48:55 +04:00
2002-12-20 02:25:55 +03:00
static int _write_lvd ( struct device * dev , uint64_t pos , struct lv_disk * disk )
2001-10-05 19:20:40 +04:00
{
2013-01-08 02:30:29 +04:00
log_debug_metadata ( " Writing %s LV %s metadata to %s at % " PRIu64 " len % "
PRIsize_t , disk - > vg_name , disk - > lv_name , dev_name ( dev ) ,
pos , sizeof ( * disk ) ) ;
2005-08-16 23:00:55 +04:00
2001-10-31 20:59:52 +03:00
_xlate_lvd ( disk ) ;
2003-07-05 02:34:56 +04:00
if ( ! dev_write ( dev , pos , sizeof ( * disk ) , disk ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-05 19:48:05 +04:00
2001-10-31 20:59:52 +03:00
_xlate_lvd ( disk ) ;
2001-10-05 19:20:40 +04:00
2001-10-04 21:48:55 +04:00
return 1 ;
2001-10-05 19:20:40 +04:00
}
2001-10-04 21:48:55 +04:00
2001-10-05 19:20:40 +04:00
static int _write_lvs ( struct disk_list * data )
{
2005-06-01 20:51:55 +04:00
struct lvd_list * ll ;
2002-12-20 02:25:55 +03:00
uint64_t pos , offset ;
2001-10-05 19:20:40 +04:00
2001-11-10 01:01:04 +03:00
pos = data - > pvd . lv_on_disk . base ;
2001-11-13 21:52:52 +03:00
2006-05-11 22:39:24 +04:00
if ( ! dev_set ( data - > dev , pos , data - > pvd . lv_on_disk . size , 0 ) ) {
2001-11-14 16:52:38 +03:00
log_error ( " Couldn't zero lv area on device '%s' " ,
2001-12-13 03:07:29 +03:00
dev_name ( data - > dev ) ) ;
2001-11-13 21:52:52 +03:00
return 0 ;
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( ll , & data - > lvds ) {
2002-05-23 15:37:51 +04:00
offset = sizeof ( struct lv_disk ) * ll - > lvd . lv_number ;
2002-11-18 17:01:16 +03:00
if ( offset + sizeof ( struct lv_disk ) > data - > pvd . lv_on_disk . size ) {
2002-05-23 15:37:51 +04:00
log_error ( " lv_number %d too large " , ll - > lvd . lv_number ) ;
return 0 ;
}
2001-10-05 19:20:40 +04:00
2002-05-23 15:37:51 +04:00
if ( ! _write_lvd ( data - > dev , pos + offset , & ll - > lvd ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-05 19:20:40 +04:00
}
return 1 ;
}
static int _write_extents ( struct disk_list * data )
{
2001-10-31 20:59:52 +03:00
size_t len = sizeof ( struct pe_disk ) * data - > pvd . pe_total ;
2001-10-05 19:20:40 +04:00
struct pe_disk * extents = data - > extents ;
2002-12-20 02:25:55 +03:00
uint64_t pos = data - > pvd . pe_on_disk . base ;
2001-10-05 19:20:40 +04:00
2013-01-08 02:30:29 +04:00
log_debug_metadata ( " Writing %s extents metadata to %s at % " PRIu64 " len % "
PRIsize_t , data - > pvd . vg_name , dev_name ( data - > dev ) ,
pos , len ) ;
2005-08-16 23:00:55 +04:00
2001-10-31 20:59:52 +03:00
_xlate_extents ( extents , data - > pvd . pe_total ) ;
2003-07-05 02:34:56 +04:00
if ( ! dev_write ( data - > dev , pos , len , extents ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-05 19:48:05 +04:00
2001-10-31 20:59:52 +03:00
_xlate_extents ( extents , data - > pvd . pe_total ) ;
2001-10-05 19:20:40 +04:00
return 1 ;
}
2001-10-31 20:59:52 +03:00
static int _write_pvd ( struct disk_list * data )
2001-10-05 19:20:40 +04:00
{
2002-01-29 18:52:11 +03:00
char * buf ;
2002-12-20 02:25:55 +03:00
uint64_t pos = data - > pvd . pv_on_disk . base ;
size_t size = data - > pvd . pv_on_disk . size ;
2001-10-05 19:20:40 +04:00
2002-04-24 22:20:51 +04:00
if ( size < sizeof ( struct pv_disk ) ) {
2002-01-29 20:23:33 +03:00
log_error ( " Invalid PV structure size. " ) ;
2002-01-29 18:52:11 +03:00
return 0 ;
}
2001-10-05 19:48:05 +04:00
2002-04-24 22:20:51 +04:00
/* Make sure that the gap between the PV structure and
2002-01-29 18:52:11 +03:00
the next one is zeroed in order to make non LVM tools
happy ( idea from AED ) */
2010-10-01 01:06:50 +04:00
buf = dm_zalloc ( size ) ;
2002-04-24 22:20:51 +04:00
if ( ! buf ) {
2009-07-16 00:02:46 +04:00
log_error ( " Couldn't allocate temporary PV buffer. " ) ;
2002-01-29 18:52:11 +03:00
return 0 ;
}
memcpy ( buf , & data - > pvd , sizeof ( struct pv_disk ) ) ;
2013-01-08 02:30:29 +04:00
log_debug_metadata ( " Writing %s PV metadata to %s at % " PRIu64 " len % "
PRIsize_t , data - > pvd . vg_name , dev_name ( data - > dev ) ,
pos , size ) ;
2005-08-16 23:00:55 +04:00
2002-04-24 22:20:51 +04:00
_xlate_pvd ( ( struct pv_disk * ) buf ) ;
2003-07-05 02:34:56 +04:00
if ( ! dev_write ( data - > dev , pos , size , buf ) ) {
2005-10-17 03:03:59 +04:00
dm_free ( buf ) ;
2008-01-30 16:19:47 +03:00
return_0 ;
2002-01-29 18:52:11 +03:00
}
2001-10-05 19:20:40 +04:00
2005-10-17 03:03:59 +04:00
dm_free ( buf ) ;
2001-10-05 19:20:40 +04:00
return 1 ;
}
2001-11-14 13:01:52 +03:00
/*
* assumes the device has been opened .
*/
2010-07-09 19:34:40 +04:00
static int __write_all_pvd ( const struct format_type * fmt __attribute__ ( ( unused ) ) ,
2013-03-25 17:30:40 +04:00
struct disk_list * data , int write_vg_metadata )
2001-10-05 19:20:40 +04:00
{
2001-10-25 18:04:18 +04:00
const char * pv_name = dev_name ( data - > dev ) ;
2001-10-05 19:20:40 +04:00
2001-10-31 20:59:52 +03:00
if ( ! _write_pvd ( data ) ) {
2001-10-10 16:45:20 +04:00
log_error ( " Failed to write PV structure onto %s " , pv_name ) ;
2001-10-05 19:20:40 +04:00
return 0 ;
}
2002-11-18 17:01:16 +03:00
/* vgcache_add(data->pvd.vg_name, data->vgd.vg_uuid, data->dev, fmt); */
2001-10-10 14:05:29 +04:00
/*
2013-03-25 17:30:40 +04:00
* Stop here for orphan PVs or if VG metadata write not requested .
2001-10-10 14:05:29 +04:00
*/
2013-03-25 17:30:40 +04:00
if ( ( data - > pvd . vg_name [ 0 ] = = ' \0 ' ) | | ! write_vg_metadata ) {
2002-11-18 17:01:16 +03:00
/* if (!test_mode())
vgcache_add ( data - > pvd . vg_name , NULL , data - > dev , fmt ) ; */
2001-10-10 14:05:29 +04:00
return 1 ;
2002-03-05 23:03:09 +03:00
}
2002-11-18 17:01:16 +03:00
/* if (!test_mode())
vgcache_add ( data - > pvd . vg_name , data - > vgd . vg_uuid , data - > dev ,
fmt ) ; */
2001-10-10 14:05:29 +04:00
2001-10-31 20:59:52 +03:00
if ( ! _write_vgd ( data ) ) {
2001-10-10 16:45:20 +04:00
log_error ( " Failed to write VG data to %s " , pv_name ) ;
2001-10-05 19:20:40 +04:00
return 0 ;
}
if ( ! _write_uuids ( data ) ) {
2001-10-10 16:45:20 +04:00
log_error ( " Failed to write PV uuid list to %s " , pv_name ) ;
2001-10-05 19:20:40 +04:00
return 0 ;
}
if ( ! _write_lvs ( data ) ) {
2001-10-10 16:45:20 +04:00
log_error ( " Failed to write LV's to %s " , pv_name ) ;
2001-10-05 19:20:40 +04:00
return 0 ;
}
if ( ! _write_extents ( data ) ) {
2001-10-10 16:45:20 +04:00
log_error ( " Failed to write extents to %s " , pv_name ) ;
2001-10-05 19:20:40 +04:00
return 0 ;
}
return 1 ;
}
2001-11-14 13:01:52 +03:00
/*
* opens the device and hands to the above fn .
*/
2013-03-25 17:30:40 +04:00
static int _write_all_pvd ( const struct format_type * fmt , struct disk_list * data , int write_vg_metadata )
2001-11-14 13:01:52 +03:00
{
int r ;
2014-06-08 23:52:54 +04:00
if ( ! data - > dev )
return_0 ;
2008-01-30 16:19:47 +03:00
if ( ! dev_open ( data - > dev ) )
return_0 ;
2001-11-14 13:01:52 +03:00
2013-03-25 17:30:40 +04:00
r = __write_all_pvd ( fmt , data , write_vg_metadata ) ;
2001-11-14 13:01:52 +03:00
if ( ! dev_close ( data - > dev ) )
stack ;
return r ;
}
2001-10-05 19:20:40 +04:00
/*
* Writes all the given pv ' s to disk . Does very
* little sanity checking , so make sure correct
2001-10-05 19:48:05 +04:00
* data is passed to here .
*/
2013-03-25 17:30:40 +04:00
int write_disks ( const struct format_type * fmt , struct dm_list * pvs , int write_vg_metadata )
2001-10-05 19:20:40 +04:00
{
struct disk_list * dl ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( dl , pvs ) {
2013-03-25 17:30:40 +04:00
if ( ! ( _write_all_pvd ( fmt , dl , write_vg_metadata ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2001-10-05 19:48:05 +04:00
2002-04-24 22:20:51 +04:00
log_very_verbose ( " Successfully wrote data to %s " ,
2002-01-28 00:30:47 +03:00
dev_name ( dl - > dev ) ) ;
2001-10-05 19:20:40 +04:00
}
return 1 ;
2001-10-04 21:48:55 +04:00
}