2002-02-25 15:02:33 +03:00
/*
2004-03-30 23:35:44 +04:00
* Copyright ( C ) 2002 - 2004 Sistina Software , Inc . All rights reserved .
2005-11-09 01:52:26 +03:00
* Copyright ( C ) 2004 - 2005 Red Hat , Inc . All rights reserved .
2002-02-25 15:02:33 +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
* of the GNU General Public License v .2 .
*
* You should have received a copy of the GNU 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
2002-02-25 15:02:33 +03:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2003-09-18 00:35:57 +04:00
# include "str_list.h"
2002-02-25 15:02:33 +03:00
# include "dev_manager.h"
2002-02-25 19:53:12 +03:00
# include "lvm-string.h"
2002-02-26 14:49:17 +03:00
# include "fs.h"
2003-04-25 02:09:13 +04:00
# include "defaults.h"
2004-09-16 22:40:56 +04:00
# include "segtype.h"
2004-05-05 01:25:57 +04:00
# include "display.h"
2003-11-13 21:47:22 +03:00
# include "toolcontext.h"
2004-05-05 01:25:57 +04:00
# include "targets.h"
# include "config.h"
2005-10-25 23:08:21 +04:00
# include "filter.h"
2002-02-25 15:02:33 +03:00
2002-02-26 17:44:13 +03:00
# include <limits.h>
2002-03-07 20:37:38 +03:00
# include <dirent.h>
2002-02-25 15:02:33 +03:00
2003-08-20 16:53:57 +04:00
# define MAX_TARGET_PARAMSIZE 50000
2005-10-25 23:08:21 +04:00
# define UUID_PREFIX "LVM-"
2003-08-20 16:53:57 +04:00
2002-03-16 01:59:12 +03:00
typedef enum {
2005-11-09 01:52:26 +03:00
PRELOAD ,
2002-03-16 01:59:12 +03:00
ACTIVATE ,
2002-03-27 21:17:43 +03:00
DEACTIVATE ,
2002-03-16 01:59:12 +03:00
SUSPEND ,
2006-08-09 01:20:00 +04:00
SUSPEND_WITH_LOCKFS ,
2005-11-09 01:52:26 +03:00
CLEAN
2002-03-27 21:17:43 +03:00
} action_t ;
2002-03-16 01:59:12 +03:00
2002-02-25 15:02:33 +03:00
struct dev_manager {
2005-10-17 03:03:59 +04:00
struct dm_pool * mem ;
2002-02-25 15:02:33 +03:00
2004-05-05 01:25:57 +04:00
struct cmd_context * cmd ;
2003-04-25 02:09:13 +04:00
const char * stripe_filler ;
2004-05-05 01:25:57 +04:00
void * target_state ;
2003-05-06 16:00:29 +04:00
uint32_t pvmove_mirror_count ;
2003-04-25 02:09:13 +04:00
2002-02-25 15:02:33 +03:00
char * vg_name ;
} ;
2005-11-09 01:52:26 +03:00
struct lv_layer {
struct logical_volume * lv ;
const char * old_name ;
} ;
2002-03-07 19:48:46 +03:00
2005-11-09 01:52:26 +03:00
static const char * stripe_filler = NULL ;
2002-03-07 19:48:46 +03:00
2005-10-17 03:03:59 +04:00
static char * _build_dlid ( struct dm_pool * mem , const char * lvid , const char * layer )
2002-03-19 02:25:50 +03:00
{
char * dlid ;
2002-12-20 02:25:55 +03:00
size_t len ;
2002-03-19 02:25:50 +03:00
if ( ! layer )
layer = " " ;
2005-10-25 23:08:21 +04:00
len = sizeof ( UUID_PREFIX ) + sizeof ( union lvid ) + strlen ( layer ) ;
2002-03-19 02:25:50 +03:00
2005-10-17 03:03:59 +04:00
if ( ! ( dlid = dm_pool_alloc ( mem , len ) ) ) {
2005-11-09 01:52:26 +03:00
log_error ( " _build_dlid: pool allocation failed for % " PRIsize_t
" %s %s. " , len , lvid , layer ) ;
2002-03-19 02:25:50 +03:00
return NULL ;
}
2005-10-25 23:08:21 +04:00
sprintf ( dlid , UUID_PREFIX " %s%s%s " , lvid , ( * layer ) ? " - " : " " , layer ) ;
2002-03-19 02:25:50 +03:00
return dlid ;
}
2005-10-21 01:07:57 +04:00
char * build_dlid ( struct dev_manager * dm , const char * lvid , const char * layer )
{
return _build_dlid ( dm - > mem , lvid , layer ) ;
}
2006-04-19 19:33:07 +04:00
static int _read_only_lv ( struct logical_volume * lv )
2005-11-09 01:52:26 +03:00
{
return ( ! ( lv - > vg - > status & LVM_WRITE ) | | ! ( lv - > status & LVM_WRITE ) ) ;
}
2002-02-25 17:46:57 +03:00
/*
* Low level device - layer operations .
*/
2003-05-06 16:00:29 +04:00
static struct dm_task * _setup_task ( const char * name , const char * uuid ,
2003-04-30 19:26:25 +04:00
uint32_t * event_nr , int task )
2002-02-25 17:46:57 +03:00
{
struct dm_task * dmt ;
if ( ! ( dmt = dm_task_create ( task ) ) ) {
stack ;
return NULL ;
}
2002-03-25 21:54:59 +03:00
if ( name )
dm_task_set_name ( dmt , name ) ;
if ( uuid & & * uuid )
dm_task_set_uuid ( dmt , uuid ) ;
2003-04-30 19:26:25 +04:00
if ( event_nr )
dm_task_set_event_nr ( dmt , * event_nr ) ;
2002-02-25 17:46:57 +03:00
return dmt ;
}
2005-10-19 17:59:18 +04:00
static int _info_run ( const char * name , const char * dlid , struct dm_info * info ,
2005-10-17 03:03:59 +04:00
int mknodes , int with_open_count , struct dm_pool * mem ,
2005-01-13 01:58:21 +03:00
char * * uuid_out )
2002-03-15 00:17:30 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
2002-03-19 02:25:50 +03:00
const char * u ;
2003-11-13 17:11:41 +03:00
int dmtask ;
2002-03-15 00:17:30 +03:00
2003-11-13 17:11:41 +03:00
dmtask = mknodes ? DM_DEVICE_MKNODES : DM_DEVICE_INFO ;
2005-10-19 17:59:18 +04:00
if ( ! ( dmt = _setup_task ( name , dlid , 0 , dmtask ) ) ) {
2002-03-15 00:17:30 +03:00
stack ;
return 0 ;
}
2005-01-13 01:58:21 +03:00
if ( ! with_open_count )
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2005-11-09 01:52:26 +03:00
if ( ! dm_task_run ( dmt ) )
goto_out ;
2002-03-15 00:17:30 +03:00
2005-11-09 01:52:26 +03:00
if ( ! dm_task_get_info ( dmt , info ) )
goto_out ;
2002-03-19 02:25:50 +03:00
if ( info - > exists & & uuid_out ) {
2005-11-09 01:52:26 +03:00
if ( ! ( u = dm_task_get_uuid ( dmt ) ) )
goto_out ;
2005-10-17 03:03:59 +04:00
* uuid_out = dm_pool_strdup ( mem , u ) ;
2002-03-19 02:25:50 +03:00
}
2002-03-15 00:17:30 +03:00
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2002-02-25 17:46:57 +03:00
2005-10-19 17:59:18 +04:00
static int _info ( const char * name , const char * dlid , int mknodes ,
2005-01-13 01:58:21 +03:00
int with_open_count , struct dm_info * info ,
2005-10-17 03:03:59 +04:00
struct dm_pool * mem , char * * uuid_out )
2002-03-25 21:54:59 +03:00
{
2005-10-26 19:00:51 +04:00
if ( ! mknodes & & dlid & & * dlid ) {
if ( _info_run ( NULL , dlid , info , 0 , with_open_count , mem ,
uuid_out ) & &
info - > exists )
return 1 ;
2005-10-26 21:56:31 +04:00
else if ( _info_run ( NULL , dlid + sizeof ( UUID_PREFIX ) - 1 , info ,
2005-10-26 19:00:51 +04:00
0 , with_open_count , mem , uuid_out ) & &
info - > exists )
return 1 ;
}
2002-03-25 21:54:59 +03:00
if ( name )
2005-01-13 01:58:21 +03:00
return _info_run ( name , NULL , info , mknodes , with_open_count ,
mem , uuid_out ) ;
2002-03-25 21:54:59 +03:00
return 0 ;
}
2005-10-19 17:59:18 +04:00
int dev_manager_info ( struct dm_pool * mem , const char * name ,
const struct logical_volume * lv , int with_mknodes ,
int with_open_count , struct dm_info * info )
2005-10-17 22:00:02 +04:00
{
2005-10-19 17:59:18 +04:00
const char * dlid ;
if ( ! ( dlid = _build_dlid ( mem , lv - > lvid . s , NULL ) ) ) {
log_error ( " dlid build failed for %s " , lv - > name ) ;
return 0 ;
}
return _info ( name , dlid , with_mknodes , with_open_count , info ,
NULL , NULL ) ;
2005-10-17 22:00:02 +04:00
}
2002-05-22 18:03:45 +04:00
/* FIXME Interface must cope with multiple targets */
2002-05-10 20:06:06 +04:00
static int _status_run ( const char * name , const char * uuid ,
unsigned long long * s , unsigned long long * l ,
char * * t , uint32_t t_size , char * * p , uint32_t p_size )
2002-05-10 01:17:57 +04:00
{
int r = 0 ;
struct dm_task * dmt ;
2005-10-26 21:56:31 +04:00
struct dm_info info ;
2002-05-10 01:17:57 +04:00
void * next = NULL ;
2002-06-07 12:37:07 +04:00
uint64_t start , length ;
2002-05-10 01:17:57 +04:00
char * type = NULL ;
2002-05-10 20:06:06 +04:00
char * params = NULL ;
2002-05-10 01:17:57 +04:00
2003-04-30 19:26:25 +04:00
if ( ! ( dmt = _setup_task ( name , uuid , 0 , DM_DEVICE_STATUS ) ) ) {
2002-05-10 01:17:57 +04:00
stack ;
return 0 ;
}
2005-01-13 01:58:21 +03:00
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2005-11-09 01:52:26 +03:00
if ( ! dm_task_run ( dmt ) )
goto_out ;
2002-05-10 01:17:57 +04:00
2005-11-09 01:52:26 +03:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
goto_out ;
2005-10-26 21:56:31 +04:00
2002-05-10 01:17:57 +04:00
do {
next = dm_get_next_target ( dmt , next , & start , & length ,
& type , & params ) ;
2002-05-22 18:03:45 +04:00
if ( type ) {
2002-05-10 20:06:06 +04:00
* s = start ;
* l = length ;
/* Make sure things are null terminated */
strncpy ( * t , type , t_size ) ;
2002-05-22 18:03:45 +04:00
( * t ) [ t_size - 1 ] = ' \0 ' ;
2002-05-10 20:06:06 +04:00
strncpy ( * p , params , p_size ) ;
2002-05-22 18:03:45 +04:00
( * p ) [ p_size - 1 ] = ' \0 ' ;
2002-05-10 20:06:06 +04:00
r = 1 ;
2002-05-22 18:03:45 +04:00
/* FIXME Cope with multiple targets! */
2002-05-10 20:06:06 +04:00
break ;
2002-05-10 01:17:57 +04:00
}
2002-05-22 18:03:45 +04:00
} while ( next ) ;
2002-05-10 01:17:57 +04:00
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2003-04-25 02:09:13 +04:00
static int _status ( const char * name , const char * uuid ,
unsigned long long * start , unsigned long long * length ,
char * * type , uint32_t type_size , char * * params ,
uint32_t param_size ) __attribute__ ( ( unused ) ) ;
2002-05-10 20:06:06 +04:00
static int _status ( const char * name , const char * uuid ,
unsigned long long * start , unsigned long long * length ,
char * * type , uint32_t type_size , char * * params ,
uint32_t param_size )
2002-05-10 01:17:57 +04:00
{
2005-10-26 19:00:51 +04:00
if ( uuid & & * uuid ) {
if ( _status_run ( NULL , uuid , start , length , type ,
type_size , params , param_size ) & &
* params )
return 1 ;
2005-10-26 21:56:31 +04:00
else if ( _status_run ( NULL , uuid + sizeof ( UUID_PREFIX ) - 1 , start ,
2005-10-26 19:00:51 +04:00
length , type , type_size , params ,
param_size ) & &
* params )
return 1 ;
}
2002-05-10 01:17:57 +04:00
2002-05-10 20:06:06 +04:00
if ( name & & _status_run ( name , NULL , start , length , type , type_size ,
2002-05-22 18:03:45 +04:00
params , param_size ) )
2002-05-10 01:17:57 +04:00
return 1 ;
2002-05-22 18:03:45 +04:00
2002-05-10 01:17:57 +04:00
return 0 ;
}
2003-05-06 16:00:29 +04:00
static int _percent_run ( struct dev_manager * dm , const char * name ,
2005-10-19 17:59:18 +04:00
const char * dlid ,
2003-05-06 16:00:29 +04:00
const char * target_type , int wait ,
struct logical_volume * lv , float * percent ,
2003-04-30 19:26:25 +04:00
uint32_t * event_nr )
2003-04-25 02:09:13 +04:00
{
int r = 0 ;
struct dm_task * dmt ;
2003-04-30 19:26:25 +04:00
struct dm_info info ;
2003-04-25 02:09:13 +04:00
void * next = NULL ;
uint64_t start , length ;
char * type = NULL ;
char * params = NULL ;
2003-05-06 16:00:29 +04:00
struct list * segh = & lv - > segments ;
struct lv_segment * seg = NULL ;
2004-05-05 01:25:57 +04:00
struct segment_type * segtype ;
2003-04-25 02:09:13 +04:00
uint64_t total_numerator = 0 , total_denominator = 0 ;
* percent = - 1 ;
2005-10-19 17:59:18 +04:00
if ( ! ( dmt = _setup_task ( name , dlid , event_nr ,
2004-05-05 01:25:57 +04:00
wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS ) ) ) {
2003-04-25 02:09:13 +04:00
stack ;
return 0 ;
}
2005-01-13 01:58:21 +03:00
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2005-11-09 01:52:26 +03:00
if ( ! dm_task_run ( dmt ) )
goto_out ;
2003-04-25 02:09:13 +04:00
2005-11-09 01:52:26 +03:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
goto_out ;
2003-04-30 19:26:25 +04:00
if ( event_nr )
* event_nr = info . event_nr ;
2003-04-25 02:09:13 +04:00
do {
next = dm_get_next_target ( dmt , next , & start , & length , & type ,
& params ) ;
2003-05-06 16:00:29 +04:00
if ( lv ) {
if ( ! ( segh = list_next ( & lv - > segments , segh ) ) ) {
log_error ( " Number of segments in active LV %s "
" does not match metadata " , lv - > name ) ;
goto out ;
}
seg = list_item ( segh , struct lv_segment ) ;
}
2003-04-25 02:09:13 +04:00
if ( ! type | | ! params | | strcmp ( type , target_type ) )
continue ;
2004-05-05 01:25:57 +04:00
if ( ! ( segtype = get_segtype_from_string ( dm - > cmd , type ) ) )
2003-04-30 19:26:25 +04:00
continue ;
2004-05-05 01:25:57 +04:00
if ( segtype - > ops - > target_percent & &
! segtype - > ops - > target_percent ( & dm - > target_state , dm - > mem ,
2006-05-17 00:53:13 +04:00
dm - > cmd , seg , params ,
2004-05-05 01:25:57 +04:00
& total_numerator ,
& total_denominator ,
2005-11-09 01:52:26 +03:00
percent ) )
goto_out ;
2004-05-05 01:25:57 +04:00
2003-04-25 02:09:13 +04:00
} while ( next ) ;
2003-05-06 16:00:29 +04:00
if ( lv & & ( segh = list_next ( & lv - > segments , segh ) ) ) {
log_error ( " Number of segments in active LV %s does not "
" match metadata " , lv - > name ) ;
goto out ;
}
2003-04-25 02:09:13 +04:00
if ( total_denominator )
2003-05-06 16:00:29 +04:00
* percent = ( float ) total_numerator * 100 / total_denominator ;
2004-05-05 01:25:57 +04:00
else if ( * percent < 0 )
2003-04-30 19:26:25 +04:00
* percent = 100 ;
2003-04-25 02:09:13 +04:00
2003-08-20 19:48:27 +04:00
log_debug ( " LV percent: %f " , * percent ) ;
2003-04-25 02:09:13 +04:00
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2005-10-19 17:59:18 +04:00
static int _percent ( struct dev_manager * dm , const char * name , const char * dlid ,
2003-05-06 16:00:29 +04:00
const char * target_type , int wait ,
struct logical_volume * lv , float * percent ,
uint32_t * event_nr )
2003-04-25 02:09:13 +04:00
{
2005-10-26 19:00:51 +04:00
if ( dlid & & * dlid ) {
if ( _percent_run ( dm , NULL , dlid , target_type , wait , lv , percent ,
event_nr ) )
return 1 ;
2005-10-26 21:56:31 +04:00
else if ( _percent_run ( dm , NULL , dlid + sizeof ( UUID_PREFIX ) - 1 ,
2005-10-26 19:00:51 +04:00
target_type , wait , lv , percent ,
event_nr ) )
return 1 ;
}
2003-04-25 02:09:13 +04:00
2003-05-06 16:00:29 +04:00
if ( name & & _percent_run ( dm , name , NULL , target_type , wait , lv , percent ,
2003-04-30 19:26:25 +04:00
event_nr ) )
2003-04-25 02:09:13 +04:00
return 1 ;
return 0 ;
}
2005-11-09 01:52:26 +03:00
/*
* dev_manager implementation .
*/
struct dev_manager * dev_manager_create ( struct cmd_context * cmd ,
const char * vg_name )
2002-03-19 02:25:50 +03:00
{
2005-11-09 01:52:26 +03:00
struct dm_pool * mem ;
struct dev_manager * dm ;
2002-03-19 02:25:50 +03:00
2005-11-09 01:52:26 +03:00
if ( ! ( mem = dm_pool_create ( " dev_manager " , 16 * 1024 ) ) ) {
2002-03-19 02:25:50 +03:00
stack ;
2005-11-09 01:52:26 +03:00
return NULL ;
2002-03-19 02:25:50 +03:00
}
2005-11-09 01:52:26 +03:00
if ( ! ( dm = dm_pool_alloc ( mem , sizeof ( * dm ) ) ) ) {
2002-03-19 02:25:50 +03:00
stack ;
2005-11-09 01:52:26 +03:00
goto bad ;
2002-03-19 02:25:50 +03:00
}
2005-11-09 01:52:26 +03:00
dm - > cmd = cmd ;
dm - > mem = mem ;
2005-01-13 01:58:21 +03:00
2005-11-09 01:52:26 +03:00
if ( ! stripe_filler ) {
2006-05-16 20:48:31 +04:00
stripe_filler = find_config_tree_str ( cmd ,
2005-11-09 01:52:26 +03:00
" activation/missing_stripe_filler " ,
DEFAULT_STRIPE_FILLER ) ;
2004-09-15 19:02:36 +04:00
}
2005-11-09 01:52:26 +03:00
dm - > stripe_filler = stripe_filler ;
2002-03-19 02:25:50 +03:00
2005-11-09 01:52:26 +03:00
if ( ! ( dm - > vg_name = dm_pool_strdup ( dm - > mem , vg_name ) ) ) {
2004-05-13 00:40:34 +04:00
stack ;
2005-11-09 01:52:26 +03:00
goto bad ;
2004-05-13 00:40:34 +04:00
}
2005-11-09 01:52:26 +03:00
dm - > target_state = NULL ;
2005-01-13 01:58:21 +03:00
2005-11-09 01:52:26 +03:00
return dm ;
2004-05-13 00:40:34 +04:00
2005-11-09 01:52:26 +03:00
bad :
dm_pool_destroy ( mem ) ;
return NULL ;
2004-05-13 00:40:34 +04:00
}
2005-11-09 01:52:26 +03:00
void dev_manager_destroy ( struct dev_manager * dm )
2004-05-13 00:40:34 +04:00
{
2005-11-09 01:52:26 +03:00
dm_pool_destroy ( dm - > mem ) ;
}
2004-05-13 00:40:34 +04:00
2006-05-16 20:48:31 +04:00
void dev_manager_release ( void )
{
dm_lib_release ( ) ;
}
2005-11-09 01:52:26 +03:00
void dev_manager_exit ( void )
{
dm_lib_exit ( ) ;
2004-05-13 00:40:34 +04:00
}
2005-11-09 01:52:26 +03:00
int dev_manager_snapshot_percent ( struct dev_manager * dm ,
2006-04-06 18:06:27 +04:00
const struct logical_volume * lv ,
float * percent )
2004-05-13 00:40:34 +04:00
{
2005-11-09 01:52:26 +03:00
char * name ;
const char * dlid ;
/*
* Build a name for the top layer .
*/
if ( ! ( name = build_dm_name ( dm - > mem , lv - > vg - > name , lv - > name , NULL ) ) )
return_0 ;
if ( ! ( dlid = build_dlid ( dm , lv - > lvid . s , NULL ) ) )
return_0 ;
2004-05-13 00:40:34 +04:00
2005-11-09 01:52:26 +03:00
/*
* Try and get some info on this device .
*/
log_debug ( " Getting device status percentage for %s " , name ) ;
if ( ! ( _percent ( dm , name , dlid , " snapshot " , 0 , NULL , percent ,
NULL ) ) ) {
2004-05-13 00:40:34 +04:00
stack ;
return 0 ;
}
2005-11-09 01:52:26 +03:00
/* FIXME dm_pool_free ? */
/* If the snapshot isn't available, percent will be -1 */
2004-05-13 00:40:34 +04:00
return 1 ;
}
2005-11-09 01:52:26 +03:00
/* FIXME Merge with snapshot_percent, auto-detecting target type */
/* FIXME Cope with more than one target */
int dev_manager_mirror_percent ( struct dev_manager * dm ,
struct logical_volume * lv , int wait ,
float * percent , uint32_t * event_nr )
2002-02-25 17:46:57 +03:00
{
2005-11-09 01:52:26 +03:00
char * name ;
const char * dlid ;
2002-02-25 17:46:57 +03:00
2002-03-26 16:41:37 +03:00
/*
2005-11-09 01:52:26 +03:00
* Build a name for the top layer .
2002-03-26 16:41:37 +03:00
*/
2005-11-09 01:52:26 +03:00
if ( ! ( name = build_dm_name ( dm - > mem , lv - > vg - > name , lv - > name , NULL ) ) )
return_0 ;
2002-03-08 13:41:48 +03:00
2005-11-09 01:52:26 +03:00
/* FIXME dm_pool_free ? */
2005-01-13 01:58:21 +03:00
2005-11-09 01:52:26 +03:00
if ( ! ( dlid = build_dlid ( dm , lv - > lvid . s , NULL ) ) ) {
log_error ( " dlid build failed for %s " , lv - > name ) ;
return 0 ;
2003-07-05 02:34:56 +04:00
}
2002-03-15 00:17:30 +03:00
2005-11-09 01:52:26 +03:00
log_debug ( " Getting device mirror status percentage for %s " , name ) ;
if ( ! ( _percent ( dm , name , dlid , " mirror " , wait , lv , percent ,
event_nr ) ) ) {
2002-03-15 00:17:30 +03:00
stack ;
2005-11-09 01:52:26 +03:00
return 0 ;
2002-03-15 00:17:30 +03:00
}
2005-11-09 01:52:26 +03:00
return 1 ;
}
2003-07-05 02:34:56 +04:00
2005-11-09 01:52:26 +03:00
#if 0
log_very_verbose ( " %s %s " , sus ? " Suspending " : " Resuming " , name ) ;
2004-05-13 00:40:34 +04:00
2005-11-09 01:52:26 +03:00
log_verbose ( " Loading %s " , dl - > name ) ;
log_very_verbose ( " Activating %s read-only " , dl - > name ) ;
2003-07-05 02:34:56 +04:00
log_very_verbose ( " Activated %s %s %03u:%03u " , dl - > name ,
dl - > dlid , dl - > info . major , dl - > info . minor ) ;
2002-03-16 01:59:12 +03:00
if ( _get_flag ( dl , VISIBLE ) )
2002-03-18 16:09:27 +03:00
log_verbose ( " Removing %s " , dl - > name ) ;
2002-03-16 01:59:12 +03:00
else
2002-03-18 16:09:27 +03:00
log_very_verbose ( " Removing %s " , dl - > name ) ;
2002-03-16 01:59:12 +03:00
2005-11-09 01:52:26 +03:00
log_debug ( " Adding target: % " PRIu64 " % " PRIu64 " %s %s " ,
extent_size * seg - > le , extent_size * seg - > len , target , params ) ;
2002-02-25 17:46:57 +03:00
2005-11-09 01:52:26 +03:00
log_debug ( " Adding target: 0 % " PRIu64 " snapshot-origin %s " ,
dl - > lv - > size , params ) ;
log_debug ( " Adding target: 0 % " PRIu64 " snapshot %s " , size , params ) ;
log_debug ( " Getting device info for %s " , dl - > name ) ;
2005-01-13 01:58:21 +03:00
2005-11-09 01:52:26 +03:00
/* Rename? */
if ( ( suffix = rindex ( dl - > dlid + sizeof ( UUID_PREFIX ) - 1 , ' - ' ) ) )
suffix + + ;
newname = build_dm_name ( dm - > mem , dm - > vg_name , dl - > lv - > name ,
suffix ) ;
2002-03-16 01:59:12 +03:00
2005-11-09 01:52:26 +03:00
static int _belong_to_vg ( const char * vgname , const char * name )
{
const char * v = vgname , * n = name ;
2002-02-25 17:46:57 +03:00
2005-11-09 01:52:26 +03:00
while ( * v ) {
if ( ( * v ! = * n ) | | ( * v = = ' - ' & & * ( + + n ) ! = ' - ' ) )
return 0 ;
v + + , n + + ;
2002-04-16 18:42:20 +04:00
}
2002-03-18 16:09:27 +03:00
2005-11-09 01:52:26 +03:00
if ( * n = = ' - ' & & * ( n + 1 ) ! = ' - ' )
return 1 ;
else
return 0 ;
}
2002-04-16 18:42:20 +04:00
2005-04-07 16:39:44 +04:00
if ( ! ( snap_seg = find_cow ( lv ) ) )
2002-04-16 18:42:20 +04:00
return 1 ;
2005-04-07 16:39:44 +04:00
old_origin = snap_seg - > origin ;
2002-04-16 18:42:20 +04:00
/* Was this the last active snapshot with this origin? */
2005-06-01 20:51:55 +04:00
list_iterate_items ( lvl , active_head ) {
active = lvl - > lv ;
2005-04-07 16:39:44 +04:00
if ( ( snap_seg = find_cow ( active ) ) & &
snap_seg - > origin = = old_origin ) {
2002-04-16 18:42:20 +04:00
return 1 ;
2002-04-24 22:20:51 +04:00
}
2002-03-18 16:09:27 +03:00
}
2005-11-09 01:52:26 +03:00
# endif
/*************************/
/* NEW CODE STARTS HERE */
/*************************/
int dev_manager_lv_mknodes ( const struct logical_volume * lv )
{
char * name ;
if ( ! ( name = build_dm_name ( lv - > vg - > cmd - > mem , lv - > vg - > name ,
lv - > name , NULL ) ) )
return_0 ;
return fs_add_lv ( lv , name ) ;
2002-03-18 16:09:27 +03:00
}
2005-11-09 01:52:26 +03:00
int dev_manager_lv_rmnodes ( const struct logical_volume * lv )
2003-04-25 02:09:13 +04:00
{
2005-11-09 01:52:26 +03:00
return fs_del_lv ( lv ) ;
}
2005-11-09 16:08:41 +03:00
static int _add_dev_to_dtree ( struct dev_manager * dm , struct dm_tree * dtree ,
2005-11-09 01:52:26 +03:00
struct logical_volume * lv , const char * layer )
{
char * dlid , * name ;
struct dm_info info ;
2003-04-25 02:09:13 +04:00
2005-11-09 01:52:26 +03:00
if ( ! ( name = build_dm_name ( dm - > mem , lv - > vg - > name , lv - > name , layer ) ) )
return_0 ;
2003-04-25 02:09:13 +04:00
2005-11-09 01:52:26 +03:00
if ( ! ( dlid = build_dlid ( dm , lv - > lvid . s , layer ) ) )
return_0 ;
log_debug ( " Getting device info for %s [%s] " , name , dlid ) ;
if ( ! _info ( name , dlid , 0 , 1 , & info , dm - > mem , NULL ) ) {
log_error ( " Failed to get info for %s [%s]. " , name , dlid ) ;
return 0 ;
}
2005-11-09 16:05:17 +03:00
if ( info . exists & & ! dm_tree_add_dev ( dtree , info . major , info . minor ) ) {
2005-11-09 16:08:41 +03:00
log_error ( " Failed to add device (% " PRIu32 " :% " PRIu32 " ) to dtree " ,
2005-11-09 01:52:26 +03:00
info . major , info . minor ) ;
return 0 ;
2003-04-25 02:09:13 +04:00
}
2005-11-09 01:52:26 +03:00
return 1 ;
}
/*
* Add LV and any known dependencies
*/
2005-11-09 16:08:41 +03:00
static int _add_lv_to_dtree ( struct dev_manager * dm , struct dm_tree * dtree , struct logical_volume * lv )
2005-11-09 01:52:26 +03:00
{
2005-11-09 16:08:41 +03:00
if ( ! _add_dev_to_dtree ( dm , dtree , lv , NULL ) )
2005-11-09 01:52:26 +03:00
return_0 ;
/* FIXME Can we avoid doing this every time? */
2005-11-09 16:08:41 +03:00
if ( ! _add_dev_to_dtree ( dm , dtree , lv , " real " ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2005-11-09 16:08:41 +03:00
if ( ! _add_dev_to_dtree ( dm , dtree , lv , " cow " ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2003-04-25 02:09:13 +04:00
2006-04-28 21:01:07 +04:00
if ( ! _add_dev_to_dtree ( dm , dtree , lv , " _mlog " ) )
return_0 ;
2003-04-25 02:09:13 +04:00
return 1 ;
}
2005-11-09 16:08:41 +03:00
static struct dm_tree * _create_partial_dtree ( struct dev_manager * dm , struct logical_volume * lv )
2004-05-05 22:11:43 +04:00
{
2005-11-09 16:05:17 +03:00
struct dm_tree * dtree ;
2005-11-09 01:52:26 +03:00
struct list * snh , * snht ;
2005-11-10 02:56:36 +03:00
struct lv_segment * seg ;
uint32_t s ;
2004-05-05 22:11:43 +04:00
2005-11-09 16:05:17 +03:00
if ( ! ( dtree = dm_tree_create ( ) ) ) {
2005-11-09 16:08:41 +03:00
log_error ( " Partial dtree creation failed for %s. " , lv - > name ) ;
2005-11-09 01:52:26 +03:00
return NULL ;
}
2004-05-05 22:11:43 +04:00
2005-11-09 16:08:41 +03:00
if ( ! _add_lv_to_dtree ( dm , dtree , lv ) ) {
2005-11-09 01:52:26 +03:00
stack ;
goto fail ;
2004-05-05 22:11:43 +04:00
}
2005-11-09 01:52:26 +03:00
/* Add any snapshots of this LV */
list_iterate_safe ( snh , snht , & lv - > snapshot_segs )
2005-11-09 16:08:41 +03:00
if ( ! _add_lv_to_dtree ( dm , dtree , list_struct_base ( snh , struct lv_segment , origin_list ) - > cow ) ) {
2005-11-09 01:52:26 +03:00
stack ;
goto fail ;
2004-05-05 22:11:43 +04:00
}
2005-11-10 02:56:36 +03:00
/* Add any LVs used by segments in this LV */
list_iterate_items ( seg , & lv - > segments )
for ( s = 0 ; s < seg - > area_count ; s + + )
if ( seg_type ( seg , s ) = = AREA_LV & & seg_lv ( seg , s ) ) {
if ( ! _add_lv_to_dtree ( dm , dtree , seg_lv ( seg , s ) ) ) {
stack ;
goto fail ;
}
}
2005-11-09 01:52:26 +03:00
return dtree ;
2004-05-05 22:11:43 +04:00
2005-11-09 01:52:26 +03:00
fail :
2005-11-09 16:05:17 +03:00
dm_tree_free ( dtree ) ;
2005-11-09 01:52:26 +03:00
return NULL ;
2004-05-05 22:11:43 +04:00
}
2005-11-09 01:52:26 +03:00
int add_areas_line ( struct dev_manager * dm , struct lv_segment * seg ,
2006-05-10 01:23:51 +04:00
struct dm_tree_node * node , uint32_t start_area ,
uint32_t areas )
2002-03-11 14:27:48 +03:00
{
2005-11-09 01:52:26 +03:00
uint64_t extent_size = seg - > lv - > vg - > extent_size ;
uint32_t s ;
2002-03-19 02:25:50 +03:00
char * dlid ;
2002-03-11 14:27:48 +03:00
2005-11-09 01:52:26 +03:00
for ( s = start_area ; s < areas ; s + + ) {
if ( ( seg_type ( seg , s ) = = AREA_PV & &
( ! seg_pvseg ( seg , s ) | |
! seg_pv ( seg , s ) | |
! seg_dev ( seg , s ) ) ) | |
( seg_type ( seg , s ) = = AREA_LV & & ! seg_lv ( seg , s ) ) )
2005-11-09 16:05:17 +03:00
dm_tree_node_add_target_area ( node ,
2005-11-09 01:52:26 +03:00
dm - > stripe_filler ,
2006-05-11 21:58:58 +04:00
NULL , UINT64_C ( 0 ) ) ;
2005-11-09 01:52:26 +03:00
else if ( seg_type ( seg , s ) = = AREA_PV )
2005-11-09 16:05:17 +03:00
dm_tree_node_add_target_area ( node ,
2005-11-09 01:52:26 +03:00
dev_name ( seg_dev ( seg , s ) ) ,
NULL ,
( seg_pv ( seg , s ) - > pe_start +
( extent_size * seg_pe ( seg , s ) ) ) ) ;
else if ( seg_type ( seg , s ) = = AREA_LV ) {
if ( ! ( dlid = build_dlid ( dm ,
seg_lv ( seg , s ) - > lvid . s ,
NULL ) ) )
return_0 ;
2005-11-09 16:05:17 +03:00
dm_tree_node_add_target_area ( node , NULL , dlid ,
2005-11-09 01:52:26 +03:00
extent_size * seg_le ( seg , s ) ) ;
} else {
log_error ( " Internal error: Unassigned area found in LV %s. " ,
seg - > lv - > name ) ;
2002-03-11 14:27:48 +03:00
return 0 ;
}
2005-11-09 01:52:26 +03:00
}
2002-03-11 14:27:48 +03:00
2005-11-09 01:52:26 +03:00
return 1 ;
}
2002-03-11 14:27:48 +03:00
2005-11-09 16:08:41 +03:00
static int _add_origin_target_to_dtree ( struct dev_manager * dm ,
2005-11-09 16:05:17 +03:00
struct dm_tree_node * dnode ,
2005-11-09 01:52:26 +03:00
struct logical_volume * lv )
{
const char * real_dlid ;
2002-03-11 23:36:04 +03:00
2005-11-09 01:52:26 +03:00
if ( ! ( real_dlid = build_dlid ( dm , lv - > lvid . s , " real " ) ) )
return_0 ;
2003-04-25 02:09:13 +04:00
2005-11-09 16:05:17 +03:00
if ( ! dm_tree_node_add_snapshot_origin_target ( dnode , lv - > size , real_dlid ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2002-03-11 14:27:48 +03:00
return 1 ;
}
2005-11-09 16:08:41 +03:00
static int _add_snapshot_target_to_dtree ( struct dev_manager * dm ,
2005-11-09 16:05:17 +03:00
struct dm_tree_node * dnode ,
2005-11-09 01:52:26 +03:00
struct logical_volume * lv )
2002-03-11 14:27:48 +03:00
{
2005-11-09 01:52:26 +03:00
const char * origin_dlid ;
const char * cow_dlid ;
struct lv_segment * snap_seg ;
uint64_t size ;
2002-03-11 14:27:48 +03:00
2005-11-09 01:52:26 +03:00
if ( ! ( snap_seg = find_cow ( lv ) ) ) {
log_error ( " Couldn't find snapshot for '%s'. " , lv - > name ) ;
2005-10-26 23:50:00 +04:00
return 0 ;
2002-03-11 14:27:48 +03:00
}
2005-11-09 01:52:26 +03:00
if ( ! ( origin_dlid = build_dlid ( dm , snap_seg - > origin - > lvid . s , " real " ) ) )
return_0 ;
2003-04-25 02:09:13 +04:00
2005-11-09 01:52:26 +03:00
if ( ! ( cow_dlid = build_dlid ( dm , snap_seg - > cow - > lvid . s , " cow " ) ) )
return_0 ;
2002-03-27 21:17:43 +03:00
2005-11-09 01:52:26 +03:00
size = ( uint64_t ) snap_seg - > len * snap_seg - > origin - > vg - > extent_size ;
2004-05-05 22:11:43 +04:00
2005-11-09 16:05:17 +03:00
if ( ! dm_tree_node_add_snapshot_target ( dnode , size , origin_dlid , cow_dlid , 1 , snap_seg - > chunk_size ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2002-03-11 14:27:48 +03:00
return 1 ;
}
2005-11-09 16:08:41 +03:00
static int _add_target_to_dtree ( struct dev_manager * dm ,
2005-11-09 16:05:17 +03:00
struct dm_tree_node * dnode ,
2005-11-09 01:52:26 +03:00
struct lv_segment * seg )
2002-03-11 14:27:48 +03:00
{
2005-11-09 01:52:26 +03:00
uint64_t extent_size = seg - > lv - > vg - > extent_size ;
if ( ! seg - > segtype - > ops - > add_target_line ) {
log_error ( " _emit_target: Internal error: Can't handle "
" segment type %s " , seg - > segtype - > name ) ;
return 0 ;
}
2006-05-16 20:48:31 +04:00
return seg - > segtype - > ops - > add_target_line ( dm , dm - > mem , dm - > cmd ,
2005-11-09 01:52:26 +03:00
& dm - > target_state , seg ,
dnode ,
extent_size * seg - > len ,
& dm - > pvmove_mirror_count ) ;
2002-03-16 01:59:12 +03:00
}
2002-03-11 14:27:48 +03:00
2005-11-09 16:08:41 +03:00
static int _add_new_lv_to_dtree ( struct dev_manager * dm , struct dm_tree * dtree ,
2005-11-09 01:52:26 +03:00
struct logical_volume * lv , const char * layer ) ;
2005-11-09 16:08:41 +03:00
static int _add_segment_to_dtree ( struct dev_manager * dm ,
2005-11-09 16:05:17 +03:00
struct dm_tree * dtree ,
struct dm_tree_node * dnode ,
2005-11-09 01:52:26 +03:00
struct lv_segment * seg ,
const char * layer )
2003-11-12 22:16:48 +03:00
{
2005-11-09 01:52:26 +03:00
uint32_t s ;
struct list * snh ;
2003-11-12 22:16:48 +03:00
2005-11-09 01:52:26 +03:00
/* Ensure required device-mapper targets are loaded */
if ( seg - > segtype - > ops - > target_present & &
! seg - > segtype - > ops - > target_present ( ) ) {
log_error ( " Can't expand LV %s: %s target support missing "
" from kernel? " , seg - > lv - > name , seg - > segtype - > name ) ;
2003-11-12 22:16:48 +03:00
return 0 ;
}
2005-11-09 01:52:26 +03:00
/* Add mirror log */
if ( seg - > log_lv & &
2005-11-09 16:08:41 +03:00
! _add_new_lv_to_dtree ( dm , dtree , seg - > log_lv , NULL ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2003-11-12 22:16:48 +03:00
2005-11-09 01:52:26 +03:00
/* If this is a snapshot origin, add real LV */
if ( lv_is_origin ( seg - > lv ) & & ! layer ) {
if ( seg - > lv - > vg - > status & CLUSTERED ) {
log_error ( " Clustered snapshots are not yet supported " ) ;
return 0 ;
}
2005-11-09 16:08:41 +03:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , seg - > lv , " real " ) )
2005-11-09 01:52:26 +03:00
return_0 ;
} else if ( lv_is_cow ( seg - > lv ) & & ! layer ) {
2005-11-09 16:08:41 +03:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , seg - > lv , " cow " ) )
2005-11-09 01:52:26 +03:00
return_0 ;
} else {
/* Add any LVs used by this segment */
for ( s = 0 ; s < seg - > area_count ; s + + )
if ( ( seg_type ( seg , s ) = = AREA_LV ) & &
2005-11-09 16:08:41 +03:00
( ! _add_new_lv_to_dtree ( dm , dtree , seg_lv ( seg , s ) , NULL ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
}
/* Now we've added its dependencies, we can add the target itself */
if ( lv_is_origin ( seg - > lv ) & & ! layer ) {
2006-05-11 21:58:58 +04:00
if ( ! _add_origin_target_to_dtree ( dm , dnode , seg - > lv ) )
2005-11-09 01:52:26 +03:00
return_0 ;
} else if ( lv_is_cow ( seg - > lv ) & & ! layer ) {
2006-05-11 21:58:58 +04:00
if ( ! _add_snapshot_target_to_dtree ( dm , dnode , seg - > lv ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2006-05-11 21:58:58 +04:00
} else if ( ! _add_target_to_dtree ( dm , dnode , seg ) )
2005-11-09 01:52:26 +03:00
return_0 ;
if ( lv_is_origin ( seg - > lv ) & & ! layer )
/* Add any snapshots of this LV */
list_iterate ( snh , & seg - > lv - > snapshot_segs )
2005-11-09 16:08:41 +03:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , list_struct_base ( snh , struct lv_segment , origin_list ) - > cow , NULL ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2003-11-12 22:16:48 +03:00
2005-11-09 01:52:26 +03:00
return 1 ;
2003-07-05 02:34:56 +04:00
}
2005-10-17 22:00:02 +04:00
2005-11-09 16:08:41 +03:00
static int _add_new_lv_to_dtree ( struct dev_manager * dm , struct dm_tree * dtree ,
2005-11-09 01:52:26 +03:00
struct logical_volume * lv , const char * layer )
2005-10-17 22:21:05 +04:00
{
2005-11-09 01:52:26 +03:00
struct lv_segment * seg ;
struct lv_layer * lvlayer ;
2005-11-09 16:05:17 +03:00
struct dm_tree_node * dnode ;
2005-11-09 01:52:26 +03:00
char * name , * dlid ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
if ( ! ( name = build_dm_name ( dm - > mem , lv - > vg - > name , lv - > name , layer ) ) )
return_0 ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
if ( ! ( dlid = build_dlid ( dm , lv - > lvid . s , layer ) ) )
return_0 ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
/* We've already processed this node if it already has a context ptr */
2005-11-09 16:05:17 +03:00
if ( ( dnode = dm_tree_find_node_by_uuid ( dtree , dlid ) ) & &
dm_tree_node_get_context ( dnode ) )
2005-11-09 01:52:26 +03:00
return 1 ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
if ( ! ( lvlayer = dm_pool_alloc ( dm - > mem , sizeof ( * lvlayer ) ) ) ) {
2005-11-09 16:08:41 +03:00
log_error ( " _add_new_lv_to_dtree: pool alloc failed for %s %s. " , lv - > name , layer ) ;
2005-10-17 22:21:05 +04:00
return 0 ;
}
2005-11-09 01:52:26 +03:00
lvlayer - > lv = lv ;
/*
2005-11-09 16:08:41 +03:00
* Add LV to dtree .
2005-11-09 01:52:26 +03:00
* If we ' re working with precommitted metadata , clear any
* existing inactive table left behind .
* Major / minor settings only apply to the visible layer .
*/
2005-11-09 16:05:17 +03:00
if ( ! ( dnode = dm_tree_add_new_dev ( dtree , name , dlid ,
2006-07-10 23:17:40 +04:00
layer ? UINT32_C ( 0 ) : ( uint32_t ) lv - > major ,
layer ? UINT32_C ( 0 ) : ( uint32_t ) lv - > minor ,
2005-11-09 01:52:26 +03:00
_read_only_lv ( lv ) ,
2006-05-11 21:58:58 +04:00
( lv - > vg - > status & PRECOMMITTED ) ? 1 : 0 ,
2005-11-09 01:52:26 +03:00
lvlayer ) ) )
return_0 ;
/* Store existing name so we can do rename later */
2005-11-09 16:05:17 +03:00
lvlayer - > old_name = dm_tree_node_get_name ( dnode ) ;
2005-11-09 01:52:26 +03:00
/* Create table */
dm - > pvmove_mirror_count = 0u ;
list_iterate_items ( seg , & lv - > segments ) {
2005-11-09 16:08:41 +03:00
if ( ! _add_segment_to_dtree ( dm , dtree , dnode , seg , layer ) )
2005-11-09 01:52:26 +03:00
return_0 ;
/* These aren't real segments in the LVM2 metadata */
if ( lv_is_origin ( lv ) & & ! layer )
break ;
if ( lv_is_cow ( lv ) & & ! layer )
break ;
}
2005-10-17 22:21:05 +04:00
2005-10-18 16:39:20 +04:00
return 1 ;
2005-10-17 22:21:05 +04:00
}
2005-11-09 01:52:26 +03:00
/*
* Create LV symlinks for children of supplied root node .
*/
2005-11-09 16:05:17 +03:00
static int _create_lv_symlinks ( struct dev_manager * dm , struct dm_tree_node * root )
2005-10-17 22:21:05 +04:00
{
2005-11-09 01:52:26 +03:00
void * handle = NULL ;
2005-11-09 16:05:17 +03:00
struct dm_tree_node * child ;
2005-11-09 01:52:26 +03:00
struct lv_layer * lvlayer ;
char * vgname , * lvname , * layer ;
const char * name ;
int r = 1 ;
2005-10-17 22:21:05 +04:00
2005-11-09 16:05:17 +03:00
while ( ( child = dm_tree_next_child ( & handle , root , 0 ) ) ) {
if ( ! ( lvlayer = ( struct lv_layer * ) dm_tree_node_get_context ( child ) ) )
2005-11-09 01:52:26 +03:00
continue ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
/* Detect rename */
2005-11-09 16:05:17 +03:00
name = dm_tree_node_get_name ( child ) ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
if ( name & & lvlayer - > old_name & & * lvlayer - > old_name & & strcmp ( name , lvlayer - > old_name ) ) {
if ( ! split_dm_name ( dm - > mem , lvlayer - > old_name , & vgname , & lvname , & layer ) ) {
log_error ( " _create_lv_symlinks: Couldn't split up old device name %s " , lvlayer - > old_name ) ;
return 0 ;
}
fs_rename_lv ( lvlayer - > lv , name , lvname ) ;
} else if ( ! dev_manager_lv_mknodes ( lvlayer - > lv ) )
r = 0 ;
2005-10-17 22:21:05 +04:00
}
2005-11-09 01:52:26 +03:00
return r ;
}
2005-10-18 16:39:20 +04:00
2006-05-11 21:58:58 +04:00
static int _clean_tree ( struct dev_manager * dm , struct dm_tree_node * root )
2005-11-09 01:52:26 +03:00
{
void * handle = NULL ;
2005-11-09 16:05:17 +03:00
struct dm_tree_node * child ;
2005-11-09 01:52:26 +03:00
char * vgname , * lvname , * layer ;
const char * name , * uuid ;
2005-11-09 16:05:17 +03:00
while ( ( child = dm_tree_next_child ( & handle , root , 0 ) ) ) {
if ( ! ( name = dm_tree_node_get_name ( child ) ) )
2005-11-09 01:52:26 +03:00
continue ;
2005-11-09 16:05:17 +03:00
if ( ! ( uuid = dm_tree_node_get_uuid ( child ) ) )
2005-11-09 01:52:26 +03:00
continue ;
if ( ! split_dm_name ( dm - > mem , name , & vgname , & lvname , & layer ) ) {
log_error ( " _clean_tree: Couldn't split up device name %s. " , name ) ;
return 0 ;
}
/* Not meant to be top level? */
if ( ! * layer )
continue ;
2005-11-09 16:05:17 +03:00
if ( ! dm_tree_deactivate_children ( root , uuid , strlen ( uuid ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
}
return 1 ;
2005-10-17 22:21:05 +04:00
}
2005-10-25 23:08:21 +04:00
static int _tree_action ( struct dev_manager * dm , struct logical_volume * lv , action_t action )
2005-10-17 22:21:05 +04:00
{
2005-11-09 16:05:17 +03:00
struct dm_tree * dtree ;
struct dm_tree_node * root ;
2005-10-18 16:39:20 +04:00
char * dlid ;
2005-10-17 22:21:05 +04:00
int r = 0 ;
2005-11-09 16:08:41 +03:00
if ( ! ( dtree = _create_partial_dtree ( dm , lv ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2005-10-17 22:21:05 +04:00
2005-11-09 16:05:17 +03:00
if ( ! ( root = dm_tree_find_node ( dtree , 0 , 0 ) ) ) {
2005-10-18 16:39:20 +04:00
log_error ( " Lost dependency tree root node " ) ;
2005-10-17 22:21:05 +04:00
goto out ;
}
2005-11-09 01:52:26 +03:00
if ( ! ( dlid = build_dlid ( dm , lv - > lvid . s , NULL ) ) )
goto_out ;
2005-10-17 22:21:05 +04:00
2005-10-19 17:59:18 +04:00
/* Only process nodes with uuid of "LVM-" plus VG id. */
2005-10-25 23:08:21 +04:00
switch ( action ) {
2005-11-09 01:52:26 +03:00
case CLEAN :
/* Deactivate any unused non-toplevel nodes */
2006-05-11 21:58:58 +04:00
if ( ! _clean_tree ( dm , root ) )
2005-11-09 01:52:26 +03:00
goto_out ;
break ;
2005-10-25 23:08:21 +04:00
case DEACTIVATE :
2005-11-09 01:52:26 +03:00
/* Deactivate LV and all devices it references that nothing else has open. */
2005-11-09 16:05:17 +03:00
if ( ! dm_tree_deactivate_children ( root , dlid , ID_LEN + sizeof ( UUID_PREFIX ) - 1 ) )
2005-11-09 01:52:26 +03:00
goto_out ;
2005-10-25 23:08:21 +04:00
break ;
case SUSPEND :
2006-08-09 01:20:00 +04:00
dm_tree_skip_lockfs ( root ) ;
case SUSPEND_WITH_LOCKFS :
2005-11-09 16:05:17 +03:00
if ( ! dm_tree_suspend_children ( root , dlid , ID_LEN + sizeof ( UUID_PREFIX ) - 1 ) )
2005-11-09 01:52:26 +03:00
goto_out ;
break ;
case PRELOAD :
case ACTIVATE :
/* Add all required new devices to tree */
2005-11-09 16:08:41 +03:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , lv , NULL ) )
2005-11-09 01:52:26 +03:00
goto_out ;
/* Preload any devices required before any suspensions */
2005-11-10 02:56:36 +03:00
if ( ! dm_tree_preload_children ( root , dlid , ID_LEN + sizeof ( UUID_PREFIX ) - 1 ) )
2005-11-09 01:52:26 +03:00
goto_out ;
if ( ( action = = ACTIVATE ) & &
2005-11-09 16:05:17 +03:00
! dm_tree_activate_children ( root , dlid , ID_LEN + sizeof ( UUID_PREFIX ) - 1 ) )
2005-11-09 01:52:26 +03:00
goto_out ;
if ( ! _create_lv_symlinks ( dm , root ) ) {
log_error ( " Failed to create symlinks for %s. " , lv - > name ) ;
2005-10-25 23:08:21 +04:00
goto out ;
}
break ;
default :
log_error ( " _tree_action: Action %u not supported. " , action ) ;
2005-10-17 22:21:05 +04:00
goto out ;
2005-10-25 23:08:21 +04:00
}
2005-10-17 22:21:05 +04:00
r = 1 ;
out :
2005-11-09 16:05:17 +03:00
dm_tree_free ( dtree ) ;
2005-10-17 22:21:05 +04:00
return r ;
}
2005-11-09 01:52:26 +03:00
int dev_manager_activate ( struct dev_manager * dm , struct logical_volume * lv )
{
if ( ! _tree_action ( dm , lv , ACTIVATE ) )
return_0 ;
return _tree_action ( dm , lv , CLEAN ) ;
}
int dev_manager_preload ( struct dev_manager * dm , struct logical_volume * lv )
{
2005-11-10 02:56:36 +03:00
/* FIXME Update the pvmove implementation! */
if ( ( lv - > status & PVMOVE ) | | ( lv - > status & LOCKED ) )
return 1 ;
2005-11-09 01:52:26 +03:00
return _tree_action ( dm , lv , PRELOAD ) ;
}
2005-10-26 18:13:52 +04:00
2005-10-25 23:08:21 +04:00
int dev_manager_deactivate ( struct dev_manager * dm , struct logical_volume * lv )
{
int r ;
r = _tree_action ( dm , lv , DEACTIVATE ) ;
fs_del_lv ( lv ) ;
return r ;
}
2006-08-09 01:20:00 +04:00
int dev_manager_suspend ( struct dev_manager * dm , struct logical_volume * lv ,
int lockfs )
2005-10-26 18:13:52 +04:00
{
2006-08-09 01:20:00 +04:00
return _tree_action ( dm , lv , lockfs ? SUSPEND_WITH_LOCKFS : SUSPEND ) ;
2005-10-26 18:13:52 +04:00
}
2005-10-25 23:08:21 +04:00
/*
* Does device use VG somewhere in its construction ?
* Returns 1 if uncertain .
*/
2006-05-11 21:58:58 +04:00
int dev_manager_device_uses_vg ( struct device * dev ,
2005-10-25 23:08:21 +04:00
struct volume_group * vg )
{
2005-11-09 16:05:17 +03:00
struct dm_tree * dtree ;
struct dm_tree_node * root ;
2005-10-25 23:08:21 +04:00
char dlid [ sizeof ( UUID_PREFIX ) + sizeof ( struct id ) - 1 ] ;
int r = 1 ;
2005-11-09 16:05:17 +03:00
if ( ! ( dtree = dm_tree_create ( ) ) ) {
2005-11-09 16:08:41 +03:00
log_error ( " partial dtree creation failed " ) ;
2005-10-25 23:08:21 +04:00
return r ;
}
2006-05-11 21:58:58 +04:00
if ( ! dm_tree_add_dev ( dtree , ( uint32_t ) MAJOR ( dev - > dev ) , ( uint32_t ) MINOR ( dev - > dev ) ) ) {
2005-11-09 16:08:41 +03:00
log_error ( " Failed to add device %s (% " PRIu32 " :% " PRIu32 " ) to dtree " ,
2005-10-25 23:08:21 +04:00
dev_name ( dev ) , ( uint32_t ) MAJOR ( dev - > dev ) , ( uint32_t ) MINOR ( dev - > dev ) ) ;
goto out ;
}
memcpy ( dlid , UUID_PREFIX , sizeof ( UUID_PREFIX ) - 1 ) ;
memcpy ( dlid + sizeof ( UUID_PREFIX ) - 1 , & vg - > id . uuid [ 0 ] , sizeof ( vg - > id ) ) ;
2005-11-09 16:05:17 +03:00
if ( ! ( root = dm_tree_find_node ( dtree , 0 , 0 ) ) ) {
2005-10-25 23:08:21 +04:00
log_error ( " Lost dependency tree root node " ) ;
goto out ;
}
2005-11-09 16:05:17 +03:00
if ( dm_tree_children_use_uuid ( root , dlid , sizeof ( UUID_PREFIX ) + sizeof ( vg - > id ) - 1 ) )
2005-11-09 01:52:26 +03:00
goto_out ;
2005-10-25 23:08:21 +04:00
r = 0 ;
out :
2005-11-09 16:05:17 +03:00
dm_tree_free ( dtree ) ;
2005-10-25 23:08:21 +04:00
return r ;
}