2002-11-18 16:53:58 +03:00
/*
2004-03-30 23:35:44 +04: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 .
2002-11-18 16:53:58 +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
2002-11-18 16:53:58 +03:00
*/
# include "lib.h"
2003-07-05 02:34:56 +04:00
# include "lvmcache.h"
2002-11-18 16:53:58 +03:00
# include "toolcontext.h"
# include "dev-cache.h"
# include "metadata.h"
2003-01-07 00:10:43 +03:00
# include "filter.h"
2003-07-05 02:34:56 +04:00
# include "memlock.h"
2003-10-16 00:04:29 +04:00
# include "str_list.h"
2003-01-07 00:10:43 +03:00
2005-10-17 03:03:59 +04:00
static struct dm_hash_table * _pvid_hash = NULL ;
static struct dm_hash_table * _vgid_hash = NULL ;
static struct dm_hash_table * _vgname_hash = NULL ;
static struct dm_hash_table * _lock_hash = NULL ;
2002-11-18 16:53:58 +03:00
static struct list _vginfos ;
2003-07-05 02:34:56 +04:00
static int _has_scanned = 0 ;
static int _vgs_locked = 0 ;
2002-11-18 16:53:58 +03:00
2003-07-05 02:34:56 +04:00
int lvmcache_init ( void )
2002-11-18 16:53:58 +03:00
{
list_init ( & _vginfos ) ;
2005-10-17 03:03:59 +04:00
if ( ! ( _vgname_hash = dm_hash_create ( 128 ) ) )
2002-11-18 16:53:58 +03:00
return 0 ;
2005-10-17 03:03:59 +04:00
if ( ! ( _vgid_hash = dm_hash_create ( 128 ) ) )
2002-11-18 16:53:58 +03:00
return 0 ;
2005-10-17 03:03:59 +04:00
if ( ! ( _pvid_hash = dm_hash_create ( 128 ) ) )
2002-11-18 16:53:58 +03:00
return 0 ;
2005-10-17 03:03:59 +04:00
if ( ! ( _lock_hash = dm_hash_create ( 128 ) ) )
2003-07-05 02:34:56 +04:00
return 0 ;
2002-11-18 16:53:58 +03:00
return 1 ;
}
2006-05-11 21:58:58 +04:00
void lvmcache_lock_vgname ( const char * vgname , int read_only __attribute ( ( unused ) ) )
2002-11-18 16:53:58 +03:00
{
2003-07-05 02:34:56 +04:00
if ( ! _lock_hash & & ! lvmcache_init ( ) ) {
log_error ( " Internal cache initialisation failed " ) ;
return ;
}
2005-10-17 03:03:59 +04:00
if ( ! dm_hash_insert ( _lock_hash , vgname , ( void * ) 1 ) )
2003-07-05 02:34:56 +04:00
log_error ( " Cache locking failure for %s " , vgname ) ;
_vgs_locked + + ;
}
2005-10-27 21:41:41 +04:00
int vgname_is_locked ( const char * vgname )
2003-07-05 02:34:56 +04:00
{
if ( ! _lock_hash )
return 0 ;
2005-10-17 03:03:59 +04:00
return dm_hash_lookup ( _lock_hash , vgname ) ? 1 : 0 ;
2003-07-05 02:34:56 +04:00
}
void lvmcache_unlock_vgname ( const char * vgname )
{
/* FIXME: Clear all CACHE_LOCKED flags in this vg */
2005-10-17 03:03:59 +04:00
dm_hash_remove ( _lock_hash , vgname ) ;
2003-07-05 02:34:56 +04:00
/* FIXME Do this per-VG */
if ( ! - - _vgs_locked )
dev_close_all ( ) ;
}
int vgs_locked ( void )
{
return _vgs_locked ;
}
2006-04-12 21:54:11 +04:00
/* If vgid supplied, require a match. */
struct lvmcache_vginfo * vginfo_from_vgname ( const char * vgname , const char * vgid )
2003-07-05 02:34:56 +04:00
{
struct lvmcache_vginfo * vginfo ;
2002-11-18 16:53:58 +03:00
if ( ! _vgname_hash )
return NULL ;
2005-10-17 03:03:59 +04:00
if ( ! ( vginfo = dm_hash_lookup ( _vgname_hash , vgname ) ) )
2002-11-18 16:53:58 +03:00
return NULL ;
2006-04-12 21:54:11 +04:00
if ( vgid )
do
2006-04-21 18:44:33 +04:00
if ( ! strncmp ( vgid , vginfo - > vgid , ID_LEN ) )
2006-04-12 21:54:11 +04:00
return vginfo ;
while ( ( vginfo = vginfo - > next ) ) ;
2002-11-18 16:53:58 +03:00
return vginfo ;
}
2006-04-13 01:23:04 +04:00
const struct format_type * fmt_from_vgname ( const char * vgname , const char * vgid )
2002-11-18 16:53:58 +03:00
{
2003-07-05 02:34:56 +04:00
struct lvmcache_vginfo * vginfo ;
2005-06-01 20:51:55 +04:00
struct lvmcache_info * info ;
2005-03-22 01:40:35 +03:00
struct label * label ;
2005-06-01 20:51:55 +04:00
struct list * devh , * tmp ;
2005-03-22 01:40:35 +03:00
struct list devs ;
struct device_list * devl ;
2006-12-01 02:11:42 +03:00
char vgid_found [ ID_LEN + 1 ] __attribute ( ( aligned ( 8 ) ) ) ;
2002-11-18 16:53:58 +03:00
2006-04-13 01:23:04 +04:00
if ( ! ( vginfo = vginfo_from_vgname ( vgname , vgid ) ) )
2002-11-18 16:53:58 +03:00
return NULL ;
2005-03-22 01:40:35 +03:00
/* This function is normally called before reading metadata so
* we check cached labels here . Unfortunately vginfo is volatile . */
list_init ( & devs ) ;
2005-06-01 20:51:55 +04:00
list_iterate_items ( info , & vginfo - > infos ) {
2006-05-10 21:49:25 +04:00
if ( ! ( devl = dm_malloc ( sizeof ( * devl ) ) ) ) {
log_error ( " device_list element allocation failed " ) ;
return NULL ;
}
2005-06-01 20:51:55 +04:00
devl - > dev = info - > dev ;
2005-03-22 01:40:35 +03:00
list_add ( & devs , & devl - > list ) ;
}
2006-04-13 01:23:04 +04:00
memcpy ( vgid_found , vginfo - > vgid , sizeof ( vgid_found ) ) ;
2006-04-12 21:54:11 +04:00
2005-03-22 01:40:35 +03:00
list_iterate_safe ( devh , tmp , & devs ) {
devl = list_item ( devh , struct device_list ) ;
2007-04-23 22:21:01 +04:00
label_read ( devl - > dev , & label , UINT64_C ( 0 ) ) ;
2005-03-22 01:40:35 +03:00
list_del ( & devl - > list ) ;
2005-10-17 03:03:59 +04:00
dm_free ( devl ) ;
2005-03-22 01:40:35 +03:00
}
2006-04-12 21:54:11 +04:00
/* If vginfo changed, caller needs to rescan */
2006-04-13 01:23:04 +04:00
if ( ! ( vginfo = vginfo_from_vgname ( vgname , vgid_found ) ) | |
2006-04-21 18:44:33 +04:00
strncmp ( vginfo - > vgid , vgid_found , ID_LEN ) )
2006-04-12 21:54:11 +04:00
return NULL ;
2002-11-18 16:53:58 +03:00
return vginfo - > fmt ;
}
2003-07-05 02:34:56 +04:00
struct lvmcache_vginfo * vginfo_from_vgid ( const char * vgid )
2002-11-18 16:53:58 +03:00
{
2003-07-05 02:34:56 +04:00
struct lvmcache_vginfo * vginfo ;
2006-12-01 02:11:42 +03:00
char id [ ID_LEN + 1 ] __attribute ( ( aligned ( 8 ) ) ) ;
2002-11-18 16:53:58 +03:00
if ( ! _vgid_hash | | ! vgid )
return NULL ;
2003-01-10 22:14:01 +03:00
/* vgid not necessarily NULL-terminated */
strncpy ( & id [ 0 ] , vgid , ID_LEN ) ;
id [ ID_LEN ] = ' \0 ' ;
2005-10-17 03:03:59 +04:00
if ( ! ( vginfo = dm_hash_lookup ( _vgid_hash , id ) ) )
2002-11-18 16:53:58 +03:00
return NULL ;
return vginfo ;
}
2006-04-14 01:08:29 +04:00
const char * vgname_from_vgid ( struct dm_pool * mem , const char * vgid )
2006-04-13 01:23:04 +04:00
{
struct lvmcache_vginfo * vginfo ;
2006-06-15 00:11:22 +04:00
const char * vgname = NULL ;
2006-04-13 01:23:04 +04:00
2006-06-15 00:11:22 +04:00
if ( ! * vgid )
vgname = ORPHAN ;
if ( ( vginfo = vginfo_from_vgid ( vgid ) ) )
vgname = vginfo - > vgname ;
if ( mem & & vgname )
return dm_pool_strdup ( mem , vgname ) ;
2006-04-13 01:23:04 +04:00
2006-06-15 00:11:22 +04:00
return vgname ;
2006-04-13 01:23:04 +04:00
}
2003-07-05 02:34:56 +04:00
struct lvmcache_info * info_from_pvid ( const char * pvid )
2002-11-18 16:53:58 +03:00
{
2003-07-05 02:34:56 +04:00
struct lvmcache_info * info ;
2006-12-01 02:11:42 +03:00
char id [ ID_LEN + 1 ] __attribute ( ( aligned ( 8 ) ) ) ;
2002-11-18 16:53:58 +03:00
if ( ! _pvid_hash | | ! pvid )
return NULL ;
2003-01-10 22:14:01 +03:00
strncpy ( & id [ 0 ] , pvid , ID_LEN ) ;
id [ ID_LEN ] = ' \0 ' ;
2005-10-17 03:03:59 +04:00
if ( ! ( info = dm_hash_lookup ( _pvid_hash , id ) ) )
2002-11-18 16:53:58 +03:00
return NULL ;
return info ;
}
2003-07-05 02:34:56 +04:00
static void _rescan_entry ( struct lvmcache_info * info )
2002-11-18 16:53:58 +03:00
{
struct label * label ;
if ( info - > status & CACHE_INVALID )
2007-04-23 22:21:01 +04:00
label_read ( info - > dev , & label , UINT64_C ( 0 ) ) ;
2002-11-18 16:53:58 +03:00
}
2002-12-20 02:25:55 +03:00
static int _scan_invalid ( void )
2002-11-18 16:53:58 +03:00
{
2005-10-17 03:03:59 +04:00
dm_hash_iter ( _pvid_hash , ( dm_hash_iterate_fn ) _rescan_entry ) ;
2002-11-18 16:53:58 +03:00
return 1 ;
}
2003-07-05 02:34:56 +04:00
int lvmcache_label_scan ( struct cmd_context * cmd , int full_scan )
2002-11-18 16:53:58 +03:00
{
struct label * label ;
struct dev_iter * iter ;
struct device * dev ;
struct format_type * fmt ;
static int _scanning_in_progress = 0 ;
int r = 0 ;
/* Avoid recursion when a PVID can't be found! */
if ( _scanning_in_progress )
return 0 ;
_scanning_in_progress = 1 ;
2003-07-05 02:34:56 +04:00
if ( ! _vgname_hash & & ! lvmcache_init ( ) ) {
2002-11-18 16:53:58 +03:00
log_error ( " Internal cache initialisation failed " ) ;
goto out ;
}
if ( _has_scanned & & ! full_scan ) {
2002-12-20 02:25:55 +03:00
r = _scan_invalid ( ) ;
2002-11-18 16:53:58 +03:00
goto out ;
}
2006-08-01 18:56:33 +04:00
if ( ! ( iter = dev_iter_create ( cmd - > filter , ( full_scan = = 2 ) ? 1 : 0 ) ) ) {
2002-11-18 16:53:58 +03:00
log_error ( " dev_iter creation failed " ) ;
goto out ;
}
while ( ( dev = dev_iter_get ( iter ) ) )
2007-04-23 22:21:01 +04:00
label_read ( dev , & label , UINT64_C ( 0 ) ) ;
2002-11-18 16:53:58 +03:00
dev_iter_destroy ( iter ) ;
_has_scanned = 1 ;
/* Perform any format-specific scanning e.g. text files */
2005-06-01 20:51:55 +04:00
list_iterate_items ( fmt , & cmd - > formats ) {
2002-11-18 16:53:58 +03:00
if ( fmt - > ops - > scan & & ! fmt - > ops - > scan ( fmt ) )
goto out ;
}
r = 1 ;
out :
_scanning_in_progress = 0 ;
return r ;
}
2006-04-13 01:23:04 +04:00
struct list * lvmcache_get_vgids ( struct cmd_context * cmd , int full_scan )
{
struct list * vgids ;
struct lvmcache_vginfo * vginfo ;
lvmcache_label_scan ( cmd , full_scan ) ;
if ( ! ( vgids = str_list_create ( cmd - > mem ) ) ) {
log_error ( " vgids list allocation failed " ) ;
return NULL ;
}
list_iterate_items ( vginfo , & _vginfos ) {
if ( ! str_list_add ( cmd - > mem , vgids ,
dm_pool_strdup ( cmd - > mem , vginfo - > vgid ) ) ) {
log_error ( " strlist allocation failed " ) ;
return NULL ;
}
}
return vgids ;
}
2003-07-05 02:34:56 +04:00
struct list * lvmcache_get_vgnames ( struct cmd_context * cmd , int full_scan )
2002-11-18 16:53:58 +03:00
{
2003-10-16 00:04:29 +04:00
struct list * vgnames ;
2006-04-11 23:09:55 +04:00
struct lvmcache_vginfo * vginfo ;
2002-11-18 16:53:58 +03:00
2003-07-05 02:34:56 +04:00
lvmcache_label_scan ( cmd , full_scan ) ;
2002-11-18 16:53:58 +03:00
2003-10-16 00:04:29 +04:00
if ( ! ( vgnames = str_list_create ( cmd - > mem ) ) ) {
2002-11-18 16:53:58 +03:00
log_error ( " vgnames list allocation failed " ) ;
return NULL ;
}
2006-04-11 23:09:55 +04:00
list_iterate_items ( vginfo , & _vginfos ) {
2003-10-16 00:04:29 +04:00
if ( ! str_list_add ( cmd - > mem , vgnames ,
2006-04-11 23:09:55 +04:00
dm_pool_strdup ( cmd - > mem , vginfo - > vgname ) ) ) {
2002-11-18 16:53:58 +03:00
log_error ( " strlist allocation failed " ) ;
return NULL ;
}
}
return vgnames ;
}
2006-04-21 23:12:41 +04:00
struct list * lvmcache_get_pvids ( struct cmd_context * cmd , const char * vgname ,
const char * vgid )
{
struct list * pvids ;
struct lvmcache_vginfo * vginfo ;
struct lvmcache_info * info ;
if ( ! ( pvids = str_list_create ( cmd - > mem ) ) ) {
log_error ( " pvids list allocation failed " ) ;
return NULL ;
}
if ( ! ( vginfo = vginfo_from_vgname ( vgname , vgid ) ) )
return pvids ;
list_iterate_items ( info , & vginfo - > infos ) {
if ( ! str_list_add ( cmd - > mem , pvids ,
dm_pool_strdup ( cmd - > mem , info - > dev - > pvid ) ) ) {
log_error ( " strlist allocation failed " ) ;
return NULL ;
}
}
return pvids ;
}
2002-11-18 16:53:58 +03:00
struct device * device_from_pvid ( struct cmd_context * cmd , struct id * pvid )
{
struct label * label ;
2003-07-05 02:34:56 +04:00
struct lvmcache_info * info ;
2002-11-18 16:53:58 +03:00
/* Already cached ? */
if ( ( info = info_from_pvid ( ( char * ) pvid ) ) ) {
2007-04-23 22:21:01 +04:00
if ( label_read ( info - > dev , & label , UINT64_C ( 0 ) ) ) {
2003-07-05 02:34:56 +04:00
info = ( struct lvmcache_info * ) label - > info ;
2002-11-18 16:53:58 +03:00
if ( id_equal ( pvid , ( struct id * ) & info - > dev - > pvid ) )
return info - > dev ;
}
}
2003-07-05 02:34:56 +04:00
lvmcache_label_scan ( cmd , 0 ) ;
2002-11-18 16:53:58 +03:00
/* Try again */
if ( ( info = info_from_pvid ( ( char * ) pvid ) ) ) {
2007-04-23 22:21:01 +04:00
if ( label_read ( info - > dev , & label , UINT64_C ( 0 ) ) ) {
2003-07-05 02:34:56 +04:00
info = ( struct lvmcache_info * ) label - > info ;
2002-11-18 16:53:58 +03:00
if ( id_equal ( pvid , ( struct id * ) & info - > dev - > pvid ) )
return info - > dev ;
}
}
2003-07-05 02:34:56 +04:00
if ( memlock ( ) )
return NULL ;
2005-03-08 16:46:17 +03:00
lvmcache_label_scan ( cmd , 2 ) ;
2002-11-18 16:53:58 +03:00
/* Try again */
if ( ( info = info_from_pvid ( ( char * ) pvid ) ) ) {
2007-04-23 22:21:01 +04:00
if ( label_read ( info - > dev , & label , UINT64_C ( 0 ) ) ) {
2003-07-05 02:34:56 +04:00
info = ( struct lvmcache_info * ) label - > info ;
2002-11-18 16:53:58 +03:00
if ( id_equal ( pvid , ( struct id * ) & info - > dev - > pvid ) )
return info - > dev ;
}
}
return NULL ;
}
2006-04-12 21:54:11 +04:00
static int _drop_vginfo ( struct lvmcache_info * info )
2002-11-18 16:53:58 +03:00
{
if ( ! list_empty ( & info - > list ) ) {
list_del ( & info - > list ) ;
list_init ( & info - > list ) ;
}
if ( info - > vginfo & & list_empty ( & info - > vginfo - > infos ) ) {
2005-10-17 03:03:59 +04:00
dm_hash_remove ( _vgname_hash , info - > vginfo - > vgname ) ;
2006-04-12 21:54:11 +04:00
if ( info - > vginfo - > next ) {
if ( ! dm_hash_insert ( _vgname_hash , info - > vginfo - > vgname , info - > vginfo - > next ) ) {
log_error ( " vg hash re-insertion failed: %s " ,
info - > vginfo - > vgname ) ;
return 0 ;
}
}
2002-11-18 16:53:58 +03:00
if ( info - > vginfo - > vgname )
2005-10-17 03:03:59 +04:00
dm_free ( info - > vginfo - > vgname ) ;
2006-04-13 21:32:24 +04:00
if ( info - > vginfo - > creation_host )
dm_free ( info - > vginfo - > creation_host ) ;
2002-11-18 16:53:58 +03:00
if ( * info - > vginfo - > vgid )
2005-10-17 03:03:59 +04:00
dm_hash_remove ( _vgid_hash , info - > vginfo - > vgid ) ;
2002-11-18 16:53:58 +03:00
list_del ( & info - > vginfo - > list ) ;
2005-10-17 03:03:59 +04:00
dm_free ( info - > vginfo ) ;
2002-11-18 16:53:58 +03:00
}
info - > vginfo = NULL ;
2006-04-12 21:54:11 +04:00
return 1 ;
2002-11-18 16:53:58 +03:00
}
/* Unused
2003-07-05 02:34:56 +04:00
void lvmcache_del ( struct lvmcache_info * info )
2002-11-18 16:53:58 +03:00
{
if ( info - > dev - > pvid [ 0 ] & & _pvid_hash )
2005-10-17 03:03:59 +04:00
dm_hash_remove ( _pvid_hash , info - > dev - > pvid ) ;
2002-11-18 16:53:58 +03:00
_drop_vginfo ( info ) ;
info - > label - > labeller - > ops - > destroy_label ( info - > label - > labeller ,
info - > label ) ;
2005-10-17 03:03:59 +04:00
dm_free ( info ) ;
2002-11-18 16:53:58 +03:00
return ;
} */
2003-07-05 02:34:56 +04:00
static int _lvmcache_update_pvid ( struct lvmcache_info * info , const char * pvid )
2002-11-18 16:53:58 +03:00
{
if ( ! strcmp ( info - > dev - > pvid , pvid ) )
return 1 ;
if ( * info - > dev - > pvid ) {
2005-10-17 03:03:59 +04:00
dm_hash_remove ( _pvid_hash , info - > dev - > pvid ) ;
2002-11-18 16:53:58 +03:00
}
strncpy ( info - > dev - > pvid , pvid , sizeof ( info - > dev - > pvid ) ) ;
2005-10-17 03:03:59 +04:00
if ( ! dm_hash_insert ( _pvid_hash , pvid , info ) ) {
2003-07-05 02:34:56 +04:00
log_error ( " _lvmcache_update: pvid insertion failed: %s " , pvid ) ;
2002-11-18 16:53:58 +03:00
return 0 ;
}
return 1 ;
}
2006-04-11 20:00:26 +04:00
static int _lvmcache_update_vgid ( struct lvmcache_info * info , const char * vgid )
2002-11-18 16:53:58 +03:00
{
2006-04-21 18:44:33 +04:00
if ( ! vgid | | ! info - > vginfo | |
! strncmp ( info - > vginfo - > vgid , vgid , ID_LEN ) )
2002-11-18 16:53:58 +03:00
return 1 ;
if ( info - > vginfo & & * info - > vginfo - > vgid )
2005-10-17 03:03:59 +04:00
dm_hash_remove ( _vgid_hash , info - > vginfo - > vgid ) ;
2006-04-11 02:09:00 +04:00
if ( ! vgid ) {
log_debug ( " lvmcache: %s: clearing VGID " , dev_name ( info - > dev ) ) ;
2002-11-18 16:53:58 +03:00
return 1 ;
2006-04-11 02:09:00 +04:00
}
2002-11-18 16:53:58 +03:00
2006-04-21 18:44:33 +04:00
strncpy ( info - > vginfo - > vgid , vgid , ID_LEN ) ;
info - > vginfo - > vgid [ ID_LEN ] = ' \0 ' ;
2005-10-17 03:03:59 +04:00
if ( ! dm_hash_insert ( _vgid_hash , info - > vginfo - > vgid , info - > vginfo ) ) {
2003-07-05 02:34:56 +04:00
log_error ( " _lvmcache_update: vgid hash insertion failed: %s " ,
info - > vginfo - > vgid ) ;
2002-11-18 16:53:58 +03:00
return 0 ;
}
2006-04-11 17:55:59 +04:00
log_debug ( " lvmcache: %s: setting %s VGID to %s " , dev_name ( info - > dev ) ,
info - > vginfo - > vgname , info - > vginfo - > vgid ) ;
2006-04-11 02:09:00 +04:00
2002-11-18 16:53:58 +03:00
return 1 ;
}
2006-04-12 21:54:11 +04:00
static int _insert_vginfo ( struct lvmcache_vginfo * new_vginfo , const char * vgid ,
2006-04-13 21:32:24 +04:00
uint32_t vgstatus , const char * creation_host ,
2006-04-12 21:54:11 +04:00
struct lvmcache_vginfo * primary_vginfo )
{
struct lvmcache_vginfo * last_vginfo = primary_vginfo ;
2006-12-01 02:11:42 +03:00
char uuid_primary [ 64 ] __attribute ( ( aligned ( 8 ) ) ) ;
char uuid_new [ 64 ] __attribute ( ( aligned ( 8 ) ) ) ;
2006-04-13 21:32:24 +04:00
int use_new = 0 ;
2006-04-13 01:23:04 +04:00
2006-04-12 21:54:11 +04:00
/* Pre-existing VG takes precedence. Unexported VG takes precedence. */
if ( primary_vginfo ) {
2006-05-10 01:23:51 +04:00
if ( ! id_write_format ( ( const struct id * ) vgid , uuid_new , sizeof ( uuid_new ) ) )
2006-04-13 01:23:04 +04:00
return_0 ;
2006-05-10 01:23:51 +04:00
if ( ! id_write_format ( ( const struct id * ) & primary_vginfo - > vgid , uuid_primary ,
2006-04-13 01:23:04 +04:00
sizeof ( uuid_primary ) ) )
return_0 ;
2006-04-13 21:32:24 +04:00
/*
* If Primary not exported , new exported = > keep
* Else Primary exported , new not exported = > change
* Else Primary has hostname for this machine = > keep
* Else Primary has no hostname , new has one = > change
* Else New has hostname for this machine = > change
* Else Keep primary .
*/
if ( ! ( primary_vginfo - > status & EXPORTED_VG ) & &
( vgstatus & EXPORTED_VG ) )
log_error ( " WARNING: Duplicate VG name %s: "
" Existing %s takes precedence over "
" exported %s " , new_vginfo - > vgname ,
uuid_primary , uuid_new ) ;
else if ( ( primary_vginfo - > status & EXPORTED_VG ) & &
! ( vgstatus & EXPORTED_VG ) ) {
2006-04-13 01:23:04 +04:00
log_error ( " WARNING: Duplicate VG name %s: "
" %s takes precedence over exported %s " ,
new_vginfo - > vgname , uuid_new ,
uuid_primary ) ;
2006-04-13 21:32:24 +04:00
use_new = 1 ;
} else if ( primary_vginfo - > creation_host & &
! strcmp ( primary_vginfo - > creation_host ,
primary_vginfo - > fmt - > cmd - > hostname ) )
log_error ( " WARNING: Duplicate VG name %s: "
" Existing %s (created here) takes precedence "
" over %s " , new_vginfo - > vgname , uuid_primary ,
uuid_new ) ;
else if ( ! primary_vginfo - > creation_host & & creation_host ) {
log_error ( " WARNING: Duplicate VG name %s: "
" %s (with creation_host) takes precedence over %s " ,
new_vginfo - > vgname , uuid_new ,
uuid_primary ) ;
use_new = 1 ;
} else if ( creation_host & &
! strcmp ( creation_host ,
primary_vginfo - > fmt - > cmd - > hostname ) ) {
log_error ( " WARNING: Duplicate VG name %s: "
" %s (created here) takes precedence over %s " ,
new_vginfo - > vgname , uuid_new ,
uuid_primary ) ;
use_new = 1 ;
}
if ( ! use_new ) {
while ( last_vginfo - > next )
last_vginfo = last_vginfo - > next ;
last_vginfo - > next = new_vginfo ;
return 1 ;
}
2006-04-12 21:54:11 +04:00
dm_hash_remove ( _vgname_hash , primary_vginfo - > vgname ) ;
}
if ( ! dm_hash_insert ( _vgname_hash , new_vginfo - > vgname , new_vginfo ) ) {
log_error ( " cache_update: vg hash insertion failed: %s " ,
new_vginfo - > vgname ) ;
return 0 ;
}
if ( primary_vginfo )
new_vginfo - > next = primary_vginfo ;
return 1 ;
}
2006-04-11 20:00:26 +04:00
static int _lvmcache_update_vgname ( struct lvmcache_info * info ,
2006-04-13 01:23:04 +04:00
const char * vgname , const char * vgid ,
2006-04-13 21:32:24 +04:00
uint32_t vgstatus , const char * creation_host )
2002-11-18 16:53:58 +03:00
{
2006-04-12 21:54:11 +04:00
struct lvmcache_vginfo * vginfo , * primary_vginfo ;
2006-04-14 01:08:29 +04:00
// struct lvmcache_vginfo *old_vginfo, *next;
2002-11-18 16:53:58 +03:00
/* If vgname is NULL and we don't already have a vgname,
* assume ORPHAN - we want every entry to have a vginfo
* attached for scanning reasons .
*/
2006-04-13 01:23:04 +04:00
if ( ! vgname & & ! info - > vginfo ) {
2002-11-18 16:53:58 +03:00
vgname = ORPHAN ;
2006-04-13 01:23:04 +04:00
vgid = ORPHAN ;
}
2002-11-18 16:53:58 +03:00
if ( ! vgname | | ( info - > vginfo & & ! strcmp ( info - > vginfo - > vgname , vgname ) ) )
return 1 ;
/* Remove existing vginfo entry */
_drop_vginfo ( info ) ;
/* Get existing vginfo or create new one */
2006-04-12 21:54:11 +04:00
if ( ! ( vginfo = vginfo_from_vgname ( vgname , vgid ) ) ) {
2006-04-14 01:08:29 +04:00
/*** FIXME - vginfo ends up duplicated instead of renamed.
// Renaming? This lookup fails.
if ( ( vginfo = vginfo_from_vgid ( vgid ) ) ) {
next = vginfo - > next ;
old_vginfo = vginfo_from_vgname ( vginfo - > vgname , NULL ) ;
if ( old_vginfo = = vginfo ) {
dm_hash_remove ( _vgname_hash , old_vginfo - > vgname ) ;
if ( old_vginfo - > next ) {
if ( ! dm_hash_insert ( _vgname_hash , old_vginfo - > vgname , old_vginfo - > next ) ) {
log_error ( " vg hash re-insertion failed: %s " ,
old_vginfo - > vgname ) ;
return 0 ;
}
}
} else do {
if ( old_vginfo - > next = = vginfo ) {
old_vginfo - > next = vginfo - > next ;
break ;
}
} while ( ( old_vginfo = old_vginfo - > next ) ) ;
vginfo - > next = NULL ;
dm_free ( vginfo - > vgname ) ;
if ( ! ( vginfo - > vgname = dm_strdup ( vgname ) ) ) {
log_error ( " cache vgname alloc failed for %s " , vgname ) ;
return 0 ;
}
// Rename so can assume new name does not already exist
if ( ! dm_hash_insert ( _vgname_hash , vginfo - > vgname , vginfo - > next ) ) {
log_error ( " vg hash re-insertion failed: %s " ,
vginfo - > vgname ) ;
return 0 ;
}
} else {
* * */
2005-10-17 03:03:59 +04:00
if ( ! ( vginfo = dm_malloc ( sizeof ( * vginfo ) ) ) ) {
2003-07-05 02:34:56 +04:00
log_error ( " lvmcache_update_vgname: list alloc failed " ) ;
2002-11-18 16:53:58 +03:00
return 0 ;
}
memset ( vginfo , 0 , sizeof ( * vginfo ) ) ;
2005-10-17 03:03:59 +04:00
if ( ! ( vginfo - > vgname = dm_strdup ( vgname ) ) ) {
dm_free ( vginfo ) ;
2002-11-18 16:53:58 +03:00
log_error ( " cache vgname alloc failed for %s " , vgname ) ;
return 0 ;
}
list_init ( & vginfo - > infos ) ;
2006-04-14 01:08:29 +04:00
primary_vginfo = vginfo_from_vgname ( vgname , NULL ) ;
2006-04-13 21:32:24 +04:00
if ( ! _insert_vginfo ( vginfo , vgid , vgstatus , creation_host ,
primary_vginfo ) ) {
2005-10-17 03:03:59 +04:00
dm_free ( vginfo - > vgname ) ;
dm_free ( vginfo ) ;
2002-11-18 16:53:58 +03:00
return 0 ;
}
/* Ensure orphans appear last on list_iterate */
if ( ! * vgname )
list_add ( & _vginfos , & vginfo - > list ) ;
else
list_add_h ( & _vginfos , & vginfo - > list ) ;
2006-04-14 01:08:29 +04:00
/***
}
* * */
2002-11-18 16:53:58 +03:00
}
info - > vginfo = vginfo ;
list_add ( & vginfo - > infos , & info - > list ) ;
/* FIXME Check consistency of list! */
vginfo - > fmt = info - > fmt ;
2006-04-11 17:55:59 +04:00
log_debug ( " lvmcache: %s: now %s%s%s%s%s " , dev_name ( info - > dev ) ,
* vgname ? " in VG " : " orphaned " , vgname ,
vginfo - > vgid [ 0 ] ? " ( " : " " ,
vginfo - > vgid [ 0 ] ? vginfo - > vgid : " " ,
vginfo - > vgid [ 0 ] ? " ) " : " " ) ;
2005-03-22 01:40:35 +03:00
2002-11-18 16:53:58 +03:00
return 1 ;
}
2006-04-13 21:32:24 +04:00
static int _lvmcache_update_vgstatus ( struct lvmcache_info * info , uint32_t vgstatus ,
const char * creation_host )
2006-04-11 21:42:15 +04:00
{
if ( ! info | | ! info - > vginfo )
return 1 ;
if ( ( info - > vginfo - > status & EXPORTED_VG ) ! = ( vgstatus & EXPORTED_VG ) )
2006-04-13 21:32:24 +04:00
log_debug ( " lvmcache: %s: VG %s %s exported " ,
dev_name ( info - > dev ) , info - > vginfo - > vgname ,
2006-04-11 21:42:15 +04:00
vgstatus & EXPORTED_VG ? " now " : " no longer " ) ;
info - > vginfo - > status = vgstatus ;
2006-04-13 21:32:24 +04:00
if ( ! creation_host )
return 1 ;
if ( info - > vginfo - > creation_host & & ! strcmp ( creation_host ,
info - > vginfo - > creation_host ) )
return 1 ;
if ( info - > vginfo - > creation_host )
dm_free ( info - > vginfo - > creation_host ) ;
if ( ! ( info - > vginfo - > creation_host = dm_strdup ( creation_host ) ) ) {
log_error ( " cache creation host alloc failed for %s " ,
creation_host ) ;
return 0 ;
}
log_debug ( " lvmcache: %s: VG %s: Set creation host to %s. " ,
dev_name ( info - > dev ) , info - > vginfo - > vgname , creation_host ) ;
2006-04-11 21:42:15 +04:00
return 1 ;
}
int lvmcache_update_vgname_and_id ( struct lvmcache_info * info ,
const char * vgname , const char * vgid ,
2006-04-13 21:32:24 +04:00
uint32_t vgstatus , const char * creation_host )
2006-04-11 20:00:26 +04:00
{
2006-04-13 21:32:24 +04:00
if ( ! _lvmcache_update_vgname ( info , vgname , vgid , vgstatus ,
creation_host ) | |
2006-04-11 21:42:15 +04:00
! _lvmcache_update_vgid ( info , vgid ) | |
2006-04-13 21:32:24 +04:00
! _lvmcache_update_vgstatus ( info , vgstatus , creation_host ) )
2006-04-11 20:00:26 +04:00
return_0 ;
return 1 ;
}
2003-07-05 02:34:56 +04:00
int lvmcache_update_vg ( struct volume_group * vg )
2002-11-18 16:53:58 +03:00
{
2005-06-01 20:51:55 +04:00
struct pv_list * pvl ;
2003-07-05 02:34:56 +04:00
struct lvmcache_info * info ;
2006-12-01 02:11:42 +03:00
char pvid_s [ ID_LEN + 1 ] __attribute ( ( aligned ( 8 ) ) ) ;
2002-11-18 16:53:58 +03:00
pvid_s [ sizeof ( pvid_s ) - 1 ] = ' \0 ' ;
2005-06-01 20:51:55 +04:00
list_iterate_items ( pvl , & vg - > pvs ) {
strncpy ( pvid_s , ( char * ) & pvl - > pv - > id , sizeof ( pvid_s ) - 1 ) ;
/* FIXME Could pvl->pv->dev->pvid ever be different? */
2006-04-11 20:00:26 +04:00
if ( ( info = info_from_pvid ( pvid_s ) ) & &
! lvmcache_update_vgname_and_id ( info , vg - > name ,
2006-04-11 21:42:15 +04:00
( char * ) & vg - > id ,
2006-04-13 21:32:24 +04:00
vg - > status , NULL ) )
2006-04-11 20:00:26 +04:00
return_0 ;
2002-11-18 16:53:58 +03:00
}
return 1 ;
}
2003-07-05 02:34:56 +04:00
struct lvmcache_info * lvmcache_add ( struct labeller * labeller , const char * pvid ,
struct device * dev ,
2006-04-11 21:42:15 +04:00
const char * vgname , const char * vgid ,
uint32_t vgstatus )
2002-11-18 16:53:58 +03:00
{
struct label * label ;
2003-07-05 02:34:56 +04:00
struct lvmcache_info * existing , * info ;
2006-12-01 02:11:42 +03:00
char pvid_s [ ID_LEN + 1 ] __attribute ( ( aligned ( 8 ) ) ) ;
2002-11-18 16:53:58 +03:00
2003-07-05 02:34:56 +04:00
if ( ! _vgname_hash & & ! lvmcache_init ( ) ) {
2002-11-18 16:53:58 +03:00
log_error ( " Internal cache initialisation failed " ) ;
return NULL ;
}
strncpy ( pvid_s , pvid , sizeof ( pvid_s ) ) ;
pvid_s [ sizeof ( pvid_s ) - 1 ] = ' \0 ' ;
if ( ! ( existing = info_from_pvid ( pvid_s ) ) & &
! ( existing = info_from_pvid ( dev - > pvid ) ) ) {
if ( ! ( label = label_create ( labeller ) ) ) {
stack ;
return NULL ;
}
2005-10-17 03:03:59 +04:00
if ( ! ( info = dm_malloc ( sizeof ( * info ) ) ) ) {
2003-07-05 02:34:56 +04:00
log_error ( " lvmcache_info allocation failed " ) ;
2002-11-18 16:53:58 +03:00
label_destroy ( label ) ;
return NULL ;
}
memset ( info , 0 , sizeof ( * info ) ) ;
label - > info = info ;
info - > label = label ;
list_init ( & info - > list ) ;
info - > dev = dev ;
} else {
2003-01-07 00:10:43 +03:00
if ( existing - > dev ! = dev ) {
/* Is the existing entry a duplicate pvid e.g. md ? */
if ( MAJOR ( existing - > dev - > dev ) = = md_major ( ) & &
MAJOR ( dev - > dev ) ! = md_major ( ) ) {
log_very_verbose ( " Ignoring duplicate PV %s on "
" %s - using md %s " ,
pvid , dev_name ( dev ) ,
dev_name ( existing - > dev ) ) ;
return NULL ;
2005-10-25 23:08:21 +04:00
} else if ( dm_is_dm_major ( MAJOR ( existing - > dev - > dev ) ) & &
! dm_is_dm_major ( MAJOR ( dev - > dev ) ) ) {
2005-09-16 22:53:01 +04:00
log_very_verbose ( " Ignoring duplicate PV %s on "
" %s - using dm %s " ,
pvid , dev_name ( dev ) ,
dev_name ( existing - > dev ) ) ;
return NULL ;
2003-01-07 00:10:43 +03:00
} else if ( MAJOR ( existing - > dev - > dev ) ! = md_major ( ) & &
MAJOR ( dev - > dev ) = = md_major ( ) )
log_very_verbose ( " Duplicate PV %s on %s - "
" using md %s " , pvid ,
dev_name ( existing - > dev ) ,
dev_name ( dev ) ) ;
2005-10-25 23:08:21 +04:00
else if ( ! dm_is_dm_major ( MAJOR ( existing - > dev - > dev ) ) & &
dm_is_dm_major ( MAJOR ( dev - > dev ) ) )
2005-09-16 22:53:01 +04:00
log_very_verbose ( " Duplicate PV %s on %s - "
" using dm %s " , pvid ,
dev_name ( existing - > dev ) ,
dev_name ( dev ) ) ;
2005-10-28 01:51:28 +04:00
/* FIXME If both dm, check dependencies */
//else if (dm_is_dm_major(MAJOR(existing->dev->dev)) &&
//dm_is_dm_major(MAJOR(dev->dev)))
//
2003-01-07 00:10:43 +03:00
else
log_error ( " Found duplicate PV %s: using %s not "
" %s " , pvid , dev_name ( dev ) ,
dev_name ( existing - > dev ) ) ;
}
2005-09-16 22:44:52 +04:00
/* Switch over to new preferred device */
existing - > dev = dev ;
2002-11-18 16:53:58 +03:00
info = existing ;
/* Has labeller changed? */
if ( info - > label - > labeller ! = labeller ) {
label_destroy ( info - > label ) ;
if ( ! ( info - > label = label_create ( labeller ) ) ) {
/* FIXME leaves info without label! */
stack ;
return NULL ;
}
info - > label - > info = info ;
}
label = info - > label ;
}
2002-12-20 02:25:55 +03:00
info - > fmt = ( const struct format_type * ) labeller - > private ;
2002-11-18 16:53:58 +03:00
info - > status | = CACHE_INVALID ;
2003-07-05 02:34:56 +04:00
if ( ! _lvmcache_update_pvid ( info , pvid_s ) ) {
2002-11-18 16:53:58 +03:00
if ( ! existing ) {
2005-10-17 03:03:59 +04:00
dm_free ( info ) ;
2002-11-18 16:53:58 +03:00
label_destroy ( label ) ;
}
return NULL ;
}
2006-04-13 21:32:24 +04:00
if ( ! lvmcache_update_vgname_and_id ( info , vgname , vgid , vgstatus , NULL ) ) {
2002-11-18 16:53:58 +03:00
if ( ! existing ) {
2005-10-17 03:03:59 +04:00
dm_hash_remove ( _pvid_hash , pvid_s ) ;
2002-11-18 16:53:58 +03:00
strcpy ( info - > dev - > pvid , " " ) ;
2005-10-17 03:03:59 +04:00
dm_free ( info ) ;
2002-11-18 16:53:58 +03:00
label_destroy ( label ) ;
}
return NULL ;
}
return info ;
}
2003-07-05 02:34:56 +04:00
static void _lvmcache_destroy_entry ( struct lvmcache_info * info )
2002-11-18 16:53:58 +03:00
{
if ( ! list_empty ( & info - > list ) )
list_del ( & info - > list ) ;
strcpy ( info - > dev - > pvid , " " ) ;
label_destroy ( info - > label ) ;
2005-10-17 03:03:59 +04:00
dm_free ( info ) ;
2002-11-18 16:53:58 +03:00
}
2003-07-05 02:34:56 +04:00
static void _lvmcache_destroy_vgnamelist ( struct lvmcache_vginfo * vginfo )
2002-11-18 16:53:58 +03:00
{
2006-04-12 21:54:11 +04:00
struct lvmcache_vginfo * next ;
do {
next = vginfo - > next ;
if ( vginfo - > vgname )
dm_free ( vginfo - > vgname ) ;
2006-04-13 21:32:24 +04:00
if ( vginfo - > creation_host )
dm_free ( vginfo - > creation_host ) ;
2006-04-12 21:54:11 +04:00
dm_free ( vginfo ) ;
} while ( ( vginfo = next ) ) ;
2002-11-18 16:53:58 +03:00
}
2006-05-11 21:58:58 +04:00
static void _lvmcache_destroy_lockname ( int present __attribute ( ( unused ) ) )
2003-07-05 02:34:56 +04:00
{
/* Nothing to do */
}
void lvmcache_destroy ( void )
2002-11-18 16:53:58 +03:00
{
2005-03-22 01:40:35 +03:00
log_verbose ( " Wiping internal VG cache " ) ;
2002-11-18 16:53:58 +03:00
_has_scanned = 0 ;
if ( _vgid_hash ) {
2005-10-17 03:03:59 +04:00
dm_hash_destroy ( _vgid_hash ) ;
2002-11-18 16:53:58 +03:00
_vgid_hash = NULL ;
}
if ( _pvid_hash ) {
2005-10-17 03:03:59 +04:00
dm_hash_iter ( _pvid_hash , ( dm_hash_iterate_fn ) _lvmcache_destroy_entry ) ;
dm_hash_destroy ( _pvid_hash ) ;
2002-11-18 16:53:58 +03:00
_pvid_hash = NULL ;
}
if ( _vgname_hash ) {
2005-10-17 03:03:59 +04:00
dm_hash_iter ( _vgname_hash ,
( dm_hash_iterate_fn ) _lvmcache_destroy_vgnamelist ) ;
dm_hash_destroy ( _vgname_hash ) ;
2002-11-18 16:53:58 +03:00
_vgname_hash = NULL ;
}
2003-07-05 02:34:56 +04:00
if ( _lock_hash ) {
2005-10-17 03:03:59 +04:00
dm_hash_iter ( _lock_hash , ( dm_hash_iterate_fn ) _lvmcache_destroy_lockname ) ;
dm_hash_destroy ( _lock_hash ) ;
2003-07-05 02:34:56 +04:00
_lock_hash = NULL ;
}
2002-11-18 16:53:58 +03:00
list_init ( & _vginfos ) ;
}