2001-12-13 03:07:29 +03:00
/*
* Copyright ( C ) 2001 Sistina Software ( UK ) Limited .
*
* This file is released under the LGPL .
*
*/
# include <stdlib.h>
# include "vgcache.h"
# include "hash.h"
# include "dbg_malloc.h"
# include "log.h"
static struct hash_table * _vghash ;
2001-12-13 18:08:58 +03:00
static struct hash_table * _pvhash ;
2001-12-13 03:07:29 +03:00
2001-12-13 18:08:58 +03:00
const char * all_devices = " \0 " ;
2001-12-13 03:07:29 +03:00
int vgcache_init ( )
{
2001-12-13 18:08:58 +03:00
if ( ! ( _vghash = hash_create ( 128 ) ) )
return 0 ;
if ( ! ( _pvhash = hash_create ( 128 ) ) )
2001-12-13 03:07:29 +03:00
return 0 ;
return 1 ;
}
2001-12-13 18:08:58 +03:00
/* A vg_name of NULL returns all_devices */
2001-12-13 03:07:29 +03:00
struct list * vgcache_find ( const char * vg_name )
{
struct vgname_entry * vgn ;
if ( ! _vghash )
return NULL ;
if ( ! vg_name )
2001-12-13 18:08:58 +03:00
vg_name = all_devices ;
2001-12-13 03:07:29 +03:00
if ( ! ( vgn = hash_lookup ( _vghash , vg_name ) ) )
return NULL ;
return & vgn - > pvdevs ;
}
2001-12-13 18:08:58 +03:00
void vgcache_del_orphan ( struct device * dev )
2001-12-13 03:07:29 +03:00
{
2001-12-13 18:08:58 +03:00
struct pvdev_list * pvdev ;
2001-12-13 03:07:29 +03:00
2001-12-13 18:08:58 +03:00
if ( _pvhash & & ( ( pvdev = hash_lookup ( _pvhash , dev_name ( dev ) ) ) ) ) {
list_del ( & pvdev - > list ) ;
hash_remove ( _pvhash , dev_name ( pvdev - > dev ) ) ;
dbg_free ( pvdev ) ;
}
}
int vgcache_add_entry ( const char * vg_name , struct device * dev )
{
const char * pv_name ;
2001-12-13 03:07:29 +03:00
struct vgname_entry * vgn ;
struct pvdev_list * pvdev ;
struct list * pvdh , * pvdevs ;
if ( ! ( pvdevs = vgcache_find ( vg_name ) ) ) {
if ( ! ( vgn = dbg_malloc ( sizeof ( struct vgname_entry ) ) ) ) {
log_error ( " struct vgname_entry allocation failed " ) ;
return 0 ;
}
pvdevs = & vgn - > pvdevs ;
list_init ( pvdevs ) ;
if ( ! ( vgn - > vgname = dbg_strdup ( vg_name ) ) ) {
log_error ( " vgcache_add: strdup vg_name failed " ) ;
return 0 ;
}
if ( ! hash_insert ( _vghash , vg_name , vgn ) ) {
2001-12-13 18:08:58 +03:00
log_error ( " vgcache_add: VG hash insertion failed " ) ;
2001-12-13 03:07:29 +03:00
return 0 ;
}
}
list_iterate ( pvdh , pvdevs ) {
pvdev = list_item ( pvdh , struct pvdev_list ) ;
if ( dev = = pvdev - > dev )
return 1 ;
}
2001-12-13 18:08:58 +03:00
/* Remove PV from any existing VG unless an all_devices request */
pvdev = NULL ;
pv_name = dev_name ( dev ) ;
if ( * vg_name & & _pvhash & & ( ( pvdev = hash_lookup ( _pvhash , pv_name ) ) ) ) {
list_del ( & pvdev - > list ) ;
hash_remove ( _pvhash , dev_name ( pvdev - > dev ) ) ;
}
/* Allocate new pvdev_list if there isn't an existing one to reuse */
if ( ! pvdev & & ! ( pvdev = dbg_malloc ( sizeof ( struct pvdev_list ) ) ) ) {
2001-12-13 03:07:29 +03:00
log_error ( " struct pvdev_list allocation failed " ) ;
return 0 ;
}
pvdev - > dev = dev ;
list_add ( pvdevs , & pvdev - > list ) ;
2001-12-13 18:08:58 +03:00
if ( * vg_name & & _pvhash & & ! hash_insert ( _pvhash , pv_name , pvdev ) ) {
log_error ( " vgcache_add: PV hash insertion for %s "
" failed " , pv_name ) ;
return 0 ;
}
2001-12-13 03:07:29 +03:00
return 1 ;
}
2001-12-13 18:08:58 +03:00
/* vg_name of "\0" is an orphan PV; NULL means only add to all_devices */
2001-12-13 03:07:29 +03:00
int vgcache_add ( const char * vg_name , struct device * dev )
{
if ( ! _vghash & & ! vgcache_init ( ) )
return 0 ;
2001-12-13 18:08:58 +03:00
/* If orphan PV remove it */
if ( vg_name & & ! * vg_name )
vgcache_del_orphan ( dev ) ;
/* Add PV if vg_name supplied */
if ( vg_name & & * vg_name & & ! vgcache_add_entry ( vg_name , dev ) )
2001-12-13 03:07:29 +03:00
return 0 ;
2001-12-13 18:08:58 +03:00
/* Always add to all_devices */
return vgcache_add_entry ( all_devices , dev ) ;
2001-12-13 03:07:29 +03:00
}
void vgcache_destroy_entry ( struct vgname_entry * vgn )
{
struct list * pvdh ;
struct pvdev_list * pvdev ;
if ( vgn ) {
pvdh = vgn - > pvdevs . n ;
while ( pvdh ! = & vgn - > pvdevs ) {
pvdev = list_item ( pvdh , struct pvdev_list ) ;
pvdh = pvdh - > n ;
dbg_free ( pvdev ) ;
}
dbg_free ( vgn - > vgname ) ;
}
dbg_free ( vgn ) ;
}
void vgcache_del ( const char * vg_name )
{
struct vgname_entry * vgn ;
if ( ! _vghash )
return ;
if ( ! vg_name )
2001-12-13 18:08:58 +03:00
vg_name = all_devices ;
2001-12-13 03:07:29 +03:00
if ( ! ( vgn = hash_lookup ( _vghash , vg_name ) ) )
return ;
hash_remove ( _vghash , vg_name ) ;
vgcache_destroy_entry ( vgn ) ;
}
void vgcache_destroy ( )
{
if ( _vghash ) {
hash_iterate ( _vghash , ( iterate_fn ) vgcache_destroy_entry ) ;
hash_destroy ( _vghash ) ;
2001-12-13 18:08:58 +03:00
_vghash = NULL ;
}
if ( _pvhash ) {
hash_destroy ( _pvhash ) ;
_pvhash = NULL ;
2001-12-13 03:07:29 +03:00
}
}