2012-02-28 22:35:04 +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
*/
2011-09-17 17:33:51 +04:00
# define _XOPEN_SOURCE 500 /* pthread */
2012-02-28 22:35:04 +04:00
# include "configure.h"
# include "daemon-shared.h"
# include "daemon-server.h"
2011-07-18 18:48:30 +04:00
# include <assert.h>
2011-07-21 01:23:43 +04:00
# include <pthread.h>
2011-07-18 18:48:30 +04:00
# include <malloc.h>
# include <stdint.h>
2011-08-31 16:39:58 +04:00
# include <unistd.h>
2011-07-18 18:48:30 +04:00
2012-02-15 15:43:06 +04:00
typedef struct {
2012-02-15 21:37:09 +04:00
struct dm_hash_table * pvid_to_pvmeta ;
struct dm_hash_table * device_to_pvid ; /* shares locks with above */
2012-02-15 21:30:07 +04:00
2012-02-15 15:43:06 +04:00
struct dm_hash_table * vgid_to_metadata ;
struct dm_hash_table * vgid_to_vgname ;
struct dm_hash_table * vgname_to_vgid ;
struct dm_hash_table * pvid_to_vgid ;
2011-07-21 01:23:43 +04:00
struct {
struct dm_hash_table * vg ;
2012-02-15 21:37:09 +04:00
pthread_mutex_t pvid_to_pvmeta ;
2012-02-15 15:43:06 +04:00
pthread_mutex_t vgid_to_metadata ;
pthread_mutex_t pvid_to_vgid ;
2011-07-21 01:23:43 +04:00
} lock ;
2011-06-14 06:36:38 +04:00
} lvmetad_state ;
2011-09-17 17:33:51 +04:00
__attribute__ ( ( format ( printf , 1 , 2 ) ) )
2011-08-31 16:39:58 +04:00
static void debug ( const char * fmt , . . . ) {
2011-07-21 01:23:43 +04:00
va_list ap ;
va_start ( ap , fmt ) ;
2011-08-31 16:39:58 +04:00
fprintf ( stderr , " [D %lu] " , pthread_self ( ) ) ;
2011-07-21 01:23:43 +04:00
vfprintf ( stderr , fmt , ap ) ;
va_end ( ap ) ;
2012-02-15 15:43:06 +04:00
}
static int debug_cft_line ( const char * line , void * baton ) {
fprintf ( stderr , " | %s \n " , line ) ;
return 0 ;
}
static void debug_cft ( const char * id , struct dm_config_node * n ) {
debug ( " %s \n " , id ) ;
dm_config_write_node ( n , & debug_cft_line , NULL ) ;
}
2011-07-21 01:23:43 +04:00
2012-02-15 21:37:09 +04:00
static void lock_pvid_to_pvmeta ( lvmetad_state * s ) {
pthread_mutex_lock ( & s - > lock . pvid_to_pvmeta ) ; }
static void unlock_pvid_to_pvmeta ( lvmetad_state * s ) {
pthread_mutex_unlock ( & s - > lock . pvid_to_pvmeta ) ; }
2011-07-21 01:23:43 +04:00
2012-02-15 15:43:06 +04:00
static void lock_vgid_to_metadata ( lvmetad_state * s ) {
pthread_mutex_lock ( & s - > lock . vgid_to_metadata ) ; }
static void unlock_vgid_to_metadata ( lvmetad_state * s ) {
pthread_mutex_unlock ( & s - > lock . vgid_to_metadata ) ; }
2011-07-21 01:23:43 +04:00
2012-02-15 15:43:06 +04:00
static void lock_pvid_to_vgid ( lvmetad_state * s ) {
pthread_mutex_lock ( & s - > lock . pvid_to_vgid ) ; }
static void unlock_pvid_to_vgid ( lvmetad_state * s ) {
pthread_mutex_unlock ( & s - > lock . pvid_to_vgid ) ; }
2011-07-21 01:23:43 +04:00
2011-07-25 19:33:04 +04:00
/*
* TODO : It may be beneficial to clean up the vg lock hash from time to time ,
* since if we have many " rogue " requests for nonexistent things , we will keep
* allocating memory that we never release . Not good .
*/
2011-08-31 16:39:58 +04:00
static struct dm_config_tree * lock_vg ( lvmetad_state * s , const char * id ) {
2011-09-17 17:33:51 +04:00
pthread_mutex_t * vg ;
struct dm_config_tree * cft ;
2012-02-15 15:43:06 +04:00
lock_vgid_to_metadata ( s ) ;
2011-09-17 17:33:51 +04:00
vg = dm_hash_lookup ( s - > lock . vg , id ) ;
2011-07-21 01:23:43 +04:00
if ( ! vg ) {
pthread_mutexattr_t rec ;
pthread_mutexattr_init ( & rec ) ;
pthread_mutexattr_settype ( & rec , PTHREAD_MUTEX_RECURSIVE_NP ) ;
vg = malloc ( sizeof ( pthread_mutex_t ) ) ;
pthread_mutex_init ( vg , & rec ) ;
dm_hash_insert ( s - > lock . vg , id , vg ) ;
}
2012-02-15 15:43:06 +04:00
// debug("lock VG %s\n", id);
2011-07-21 01:23:43 +04:00
pthread_mutex_lock ( vg ) ;
2012-02-15 15:43:06 +04:00
cft = dm_hash_lookup ( s - > vgid_to_metadata , id ) ;
unlock_vgid_to_metadata ( s ) ;
2011-07-21 01:23:43 +04:00
return cft ;
}
2011-08-31 16:39:58 +04:00
static void unlock_vg ( lvmetad_state * s , const char * id ) {
2012-02-15 15:43:06 +04:00
// debug("unlock VG %s\n", id);
lock_vgid_to_metadata ( s ) ; /* someone might be changing the s->lock.vg structure right
* now , so avoid stepping on each other ' s toes */
2011-07-21 01:23:43 +04:00
pthread_mutex_unlock ( dm_hash_lookup ( s - > lock . vg , id ) ) ;
2012-02-15 15:43:06 +04:00
unlock_vgid_to_metadata ( s ) ;
2011-07-21 01:23:43 +04:00
}
2011-08-30 19:44:01 +04:00
static struct dm_config_node * pvs ( struct dm_config_node * vg )
2011-07-25 21:59:50 +04:00
{
2011-08-30 19:44:01 +04:00
struct dm_config_node * pv = dm_config_find_node ( vg , " metadata/physical_volumes " ) ;
2011-07-25 21:59:50 +04:00
if ( pv )
pv = pv - > child ;
return pv ;
}
/*
* TODO : This set_flag function is pretty generic and might make sense in a
* library here or there .
*/
2012-02-13 18:25:14 +04:00
static int set_flag ( struct dm_config_tree * cft , struct dm_config_node * parent ,
2011-08-31 16:39:58 +04:00
const char * field , const char * flag , int want ) {
2011-08-30 19:44:01 +04:00
struct dm_config_value * value = NULL , * pred = NULL ;
struct dm_config_node * node = dm_config_find_node ( parent - > child , field ) ;
2011-09-17 17:33:51 +04:00
struct dm_config_value * new ;
2011-07-25 21:59:50 +04:00
if ( node )
value = node - > v ;
2011-08-30 19:44:01 +04:00
while ( value & & value - > type ! = DM_CFG_EMPTY_ARRAY & & strcmp ( value - > v . str , flag ) ) {
2011-07-25 21:59:50 +04:00
pred = value ;
value = value - > next ;
}
if ( value & & want )
2012-02-13 18:25:14 +04:00
return 1 ;
2011-07-25 21:59:50 +04:00
if ( ! value & & ! want )
2012-02-13 18:25:14 +04:00
return 1 ;
2011-07-25 21:59:50 +04:00
if ( value & & ! want ) {
2012-01-16 12:25:32 +04:00
if ( pred ) {
2011-07-25 21:59:50 +04:00
pred - > next = value - > next ;
2012-01-16 12:25:32 +04:00
} else if ( value = = node - > v & & value - > next ) {
2011-07-25 21:59:50 +04:00
node - > v = value - > next ;
2012-01-16 12:25:32 +04:00
} else {
node - > v - > type = DM_CFG_EMPTY_ARRAY ;
}
2011-07-25 21:59:50 +04:00
}
if ( ! value & & want ) {
if ( ! node ) {
2011-08-30 19:44:01 +04:00
node = dm_config_create_node ( cft , field ) ;
2011-07-25 21:59:50 +04:00
node - > sib = parent - > child ;
2011-08-30 19:44:01 +04:00
node - > v = dm_config_create_value ( cft ) ;
node - > v - > type = DM_CFG_EMPTY_ARRAY ;
2011-07-25 21:59:50 +04:00
node - > parent = parent ;
parent - > child = node ;
}
2012-02-13 18:25:14 +04:00
if ( ! ( new = dm_config_create_value ( cft ) ) ) {
/* FIXME error reporting */
return 0 ;
}
2011-08-30 19:44:01 +04:00
new - > type = DM_CFG_STRING ;
2011-07-25 21:59:50 +04:00
new - > v . str = flag ;
new - > next = node - > v ;
node - > v = new ;
}
2012-02-13 18:25:14 +04:00
return 1 ;
2011-07-25 21:59:50 +04:00
}
2012-02-15 21:30:07 +04:00
static struct dm_config_node * make_config_node ( struct dm_config_tree * cft ,
const char * key ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib )
{
struct dm_config_node * cn = dm_config_create_node ( cft , key ) ;
cn - > parent = parent ;
cn - > sib = NULL ;
cn - > v = NULL ;
cn - > child = NULL ;
if ( parent & & parent - > child & & ! pre_sib ) { /* find the last one */
pre_sib = parent - > child ;
while ( pre_sib & & pre_sib - > sib ) pre_sib = pre_sib - > sib ;
}
if ( parent & & ! parent - > child )
parent - > child = cn ;
if ( pre_sib )
pre_sib - > sib = cn ;
return cn ;
}
static struct dm_config_node * make_text_node ( struct dm_config_tree * cft ,
const char * key ,
const char * value ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib )
{
struct dm_config_node * cn = make_config_node ( cft , key , parent , pre_sib ) ;
cn - > v = dm_config_create_value ( cft ) ;
cn - > v - > type = DM_CFG_STRING ;
cn - > v - > v . str = value ;
return cn ;
}
2012-02-28 22:35:04 +04:00
#if 0
2012-02-15 21:30:07 +04:00
static struct dm_config_node * make_int_node ( struct dm_config_tree * cft ,
const char * key ,
int64_t value ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib )
{
struct dm_config_node * cn = make_config_node ( cft , key , parent , pre_sib ) ;
cn - > v = dm_config_create_value ( cft ) ;
cn - > v - > type = DM_CFG_INT ;
cn - > v - > v . i = value ;
return cn ;
}
2012-02-28 22:35:04 +04:00
# endif
2012-02-15 21:30:07 +04:00
2012-02-15 15:43:06 +04:00
static void filter_metadata ( struct dm_config_node * vg ) {
struct dm_config_node * pv = pvs ( vg ) ;
while ( pv ) {
struct dm_config_node * item = pv - > child ;
while ( item ) {
/* Remove the advisory device nodes. */
if ( item - > sib & & ! strcmp ( item - > sib - > key , " device " ) )
item - > sib = item - > sib - > sib ;
item = item - > sib ;
}
pv = pv - > sib ;
}
vg - > sib = NULL ; /* Drop any trailing garbage. */
}
2012-02-21 13:19:08 +04:00
static void merge_pvmeta ( struct dm_config_node * pv , struct dm_config_node * pvmeta )
{
2012-02-23 21:59:32 +04:00
struct dm_config_node * tmp ;
2012-02-21 13:19:08 +04:00
if ( ! pvmeta )
return ;
2012-02-23 21:59:32 +04:00
tmp = pvmeta ;
2012-02-21 13:19:08 +04:00
while ( tmp - > sib ) {
/* drop the redundant ID and dev_size nodes */
if ( ! strcmp ( tmp - > sib - > key , " id " ) | | ! strcmp ( tmp - > sib - > key , " dev_size " ) )
tmp - > sib = tmp - > sib - > sib ;
if ( ! tmp - > sib ) break ;
tmp = tmp - > sib ;
tmp - > parent = pv ;
}
tmp - > sib = pv - > child ;
pv - > child = pvmeta ;
pvmeta - > parent = pv ;
}
2011-07-25 21:59:50 +04:00
/* Either the "big" vgs lock, or a per-vg lock needs to be held before entering
* this function . */
2011-08-30 19:44:01 +04:00
static int update_pv_status ( lvmetad_state * s ,
struct dm_config_tree * cft ,
struct dm_config_node * vg , int act )
2011-07-25 21:59:50 +04:00
{
2011-09-17 17:33:51 +04:00
struct dm_config_node * pv ;
2011-07-25 21:59:50 +04:00
int complete = 1 ;
2012-02-15 21:37:09 +04:00
lock_pvid_to_pvmeta ( s ) ;
2011-09-17 17:33:51 +04:00
pv = pvs ( vg ) ;
2011-07-25 21:59:50 +04:00
while ( pv ) {
2011-08-30 19:44:01 +04:00
const char * uuid = dm_config_find_str ( pv - > child , " id " , NULL ) ;
2012-02-15 21:37:09 +04:00
struct dm_config_tree * pvmeta = dm_hash_lookup ( s - > pvid_to_pvmeta , uuid ) ;
2012-02-15 15:43:06 +04:00
if ( act ) {
2012-02-15 21:37:09 +04:00
set_flag ( cft , pv , " status " , " MISSING " , ! pvmeta ) ;
2012-02-15 21:30:07 +04:00
if ( pvmeta ) {
2012-02-21 13:19:08 +04:00
struct dm_config_node * pvmeta_cn =
dm_config_clone_node ( cft , pvmeta - > root - > child , 1 ) ;
merge_pvmeta ( pv , pvmeta_cn ) ;
2012-02-15 15:43:06 +04:00
}
2012-02-13 18:25:14 +04:00
}
2012-02-15 21:37:09 +04:00
if ( ! pvmeta ) {
2011-07-25 21:59:50 +04:00
complete = 0 ;
2012-02-15 15:43:06 +04:00
if ( ! act ) { /* optimisation */
2012-02-15 21:37:09 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2011-07-25 21:59:50 +04:00
return complete ;
}
}
pv = pv - > sib ;
}
2012-02-15 21:37:09 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2011-07-25 21:59:50 +04:00
return complete ;
}
2012-02-15 15:43:06 +04:00
static struct dm_config_node * make_pv_node ( lvmetad_state * s , const char * pvid ,
struct dm_config_tree * cft ,
struct dm_config_node * parent ,
struct dm_config_node * pre_sib )
{
2012-02-15 21:30:07 +04:00
struct dm_config_tree * pvmeta = dm_hash_lookup ( s - > pvid_to_pvmeta , pvid ) ;
const char * vgid = dm_hash_lookup ( s - > pvid_to_vgid , pvid ) , * vgname = NULL ;
2012-02-23 21:59:32 +04:00
struct dm_config_node * pv ;
struct dm_config_node * cn = NULL ;
2012-02-15 21:30:07 +04:00
if ( ! pvmeta )
return NULL ;
2012-02-15 15:43:06 +04:00
if ( vgid ) {
lock_vgid_to_metadata ( s ) ; // XXX
vgname = dm_hash_lookup ( s - > vgid_to_vgname , vgid ) ;
unlock_vgid_to_metadata ( s ) ;
}
2012-02-15 21:30:07 +04:00
/* Nick the pvmeta config tree. */
2012-02-23 21:59:32 +04:00
pv = dm_config_clone_node ( cft , pvmeta - > root , 0 ) ;
2012-02-15 21:30:07 +04:00
if ( pre_sib )
pre_sib - > sib = pv ;
if ( parent & & ! parent - > child )
parent - > child = pv ;
pv - > parent = parent ;
2012-02-21 13:19:08 +04:00
pv - > key = pvid ;
2012-02-15 21:30:07 +04:00
/* Add the "variable" bits to it. */
2012-02-15 15:43:06 +04:00
if ( vgid & & strcmp ( vgid , " #orphan " ) )
cn = make_text_node ( cft , " vgid " , vgid , pv , cn ) ;
if ( vgname )
cn = make_text_node ( cft , " vgname " , vgname , pv , cn ) ;
return pv ;
}
static response pv_list ( lvmetad_state * s , request r )
{
2012-02-15 18:15:50 +04:00
struct dm_config_node * cn = NULL , * cn_pvs ;
2012-02-23 21:59:32 +04:00
struct dm_hash_node * n ;
const char * id ;
2012-02-15 15:43:06 +04:00
response res = { . buffer = NULL } ;
res . cft = dm_config_create ( ) ;
/* The response field */
res . cft - > root = make_text_node ( res . cft , " response " , " OK " , NULL , NULL ) ;
cn_pvs = make_config_node ( res . cft , " physical_volumes " , NULL , res . cft - > root ) ;
2012-02-15 21:37:09 +04:00
lock_pvid_to_pvmeta ( s ) ;
2012-02-15 15:43:06 +04:00
2012-02-23 21:59:32 +04:00
n = dm_hash_get_first ( s - > pvid_to_pvmeta ) ;
2012-02-15 15:43:06 +04:00
while ( n ) {
2012-02-23 21:59:32 +04:00
id = dm_hash_get_key ( s - > pvid_to_pvmeta , n ) ;
2012-02-15 15:43:06 +04:00
cn = make_pv_node ( s , id , res . cft , cn_pvs , cn ) ;
2012-02-15 21:30:07 +04:00
n = dm_hash_get_next ( s - > pvid_to_pvmeta , n ) ;
2012-02-15 15:43:06 +04:00
}
2012-02-15 21:37:09 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2012-02-15 15:43:06 +04:00
return res ;
}
static response pv_lookup ( lvmetad_state * s , request r )
{
const char * pvid = daemon_request_str ( r , " uuid " , NULL ) ;
2012-02-21 13:19:08 +04:00
int64_t devt = daemon_request_int ( r , " device " , 0 ) ;
2012-02-23 21:59:32 +04:00
response res = { . buffer = NULL } ;
struct dm_config_node * pv ;
2012-02-21 13:19:08 +04:00
if ( ! pvid & & ! devt )
return daemon_reply_simple ( " failed " , " reason = %s " , " need PVID or device " , NULL ) ;
2012-02-15 15:43:06 +04:00
res . cft = dm_config_create ( ) ;
res . cft - > root = make_text_node ( res . cft , " response " , " OK " , NULL , NULL ) ;
2012-02-15 21:37:09 +04:00
lock_pvid_to_pvmeta ( s ) ;
2012-02-21 13:19:08 +04:00
if ( ! pvid & & devt )
pvid = dm_hash_lookup_binary ( s - > device_to_pvid , & devt , sizeof ( devt ) ) ;
if ( ! pvid ) {
2012-02-23 21:59:32 +04:00
debug ( " pv_lookup: could not find device % " PRIu64 " \n " , devt ) ;
2012-02-21 13:19:08 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2012-02-24 04:24:37 +04:00
dm_config_destroy ( res . cft ) ;
2012-02-21 13:19:08 +04:00
return daemon_reply_simple ( " failed " , " reason = %s " , " device not found " , NULL ) ;
}
2012-02-15 15:43:06 +04:00
pv = make_pv_node ( s , pvid , res . cft , NULL , res . cft - > root ) ;
2012-02-15 21:30:07 +04:00
if ( ! pv ) {
2012-02-15 21:37:09 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2012-02-24 04:24:37 +04:00
dm_config_destroy ( res . cft ) ;
2012-02-15 21:30:07 +04:00
return daemon_reply_simple ( " failed " , " reason = %s " , " PV not found " , NULL ) ;
}
2012-02-15 15:43:06 +04:00
pv - > key = " physical_volume " ;
2012-02-15 21:37:09 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2012-02-15 15:43:06 +04:00
return res ;
}
static response vg_list ( lvmetad_state * s , request r )
{
struct dm_config_node * cn , * cn_vgs , * cn_last = NULL ;
2012-02-23 21:59:32 +04:00
struct dm_hash_node * n ;
const char * id ;
const char * name ;
2012-02-15 15:43:06 +04:00
response res = { . buffer = NULL } ;
res . cft = dm_config_create ( ) ;
/* The response field */
res . cft - > root = cn = dm_config_create_node ( res . cft , " response " ) ;
cn - > parent = res . cft - > root ;
cn - > v = dm_config_create_value ( res . cft ) ;
cn - > v - > type = DM_CFG_STRING ;
cn - > v - > v . str = " OK " ;
cn_vgs = cn = cn - > sib = dm_config_create_node ( res . cft , " volume_groups " ) ;
cn - > parent = res . cft - > root ;
cn - > v = NULL ;
cn - > child = NULL ;
lock_vgid_to_metadata ( s ) ;
2012-02-23 21:59:32 +04:00
n = dm_hash_get_first ( s - > vgid_to_vgname ) ;
2012-02-15 15:43:06 +04:00
while ( n ) {
2012-02-23 21:59:32 +04:00
id = dm_hash_get_key ( s - > vgid_to_vgname , n ) ,
name = dm_hash_get_data ( s - > vgid_to_vgname , n ) ;
2012-02-15 15:43:06 +04:00
cn = dm_config_create_node ( res . cft , id ) ;
if ( cn_last )
cn_last - > sib = cn ;
cn - > parent = cn_vgs ;
cn - > sib = NULL ;
cn - > v = NULL ;
cn - > child = dm_config_create_node ( res . cft , " name " ) ;
cn - > child - > parent = cn ;
cn - > child - > sib = 0 ;
cn - > child - > v = dm_config_create_value ( res . cft ) ;
cn - > child - > v - > type = DM_CFG_STRING ;
cn - > child - > v - > v . str = name ;
if ( ! cn_vgs - > child )
cn_vgs - > child = cn ;
cn_last = cn ;
n = dm_hash_get_next ( s - > vgid_to_vgname , n ) ;
}
unlock_vgid_to_metadata ( s ) ;
return res ;
}
2012-01-16 12:25:32 +04:00
static response vg_lookup ( lvmetad_state * s , request r )
2011-07-18 18:48:30 +04:00
{
2012-01-25 17:06:57 +04:00
struct dm_config_tree * cft ;
struct dm_config_node * metadata , * n ;
response res = { . buffer = NULL } ;
2012-02-23 21:59:32 +04:00
const char * uuid = daemon_request_str ( r , " uuid " , NULL ) ;
const char * name = daemon_request_str ( r , " name " , NULL ) ;
2012-02-15 15:43:06 +04:00
2012-01-16 12:25:32 +04:00
debug ( " vg_lookup: uuid = %s, name = %s \n " , uuid , name ) ;
if ( ! uuid | | ! name ) {
2012-02-15 15:43:06 +04:00
lock_vgid_to_metadata ( s ) ;
2012-01-16 12:25:32 +04:00
if ( name & & ! uuid )
2012-02-23 21:59:32 +04:00
uuid = dm_hash_lookup ( s - > vgname_to_vgid , name ) ;
2012-01-16 12:25:32 +04:00
if ( uuid & & ! name )
2012-02-23 21:59:32 +04:00
name = dm_hash_lookup ( s - > vgid_to_vgname , uuid ) ;
2012-02-15 15:43:06 +04:00
unlock_vgid_to_metadata ( s ) ;
2012-01-16 12:25:32 +04:00
}
2011-09-17 17:33:51 +04:00
2012-01-16 12:25:32 +04:00
debug ( " vg_lookup: updated uuid = %s, name = %s \n " , uuid , name ) ;
if ( ! uuid )
return daemon_reply_simple ( " failed " , " reason = %s " , " VG not found " , NULL ) ;
2012-01-25 17:06:57 +04:00
cft = lock_vg ( s , uuid ) ;
2011-07-21 01:23:43 +04:00
if ( ! cft | | ! cft - > root ) {
unlock_vg ( s , uuid ) ;
2012-01-16 12:25:32 +04:00
return daemon_reply_simple ( " failed " , " reason = %s " , " UUID not found " , NULL ) ;
2011-07-21 01:23:43 +04:00
}
2011-07-19 20:48:13 +04:00
2012-01-25 17:06:57 +04:00
metadata = cft - > root ;
2011-12-19 02:31:10 +04:00
res . cft = dm_config_create ( ) ;
2011-07-18 18:48:30 +04:00
/* The response field */
2011-08-30 19:44:01 +04:00
res . cft - > root = n = dm_config_create_node ( res . cft , " response " ) ;
2012-01-16 12:25:32 +04:00
n - > parent = res . cft - > root ;
2011-08-30 19:44:01 +04:00
n - > v - > type = DM_CFG_STRING ;
2011-07-18 18:48:30 +04:00
n - > v - > v . str = " OK " ;
2012-01-16 12:25:32 +04:00
n = n - > sib = dm_config_create_node ( res . cft , " name " ) ;
n - > parent = res . cft - > root ;
n - > v - > type = DM_CFG_STRING ;
n - > v - > v . str = name ;
2011-07-18 18:48:30 +04:00
/* The metadata section */
2011-08-30 19:44:01 +04:00
n = n - > sib = dm_config_clone_node ( res . cft , metadata , 1 ) ;
2011-07-18 18:48:30 +04:00
n - > parent = res . cft - > root ;
res . error = 0 ;
2011-07-21 01:23:43 +04:00
unlock_vg ( s , uuid ) ;
2012-02-15 15:43:06 +04:00
update_pv_status ( s , res . cft , n , 1 ) ; /* FIXME report errors */
2011-07-18 18:48:30 +04:00
return res ;
}
2011-08-30 19:44:01 +04:00
static int compare_value ( struct dm_config_value * a , struct dm_config_value * b )
2011-07-25 19:51:51 +04:00
{
2011-08-31 16:39:58 +04:00
int r = 0 ;
2011-07-25 19:51:51 +04:00
if ( a - > type > b - > type )
return 1 ;
if ( a - > type < b - > type )
return - 1 ;
switch ( a - > type ) {
2012-01-26 01:42:09 +04:00
case DM_CFG_STRING : r = strcmp ( a - > v . str , b - > v . str ) ; break ;
2012-02-15 15:43:06 +04:00
case DM_CFG_FLOAT : r = ( a - > v . f = = b - > v . f ) ? 0 : ( a - > v . f > b - > v . f ) ? 1 : - 1 ; break ;
case DM_CFG_INT : r = ( a - > v . i = = b - > v . i ) ? 0 : ( a - > v . i > b - > v . i ) ? 1 : - 1 ; break ;
2011-08-30 19:44:01 +04:00
case DM_CFG_EMPTY_ARRAY : return 0 ;
2011-07-25 19:51:51 +04:00
}
2011-08-31 16:39:58 +04:00
if ( r = = 0 & & a - > next & & b - > next )
r = compare_value ( a - > next , b - > next ) ;
return r ;
2011-07-25 19:51:51 +04:00
}
2011-08-30 19:44:01 +04:00
static int compare_config ( struct dm_config_node * a , struct dm_config_node * b )
2011-07-25 19:51:51 +04:00
{
int result = 0 ;
if ( a - > v & & b - > v )
result = compare_value ( a - > v , b - > v ) ;
if ( a - > v & & ! b - > v )
result = 1 ;
if ( ! a - > v & & b - > v )
result = - 1 ;
if ( a - > child & & b - > child )
result = compare_config ( a - > child , b - > child ) ;
2012-02-15 15:43:06 +04:00
if ( result ) {
debug ( " config inequality at %s / %s \n " , a - > key , b - > key ) ;
2011-07-25 19:51:51 +04:00
return result ;
2012-02-15 15:43:06 +04:00
}
2011-07-25 19:51:51 +04:00
if ( a - > sib & & b - > sib )
result = compare_config ( a - > sib , b - > sib ) ;
if ( a - > sib & & ! b - > sib )
result = 1 ;
if ( ! a - > sib & & b - > sib )
result = - 1 ;
return result ;
}
2012-02-15 18:06:48 +04:00
static int vg_remove_if_missing ( lvmetad_state * s , const char * vgid ) ;
2012-02-15 15:43:06 +04:00
/* You need to be holding the pvid_to_vgid lock already to call this. */
2012-02-15 18:06:48 +04:00
static int update_pvid_to_vgid ( lvmetad_state * s , struct dm_config_tree * vg ,
const char * vgid , int nuke_empty )
2011-07-20 20:46:40 +04:00
{
2011-08-30 19:44:01 +04:00
struct dm_config_node * pv = pvs ( vg - > root ) ;
2012-02-27 14:10:43 +04:00
struct dm_hash_table * to_check ;
2012-02-23 21:59:32 +04:00
struct dm_hash_node * n ;
const char * pvid ;
const char * vgid_old ;
2011-07-20 20:46:40 +04:00
2011-07-20 22:34:57 +04:00
if ( ! vgid )
return 0 ;
2011-07-20 20:46:40 +04:00
2012-02-27 14:10:43 +04:00
if ( ! ( to_check = dm_hash_create ( 32 ) ) )
return 0 ;
2011-07-20 22:34:57 +04:00
while ( pv ) {
2012-02-23 21:59:32 +04:00
pvid = dm_config_find_str ( pv - > child , " id " , NULL ) ;
vgid_old = dm_hash_lookup ( s - > pvid_to_vgid , pvid ) ;
2012-02-15 18:06:48 +04:00
if ( vgid_old & & nuke_empty )
dm_hash_insert ( to_check , vgid_old , ( void * ) 1 ) ;
2012-02-23 21:59:32 +04:00
dm_hash_insert ( s - > pvid_to_vgid , pvid , ( void * ) vgid ) ;
2012-02-15 15:43:06 +04:00
debug ( " remap PV %s to VG %s \n " , pvid , vgid ) ;
2011-07-20 22:34:57 +04:00
pv = pv - > sib ;
2011-07-20 20:46:40 +04:00
}
2011-07-20 22:34:57 +04:00
2012-02-23 21:59:32 +04:00
n = dm_hash_get_first ( to_check ) ;
2012-02-15 18:06:48 +04:00
while ( n ) {
const char * check_vgid = dm_hash_get_key ( to_check , n ) ;
lock_vg ( s , check_vgid ) ;
vg_remove_if_missing ( s , check_vgid ) ;
unlock_vg ( s , check_vgid ) ;
n = dm_hash_get_next ( to_check , n ) ;
}
dm_hash_destroy ( to_check ) ;
2011-07-20 22:34:57 +04:00
return 1 ;
2011-07-20 20:46:40 +04:00
}
2012-02-15 18:06:48 +04:00
/* A pvid map lock needs to be held if update_pvids = 1. */
static int remove_metadata ( lvmetad_state * s , const char * vgid , int update_pvids )
2012-01-16 12:25:32 +04:00
{
2012-01-25 17:06:57 +04:00
struct dm_config_tree * old ;
const char * oldname ;
2012-02-15 15:43:06 +04:00
lock_vgid_to_metadata ( s ) ;
old = dm_hash_lookup ( s - > vgid_to_metadata , vgid ) ;
oldname = dm_hash_lookup ( s - > vgid_to_vgname , vgid ) ;
unlock_vgid_to_metadata ( s ) ;
2012-01-16 12:25:32 +04:00
if ( ! old )
return 0 ;
2012-02-27 14:19:00 +04:00
assert ( oldname ) ;
2012-01-16 12:25:32 +04:00
2012-02-15 18:06:48 +04:00
if ( update_pvids )
update_pvid_to_vgid ( s , old , " #orphan " , 0 ) ;
2012-01-16 12:25:32 +04:00
/* need to update what we have since we found a newer version */
2012-02-15 15:43:06 +04:00
dm_hash_remove ( s - > vgid_to_metadata , vgid ) ;
dm_hash_remove ( s - > vgid_to_vgname , vgid ) ;
dm_hash_remove ( s - > vgname_to_vgid , oldname ) ;
2012-01-16 12:25:32 +04:00
dm_config_destroy ( old ) ;
return 1 ;
}
2012-02-15 15:43:06 +04:00
/* The VG must be locked. */
static int vg_remove_if_missing ( lvmetad_state * s , const char * vgid )
{
2012-02-23 21:59:32 +04:00
struct dm_config_tree * vg ;
struct dm_config_node * pv ;
int missing = 1 ;
2012-02-15 15:43:06 +04:00
if ( ! vgid )
return 0 ;
2012-02-23 21:59:32 +04:00
if ( ! ( vg = dm_hash_lookup ( s - > vgid_to_metadata , vgid ) ) )
2012-02-15 15:43:06 +04:00
return 1 ;
2012-02-23 21:59:32 +04:00
pv = pvs ( vg - > root ) ;
2012-02-15 21:37:09 +04:00
lock_pvid_to_pvmeta ( s ) ;
2012-02-15 15:43:06 +04:00
while ( pv ) {
const char * pvid = dm_config_find_str ( pv - > child , " id " , NULL ) ;
const char * vgid_check = dm_hash_lookup ( s - > pvid_to_vgid , pvid ) ;
2012-02-15 21:37:09 +04:00
if ( dm_hash_lookup ( s - > pvid_to_pvmeta , pvid ) & &
2012-02-15 15:43:06 +04:00
vgid_check & & ! strcmp ( vgid , vgid_check ) )
missing = 0 ; /* at least one PV is around */
pv = pv - > sib ;
}
if ( missing ) {
debug ( " nuking VG %s \n " , vgid ) ;
2012-02-15 18:06:48 +04:00
remove_metadata ( s , vgid , 0 ) ;
2012-02-15 15:43:06 +04:00
}
2012-02-15 21:37:09 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2012-02-15 15:43:06 +04:00
return 1 ;
}
2011-07-21 01:23:43 +04:00
/* No locks need to be held. The pointers are never used outside of the scope of
* this function , so they can be safely destroyed after update_metadata returns
* ( anything that might have been retained is copied ) . */
2012-01-16 12:25:32 +04:00
static int update_metadata ( lvmetad_state * s , const char * name , const char * _vgid ,
struct dm_config_node * metadata )
2011-07-19 18:13:59 +04:00
{
2011-09-17 17:33:51 +04:00
struct dm_config_tree * cft ;
struct dm_config_tree * old ;
2011-07-21 01:23:43 +04:00
int retval = 0 ;
2012-01-25 17:06:57 +04:00
int seq ;
int haveseq = - 1 ;
const char * oldname = NULL ;
const char * vgid ;
2011-09-17 17:33:51 +04:00
2012-02-15 15:43:06 +04:00
lock_vgid_to_metadata ( s ) ;
old = dm_hash_lookup ( s - > vgid_to_metadata , _vgid ) ;
2011-07-21 01:23:43 +04:00
lock_vg ( s , _vgid ) ;
2012-02-15 15:43:06 +04:00
unlock_vgid_to_metadata ( s ) ;
2011-07-21 01:23:43 +04:00
2012-01-25 17:06:57 +04:00
seq = dm_config_find_int ( metadata , " metadata/seqno " , - 1 ) ;
2011-07-19 20:48:13 +04:00
2012-01-16 12:25:32 +04:00
if ( old ) {
2011-08-30 19:44:01 +04:00
haveseq = dm_config_find_int ( old - > root , " metadata/seqno " , - 1 ) ;
2012-02-15 15:43:06 +04:00
oldname = dm_hash_lookup ( s - > vgid_to_vgname , _vgid ) ;
2012-01-16 12:25:32 +04:00
assert ( oldname ) ;
}
2011-07-19 20:48:13 +04:00
if ( seq < 0 )
2011-07-21 01:23:43 +04:00
goto out ;
2011-07-19 20:48:13 +04:00
2012-02-15 15:43:06 +04:00
filter_metadata ( metadata ) ; /* sanitize */
2011-07-19 20:48:13 +04:00
if ( seq = = haveseq ) {
2011-07-21 01:23:43 +04:00
retval = 1 ;
2011-07-25 19:51:51 +04:00
if ( compare_config ( metadata , old - > root ) )
retval = 0 ;
2012-02-15 15:43:06 +04:00
debug ( " Not updating metadata for %s at %d (%s) \n " , _vgid , haveseq ,
retval ? " ok " : " MISMATCH " ) ;
if ( ! retval ) {
debug_cft ( " OLD: " , old - > root ) ;
debug_cft ( " NEW: " , metadata ) ;
}
2011-07-21 01:23:43 +04:00
goto out ;
2011-07-19 20:48:13 +04:00
}
if ( seq < haveseq ) {
2012-01-16 12:25:32 +04:00
debug ( " Refusing to update metadata for %s at %d to %d \n " , _vgid , haveseq , seq ) ;
2012-02-15 15:43:06 +04:00
/* TODO: notify the client that their metadata is out of date? */
2011-07-21 01:23:43 +04:00
retval = 1 ;
goto out ;
2011-07-19 20:48:13 +04:00
}
2011-12-19 02:31:10 +04:00
cft = dm_config_create ( ) ;
2011-08-30 19:44:01 +04:00
cft - > root = dm_config_clone_node ( cft , metadata , 0 ) ;
2011-07-20 22:45:32 +04:00
2012-01-25 17:06:57 +04:00
vgid = dm_config_find_str ( cft - > root , " metadata/id " , NULL ) ;
2012-01-16 12:25:32 +04:00
if ( ! vgid | | ! name ) {
debug ( " Name '%s' or uuid '%s' missing! \n " , name , vgid ) ;
2011-07-21 01:23:43 +04:00
goto out ;
2012-01-16 12:25:32 +04:00
}
2011-07-21 01:23:43 +04:00
2012-02-15 15:43:06 +04:00
lock_pvid_to_vgid ( s ) ;
2011-07-20 22:45:32 +04:00
2011-07-19 20:48:13 +04:00
if ( haveseq > = 0 & & haveseq < seq ) {
2012-01-16 12:25:32 +04:00
debug ( " Updating metadata for %s at %d to %d \n " , _vgid , haveseq , seq ) ;
2011-07-20 22:45:32 +04:00
/* temporarily orphan all of our PVs */
2012-02-15 18:06:48 +04:00
remove_metadata ( s , vgid , 1 ) ;
2011-07-19 20:48:13 +04:00
}
2012-02-15 15:43:06 +04:00
lock_vgid_to_metadata ( s ) ;
dm_hash_insert ( s - > vgid_to_metadata , vgid , cft ) ;
2012-01-16 12:25:32 +04:00
debug ( " Mapping %s to %s \n " , vgid , name ) ;
2012-02-15 15:43:06 +04:00
dm_hash_insert ( s - > vgid_to_vgname , vgid , dm_pool_strdup ( dm_config_memory ( cft ) , name ) ) ;
2012-02-23 21:59:32 +04:00
dm_hash_insert ( s - > vgname_to_vgid , name , ( void * ) vgid ) ;
2012-02-15 15:43:06 +04:00
unlock_vgid_to_metadata ( s ) ;
2011-07-21 01:23:43 +04:00
2012-02-15 18:06:48 +04:00
update_pvid_to_vgid ( s , cft , vgid , 1 ) ;
2011-07-19 20:48:13 +04:00
2012-02-15 15:43:06 +04:00
unlock_pvid_to_vgid ( s ) ;
2011-07-21 01:23:43 +04:00
retval = 1 ;
out :
unlock_vg ( s , _vgid ) ;
return retval ;
2011-07-19 18:13:59 +04:00
}
2012-01-16 12:25:32 +04:00
static response pv_gone ( lvmetad_state * s , request r )
{
2012-02-15 21:30:07 +04:00
const char * pvid = daemon_request_str ( r , " uuid " , NULL ) ;
int64_t device = daemon_request_int ( r , " device " , 0 ) ;
2012-02-23 21:59:32 +04:00
struct dm_config_tree * pvmeta ;
2012-02-15 15:43:06 +04:00
2012-02-23 21:59:32 +04:00
debug ( " pv_gone: %s / % " PRIu64 " \n " , pvid , device ) ;
2012-02-15 15:43:06 +04:00
2012-02-15 21:37:09 +04:00
lock_pvid_to_pvmeta ( s ) ;
2012-02-15 21:30:07 +04:00
if ( ! pvid & & device > 0 )
pvid = dm_hash_lookup_binary ( s - > device_to_pvid , & device , sizeof ( device ) ) ;
2012-02-15 15:43:06 +04:00
if ( ! pvid ) {
2012-02-15 21:37:09 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2012-02-15 15:43:06 +04:00
return daemon_reply_simple ( " failed " , " reason = %s " , " device not in cache " , NULL ) ;
}
2012-02-23 21:59:32 +04:00
debug ( " pv_gone (updated): %s / % " PRIu64 " \n " , pvid , device ) ;
2012-02-15 15:43:06 +04:00
2012-02-23 21:59:32 +04:00
pvmeta = dm_hash_lookup ( s - > pvid_to_pvmeta , pvid ) ;
2012-02-15 21:30:07 +04:00
dm_hash_remove_binary ( s - > device_to_pvid , & device , sizeof ( device ) ) ;
dm_hash_remove ( s - > pvid_to_pvmeta , pvid ) ;
2012-02-15 15:43:06 +04:00
vg_remove_if_missing ( s , dm_hash_lookup ( s - > pvid_to_vgid , pvid ) ) ;
2012-02-15 21:37:09 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2012-01-16 12:25:32 +04:00
2012-02-15 21:30:07 +04:00
if ( pvmeta ) {
dm_config_destroy ( pvmeta ) ;
2012-01-16 12:25:32 +04:00
return daemon_reply_simple ( " OK " , NULL ) ;
2012-02-15 21:30:07 +04:00
} else
2012-01-16 12:25:32 +04:00
return daemon_reply_simple ( " failed " , " reason = %s " , " PVID does not exist " , NULL ) ;
}
static response pv_found ( lvmetad_state * s , request r )
2011-07-18 18:48:30 +04:00
{
2011-08-30 19:44:01 +04:00
struct dm_config_node * metadata = dm_config_find_node ( r . cft - > root , " metadata " ) ;
2012-02-15 21:30:07 +04:00
const char * pvid = daemon_request_str ( r , " pvmeta/id " , NULL ) ;
2012-01-16 12:25:32 +04:00
const char * vgname = daemon_request_str ( r , " vgname " , NULL ) ;
2011-07-20 19:14:17 +04:00
const char * vgid = daemon_request_str ( r , " metadata/id " , NULL ) ;
2012-02-15 21:30:07 +04:00
struct dm_config_node * pvmeta = dm_config_find_node ( r . cft - > root , " pvmeta " ) ;
uint64_t device ;
2012-02-24 04:24:37 +04:00
struct dm_config_tree * cft , * pvmeta_old = NULL ;
2012-02-23 21:59:32 +04:00
const char * old ;
const char * pvid_dup ;
2012-02-15 15:43:06 +04:00
int complete = 0 , orphan = 0 ;
2011-07-18 18:48:30 +04:00
if ( ! pvid )
return daemon_reply_simple ( " failed " , " reason = %s " , " need PV UUID " , NULL ) ;
2012-02-15 21:30:07 +04:00
if ( ! pvmeta )
return daemon_reply_simple ( " failed " , " reason = %s " , " need PV metadata " , NULL ) ;
if ( ! dm_config_get_uint64 ( pvmeta , " pvmeta/device " , & device ) )
return daemon_reply_simple ( " failed " , " reason = %s " , " need PV device number " , NULL ) ;
2011-07-18 18:48:30 +04:00
2012-02-23 21:59:32 +04:00
debug ( " pv_found %s, vgid = %s, device = % " PRIu64 " \n " , pvid , vgid , device ) ;
2011-07-21 01:33:41 +04:00
2012-02-15 21:37:09 +04:00
lock_pvid_to_pvmeta ( s ) ;
2012-02-23 21:59:32 +04:00
2012-02-24 04:24:37 +04:00
if ( ( old = dm_hash_lookup_binary ( s - > device_to_pvid , & device , sizeof ( device ) ) ) ) {
pvmeta_old = dm_hash_lookup ( s - > pvid_to_pvmeta , old ) ;
2012-02-23 21:59:32 +04:00
dm_hash_remove ( s - > pvid_to_pvmeta , old ) ;
2012-02-24 04:24:37 +04:00
}
2012-02-23 21:59:32 +04:00
cft = dm_config_create ( ) ;
cft - > root = dm_config_clone_node ( cft , pvmeta , 0 ) ;
pvid_dup = dm_config_find_str ( cft - > root , " pvmeta/id " , NULL ) ;
dm_hash_insert ( s - > pvid_to_pvmeta , pvid , cft ) ;
dm_hash_insert_binary ( s - > device_to_pvid , & device , sizeof ( device ) , ( void * ) pvid_dup ) ;
2012-02-24 04:24:37 +04:00
if ( pvmeta_old )
dm_config_destroy ( pvmeta_old ) ;
2012-02-23 21:59:32 +04:00
2012-02-15 21:37:09 +04:00
unlock_pvid_to_pvmeta ( s ) ;
2011-07-19 18:13:59 +04:00
2011-07-18 18:48:30 +04:00
if ( metadata ) {
if ( ! vgid )
return daemon_reply_simple ( " failed " , " reason = %s " , " need VG UUID " , NULL ) ;
2012-02-21 13:19:08 +04:00
debug ( " obtained vgid = %s, vgname = %s \n " , vgid , vgname ) ;
2012-01-16 12:25:32 +04:00
if ( ! vgname )
return daemon_reply_simple ( " failed " , " reason = %s " , " need VG name " , NULL ) ;
2011-07-19 20:48:13 +04:00
if ( daemon_request_int ( r , " metadata/seqno " , - 1 ) < 0 )
return daemon_reply_simple ( " failed " , " reason = %s " , " need VG seqno " , NULL ) ;
2011-07-19 18:13:59 +04:00
2012-01-16 12:25:32 +04:00
if ( ! update_metadata ( s , vgname , vgid , metadata ) )
2011-07-19 20:48:13 +04:00
return daemon_reply_simple ( " failed " , " reason = %s " ,
" metadata update failed " , NULL ) ;
2011-07-21 01:23:43 +04:00
} else {
2012-02-15 15:43:06 +04:00
lock_pvid_to_vgid ( s ) ;
vgid = dm_hash_lookup ( s - > pvid_to_vgid , pvid ) ;
unlock_pvid_to_vgid ( s ) ;
2011-07-21 01:23:43 +04:00
}
if ( vgid ) {
2012-02-23 21:59:32 +04:00
if ( ( cft = lock_vg ( s , vgid ) ) )
2012-02-15 15:43:06 +04:00
complete = update_pv_status ( s , cft , cft - > root , 0 ) ;
2012-02-23 21:59:32 +04:00
else if ( ! strcmp ( vgid , " #orphan " ) )
2012-02-15 15:43:06 +04:00
orphan = 1 ;
2012-02-23 21:59:32 +04:00
else {
2012-01-16 12:25:32 +04:00
unlock_vg ( s , vgid ) ;
2012-02-15 15:43:06 +04:00
return daemon_reply_simple ( " failed " , " reason = %s " ,
" internal treason! " , NULL ) ;
2012-01-16 12:25:32 +04:00
}
2011-07-21 01:23:43 +04:00
unlock_vg ( s , vgid ) ;
}
2011-07-18 18:48:30 +04:00
2011-07-20 19:14:17 +04:00
return daemon_reply_simple ( " OK " ,
2012-02-15 15:43:06 +04:00
" status = %s " , orphan ? " orphan " :
( complete ? " complete " : " partial " ) ,
2011-07-20 20:46:40 +04:00
" vgid = %s " , vgid ? vgid : " #orphan " ,
2011-07-20 19:14:17 +04:00
NULL ) ;
2011-07-18 18:48:30 +04:00
}
2012-01-16 12:25:32 +04:00
static response vg_update ( lvmetad_state * s , request r )
{
struct dm_config_node * metadata = dm_config_find_node ( r . cft - > root , " metadata " ) ;
const char * vgid = daemon_request_str ( r , " metadata/id " , NULL ) ;
const char * vgname = daemon_request_str ( r , " vgname " , NULL ) ;
if ( metadata ) {
if ( ! vgid )
return daemon_reply_simple ( " failed " , " reason = %s " , " need VG UUID " , NULL ) ;
if ( ! vgname )
return daemon_reply_simple ( " failed " , " reason = %s " , " need VG name " , NULL ) ;
if ( daemon_request_int ( r , " metadata/seqno " , - 1 ) < 0 )
return daemon_reply_simple ( " failed " , " reason = %s " , " need VG seqno " , NULL ) ;
2012-02-15 15:43:06 +04:00
/* TODO defer metadata update here; add a separate vg_commit
* call ; if client does not commit , die */
2012-01-16 12:25:32 +04:00
if ( ! update_metadata ( s , vgname , vgid , metadata ) )
return daemon_reply_simple ( " failed " , " reason = %s " ,
" metadata update failed " , NULL ) ;
}
return daemon_reply_simple ( " OK " , NULL ) ;
}
static response vg_remove ( lvmetad_state * s , request r )
2011-07-18 18:48:30 +04:00
{
2012-01-16 12:25:32 +04:00
const char * vgid = daemon_request_str ( r , " uuid " , NULL ) ;
if ( ! vgid )
return daemon_reply_simple ( " failed " , " reason = %s " , " need VG UUID " , NULL ) ;
fprintf ( stderr , " vg_remove: %s \n " , vgid ) ;
2012-02-15 15:43:06 +04:00
lock_pvid_to_vgid ( s ) ;
2012-02-15 18:06:48 +04:00
remove_metadata ( s , vgid , 1 ) ;
2012-02-15 15:43:06 +04:00
unlock_pvid_to_vgid ( s ) ;
2012-01-16 12:25:32 +04:00
return daemon_reply_simple ( " OK " , NULL ) ;
2011-07-18 18:48:30 +04:00
}
2011-06-14 06:36:38 +04:00
static response handler ( daemon_state s , client_handle h , request r )
{
2011-07-18 18:48:30 +04:00
lvmetad_state * state = s . private ;
const char * rq = daemon_request_str ( r , " request " , " NONE " ) ;
2012-02-15 15:43:06 +04:00
/*
* TODO Add a stats call , with transaction count / rate , time since last
* update & c .
*/
2012-01-16 12:25:32 +04:00
if ( ! strcmp ( rq , " pv_found " ) )
return pv_found ( state , r ) ;
2011-07-18 18:48:30 +04:00
2012-01-16 12:25:32 +04:00
if ( ! strcmp ( rq , " pv_gone " ) )
2012-02-15 15:43:06 +04:00
return pv_gone ( state , r ) ;
if ( ! strcmp ( rq , " pv_lookup " ) )
return pv_lookup ( state , r ) ;
2012-01-16 12:25:32 +04:00
if ( ! strcmp ( rq , " vg_update " ) )
return vg_update ( state , r ) ;
if ( ! strcmp ( rq , " vg_remove " ) )
return vg_remove ( state , r ) ;
if ( ! strcmp ( rq , " vg_lookup " ) )
return vg_lookup ( state , r ) ;
2012-02-15 15:43:06 +04:00
if ( ! strcmp ( rq , " pv_list " ) ) {
return pv_list ( state , r ) ;
}
if ( ! strcmp ( rq , " vg_list " ) )
return vg_list ( state , r ) ;
2012-01-16 12:25:32 +04:00
return daemon_reply_simple ( " failed " , " reason = %s " , " no such request " , NULL ) ;
2011-06-14 06:36:38 +04:00
}
2011-07-18 18:48:30 +04:00
static int init ( daemon_state * s )
2011-06-14 06:36:38 +04:00
{
2011-09-17 17:33:51 +04:00
pthread_mutexattr_t rec ;
2011-06-14 06:36:38 +04:00
lvmetad_state * ls = s - > private ;
2012-02-15 21:30:07 +04:00
ls - > pvid_to_pvmeta = dm_hash_create ( 32 ) ;
2012-02-15 15:43:06 +04:00
ls - > device_to_pvid = dm_hash_create ( 32 ) ;
ls - > vgid_to_metadata = dm_hash_create ( 32 ) ;
ls - > vgid_to_vgname = dm_hash_create ( 32 ) ;
ls - > pvid_to_vgid = dm_hash_create ( 32 ) ;
ls - > vgname_to_vgid = dm_hash_create ( 32 ) ;
2011-07-21 01:23:43 +04:00
ls - > lock . vg = dm_hash_create ( 32 ) ;
pthread_mutexattr_init ( & rec ) ;
pthread_mutexattr_settype ( & rec , PTHREAD_MUTEX_RECURSIVE_NP ) ;
2012-02-15 21:37:09 +04:00
pthread_mutex_init ( & ls - > lock . pvid_to_pvmeta , & rec ) ;
2012-02-15 15:43:06 +04:00
pthread_mutex_init ( & ls - > lock . vgid_to_metadata , & rec ) ;
pthread_mutex_init ( & ls - > lock . pvid_to_vgid , NULL ) ;
2011-07-21 01:23:43 +04:00
2012-02-15 15:43:06 +04:00
debug ( " initialised state: vgid_to_metadata = %p \n " , ls - > vgid_to_metadata ) ;
if ( ! ls - > pvid_to_vgid | | ! ls - > vgid_to_metadata )
2011-07-18 18:48:30 +04:00
return 0 ;
2011-06-14 06:36:38 +04:00
/* if (ls->initial_registrations)
_process_initial_registrations ( ds - > initial_registrations ) ; */
return 1 ;
}
2011-07-18 18:48:30 +04:00
static int fini ( daemon_state * s )
{
lvmetad_state * ls = s - > private ;
2012-02-15 15:43:06 +04:00
struct dm_hash_node * n = dm_hash_get_first ( ls - > vgid_to_metadata ) ;
2011-09-17 17:33:51 +04:00
debug ( " fini \n " ) ;
2011-07-20 22:24:49 +04:00
while ( n ) {
2012-02-15 15:43:06 +04:00
dm_config_destroy ( dm_hash_get_data ( ls - > vgid_to_metadata , n ) ) ;
n = dm_hash_get_next ( ls - > vgid_to_metadata , n ) ;
2011-07-20 22:24:49 +04:00
}
2011-07-25 19:33:04 +04:00
2012-02-24 04:11:59 +04:00
n = dm_hash_get_first ( ls - > pvid_to_pvmeta ) ;
while ( n ) {
dm_config_destroy ( dm_hash_get_data ( ls - > pvid_to_pvmeta , n ) ) ;
n = dm_hash_get_next ( ls - > pvid_to_pvmeta , n ) ;
}
2011-07-25 19:33:04 +04:00
n = dm_hash_get_first ( ls - > lock . vg ) ;
while ( n ) {
pthread_mutex_destroy ( dm_hash_get_data ( ls - > lock . vg , n ) ) ;
free ( dm_hash_get_data ( ls - > lock . vg , n ) ) ;
n = dm_hash_get_next ( ls - > lock . vg , n ) ;
}
dm_hash_destroy ( ls - > lock . vg ) ;
2012-02-15 21:30:07 +04:00
dm_hash_destroy ( ls - > pvid_to_pvmeta ) ;
2012-02-15 15:43:06 +04:00
dm_hash_destroy ( ls - > device_to_pvid ) ;
dm_hash_destroy ( ls - > vgid_to_metadata ) ;
2012-02-24 04:11:59 +04:00
dm_hash_destroy ( ls - > vgid_to_vgname ) ;
dm_hash_destroy ( ls - > vgname_to_vgid ) ;
2012-02-15 15:43:06 +04:00
dm_hash_destroy ( ls - > pvid_to_vgid ) ;
2011-07-18 18:48:30 +04:00
return 1 ;
}
2011-06-14 06:36:38 +04:00
static void usage ( char * prog , FILE * file )
{
fprintf ( file , " Usage: \n "
" %s [-V] [-h] [-d] [-d] [-d] [-f] \n \n "
" -V Show version of lvmetad \n "
" -h Show this help information \n "
" -d Log debug messages to syslog (-d, -dd, -ddd) \n "
" -R Replace a running lvmetad instance, loading its data \n "
" -f Don't fork, run in the foreground \n \n " , prog ) ;
}
int main ( int argc , char * argv [ ] )
{
signed char opt ;
2011-10-31 01:58:59 +04:00
daemon_state s = { . private = NULL } ;
2011-06-14 06:36:38 +04:00
lvmetad_state ls ;
int _restart = 0 ;
2011-07-18 18:48:30 +04:00
s . name = " lvmetad " ;
2011-06-14 06:36:38 +04:00
s . private = & ls ;
2011-07-18 18:48:30 +04:00
s . daemon_init = init ;
s . daemon_fini = fini ;
2011-06-14 06:36:38 +04:00
s . handler = handler ;
2012-02-15 15:43:06 +04:00
s . socket_path = getenv ( " LVM_LVMETAD_SOCKET " ) ;
if ( ! s . socket_path )
s . socket_path = DEFAULT_RUN_DIR " /lvmetad.socket " ;
s . pidfile = DEFAULT_RUN_DIR " /lvmetad.pid " ;
2011-09-17 17:33:51 +04:00
s . log_level = 0 ;
2012-02-24 03:52:11 +04:00
s . protocol = " lvmetad " ;
s . protocol_version = 1 ;
2011-06-14 06:36:38 +04:00
2012-02-15 15:43:06 +04:00
// use getopt_long
2012-01-16 12:25:32 +04:00
while ( ( opt = getopt ( argc , argv , " ?fhVdRs: " ) ) ! = EOF ) {
2011-06-14 06:36:38 +04:00
switch ( opt ) {
case ' h ' :
usage ( argv [ 0 ] , stdout ) ;
exit ( 0 ) ;
case ' ? ' :
usage ( argv [ 0 ] , stderr ) ;
exit ( 0 ) ;
case ' R ' :
_restart + + ;
break ;
case ' f ' :
s . foreground = 1 ;
break ;
case ' d ' :
s . log_level + + ;
break ;
2012-02-15 15:43:06 +04:00
case ' s ' : // --socket
2012-01-16 12:25:32 +04:00
s . socket_path = optarg ;
break ;
2011-06-14 06:36:38 +04:00
case ' V ' :
printf ( " lvmetad version 0 \n " ) ;
exit ( 1 ) ;
}
}
daemon_start ( s ) ;
return 0 ;
}