2002-11-18 16:53:58 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2001 - 2004 Sistina Software , Inc . All rights reserved .
2008-04-02 02:40:13 +04:00
* Copyright ( C ) 2004 - 2008 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"
2008-04-03 22:56:40 +04:00
# include "locking.h"
2002-11-18 16:53:58 +03:00
# include "metadata.h"
2003-01-07 00:10:43 +03:00
# include "filter.h"
2009-11-24 19:11:37 +03:00
# include "filter-persistent.h"
2003-07-05 02:34:56 +04:00
# include "memlock.h"
2003-10-16 00:04:29 +04:00
# include "str_list.h"
2008-05-08 22:28:27 +04:00
# include "format-text.h"
# include "format_pool.h"
# include "format1.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 ;
2008-11-04 01:14:30 +03:00
static struct dm_list _vginfos ;
2008-05-29 02:27:47 +04:00
static int _scanning_in_progress = 0 ;
2003-07-05 02:34:56 +04:00
static int _has_scanned = 0 ;
static int _vgs_locked = 0 ;
2008-04-03 22:56:40 +04:00
static int _vg_global_lock_held = 0 ; /* Global lock held when cache wiped? */
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
{
2010-01-11 22:08:18 +03:00
/*
* FIXME add a proper lvmcache_locking_reset ( ) that
* resets the cache so no previous locks are locked
*/
_vgs_locked = 0 ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & _vginfos ) ;
2002-11-18 16:53:58 +03:00
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 ;
2009-10-22 21:33:09 +04:00
/*
* Reinitialising the cache clears the internal record of
* which locks are held . The global lock can be held during
* this operation so its state must be restored afterwards .
*/
if ( _vg_global_lock_held ) {
2008-04-03 22:56:40 +04:00
lvmcache_lock_vgname ( VG_GLOBAL , 0 ) ;
2009-10-22 21:33:09 +04:00
_vg_global_lock_held = 0 ;
}
2008-04-03 22:56:40 +04:00
2002-11-18 16:53:58 +03:00
return 1 ;
}
2008-04-02 02:40:13 +04:00
/* Volume Group metadata cache functions */
static void _free_cached_vgmetadata ( struct lvmcache_vginfo * vginfo )
{
if ( ! vginfo | | ! vginfo - > vgmetadata )
return ;
dm_free ( vginfo - > vgmetadata ) ;
vginfo - > vgmetadata = NULL ;
log_debug ( " Metadata cache: VG %s wiped. " , vginfo - > vgname ) ;
}
2009-02-17 21:56:41 +03:00
/*
* Cache VG metadata against the vginfo with matching vgid .
*/
static void _store_metadata ( struct volume_group * vg , unsigned precommitted )
2008-04-02 02:40:13 +04:00
{
2009-02-17 21:56:41 +03:00
char uuid [ 64 ] __attribute ( ( aligned ( 8 ) ) ) ;
struct lvmcache_vginfo * vginfo ;
2008-04-02 02:40:13 +04:00
int size ;
2009-02-17 21:56:41 +03:00
if ( ! ( vginfo = vginfo_from_vgid ( ( const char * ) & vg - > id ) ) ) {
stack ;
return ;
}
2008-04-02 02:40:13 +04:00
if ( vginfo - > vgmetadata )
_free_cached_vgmetadata ( vginfo ) ;
if ( ! ( size = export_vg_to_buffer ( vg , & vginfo - > vgmetadata ) ) ) {
stack ;
return ;
}
vginfo - > precommitted = precommitted ;
2009-02-17 21:56:41 +03:00
if ( ! id_write_format ( ( const struct id * ) vginfo - > vgid , uuid , sizeof ( uuid ) ) ) {
stack ;
return ;
}
log_debug ( " Metadata cache: VG %s (%s) stored (%d bytes%s). " ,
vginfo - > vgname , uuid , size ,
precommitted ? " , precommitted " : " " ) ;
2008-04-02 02:40:13 +04:00
}
static void _update_cache_info_lock_state ( struct lvmcache_info * info ,
int locked ,
int * cached_vgmetadata_valid )
2008-01-30 02:45:48 +03:00
{
int was_locked = ( info - > status & CACHE_LOCKED ) ? 1 : 0 ;
/*
2008-09-16 22:05:11 +04:00
* Cache becomes invalid whenever lock state changes unless
* exclusive VG_GLOBAL is held ( i . e . while scanning ) .
2008-01-30 02:45:48 +03:00
*/
2008-09-16 22:05:11 +04:00
if ( ! vgname_is_locked ( VG_GLOBAL ) & & ( was_locked ! = locked ) ) {
2008-01-30 02:45:48 +03:00
info - > status | = CACHE_INVALID ;
2008-04-02 02:40:13 +04:00
* cached_vgmetadata_valid = 0 ;
}
2008-01-30 02:45:48 +03:00
if ( locked )
info - > status | = CACHE_LOCKED ;
else
info - > status & = ~ CACHE_LOCKED ;
}
static void _update_cache_vginfo_lock_state ( struct lvmcache_vginfo * vginfo ,
int locked )
{
struct lvmcache_info * info ;
2008-04-02 02:40:13 +04:00
int cached_vgmetadata_valid = 1 ;
2008-01-30 02:45:48 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( info , & vginfo - > infos )
2008-04-02 02:40:13 +04:00
_update_cache_info_lock_state ( info , locked ,
& cached_vgmetadata_valid ) ;
if ( ! cached_vgmetadata_valid )
_free_cached_vgmetadata ( vginfo ) ;
2008-01-30 02:45:48 +03:00
}
static void _update_cache_lock_state ( const char * vgname , int locked )
{
struct lvmcache_vginfo * vginfo ;
if ( ! ( vginfo = vginfo_from_vgname ( vgname , NULL ) ) )
return ;
_update_cache_vginfo_lock_state ( vginfo , locked ) ;
}
2010-01-05 19:06:42 +03:00
static void _drop_metadata ( const char * vgname , int drop_precommitted )
2008-04-15 18:46:19 +04:00
{
struct lvmcache_vginfo * vginfo ;
2008-05-08 22:28:27 +04:00
struct lvmcache_info * info ;
2008-04-15 18:46:19 +04:00
if ( ! ( vginfo = vginfo_from_vgname ( vgname , NULL ) ) )
return ;
2008-05-08 22:28:27 +04:00
/*
* Invalidate cached PV labels .
* If cached precommitted metadata exists that means we
* already invalidated the PV labels ( before caching it )
* and we must not do it again .
*/
2010-01-05 19:06:42 +03:00
if ( ! drop_precommitted & & vginfo - > precommitted & & ! vginfo - > vgmetadata )
log_error ( INTERNAL_ERROR " metadata commit (or revert) missing before "
" dropping metadata from cache. " ) ;
2008-05-08 22:28:27 +04:00
2010-01-05 19:06:42 +03:00
if ( drop_precommitted | | ! vginfo - > precommitted )
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( info , & vginfo - > infos )
2008-05-08 22:28:27 +04:00
info - > status | = CACHE_INVALID ;
2008-04-15 18:46:19 +04:00
_free_cached_vgmetadata ( vginfo ) ;
}
2010-01-05 19:06:42 +03:00
/*
* Remote node uses this to upgrade precommited metadata to commited state
* when receives vg_commit notification .
* ( Note that devices can be suspended here , if so , precommited metadata are already read . )
*/
void lvmcache_commit_metadata ( const char * vgname )
{
struct lvmcache_vginfo * vginfo ;
if ( ! ( vginfo = vginfo_from_vgname ( vgname , NULL ) ) )
return ;
if ( vginfo - > precommitted ) {
log_debug ( " Precommitted metadata cache: VG %s upgraded to committed. " ,
vginfo - > vgname ) ;
vginfo - > precommitted = 0 ;
}
}
void lvmcache_drop_metadata ( const char * vgname , int drop_precommitted )
2008-05-08 22:28:27 +04:00
{
/* For VG_ORPHANS, we need to invalidate all labels on orphan PVs. */
2008-05-09 19:13:20 +04:00
if ( ! strcmp ( vgname , VG_ORPHANS ) ) {
2010-01-05 19:06:42 +03:00
_drop_metadata ( FMT_TEXT_ORPHAN_VG_NAME , 0 ) ;
_drop_metadata ( FMT_LVM1_ORPHAN_VG_NAME , 0 ) ;
_drop_metadata ( FMT_POOL_ORPHAN_VG_NAME , 0 ) ;
2008-05-09 22:45:15 +04:00
/* Indicate that PVs could now be missing from the cache */
init_full_scan_done ( 0 ) ;
2008-09-16 22:05:11 +04:00
} else if ( ! vgname_is_locked ( VG_GLOBAL ) )
2010-01-05 19:06:42 +03:00
_drop_metadata ( vgname , drop_precommitted ) ;
2008-05-08 22:28:27 +04:00
}
2009-09-03 01:34:11 +04:00
/*
* Ensure vgname2 comes after vgname1 alphabetically .
* Special VG names beginning with ' # ' don ' t count .
*/
static int _vgname_order_correct ( const char * vgname1 , const char * vgname2 )
{
2009-09-15 17:49:10 +04:00
if ( ( * vgname1 = = ' # ' ) | | ( * vgname2 = = ' # ' ) )
2009-09-03 01:34:11 +04:00
return 1 ;
if ( strcmp ( vgname1 , vgname2 ) < 0 )
return 1 ;
2009-09-15 17:49:10 +04:00
2009-09-03 01:34:11 +04:00
return 0 ;
}
/*
* Ensure VG locks are acquired in alphabetical order .
*/
int lvmcache_verify_lock_order ( const char * vgname )
{
struct dm_hash_node * n ;
const char * vgname2 ;
if ( ! _lock_hash )
return_0 ;
dm_hash_iterate ( n , _lock_hash ) {
if ( ! dm_hash_get_data ( _lock_hash , n ) )
return_0 ;
2009-09-15 17:49:10 +04:00
2009-09-03 01:34:11 +04:00
vgname2 = dm_hash_get_key ( _lock_hash , n ) ;
2009-09-15 17:49:10 +04:00
2009-09-03 01:34:11 +04:00
if ( ! _vgname_order_correct ( vgname2 , vgname ) ) {
2009-12-16 22:22:11 +03:00
log_errno ( EDEADLK , INTERNAL_ERROR " VG lock %s must "
2009-09-03 01:34:11 +04:00
" be requested before %s, not after. " ,
vgname , vgname2 ) ;
return_0 ;
}
}
2009-09-15 17:49:10 +04:00
2009-09-03 01:34:11 +04: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 ;
}
2008-04-03 22:56:40 +04:00
if ( dm_hash_lookup ( _lock_hash , vgname ) )
2009-12-16 22:22:11 +03:00
log_error ( INTERNAL_ERROR " Nested locking attempted on VG %s. " ,
2008-04-03 22:56:40 +04:00
vgname ) ;
2009-09-03 01:34:11 +04:00
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 ) ;
2008-01-30 02:45:48 +03:00
_update_cache_lock_state ( vgname , 1 ) ;
2008-04-24 06:22:07 +04:00
if ( strcmp ( vgname , VG_GLOBAL ) )
_vgs_locked + + ;
2003-07-05 02:34:56 +04:00
}
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 )
{
2008-04-03 22:56:40 +04:00
if ( ! dm_hash_lookup ( _lock_hash , vgname ) )
2009-12-16 22:22:11 +03:00
log_error ( INTERNAL_ERROR " Attempt to unlock unlocked VG %s. " ,
2008-04-03 22:56:40 +04:00
vgname ) ;
2008-01-30 02:45:48 +03:00
_update_cache_lock_state ( vgname , 0 ) ;
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 */
2008-04-24 06:22:07 +04:00
if ( strcmp ( vgname , VG_GLOBAL ) & & ! - - _vgs_locked )
2003-07-05 02:34:56 +04:00
dev_close_all ( ) ;
}
int vgs_locked ( void )
{
return _vgs_locked ;
}
2008-05-19 23:49:56 +04:00
static void _vginfo_attach_info ( struct lvmcache_vginfo * vginfo ,
struct lvmcache_info * info )
{
2008-05-29 02:27:47 +04:00
if ( ! vginfo )
return ;
2008-05-19 23:49:56 +04:00
info - > vginfo = vginfo ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & vginfo - > infos , & info - > list ) ;
2008-05-19 23:49:56 +04:00
}
static void _vginfo_detach_info ( struct lvmcache_info * info )
{
2008-11-04 01:14:30 +03:00
if ( ! dm_list_empty ( & info - > list ) ) {
dm_list_del ( & info - > list ) ;
dm_list_init ( & info - > list ) ;
2008-05-19 23:49:56 +04:00
}
info - > vginfo = NULL ;
}
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
2008-06-06 15:12:50 +04:00
if ( ! vgname )
return vginfo_from_vgid ( vgid ) ;
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 )
2008-01-30 17:00:02 +03:00
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 ;
2008-11-04 01:14:30 +03:00
struct dm_list * devh , * tmp ;
struct dm_list devs ;
2005-03-22 01:40:35 +03:00
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 . */
2008-11-04 01:14:30 +03:00
dm_list_init ( & devs ) ;
dm_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 ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & devs , & devl - > list ) ;
2005-03-22 01:40:35 +03:00
}
2006-04-13 01:23:04 +04:00
memcpy ( vgid_found , vginfo - > vgid , sizeof ( vgid_found ) ) ;
2006-04-12 21:54:11 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_safe ( devh , tmp , & devs ) {
devl = dm_list_item ( devh , struct device_list ) ;
2007-04-23 22:21:01 +04:00
label_read ( devl - > dev , & label , UINT64_C ( 0 ) ) ;
2008-11-04 01:14:30 +03:00
dm_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 ( ( 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
}
2008-01-30 02:45:48 +03:00
static int _info_is_valid ( struct lvmcache_info * info )
{
if ( info - > status & CACHE_INVALID )
return 0 ;
2008-01-30 19:18:37 +03:00
/*
* The caller must hold the VG lock to manipulate metadata .
* In a cluster , remote nodes sometimes read metadata in the
* knowledge that the controlling node is holding the lock .
* So if the VG appears to be unlocked here , it should be safe
* to use the cached value .
*/
if ( info - > vginfo & & ! vgname_is_locked ( info - > vginfo - > vgname ) )
return 1 ;
2008-01-30 02:45:48 +03:00
if ( ! ( info - > status & CACHE_LOCKED ) )
return 0 ;
return 1 ;
}
2008-04-02 02:40:13 +04:00
static int _vginfo_is_valid ( struct lvmcache_vginfo * vginfo )
{
struct lvmcache_info * info ;
2008-05-19 23:49:56 +04:00
/* Invalid if any info is invalid */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( info , & vginfo - > infos )
2008-04-02 02:40:13 +04:00
if ( ! _info_is_valid ( info ) )
return 0 ;
return 1 ;
}
2008-05-29 02:27:47 +04:00
/* vginfo is invalid if it does not contain at least one valid info */
static int _vginfo_is_invalid ( struct lvmcache_vginfo * vginfo )
{
struct lvmcache_info * info ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( info , & vginfo - > infos )
2008-05-29 02:27:47 +04:00
if ( _info_is_valid ( info ) )
return 0 ;
return 1 ;
}
2008-01-30 02:45:48 +03:00
/*
* If valid_only is set , data will only be returned if the cached data is
* known still to be valid .
*/
struct lvmcache_info * info_from_pvid ( const char * pvid , int valid_only )
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 ;
2008-01-30 02:45:48 +03:00
if ( valid_only & & ! _info_is_valid ( info ) )
return NULL ;
2002-11-18 16:53:58 +03:00
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 ;
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 ;
}
2009-11-24 19:10:25 +03:00
if ( full_scan = = 2 & & ! refresh_filters ( cmd ) ) {
log_error ( " refresh filters failed " ) ;
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 */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( fmt , & cmd - > formats ) {
2002-11-18 16:53:58 +03:00
if ( fmt - > ops - > scan & & ! fmt - > ops - > scan ( fmt ) )
goto out ;
}
2009-11-24 19:11:37 +03:00
/*
* If we are a long - lived process , write out the updated persistent
* device cache for the benefit of short - lived processes .
*/
if ( full_scan = = 2 & & cmd - > is_long_lived & & cmd - > dump_filter )
persistent_filter_dump ( cmd - > filter ) ;
2002-11-18 16:53:58 +03:00
r = 1 ;
out :
_scanning_in_progress = 0 ;
return r ;
}
2008-04-02 02:40:13 +04:00
struct volume_group * lvmcache_get_vg ( const char * vgid , unsigned precommitted )
{
struct lvmcache_vginfo * vginfo ;
struct volume_group * vg ;
2008-04-14 23:24:16 +04:00
struct format_instance * fid ;
2008-04-02 02:40:13 +04:00
if ( ! vgid | | ! ( vginfo = vginfo_from_vgid ( vgid ) ) | | ! vginfo - > vgmetadata )
return NULL ;
if ( ! _vginfo_is_valid ( vginfo ) )
return NULL ;
2008-06-05 17:06:39 +04:00
/*
* Don ' t return cached data if either :
* ( i ) precommitted metadata is requested but we don ' t have it cached
* - caller should read it off disk ;
* ( ii ) live metadata is requested but we have precommitted metadata cached
* and no devices are suspended so caller may read it off disk .
*
* If live metadata is requested but we have precommitted metadata cached
* and devices are suspended , we assume this precommitted metadata has
* already been preloaded and committed so it ' s OK to return it as live .
* Note that we do not clear the PRECOMMITTED flag .
*/
2008-04-02 02:40:13 +04:00
if ( ( precommitted & & ! vginfo - > precommitted ) | |
2008-06-05 17:06:39 +04:00
( ! precommitted & & vginfo - > precommitted & & ! memlock ( ) ) )
2008-04-02 02:40:13 +04:00
return NULL ;
2010-03-16 22:06:57 +03:00
if ( ! ( fid = vginfo - > fmt - > ops - > create_instance ( vginfo - > fmt ,
vginfo - > vgname ,
vgid , NULL ) ) )
2008-04-15 18:57:12 +04:00
return_NULL ;
2008-04-14 23:24:16 +04:00
2010-03-31 21:20:44 +04:00
if ( ! ( vg = import_vg_from_buffer ( vginfo - > vgmetadata , fid ) ) ) {
2008-04-02 02:40:13 +04:00
_free_cached_vgmetadata ( vginfo ) ;
2009-04-24 16:03:55 +04:00
vg_release ( vg ) ;
2008-04-02 02:40:13 +04:00
return_NULL ;
}
2008-06-05 18:24:28 +04:00
log_debug ( " Using cached %smetadata for VG %s. " ,
vginfo - > precommitted ? " pre-committed " : " " , vginfo - > vgname ) ;
2008-04-02 02:40:13 +04:00
return vg ;
}
2010-03-16 19:57:03 +03:00
struct dm_list * lvmcache_get_vgids ( struct cmd_context * cmd ,
int include_internal )
2006-04-13 01:23:04 +04:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * vgids ;
2006-04-13 01:23:04 +04:00
struct lvmcache_vginfo * vginfo ;
2010-03-16 19:57:03 +03:00
lvmcache_label_scan ( cmd , 0 ) ;
2006-04-13 01:23:04 +04:00
if ( ! ( vgids = str_list_create ( cmd - > mem ) ) ) {
log_error ( " vgids list allocation failed " ) ;
return NULL ;
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( vginfo , & _vginfos ) {
2010-02-03 17:08:39 +03:00
if ( ! include_internal & & is_orphan_vg ( vginfo - > vgname ) )
continue ;
2008-01-30 17:00:02 +03:00
if ( ! str_list_add ( cmd - > mem , vgids ,
2006-04-13 01:23:04 +04:00
dm_pool_strdup ( cmd - > mem , vginfo - > vgid ) ) ) {
log_error ( " strlist allocation failed " ) ;
return NULL ;
}
}
return vgids ;
}
2010-03-16 19:57:03 +03:00
struct dm_list * lvmcache_get_vgnames ( struct cmd_context * cmd ,
int include_internal )
2002-11-18 16:53:58 +03:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * vgnames ;
2006-04-11 23:09:55 +04:00
struct lvmcache_vginfo * vginfo ;
2002-11-18 16:53:58 +03:00
2010-03-16 19:57:03 +03:00
lvmcache_label_scan ( cmd , 0 ) ;
2002-11-18 16:53:58 +03:00
2003-10-16 00:04:29 +04:00
if ( ! ( vgnames = str_list_create ( cmd - > mem ) ) ) {
2009-07-27 15:00:17 +04:00
log_errno ( ENOMEM , " vgnames list allocation failed " ) ;
2002-11-18 16:53:58 +03:00
return NULL ;
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( vginfo , & _vginfos ) {
2010-02-03 17:08:39 +03:00
if ( ! include_internal & & is_orphan_vg ( vginfo - > vgname ) )
continue ;
2008-01-30 17:00:02 +03:00
if ( ! str_list_add ( cmd - > mem , vgnames ,
2006-04-11 23:09:55 +04:00
dm_pool_strdup ( cmd - > mem , vginfo - > vgname ) ) ) {
2009-07-27 15:00:17 +04:00
log_errno ( ENOMEM , " strlist allocation failed " ) ;
2002-11-18 16:53:58 +03:00
return NULL ;
}
}
return vgnames ;
}
2008-11-04 01:14:30 +03:00
struct dm_list * lvmcache_get_pvids ( struct cmd_context * cmd , const char * vgname ,
2006-04-21 23:12:41 +04:00
const char * vgid )
{
2008-11-04 01:14:30 +03:00
struct dm_list * pvids ;
2006-04-21 23:12:41 +04:00
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 ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( info , & vginfo - > infos ) {
2008-01-30 17:00:02 +03:00
if ( ! str_list_add ( cmd - > mem , pvids ,
2006-04-21 23:12:41 +04:00
dm_pool_strdup ( cmd - > mem , info - > dev - > pvid ) ) ) {
log_error ( " strlist allocation failed " ) ;
return NULL ;
}
}
return pvids ;
}
2010-03-16 20:30:00 +03:00
struct device * device_from_pvid ( struct cmd_context * cmd , struct id * pvid ,
2010-03-17 05:11:18 +03:00
unsigned * scan_done_once )
2002-11-18 16:53:58 +03:00
{
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 ? */
2008-01-30 02:45:48 +03:00
if ( ( info = info_from_pvid ( ( char * ) pvid , 0 ) ) ) {
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 */
2008-01-30 02:45:48 +03:00
if ( ( info = info_from_pvid ( ( char * ) pvid , 0 ) ) ) {
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 ;
}
}
2010-03-16 20:30:00 +03:00
if ( memlock ( ) | | ( scan_done_once & & * scan_done_once ) )
2003-07-05 02:34:56 +04:00
return NULL ;
2005-03-08 16:46:17 +03:00
lvmcache_label_scan ( cmd , 2 ) ;
2010-03-16 22:06:57 +03:00
if ( scan_done_once )
* scan_done_once = 1 ;
2002-11-18 16:53:58 +03:00
/* Try again */
2008-01-30 02:45:48 +03:00
if ( ( info = info_from_pvid ( ( char * ) pvid , 0 ) ) ) {
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 ;
}
2008-05-19 23:49:56 +04:00
static int _free_vginfo ( struct lvmcache_vginfo * vginfo )
{
2008-06-09 20:22:33 +04:00
struct lvmcache_vginfo * primary_vginfo , * vginfo2 ;
2008-05-19 23:49:56 +04:00
int r = 1 ;
_free_cached_vgmetadata ( vginfo ) ;
2008-06-09 20:22:33 +04:00
vginfo2 = primary_vginfo = vginfo_from_vgname ( vginfo - > vgname , NULL ) ;
if ( vginfo = = primary_vginfo ) {
2008-05-29 02:27:47 +04:00
dm_hash_remove ( _vgname_hash , vginfo - > vgname ) ;
if ( vginfo - > next & & ! dm_hash_insert ( _vgname_hash , vginfo - > vgname ,
vginfo - > next ) ) {
log_error ( " _vgname_hash re-insertion for %s failed " ,
vginfo - > vgname ) ;
r = 0 ;
}
2008-06-09 20:22:33 +04:00
} else do
if ( vginfo2 - > next = = vginfo ) {
vginfo2 - > next = vginfo - > next ;
break ;
}
while ( ( vginfo2 = primary_vginfo - > next ) ) ;
2008-05-19 23:49:56 +04:00
if ( vginfo - > vgname )
dm_free ( vginfo - > vgname ) ;
if ( vginfo - > creation_host )
dm_free ( vginfo - > creation_host ) ;
2008-06-06 16:43:40 +04:00
if ( * vginfo - > vgid & & _vgid_hash & &
vginfo_from_vgid ( vginfo - > vgid ) = = vginfo )
2008-05-19 23:49:56 +04:00
dm_hash_remove ( _vgid_hash , vginfo - > vgid ) ;
2008-11-04 01:14:30 +03:00
dm_list_del ( & vginfo - > list ) ;
2008-05-19 23:49:56 +04:00
dm_free ( vginfo ) ;
return r ;
}
2008-04-08 16:49:21 +04:00
/*
* vginfo must be info - > vginfo unless info is NULL
*/
static int _drop_vginfo ( struct lvmcache_info * info , struct lvmcache_vginfo * vginfo )
2002-11-18 16:53:58 +03:00
{
2008-05-19 23:49:56 +04:00
if ( info )
_vginfo_detach_info ( info ) ;
2006-04-12 21:54:11 +04:00
2008-05-19 23:49:56 +04:00
/* vginfo still referenced? */
if ( ! vginfo | | is_orphan_vg ( vginfo - > vgname ) | |
2008-11-04 01:14:30 +03:00
! dm_list_empty ( & vginfo - > infos ) )
2008-05-19 23:49:56 +04:00
return 1 ;
2002-11-18 16:53:58 +03:00
2008-05-19 23:49:56 +04:00
if ( ! _free_vginfo ( vginfo ) )
return_0 ;
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
2008-04-08 16:49:21 +04:00
_drop_vginfo ( info , info - > vginfo ) ;
2002-11-18 16:53:58 +03:00
info - > label - > labeller - > ops - > destroy_label ( info - > label - > labeller ,
2008-01-30 17:00:02 +03:00
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
{
2008-11-27 21:13:50 +03:00
/*
* Nothing to do if already stored with same pvid .
*/
if ( ( ( dm_hash_lookup ( _pvid_hash , pvid ) ) = = info ) & &
! strcmp ( info - > dev - > pvid , pvid ) )
2002-11-18 16:53:58 +03:00
return 1 ;
2008-11-28 18:51:40 +03:00
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 ;
}
2008-04-08 16:49:21 +04:00
/*
* vginfo must be info - > vginfo unless info is NULL ( orphans )
*/
static int _lvmcache_update_vgid ( struct lvmcache_info * info ,
struct lvmcache_vginfo * vginfo ,
const char * vgid )
2002-11-18 16:53:58 +03:00
{
2008-04-08 16:49:21 +04:00
if ( ! vgid | | ! vginfo | |
! strncmp ( vginfo - > vgid , vgid , ID_LEN ) )
2002-11-18 16:53:58 +03:00
return 1 ;
2008-04-08 16:49:21 +04:00
if ( vginfo & & * vginfo - > vgid )
dm_hash_remove ( _vgid_hash , vginfo - > vgid ) ;
2006-04-11 02:09:00 +04:00
if ( ! vgid ) {
2008-04-08 16:49:21 +04:00
log_debug ( " lvmcache: %s: clearing VGID " , info ? dev_name ( info - > dev ) : vginfo - > vgname ) ;
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
2008-04-08 16:49:21 +04:00
strncpy ( vginfo - > vgid , vgid , ID_LEN ) ;
vginfo - > vgid [ ID_LEN ] = ' \0 ' ;
if ( ! dm_hash_insert ( _vgid_hash , vginfo - > vgid , vginfo ) ) {
2003-07-05 02:34:56 +04:00
log_error ( " _lvmcache_update: vgid hash insertion failed: %s " ,
2008-04-08 16:49:21 +04:00
vginfo - > vgid ) ;
2002-11-18 16:53:58 +03:00
return 0 ;
}
2008-04-08 16:49:21 +04:00
if ( ! is_orphan_vg ( vginfo - > vgname ) )
2008-02-06 18:47:28 +03:00
log_debug ( " lvmcache: %s: setting %s VGID to %s " ,
2008-04-08 16:49:21 +04:00
dev_name ( info - > dev ) , vginfo - > vgname ,
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 ;
2009-09-14 23:44:15 +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 ) )
2010-04-01 14:34:09 +04:00
log_warn ( " WARNING: Duplicate VG name %s: "
" Existing %s takes precedence over "
" exported %s " , new_vginfo - > vgname ,
uuid_primary , uuid_new ) ;
2006-04-13 21:32:24 +04:00
else if ( ( primary_vginfo - > status & EXPORTED_VG ) & &
! ( vgstatus & EXPORTED_VG ) ) {
2010-04-01 14:34:09 +04:00
log_warn ( " 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 ) )
2010-04-01 14:34:09 +04:00
log_warn ( " WARNING: Duplicate VG name %s: "
" Existing %s (created here) takes precedence "
" over %s " , new_vginfo - > vgname , uuid_primary ,
uuid_new ) ;
2006-04-13 21:32:24 +04:00
else if ( ! primary_vginfo - > creation_host & & creation_host ) {
2010-04-01 14:34:09 +04:00
log_warn ( " WARNING: Duplicate VG name %s: "
" %s (with creation_host) takes precedence over %s " ,
new_vginfo - > vgname , uuid_new ,
uuid_primary ) ;
2006-04-13 21:32:24 +04:00
use_new = 1 ;
} else if ( creation_host & &
! strcmp ( creation_host ,
primary_vginfo - > fmt - > cmd - > hostname ) ) {
2010-04-01 14:34:09 +04:00
log_warn ( " WARNING: Duplicate VG name %s: "
" %s (created here) takes precedence over %s " ,
new_vginfo - > vgname , uuid_new ,
uuid_primary ) ;
2006-04-13 21:32:24 +04:00
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 ,
2008-04-08 16:49:21 +04:00
uint32_t vgstatus , const char * creation_host ,
const struct format_type * fmt )
2002-11-18 16:53:58 +03:00
{
2008-05-29 02:27:47 +04:00
struct lvmcache_vginfo * vginfo , * primary_vginfo , * orphan_vginfo ;
struct lvmcache_info * info2 , * info3 ;
2008-06-27 19:18:31 +04:00
char mdabuf [ 32 ] ;
2006-04-14 01:08:29 +04:00
// struct lvmcache_vginfo *old_vginfo, *next;
2002-11-18 16:53:58 +03:00
2008-04-08 16:49:21 +04:00
if ( ! vgname | | ( info & & info - > vginfo & & ! strcmp ( info - > vginfo - > vgname , vgname ) ) )
2002-11-18 16:53:58 +03:00
return 1 ;
/* Remove existing vginfo entry */
2008-04-08 16:49:21 +04:00
if ( info )
_drop_vginfo ( info , info - > vginfo ) ;
2002-11-18 16:53:58 +03:00
/* 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 ) ) {
2008-01-30 17:00:02 +03:00
log_error ( " vg hash re-insertion failed: %s " ,
2006-04-14 01:08:29 +04:00
old_vginfo - > vgname ) ;
2008-01-30 17:00:02 +03:00
return 0 ;
2006-04-14 01:08:29 +04:00
}
}
} 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 ;
}
2008-01-30 17:00:02 +03:00
// Rename so can assume new name does not already exist
2006-04-14 01:08:29 +04:00
if ( ! dm_hash_insert ( _vgname_hash , vginfo - > vgname , vginfo - > next ) ) {
log_error ( " vg hash re-insertion failed: %s " ,
vginfo - > vgname ) ;
2008-01-30 17:00:02 +03:00
return 0 ;
2006-04-14 01:08:29 +04:00
}
} 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 ;
}
2008-11-04 01:14:30 +03:00
dm_list_init ( & vginfo - > infos ) ;
2008-05-29 02:27:47 +04:00
/*
* If we ' re scanning and there ' s an invalidated entry , remove it .
* Otherwise we risk bogus warnings of duplicate VGs .
*/
while ( ( primary_vginfo = vginfo_from_vgname ( vgname , NULL ) ) & &
_scanning_in_progress & & _vginfo_is_invalid ( primary_vginfo ) )
2008-11-04 01:14:30 +03:00
dm_list_iterate_items_safe ( info2 , info3 , & primary_vginfo - > infos ) {
2008-05-29 02:27:47 +04:00
orphan_vginfo = vginfo_from_vgname ( primary_vginfo - > fmt - > orphan_vg_name , NULL ) ;
_drop_vginfo ( info2 , primary_vginfo ) ;
_vginfo_attach_info ( orphan_vginfo , info2 ) ;
2008-06-27 19:18:31 +04:00
if ( info2 - > mdas . n )
sprintf ( mdabuf , " with %u mdas " ,
2008-11-04 01:14:30 +03:00
dm_list_size ( & info2 - > mdas ) ) ;
2008-06-27 19:18:31 +04:00
else
mdabuf [ 0 ] = ' \0 ' ;
log_debug ( " lvmcache: %s: now in VG %s%s%s%s%s " ,
2008-05-29 02:27:47 +04:00
dev_name ( info2 - > dev ) ,
vgname , orphan_vginfo - > vgid [ 0 ] ? " ( " : " " ,
orphan_vginfo - > vgid [ 0 ] ? orphan_vginfo - > vgid : " " ,
2008-06-27 19:18:31 +04:00
orphan_vginfo - > vgid [ 0 ] ? " ) " : " " , mdabuf ) ;
2008-05-29 02:27:47 +04:00
}
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 */
2007-11-02 16:06:42 +03:00
if ( is_orphan_vg ( vgname ) )
2008-11-04 01:14:30 +03:00
dm_list_add ( & _vginfos , & vginfo - > list ) ;
2002-11-18 16:53:58 +03:00
else
2008-11-04 01:14:30 +03:00
dm_list_add_h ( & _vginfos , & vginfo - > list ) ;
2006-04-14 01:08:29 +04:00
/***
}
* * */
2002-11-18 16:53:58 +03:00
}
2008-05-19 23:49:56 +04:00
if ( info )
_vginfo_attach_info ( vginfo , info ) ;
else if ( ! _lvmcache_update_vgid ( NULL , vginfo , vgid ) ) /* Orphans */
2008-04-08 16:49:21 +04:00
return_0 ;
2002-11-18 16:53:58 +03:00
2008-01-30 02:45:48 +03:00
_update_cache_vginfo_lock_state ( vginfo , vgname_is_locked ( vgname ) ) ;
2002-11-18 16:53:58 +03:00
/* FIXME Check consistency of list! */
2008-04-08 16:49:21 +04:00
vginfo - > fmt = fmt ;
2008-06-27 19:18:31 +04:00
if ( info ) {
if ( info - > mdas . n )
2008-11-04 01:14:30 +03:00
sprintf ( mdabuf , " with %u mdas " , dm_list_size ( & info - > mdas ) ) ;
2008-06-27 19:18:31 +04:00
else
mdabuf [ 0 ] = ' \0 ' ;
log_debug ( " lvmcache: %s: now in VG %s%s%s%s%s " ,
2008-04-08 16:49:21 +04:00
dev_name ( info - > dev ) ,
vgname , vginfo - > vgid [ 0 ] ? " ( " : " " ,
vginfo - > vgid [ 0 ] ? vginfo - > vgid : " " ,
2008-06-27 19:18:31 +04:00
vginfo - > vgid [ 0 ] ? " ) " : " " , mdabuf ) ;
} else
2008-04-08 16:49:21 +04:00
log_debug ( " lvmcache: initialised VG %s " , vgname ) ;
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 ;
}
2008-04-08 16:49:21 +04:00
int lvmcache_add_orphan_vginfo ( const char * vgname , struct format_type * fmt )
{
if ( ! _lock_hash & & ! lvmcache_init ( ) ) {
log_error ( " Internal cache initialisation failed " ) ;
return 0 ;
}
return _lvmcache_update_vgname ( NULL , vgname , vgname , 0 , " " , fmt ) ;
}
2006-04-11 21:42:15 +04:00
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
{
2008-02-06 18:47:28 +03:00
if ( ! vgname & & ! info - > vginfo ) {
2009-12-16 22:22:11 +03:00
log_error ( INTERNAL_ERROR " NULL vgname handed to cache " ) ;
2008-02-06 18:47:28 +03:00
/* FIXME Remove this */
vgname = info - > fmt - > orphan_vg_name ;
vgid = vgname ;
}
2008-04-08 16:49:21 +04:00
2008-06-11 15:02:05 +04:00
/* If PV without mdas is already in a real VG, don't make it orphan */
2008-11-04 01:14:30 +03:00
if ( is_orphan_vg ( vgname ) & & info - > vginfo & & ! dm_list_size ( & info - > mdas ) & &
2008-06-11 15:02:05 +04:00
! is_orphan_vg ( info - > vginfo - > vgname ) & & memlock ( ) )
return 1 ;
/* If moving PV from orphan to real VG, always mark it valid */
if ( ! is_orphan_vg ( vgname ) )
info - > status & = ~ CACHE_INVALID ;
2006-04-13 21:32:24 +04:00
if ( ! _lvmcache_update_vgname ( info , vgname , vgid , vgstatus ,
2008-04-08 16:49:21 +04:00
creation_host , info - > fmt ) | |
! _lvmcache_update_vgid ( info , info - > vginfo , 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 ;
}
2008-03-17 19:51:31 +03:00
int lvmcache_update_vg ( struct volume_group * vg , unsigned precommitted )
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 ' ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( pvl , & vg - > pvs ) {
2005-06-01 20:51:55 +04:00
strncpy ( pvid_s , ( char * ) & pvl - > pv - > id , sizeof ( pvid_s ) - 1 ) ;
/* FIXME Could pvl->pv->dev->pvid ever be different? */
2008-01-30 02:45:48 +03:00
if ( ( info = info_from_pvid ( pvid_s , 0 ) ) & &
2006-04-11 20:00:26 +04:00
! 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
}
2008-03-17 19:51:31 +03:00
/* store text representation of vg to cache */
2009-02-17 21:56:41 +03:00
if ( vg - > cmd - > current_settings . cache_vgmetadata )
_store_metadata ( vg , precommitted ) ;
2008-03-17 19:51:31 +03:00
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 ' ;
2008-01-30 02:45:48 +03:00
if ( ! ( existing = info_from_pvid ( pvid_s , 0 ) ) & &
! ( existing = info_from_pvid ( dev - > pvid , 0 ) ) ) {
2008-01-30 16:19:47 +03:00
if ( ! ( label = label_create ( labeller ) ) )
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 ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & info - > list ) ;
2002-11-18 16:53:58 +03:00
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 ? */
2009-10-27 20:00:44 +03:00
if ( dev_subsystem_part_major ( existing - > dev ) & &
! dev_subsystem_part_major ( dev ) ) {
2003-01-07 00:10:43 +03:00
log_very_verbose ( " Ignoring duplicate PV %s on "
2009-10-27 20:00:44 +03:00
" %s - using %s %s " ,
2003-01-07 00:10:43 +03:00
pvid , dev_name ( dev ) ,
2009-10-27 20:00:44 +03:00
dev_subsystem_name ( existing - > dev ) ,
2003-01-07 00:10:43 +03:00
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 ;
2009-10-27 20:00:44 +03:00
} else if ( ! dev_subsystem_part_major ( existing - > dev ) & &
dev_subsystem_part_major ( dev ) )
2003-01-07 00:10:43 +03:00
log_very_verbose ( " Duplicate PV %s on %s - "
2009-10-27 20:00:44 +03:00
" using %s %s " , pvid ,
2003-01-07 00:10:43 +03:00
dev_name ( existing - > dev ) ,
2009-10-27 20:00:44 +03:00
dev_subsystem_name ( existing - > dev ) ,
2003-01-07 00:10:43 +03:00
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)))
//
2008-11-28 18:51:40 +03:00
else if ( ! strcmp ( pvid_s , existing - > dev - > pvid ) )
2003-01-07 00:10:43 +03:00
log_error ( " Found duplicate PV %s: using %s not "
" %s " , pvid , dev_name ( dev ) ,
dev_name ( existing - > dev ) ) ;
}
2008-11-28 18:51:40 +03:00
if ( strcmp ( pvid_s , existing - > dev - > pvid ) )
log_debug ( " Updating pvid cache to %s (%s) from %s (%s) " ,
pvid_s , dev_name ( dev ) ,
existing - > dev - > pvid , 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 ) ;
2008-01-30 16:19:47 +03:00
if ( ! ( info - > label = label_create ( labeller ) ) )
2002-11-18 16:53:58 +03:00
/* FIXME leaves info without label! */
2008-01-30 16:19:47 +03:00
return_NULL ;
2002-11-18 16:53:58 +03:00
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
{
2008-05-19 23:49:56 +04:00
_vginfo_detach_info ( info ) ;
2002-11-18 16:53:58 +03:00
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 ;
2008-05-19 23:49:56 +04:00
if ( ! _free_vginfo ( vginfo ) )
stack ;
2006-04-12 21:54:11 +04:00
} while ( ( vginfo = next ) ) ;
2002-11-18 16:53:58 +03:00
}
2008-04-03 22:56:40 +04:00
static void _lvmcache_destroy_lockname ( struct dm_hash_node * n )
2003-07-05 02:34:56 +04:00
{
2008-04-03 22:56:40 +04:00
char * vgname ;
if ( ! dm_hash_get_data ( _lock_hash , n ) )
return ;
vgname = dm_hash_get_key ( _lock_hash , n ) ;
if ( ! strcmp ( vgname , VG_GLOBAL ) )
_vg_global_lock_held = 1 ;
else
2009-12-16 22:22:11 +03:00
log_error ( INTERNAL_ERROR " Volume Group %s was not unlocked " ,
2008-04-03 22:56:40 +04:00
dm_hash_get_key ( _lock_hash , n ) ) ;
2003-07-05 02:34:56 +04:00
}
2008-04-08 16:49:21 +04:00
void lvmcache_destroy ( struct cmd_context * cmd , int retain_orphans )
2002-11-18 16:53:58 +03:00
{
2008-04-03 22:56:40 +04:00
struct dm_hash_node * n ;
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 ) {
2008-04-03 22:56:40 +04:00
dm_hash_iterate ( n , _lock_hash )
_lvmcache_destroy_lockname ( n ) ;
2005-10-17 03:03:59 +04:00
dm_hash_destroy ( _lock_hash ) ;
2003-07-05 02:34:56 +04:00
_lock_hash = NULL ;
}
2008-11-04 01:14:30 +03:00
if ( ! dm_list_empty ( & _vginfos ) )
2009-12-16 22:22:11 +03:00
log_error ( INTERNAL_ERROR " _vginfos list should be empty " ) ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & _vginfos ) ;
2008-04-08 16:49:21 +04:00
if ( retain_orphans )
init_lvmcache_orphans ( cmd ) ;
2002-11-18 16:53:58 +03:00
}