2012-02-28 22:23:56 +04:00
/*
* Copyright ( C ) 2012 Red Hat , Inc .
*
* This file is part of LVM2 .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2012-02-23 17:11:07 +04:00
# include "lib.h"
# include "toolcontext.h"
# include "metadata.h"
# include "device.h"
# include "lvmetad.h"
# include "lvmcache.h"
# include "lvmetad-client.h"
# include "format-text.h" // TODO for disk_locn, used as a DA representation
static int _using_lvmetad = 0 ;
static daemon_handle _lvmetad ;
void lvmetad_init ( void )
{
const char * socket = getenv ( " LVM_LVMETAD_SOCKET " ) ;
if ( _using_lvmetad ) { /* configured by the toolcontext */
_lvmetad = lvmetad_open ( socket ? : DEFAULT_RUN_DIR " /lvmetad.socket " ) ;
2012-02-26 12:49:40 +04:00
if ( _lvmetad . socket_fd < 0 | | _lvmetad . error ) {
2012-03-03 00:46:36 +04:00
log_warn ( " WARNING: Failed to connect to lvmetad: %s. Falling back to internal scanning. " , strerror ( _lvmetad . error ) ) ;
2012-02-23 17:11:07 +04:00
_using_lvmetad = 0 ;
}
}
}
/*
* Helper ; evaluate the reply from lvmetad , check for errors , print diagnostics
2012-03-03 00:46:36 +04:00
* and return a summary success / failure exit code .
*
* If found is set , * found indicates whether or not device exists ,
* and missing device is not treated as an error .
2012-02-23 17:11:07 +04:00
*/
2012-03-03 00:46:36 +04:00
static int _lvmetad_handle_reply ( daemon_reply reply , const char * action , const char * object ,
int * found )
{
if ( reply . error ) {
log_error ( " Request to %s %s%sin lvmetad gave response %s. " ,
action , object , * object ? " " : " " , strerror ( reply . error ) ) ;
2012-02-23 17:11:07 +04:00
return 0 ;
}
2012-03-03 00:46:36 +04:00
/* All OK? */
if ( ! strcmp ( daemon_reply_str ( reply , " response " , " " ) , " OK " ) ) {
if ( found )
* found = 1 ;
return 1 ;
}
/* Unknown device permitted? */
if ( found & & ! strcmp ( daemon_reply_str ( reply , " response " , " " ) , " unknown " ) ) {
log_very_verbose ( " Request to %s %s%sin lvmetad did not find object. " ,
action , object , * object ? " " : " " ) ;
* found = 0 ;
return 1 ;
}
log_error ( " Request to %s %s%sin lvmetad gave response %s. Reason: %s " ,
action , object , * object ? " " : " " ,
daemon_reply_str ( reply , " response " , " <missing> " ) ,
daemon_reply_str ( reply , " reason " , " <missing> " ) ) ;
return 0 ;
2012-02-23 17:11:07 +04:00
}
static int _read_mda ( struct lvmcache_info * info ,
struct format_type * fmt ,
const struct dm_config_node * cn )
{
struct metadata_area_ops * ops ;
2012-02-23 21:59:32 +04:00
dm_list_iterate_items ( ops , & fmt - > mda_ops )
2012-02-23 17:11:07 +04:00
if ( ops - > mda_import_text & & ops - > mda_import_text ( info , cn ) )
return 1 ;
2012-02-23 21:59:32 +04:00
2012-02-23 17:11:07 +04:00
return 0 ;
}
static struct lvmcache_info * _pv_populate_lvmcache (
struct cmd_context * cmd , struct dm_config_node * cn , dev_t fallback )
{
2012-02-23 21:59:32 +04:00
struct device * device ;
struct id pvid , vgid ;
char mda_id [ 32 ] ;
char da_id [ 32 ] ;
int i = 0 ;
struct dm_config_node * mda = NULL ;
struct dm_config_node * da = NULL ;
uint64_t offset , size ;
struct lvmcache_info * info ;
2012-02-23 17:11:07 +04:00
const char * pvid_txt = dm_config_find_str ( cn - > child , " id " , NULL ) ,
* vgid_txt = dm_config_find_str ( cn - > child , " vgid " , NULL ) ,
* vgname = dm_config_find_str ( cn - > child , " vgname " , NULL ) ,
* fmt_name = dm_config_find_str ( cn - > child , " format " , NULL ) ;
dev_t devt = dm_config_find_int ( cn - > child , " device " , 0 ) ;
2012-03-02 00:04:44 +04:00
uint64_t devsize = dm_config_find_int64 ( cn - > child , " dev_size " , 0 ) ,
label_sector = dm_config_find_int64 ( cn - > child , " label_sector " , 0 ) ;
2012-02-23 17:11:07 +04:00
struct format_type * fmt = fmt_name ? get_format_by_name ( cmd , fmt_name ) : NULL ;
if ( ! fmt ) {
2012-03-02 20:58:41 +04:00
log_error ( " PV %s not recognised. Is the device missing? " , pvid_txt ) ;
2012-02-23 21:59:32 +04:00
return NULL ;
2012-02-23 17:11:07 +04:00
}
2012-02-23 21:59:32 +04:00
device = dev_cache_get_by_devt ( devt , cmd - > filter ) ;
2012-02-23 17:11:07 +04:00
if ( ! device & & fallback )
device = dev_cache_get_by_devt ( fallback , cmd - > filter ) ;
if ( ! device ) {
2012-03-02 20:58:41 +04:00
log_error ( " No device found for PV %s. " , pvid_txt ) ;
2012-02-23 21:59:32 +04:00
return NULL ;
2012-02-23 17:11:07 +04:00
}
if ( ! pvid_txt | | ! id_read_format ( & pvid , pvid_txt ) ) {
2012-03-02 20:58:41 +04:00
log_error ( " Missing or ill-formatted PVID for PV: %s. " , pvid_txt ) ;
2012-02-23 21:59:32 +04:00
return NULL ;
2012-02-23 17:11:07 +04:00
}
if ( vgid_txt )
id_read_format ( & vgid , vgid_txt ) ;
else
strcpy ( ( char * ) & vgid , fmt - > orphan_vg_name ) ;
if ( ! vgname )
vgname = fmt - > orphan_vg_name ;
2012-04-10 16:26:27 +04:00
if ( ! ( info = lvmcache_add ( fmt - > labeller , ( const char * ) & pvid , device ,
vgname , ( const char * ) & vgid , 0 ) ) )
return_NULL ;
2012-02-23 17:11:07 +04:00
lvmcache_get_label ( info ) - > sector = label_sector ;
lvmcache_set_device_size ( info , devsize ) ;
lvmcache_del_das ( info ) ;
lvmcache_del_mdas ( info ) ;
do {
sprintf ( mda_id , " mda%d " , i ) ;
mda = dm_config_find_node ( cn - > child , mda_id ) ;
if ( mda )
_read_mda ( info , fmt , mda ) ;
+ + i ;
} while ( mda ) ;
i = 0 ;
do {
sprintf ( da_id , " da%d " , i ) ;
da = dm_config_find_node ( cn - > child , da_id ) ;
if ( da ) {
if ( ! dm_config_get_uint64 ( da - > child , " offset " , & offset ) ) return_0 ;
if ( ! dm_config_get_uint64 ( da - > child , " size " , & size ) ) return_0 ;
lvmcache_add_da ( info , offset , size ) ;
}
+ + i ;
} while ( da ) ;
return info ;
}
struct volume_group * lvmetad_vg_lookup ( struct cmd_context * cmd , const char * vgname , const char * vgid )
{
2012-02-23 21:59:32 +04:00
struct volume_group * vg = NULL ;
daemon_reply reply ;
char uuid [ 64 ] ;
struct format_instance * fid ;
struct format_instance_ctx fic ;
struct dm_config_node * top ;
const char * name ;
const char * fmt_name ;
struct format_type * fmt ;
struct dm_config_node * pvcn ;
struct pv_list * pvl ;
struct lvmcache_info * info ;
2012-02-23 17:11:07 +04:00
if ( ! _using_lvmetad )
return NULL ;
if ( vgid ) {
2012-02-27 15:32:48 +04:00
if ( ! id_write_format ( ( const struct id * ) vgid , uuid , sizeof ( uuid ) ) )
2012-08-17 14:04:52 +04:00
return_NULL ;
2012-02-23 17:11:07 +04:00
reply = daemon_send_simple ( _lvmetad , " vg_lookup " , " uuid = %s " , uuid , NULL ) ;
} else {
if ( ! vgname )
log_error ( INTERNAL_ERROR " VG name required (VGID not available) " ) ;
reply = daemon_send_simple ( _lvmetad , " vg_lookup " , " name = %s " , vgname , NULL ) ;
}
if ( ! strcmp ( daemon_reply_str ( reply , " response " , " " ) , " OK " ) ) {
2012-06-21 14:43:31 +04:00
if ( ! ( top = dm_config_find_node ( reply . cft - > root , " metadata " ) ) ) {
log_error ( INTERNAL_ERROR " metadata config node not found. " ) ;
goto out ;
}
2012-02-23 21:59:32 +04:00
name = daemon_reply_str ( reply , " name " , NULL ) ;
2012-02-23 17:11:07 +04:00
/* fall back to lvm2 if we don't know better */
2012-02-23 21:59:32 +04:00
fmt_name = dm_config_find_str ( top , " metadata/format " , " lvm2 " ) ;
if ( ! ( fmt = get_format_by_name ( cmd , fmt_name ) ) ) {
2012-02-23 17:11:07 +04:00
log_error ( INTERNAL_ERROR
" We do not know the format (%s) reported by lvmetad. " ,
fmt_name ) ;
2012-03-03 01:24:37 +04:00
goto out ;
2012-02-23 17:11:07 +04:00
}
fic . type = FMT_INSTANCE_MDAS | FMT_INSTANCE_AUX_MDAS ;
fic . context . vg_ref . vg_name = name ;
fic . context . vg_ref . vg_id = vgid ;
if ( ! ( fid = fmt - > ops - > create_instance ( fmt , & fic ) ) )
2012-03-03 01:24:37 +04:00
goto_out ;
2012-02-23 17:11:07 +04:00
2012-03-02 02:52:59 +04:00
if ( ( pvcn = dm_config_find_node ( top , " metadata/physical_volumes " ) ) )
for ( pvcn = pvcn - > child ; pvcn ; pvcn = pvcn - > sib )
_pv_populate_lvmcache ( cmd , pvcn , 0 ) ;
2012-02-23 17:11:07 +04:00
top - > key = name ;
2012-03-02 02:52:59 +04:00
if ( ! ( vg = import_vg_from_config_tree ( reply . cft , fid ) ) )
2012-03-03 01:24:37 +04:00
goto_out ;
2012-02-23 17:11:07 +04:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2012-02-23 21:59:32 +04:00
if ( ( info = lvmcache_info_from_pvid ( ( const char * ) & pvl - > pv - > id , 0 ) ) ) {
2012-02-23 17:11:07 +04:00
pvl - > pv - > label_sector = lvmcache_get_label ( info ) - > sector ;
pvl - > pv - > dev = lvmcache_device ( info ) ;
2012-03-03 01:24:37 +04:00
if ( ! lvmcache_fid_add_mdas_pv ( info , fid ) ) {
vg = NULL ;
goto_out ; /* FIXME error path */
}
2012-02-23 17:11:07 +04:00
} /* else probably missing */
}
lvmcache_update_vg ( vg , 0 ) ;
}
2012-03-03 01:24:37 +04:00
out :
2012-02-23 17:11:07 +04:00
daemon_reply_destroy ( reply ) ;
2012-03-03 01:24:37 +04:00
2012-02-23 17:11:07 +04:00
return vg ;
}
struct _fixup_baton {
int i ;
int find ;
int ignore ;
} ;
static int _fixup_ignored ( struct metadata_area * mda , void * baton ) {
struct _fixup_baton * b = baton ;
if ( b - > i = = b - > find )
mda_set_ignored ( mda , b - > ignore ) ;
b - > i + + ;
return 1 ;
}
int lvmetad_vg_update ( struct volume_group * vg )
{
char * buf = NULL ;
2012-02-23 21:59:32 +04:00
daemon_reply reply ;
struct dm_hash_node * n ;
struct metadata_area * mda ;
char mda_id [ 128 ] , * num ;
struct pv_list * pvl ;
struct lvmcache_info * info ;
2012-02-23 23:03:48 +04:00
struct _fixup_baton baton ;
2012-02-23 21:59:32 +04:00
2012-02-23 17:11:07 +04:00
if ( ! vg )
return 0 ;
2012-02-23 21:59:32 +04:00
2012-07-30 12:44:11 +04:00
if ( ! _using_lvmetad | | test_mode ( ) )
2012-02-23 17:11:07 +04:00
return 1 ; /* fake it */
/* TODO. This is not entirely correct, since export_vg_to_buffer
* adds trailing nodes to the buffer . We may need to use
* export_vg_to_config_tree and format the buffer ourselves . It
* does , however , work for now , since the garbage is well
* formatted and has no conflicting keys with the rest of the
* request . */
if ( ! export_vg_to_buffer ( vg , & buf ) ) {
log_error ( " Could not format VG metadata. " ) ;
2012-02-24 02:24:47 +04:00
return 0 ;
2012-02-23 17:11:07 +04:00
}
reply = daemon_send_simple ( _lvmetad , " vg_update " , " vgname = %s " , vg - > name ,
2012-03-03 01:24:37 +04:00
" metadata = %b " , strchr ( buf , ' { ' ) , NULL ) ;
2012-02-26 12:49:40 +04:00
dm_free ( buf ) ;
2012-02-23 17:11:07 +04:00
2012-03-03 00:46:36 +04:00
if ( ! _lvmetad_handle_reply ( reply , " update VG " , vg - > name , NULL ) ) {
daemon_reply_destroy ( reply ) ;
2012-02-23 17:11:07 +04:00
return 0 ;
2012-03-03 00:46:36 +04:00
}
2012-02-23 17:11:07 +04:00
2012-03-03 01:24:37 +04:00
daemon_reply_destroy ( reply ) ;
2012-02-23 21:59:32 +04:00
n = ( vg - > fid & & vg - > fid - > metadata_areas_index ) ?
2012-02-23 17:11:07 +04:00
dm_hash_get_first ( vg - > fid - > metadata_areas_index ) : NULL ;
while ( n ) {
2012-02-23 21:59:32 +04:00
mda = dm_hash_get_data ( vg - > fid - > metadata_areas_index , n ) ;
2012-02-23 17:11:07 +04:00
strcpy ( mda_id , dm_hash_get_key ( vg - > fid - > metadata_areas_index , n ) ) ;
if ( ( num = strchr ( mda_id , ' _ ' ) ) ) {
* num = 0 ;
+ + num ;
2012-02-23 21:59:32 +04:00
if ( ( info = lvmcache_info_from_pvid ( mda_id , 0 ) ) ) {
2012-02-23 23:03:48 +04:00
memset ( & baton , 0 , sizeof ( baton ) ) ;
2012-02-23 21:59:32 +04:00
baton . find = atoi ( num ) ;
baton . ignore = mda_is_ignored ( mda ) ;
2012-02-23 17:11:07 +04:00
lvmcache_foreach_mda ( info , _fixup_ignored , & baton ) ;
2012-02-23 21:59:32 +04:00
}
2012-02-23 17:11:07 +04:00
}
n = dm_hash_get_next ( vg - > fid - > metadata_areas_index , n ) ;
}
dm_list_iterate_items ( pvl , & vg - > pvs ) {
/* NB. the PV fmt pointer is sometimes wrong during vgconvert */
if ( pvl - > pv - > dev & & ! lvmetad_pv_found ( pvl - > pv - > id , pvl - > pv - > dev ,
vg - > fid ? vg - > fid - > fmt : pvl - > pv - > fmt ,
2012-06-27 16:59:34 +04:00
pvl - > pv - > label_sector , NULL , NULL ) )
2012-02-23 17:11:07 +04:00
return 0 ;
}
return 1 ;
}
int lvmetad_vg_remove ( struct volume_group * vg )
{
2012-02-23 21:59:32 +04:00
char uuid [ 64 ] ;
daemon_reply reply ;
2012-03-03 00:46:36 +04:00
int result ;
2012-02-23 21:59:32 +04:00
2012-07-30 12:44:11 +04:00
if ( ! _using_lvmetad | | test_mode ( ) )
2012-02-23 17:11:07 +04:00
return 1 ; /* just fake it */
2012-02-23 21:59:32 +04:00
2012-02-27 15:32:48 +04:00
if ( ! id_write_format ( & vg - > id , uuid , sizeof ( uuid ) ) )
return_0 ;
2012-02-23 21:59:32 +04:00
reply = daemon_send_simple ( _lvmetad , " vg_remove " , " uuid = %s " , uuid , NULL ) ;
2012-02-23 17:11:07 +04:00
2012-03-03 00:46:36 +04:00
result = _lvmetad_handle_reply ( reply , " remove VG " , vg - > name , NULL ) ;
daemon_reply_destroy ( reply ) ;
return result ;
2012-02-23 17:11:07 +04:00
}
2012-03-03 00:46:36 +04:00
int lvmetad_pv_lookup ( struct cmd_context * cmd , struct id pvid , int * found )
2012-02-23 17:11:07 +04:00
{
2012-02-23 21:59:32 +04:00
char uuid [ 64 ] ;
daemon_reply reply ;
2012-03-03 00:46:36 +04:00
int result = 0 ;
2012-02-23 21:59:32 +04:00
struct dm_config_node * cn ;
2012-02-23 17:11:07 +04:00
if ( ! _using_lvmetad )
return_0 ;
2012-02-27 15:32:48 +04:00
if ( ! id_write_format ( & pvid , uuid , sizeof ( uuid ) ) )
return_0 ;
2012-02-23 17:11:07 +04:00
2012-02-23 21:59:32 +04:00
reply = daemon_send_simple ( _lvmetad , " pv_lookup " , " uuid = %s " , uuid , NULL ) ;
2012-02-23 17:11:07 +04:00
2012-03-03 00:46:36 +04:00
if ( ! _lvmetad_handle_reply ( reply , " lookup PV " , " " , found ) )
goto_out ;
if ( found & & ! * found )
goto out_success ;
2012-02-23 17:11:07 +04:00
2012-03-02 02:52:59 +04:00
if ( ! ( cn = dm_config_find_node ( reply . cft - > root , " physical_volume " ) ) )
2012-03-03 00:46:36 +04:00
goto_out ;
2012-03-02 02:52:59 +04:00
else if ( ! _pv_populate_lvmcache ( cmd , cn , 0 ) )
2012-03-03 00:46:36 +04:00
goto_out ;
2012-02-23 17:11:07 +04:00
2012-03-03 00:46:36 +04:00
out_success :
result = 1 ;
out :
2012-02-23 17:11:07 +04:00
daemon_reply_destroy ( reply ) ;
2012-03-03 00:46:36 +04:00
2012-02-23 17:11:07 +04:00
return result ;
}
2012-03-03 00:46:36 +04:00
int lvmetad_pv_lookup_by_dev ( struct cmd_context * cmd , struct device * dev , int * found )
2012-02-23 17:11:07 +04:00
{
2012-03-03 00:46:36 +04:00
int result = 0 ;
2012-02-23 21:59:32 +04:00
daemon_reply reply ;
struct dm_config_node * cn ;
2012-02-23 17:11:07 +04:00
if ( ! _using_lvmetad )
return_0 ;
2012-03-03 00:46:36 +04:00
reply = daemon_send_simple ( _lvmetad , " pv_lookup " , " device = %d " , dev - > dev , NULL ) ;
2012-02-23 17:11:07 +04:00
2012-03-03 00:46:36 +04:00
if ( ! _lvmetad_handle_reply ( reply , " lookup PV " , dev_name ( dev ) , found ) )
goto_out ;
if ( found & & ! * found )
goto out_success ;
2012-02-23 17:11:07 +04:00
2012-02-23 21:59:32 +04:00
cn = dm_config_find_node ( reply . cft - > root , " physical_volume " ) ;
2012-03-03 00:46:36 +04:00
if ( ! cn | | ! _pv_populate_lvmcache ( cmd , cn , dev - > dev ) )
goto_out ;
2012-02-23 17:11:07 +04:00
2012-03-03 00:46:36 +04:00
out_success :
result = 1 ;
out :
2012-02-23 17:11:07 +04:00
daemon_reply_destroy ( reply ) ;
return result ;
}
int lvmetad_pv_list_to_lvmcache ( struct cmd_context * cmd )
{
2012-02-23 21:59:32 +04:00
daemon_reply reply ;
struct dm_config_node * cn ;
2012-02-23 17:11:07 +04:00
if ( ! _using_lvmetad )
2012-02-28 22:23:56 +04:00
return 1 ;
2012-02-23 17:11:07 +04:00
2012-02-23 21:59:32 +04:00
reply = daemon_send_simple ( _lvmetad , " pv_list " , NULL ) ;
2012-02-23 17:11:07 +04:00
2012-03-03 00:46:36 +04:00
if ( ! _lvmetad_handle_reply ( reply , " list PVs " , " " , NULL ) ) {
daemon_reply_destroy ( reply ) ;
2012-02-23 17:11:07 +04:00
return_0 ;
}
2012-03-02 02:52:59 +04:00
if ( ( cn = dm_config_find_node ( reply . cft - > root , " physical_volumes " ) ) )
for ( cn = cn - > child ; cn ; cn = cn - > sib )
_pv_populate_lvmcache ( cmd , cn , 0 ) ;
2012-02-23 17:11:07 +04:00
daemon_reply_destroy ( reply ) ;
2012-03-03 00:46:36 +04:00
2012-02-23 17:11:07 +04:00
return 1 ;
}
int lvmetad_vg_list_to_lvmcache ( struct cmd_context * cmd )
{
2012-02-23 21:59:32 +04:00
struct volume_group * tmp ;
struct id vgid ;
const char * vgid_txt ;
daemon_reply reply ;
struct dm_config_node * cn ;
2012-02-23 17:11:07 +04:00
if ( ! _using_lvmetad )
2012-02-28 22:23:56 +04:00
return 1 ;
2012-02-23 17:11:07 +04:00
2012-02-23 21:59:32 +04:00
reply = daemon_send_simple ( _lvmetad , " vg_list " , NULL ) ;
2012-03-03 00:46:36 +04:00
if ( ! _lvmetad_handle_reply ( reply , " list VGs " , " " , NULL ) ) {
daemon_reply_destroy ( reply ) ;
2012-02-23 17:11:07 +04:00
return_0 ;
}
2012-03-02 02:52:59 +04:00
if ( ( cn = dm_config_find_node ( reply . cft - > root , " volume_groups " ) ) )
for ( cn = cn - > child ; cn ; cn = cn - > sib ) {
vgid_txt = cn - > key ;
if ( ! id_read_format ( & vgid , vgid_txt ) ) {
stack ;
continue ;
}
2012-02-23 17:11:07 +04:00
2012-03-02 02:52:59 +04:00
/* the call to lvmetad_vg_lookup will poke the VG into lvmcache */
tmp = lvmetad_vg_lookup ( cmd , NULL , ( const char * ) & vgid ) ;
release_vg ( tmp ) ;
}
2012-02-23 17:11:07 +04:00
daemon_reply_destroy ( reply ) ;
return 1 ;
}
struct _print_mda_baton {
int i ;
char * buffer ;
} ;
static int _print_mda ( struct metadata_area * mda , void * baton )
{
int result = 0 ;
struct _print_mda_baton * b = baton ;
2012-02-23 21:59:32 +04:00
char * buf , * mda_txt ;
2012-02-23 17:11:07 +04:00
if ( ! mda - > ops - > mda_export_text ) /* do nothing */
return 1 ;
2012-02-23 21:59:32 +04:00
buf = b - > buffer ;
mda_txt = mda - > ops - > mda_export_text ( mda ) ;
2012-02-23 17:11:07 +04:00
if ( ! dm_asprintf ( & b - > buffer , " %s mda%i { %s } " , b - > buffer ? : " " , b - > i , mda_txt ) )
goto_out ;
b - > i + + ;
result = 1 ;
out :
dm_free ( mda_txt ) ;
dm_free ( buf ) ;
return result ;
}
static int _print_da ( struct disk_locn * da , void * baton )
{
2012-02-23 21:59:32 +04:00
struct _print_mda_baton * b ;
char * buf ;
2012-02-23 17:11:07 +04:00
if ( ! da )
return 1 ;
2012-02-23 21:59:32 +04:00
b = baton ;
buf = b - > buffer ;
if ( ! dm_asprintf ( & b - > buffer , " %s da%i { offset = % " PRIu64
" size = % " PRIu64 " } " ,
2012-02-23 17:11:07 +04:00
b - > buffer ? : " " , b - > i , da - > offset , da - > size ) )
{
dm_free ( buf ) ;
return_0 ;
}
b - > i + + ;
dm_free ( buf ) ;
2012-02-23 21:59:32 +04:00
2012-02-23 17:11:07 +04:00
return 1 ;
}
static const char * _print_mdas ( struct lvmcache_info * info )
{
struct _print_mda_baton baton = { . i = 0 , . buffer = NULL } ;
2012-02-23 21:59:32 +04:00
2012-02-23 17:11:07 +04:00
if ( ! lvmcache_foreach_mda ( info , & _print_mda , & baton ) )
return NULL ;
baton . i = 0 ;
if ( ! lvmcache_foreach_da ( info , & _print_da , & baton ) )
return NULL ;
2012-02-23 21:59:32 +04:00
2012-02-23 17:11:07 +04:00
return baton . buffer ;
}
int lvmetad_pv_found ( struct id pvid , struct device * device , const struct format_type * fmt ,
2012-06-27 16:59:34 +04:00
uint64_t label_sector , struct volume_group * vg , activation_handler handler )
2012-02-23 17:11:07 +04:00
{
2012-02-23 21:59:32 +04:00
char uuid [ 64 ] ;
daemon_reply reply ;
struct lvmcache_info * info ;
const char * mdas = NULL ;
char * pvmeta ;
char * buf = NULL ;
2012-06-27 16:59:34 +04:00
const char * status ;
2012-03-03 00:46:36 +04:00
int result ;
2012-02-23 21:59:32 +04:00
2012-07-30 12:44:11 +04:00
if ( ! _using_lvmetad | | test_mode ( ) )
2012-02-23 17:11:07 +04:00
return 1 ;
2012-02-27 15:32:48 +04:00
if ( ! id_write_format ( & pvid , uuid , sizeof ( uuid ) ) )
return_0 ;
2012-02-23 17:11:07 +04:00
/* FIXME A more direct route would be much preferable. */
2012-02-23 21:59:32 +04:00
if ( ( info = lvmcache_info_from_pvid ( ( const char * ) & pvid , 0 ) ) )
2012-02-23 17:11:07 +04:00
mdas = _print_mdas ( info ) ;
if ( ! dm_asprintf ( & pvmeta ,
2012-02-23 21:59:32 +04:00
" { device = % " PRIu64 " \n "
" dev_size = % " PRIu64 " \n "
2012-02-23 17:11:07 +04:00
" format = \" %s \" \n "
2012-02-23 21:59:32 +04:00
" label_sector = % " PRIu64 " \n "
2012-02-23 17:11:07 +04:00
" id = \" %s \" \n "
" %s "
2012-02-23 21:59:32 +04:00
" } " , device - > dev ,
info ? lvmcache_device_size ( info ) : 0 ,
2012-02-26 12:49:40 +04:00
fmt - > name , label_sector , uuid , mdas ? : " " ) ) {
dm_free ( ( char * ) mdas ) ;
2012-02-23 17:11:07 +04:00
return_0 ;
2012-02-26 12:49:40 +04:00
}
dm_free ( ( char * ) mdas ) ;
2012-02-23 17:11:07 +04:00
if ( vg ) {
/*
* TODO . This is not entirely correct , since export_vg_to_buffer
* adds trailing garbage to the buffer . We may need to use
* export_vg_to_config_tree and format the buffer ourselves . It
* does , however , work for now , since the garbage is well
* formatted and has no conflicting keys with the rest of the
* request .
*/
2012-02-28 15:09:06 +04:00
if ( ! export_vg_to_buffer ( vg , & buf ) ) {
dm_free ( pvmeta ) ;
return_0 ;
}
2012-02-23 17:11:07 +04:00
reply = daemon_send_simple ( _lvmetad ,
" pv_found " ,
" pvmeta = %b " , pvmeta ,
" vgname = %s " , vg - > name ,
" metadata = %b " , strchr ( buf , ' { ' ) ,
NULL ) ;
} else {
2012-06-21 14:43:31 +04:00
if ( handler ) {
log_error ( INTERNAL_ERROR " Handler needs existing VG. " ) ;
dm_free ( pvmeta ) ;
return 0 ;
}
2012-02-23 17:11:07 +04:00
/* There are no MDAs on this PV. */
reply = daemon_send_simple ( _lvmetad ,
" pv_found " ,
" pvmeta = %b " , pvmeta ,
NULL ) ;
}
dm_free ( pvmeta ) ;
2012-03-03 00:46:36 +04:00
result = _lvmetad_handle_reply ( reply , " update PV " , uuid , NULL ) ;
2012-06-27 16:59:34 +04:00
if ( result & & handler ) {
status = daemon_reply_str ( reply , " status " , " <missing> " ) ;
if ( ! strcmp ( status , " partial " ) )
handler ( vg , 1 , CHANGE_AAY ) ;
else if ( ! strcmp ( status , " complete " ) )
handler ( vg , 0 , CHANGE_AAY ) ;
else if ( ! strcmp ( status , " orphan " ) )
;
else
log_error ( " Request to %s %s in lvmetad gave status %s. " ,
" update PV " , uuid , status ) ;
}
2012-03-03 00:46:36 +04:00
daemon_reply_destroy ( reply ) ;
return result ;
2012-02-23 17:11:07 +04:00
}
2012-06-27 16:59:34 +04:00
int lvmetad_pv_gone ( dev_t device , const char * pv_name , activation_handler handler )
2012-02-23 17:11:07 +04:00
{
2012-03-14 21:15:22 +04:00
daemon_reply reply ;
2012-03-03 00:46:36 +04:00
int result ;
int found ;
2012-07-30 12:44:11 +04:00
if ( ! _using_lvmetad | | test_mode ( ) )
2012-02-26 12:49:40 +04:00
return 1 ;
2012-06-27 16:59:34 +04:00
/*
* TODO : automatic volume deactivation takes place here * before *
* all cached info is gone - call handler . Also , consider
* integrating existing deactivation script that deactivates
* the whole stack from top to bottom ( not yet upstream ) .
*/
2012-03-14 21:15:22 +04:00
reply = daemon_send_simple ( _lvmetad , " pv_gone " , " device = %d " , device , NULL ) ;
2012-03-03 00:46:36 +04:00
result = _lvmetad_handle_reply ( reply , " drop PV " , pv_name , & found ) ;
/* We don't care whether or not the daemon had the PV cached. */
2012-02-23 17:11:07 +04:00
2012-03-03 00:46:36 +04:00
daemon_reply_destroy ( reply ) ;
return result ;
2012-03-02 20:58:41 +04:00
}
2012-06-27 16:59:34 +04:00
int lvmetad_pv_gone_by_dev ( struct device * dev , activation_handler handler )
2012-03-02 20:58:41 +04:00
{
2012-06-27 16:59:34 +04:00
return lvmetad_pv_gone ( dev - > dev , dev_name ( dev ) , handler ) ;
2012-02-23 17:11:07 +04:00
}
2012-02-23 21:59:32 +04:00
int lvmetad_active ( void )
2012-02-23 17:11:07 +04:00
{
return _using_lvmetad ;
}
void lvmetad_set_active ( int active )
{
_using_lvmetad = active ;
}
/*
2012-03-02 22:09:46 +04:00
* The following code implements pvscan - - cache .
2012-02-23 17:11:07 +04:00
*/
struct _pvscan_lvmetad_baton {
struct volume_group * vg ;
struct format_instance * fid ;
} ;
static int _pvscan_lvmetad_single ( struct metadata_area * mda , void * baton )
{
struct _pvscan_lvmetad_baton * b = baton ;
2012-02-29 06:35:35 +04:00
struct volume_group * this = mda - > ops - > vg_read ( b - > fid , " " , mda , 1 ) ;
2012-03-03 02:44:31 +04:00
/* FIXME Also ensure contents match etc. */
2012-02-26 17:42:50 +04:00
if ( ! b - > vg | | this - > seqno > b - > vg - > seqno )
2012-02-23 17:11:07 +04:00
b - > vg = this ;
2012-02-26 17:42:50 +04:00
else if ( b - > vg )
release_vg ( this ) ;
2012-02-29 06:35:35 +04:00
2012-02-23 17:11:07 +04:00
return 1 ;
}
2012-06-27 16:59:34 +04:00
int pvscan_lvmetad_single ( struct cmd_context * cmd , struct device * dev ,
activation_handler handler )
2012-02-23 17:11:07 +04:00
{
2012-02-23 21:59:32 +04:00
struct label * label ;
struct lvmcache_info * info ;
struct _pvscan_lvmetad_baton baton ;
/* Create a dummy instance. */
struct format_instance_ctx fic = { . type = 0 } ;
2012-02-23 17:11:07 +04:00
if ( ! lvmetad_active ( ) ) {
log_error ( " Cannot proceed since lvmetad is not active. " ) ;
return 0 ;
}
if ( ! label_read ( dev , & label , 0 ) ) {
2012-03-02 20:58:41 +04:00
log_print ( " No PV label found on %s. " , dev_name ( dev ) ) ;
2012-06-27 16:59:34 +04:00
if ( ! lvmetad_pv_gone_by_dev ( dev , handler ) )
2012-03-02 20:58:41 +04:00
goto_bad ;
2012-02-23 17:11:07 +04:00
return 1 ;
}
2012-02-23 21:59:32 +04:00
info = ( struct lvmcache_info * ) label - > info ;
2012-02-23 17:11:07 +04:00
baton . vg = NULL ;
2012-02-23 21:59:32 +04:00
baton . fid = lvmcache_fmt ( info ) - > ops - > create_instance ( lvmcache_fmt ( info ) ,
& fic ) ;
2012-02-23 17:11:07 +04:00
2012-06-21 15:43:55 +04:00
if ( ! baton . fid )
goto_bad ;
2012-02-23 17:11:07 +04:00
lvmcache_foreach_mda ( info , _pvscan_lvmetad_single , & baton ) ;
2012-02-26 17:42:50 +04:00
if ( ! baton . vg )
lvmcache_fmt ( info ) - > ops - > destroy_instance ( baton . fid ) ;
2012-02-23 17:11:07 +04:00
/*
* NB . If this command failed and we are relying on lvmetad to have an
* * exact * image of the system , the lvmetad instance that went out of
* sync needs to be killed .
*/
if ( ! lvmetad_pv_found ( * ( struct id * ) dev - > pvid , dev , lvmcache_fmt ( info ) ,
2012-06-27 16:59:34 +04:00
label - > sector , baton . vg , handler ) ) {
2012-03-02 20:58:41 +04:00
release_vg ( baton . vg ) ;
goto_bad ;
}
2012-02-23 17:11:07 +04:00
release_vg ( baton . vg ) ;
return 1 ;
2012-03-02 20:58:41 +04:00
bad :
2012-02-23 17:11:07 +04:00
/* FIXME kill lvmetad automatically if we can */
log_error ( " Update of lvmetad failed. This is a serious problem. \n "
" It is strongly recommended that you restart lvmetad immediately. " ) ;
return 0 ;
}