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 .
* Copyright ( C ) 2004 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"
# include "pool.h"
# include "hash.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-05-05 01:25:57 +04:00
# include "segtypes.h"
# 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"
2002-02-25 15:02:33 +03:00
2002-02-25 17:46:57 +03:00
# include <libdevmapper.h>
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
2002-03-07 19:48:46 +03:00
/*
2002-03-27 21:17:43 +03:00
* Algorithm
* - - - - - - - - -
2002-03-07 19:48:46 +03:00
*
2002-03-27 21:17:43 +03:00
* 1 ) Examine dm directory , and store details of active mapped devices
* in the VG . Indexed by lvid - layer . ( _scan_existing_devices )
2002-03-07 19:48:46 +03:00
*
2002-03-27 21:17:43 +03:00
* 2 ) Build lists of visible devices that need to be left in each state :
* active , reloaded , suspended .
2002-03-07 19:48:46 +03:00
*
2002-03-27 21:17:43 +03:00
* 3 ) Run through these lists and set the appropriate marks on each device
* and its dependencies .
2002-03-07 19:48:46 +03:00
*
2002-03-27 21:17:43 +03:00
* 4 ) Add layers not marked active to remove_list for removal at the end .
2002-03-07 19:48:46 +03:00
*
2002-03-27 21:17:43 +03:00
* 5 ) Remove unmarked layers from core .
2002-03-07 19:48:46 +03:00
*
2002-03-27 21:17:43 +03:00
* 6 ) Activate remaining layers , recursing to handle dependedncies and
* skipping any that already exist unless they are marked as needing
* reloading .
2002-03-07 19:48:46 +03:00
*
2002-03-27 21:17:43 +03:00
* 7 ) Remove layers in the remove_list . ( _remove_old_layers )
2002-03-07 19:48:46 +03:00
*
*/
2003-08-20 16:53:57 +04:00
# define MAX_TARGET_PARAMSIZE 50000
2002-03-07 19:48:46 +03:00
enum {
2002-03-11 23:36:04 +03:00
ACTIVE = 0 ,
2002-03-27 21:17:43 +03:00
RELOAD = 1 ,
2002-03-25 21:54:59 +03:00
VISIBLE = 2 ,
2002-03-27 21:17:43 +03:00
READWRITE = 3 ,
2003-04-25 02:09:13 +04:00
SUSPENDED = 4 ,
2003-05-06 16:00:29 +04:00
NOPROPAGATE = 5 ,
2003-07-05 02:34:56 +04:00
TOPLEVEL = 6 ,
2004-05-13 00:40:34 +04:00
REMOVE = 7 ,
RESUME_IMMEDIATE = 8
2003-05-06 16:00:29 +04:00
} ;
2002-03-16 01:59:12 +03:00
typedef enum {
ACTIVATE ,
2002-03-27 21:17:43 +03:00
DEACTIVATE ,
2002-03-16 01:59:12 +03:00
SUSPEND ,
RESUME
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_layer {
char * name ;
2002-03-07 19:48:46 +03:00
int flags ;
2002-02-25 15:02:33 +03:00
/*
* Setup the dm_task .
*/
2002-03-19 02:25:50 +03:00
int ( * populate ) ( struct dev_manager * dm ,
struct dm_task * dmt , struct dev_layer * dl ) ;
2002-02-25 17:46:57 +03:00
struct dm_info info ;
2002-03-19 02:25:50 +03:00
/* lvid plus layer */
2002-12-20 02:25:55 +03:00
const char * dlid ;
2002-03-19 02:25:50 +03:00
2002-02-25 15:02:33 +03:00
struct logical_volume * lv ;
/*
2003-04-25 02:09:13 +04:00
* Devices that must be created before this one can be created .
* Reloads get propagated to this list . Holds str_lists .
2002-02-25 15:02:33 +03:00
*/
2002-03-15 00:17:30 +03:00
struct list pre_create ;
2002-02-25 15:02:33 +03:00
2003-07-05 02:34:56 +04:00
/* Inverse of pre_create */
struct list pre_suspend ;
2002-02-25 15:02:33 +03:00
} ;
2002-03-11 23:36:04 +03:00
struct dl_list {
struct list list ;
struct dev_layer * dl ;
} ;
2003-04-25 02:09:13 +04:00
static const char * stripe_filler = NULL ;
2002-02-25 15:02:33 +03:00
struct dev_manager {
struct pool * mem ;
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 ;
2002-03-11 23:36:04 +03:00
/*
* list of struct lv_list , contains lvs that we wish to
* be active after execution .
*/
2002-03-08 13:41:48 +03:00
struct list active_list ;
2002-03-11 23:36:04 +03:00
/*
* Layers that need reloading .
*/
2002-03-27 21:17:43 +03:00
struct list reload_list ;
/*
* Layers that need suspending .
*/
struct list suspend_list ;
2002-03-11 23:36:04 +03:00
/*
* Layers that will need removing after activation .
*/
2002-03-11 14:27:48 +03:00
struct list remove_list ;
2002-03-08 13:41:48 +03:00
2002-02-25 15:02:33 +03:00
struct hash_table * layers ;
} ;
2002-03-07 19:48:46 +03:00
/*
* Functions to manage the flags .
*/
2002-03-15 00:17:30 +03:00
static inline int _get_flag ( struct dev_layer * dl , int bit )
{
2002-03-07 19:48:46 +03:00
return ( dl - > flags & ( 1 < < bit ) ) ? 1 : 0 ;
}
2002-03-15 00:17:30 +03:00
static inline void _set_flag ( struct dev_layer * dl , int bit )
{
2002-03-07 19:48:46 +03:00
dl - > flags | = ( 1 < < bit ) ;
}
2002-03-15 00:17:30 +03:00
static inline void _clear_flag ( struct dev_layer * dl , int bit )
{
2002-03-07 19:48:46 +03:00
dl - > flags & = ~ ( 1 < < bit ) ;
}
2002-02-25 17:46:57 +03:00
/*
2002-02-27 15:26:41 +03:00
* Device layer names are all of the form < vg > - < lv > - < layer > , any
* other hyphens that appear in these names are quoted with yet
2002-03-11 23:36:04 +03:00
* another hyphen . The top layer of any device has no layer
* name . eg , vg0 - lvol0 .
2002-02-25 17:46:57 +03:00
*/
2002-11-18 17:01:16 +03:00
static void _count_hyphens ( const char * str , size_t * len , int * hyphens )
2002-02-25 15:02:33 +03:00
{
const char * ptr ;
for ( ptr = str ; * ptr ; ptr + + , ( * len ) + + )
2002-02-27 15:26:41 +03:00
if ( * ptr = = ' - ' )
( * hyphens ) + + ;
2002-02-25 15:02:33 +03:00
}
/*
2002-02-27 15:26:41 +03:00
* Copies a string , quoting hyphens with hyphens .
2002-02-25 15:02:33 +03:00
*/
2002-02-27 15:26:41 +03:00
static void _quote_hyphens ( char * * out , const char * src )
2002-02-25 15:02:33 +03:00
{
while ( * src ) {
2002-02-27 15:26:41 +03:00
if ( * src = = ' - ' )
* ( * out ) + + = ' - ' ;
2002-02-25 15:02:33 +03:00
* ( * out ) + + = * src + + ;
}
}
2002-03-07 18:29:31 +03:00
/*
* < vg > - < lv > - < layer > or if ! layer just < vg > - < lv > .
*/
2002-02-25 15:02:33 +03:00
static char * _build_name ( struct pool * mem , const char * vg ,
const char * lv , const char * layer )
{
size_t len = 0 ;
2002-02-27 15:26:41 +03:00
int hyphens = 0 ;
2002-02-25 15:02:33 +03:00
char * r , * out ;
2002-02-27 15:26:41 +03:00
_count_hyphens ( vg , & len , & hyphens ) ;
_count_hyphens ( lv , & len , & hyphens ) ;
2002-03-07 18:29:31 +03:00
2002-03-19 02:25:50 +03:00
if ( layer & & * layer )
2002-03-07 18:29:31 +03:00
_count_hyphens ( layer , & len , & hyphens ) ;
2002-02-25 15:02:33 +03:00
2002-02-27 15:26:41 +03:00
len + = hyphens + 2 ;
2002-02-25 15:02:33 +03:00
if ( ! ( r = pool_alloc ( mem , len ) ) ) {
stack ;
return NULL ;
}
out = r ;
2002-03-07 18:29:31 +03:00
_quote_hyphens ( & out , vg ) ;
* out + + = ' - ' ;
_quote_hyphens ( & out , lv ) ;
2002-03-19 02:25:50 +03:00
if ( layer & & * layer ) {
2002-03-07 18:29:31 +03:00
* out + + = ' - ' ;
_quote_hyphens ( & out , layer ) ;
}
* out = ' \0 ' ;
2002-02-25 15:02:33 +03:00
return r ;
}
2002-03-19 02:25:50 +03:00
/* Find start of LV component in hyphenated name */
static char * _find_lv_name ( char * vg )
{
char * c = vg ;
while ( * c & & * ( c + 1 ) ) {
if ( * c = = ' - ' ) {
if ( * ( c + 1 ) = = ' - ' )
c + + ;
else
return ( c + 1 ) ;
}
c + + ;
}
return NULL ;
}
static char * _build_dlid ( struct pool * mem , const char * lvid , const char * layer )
{
char * dlid ;
2002-12-20 02:25:55 +03:00
size_t len ;
2002-03-19 02:25:50 +03:00
if ( ! layer )
layer = " " ;
len = strlen ( lvid ) + strlen ( layer ) + 2 ;
if ( ! ( dlid = pool_alloc ( mem , len ) ) ) {
stack ;
return NULL ;
}
sprintf ( dlid , " %s%s%s " , lvid , ( * layer ) ? " - " : " " , layer ) ;
return dlid ;
}
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 ;
}
2002-03-25 21:54:59 +03:00
static int _info_run ( const char * name , const char * uuid , struct dm_info * info ,
2003-11-13 17:11:41 +03:00
int mknodes , struct pool * mem , 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 ;
if ( ! ( dmt = _setup_task ( name , uuid , 0 , dmtask ) ) ) {
2002-03-15 00:17:30 +03:00
stack ;
return 0 ;
}
if ( ! dm_task_run ( dmt ) ) {
stack ;
goto out ;
}
if ( ! dm_task_get_info ( dmt , info ) ) {
stack ;
goto out ;
}
2002-03-19 02:25:50 +03:00
if ( info - > exists & & uuid_out ) {
if ( ! ( u = dm_task_get_uuid ( dmt ) ) ) {
stack ;
goto out ;
}
* uuid_out = pool_strdup ( mem , u ) ;
}
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
2003-11-13 17:11:41 +03:00
static int _info ( const char * name , const char * uuid , int mknodes ,
struct dm_info * info , struct pool * mem , char * * uuid_out )
2002-03-25 21:54:59 +03:00
{
2004-05-05 01:25:57 +04:00
if ( ! mknodes & & uuid & & * uuid & &
2003-11-13 17:11:41 +03:00
_info_run ( NULL , uuid , info , 0 , mem , uuid_out ) & & info - > exists )
2002-03-25 21:54:59 +03:00
return 1 ;
if ( name )
2003-11-13 17:11:41 +03:00
return _info_run ( name , NULL , info , mknodes , mem , uuid_out ) ;
2002-03-25 21:54:59 +03:00
return 0 ;
}
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 ;
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 ;
}
if ( ! dm_task_run ( dmt ) ) {
stack ;
goto out ;
}
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
{
2002-05-10 20:06:06 +04:00
if ( uuid & & * uuid & & _status_run ( NULL , uuid , start , length , type ,
type_size , params , param_size )
& & * params )
2002-05-10 01:17:57 +04:00
return 1 ;
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 ,
const char * uuid ,
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 ;
2003-04-30 19:26:25 +04:00
if ( ! ( dmt = _setup_task ( name , uuid , 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 ;
}
if ( ! dm_task_run ( dmt ) ) {
stack ;
goto out ;
}
2003-04-30 19:26:25 +04:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists ) {
stack ;
goto out ;
}
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 ,
dm - > cmd - > cft , seg , params ,
& total_numerator ,
& total_denominator ,
percent ) ) {
stack ;
goto out ;
2003-04-25 02:09:13 +04:00
}
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 ;
}
2003-05-06 16:00:29 +04:00
static int _percent ( struct dev_manager * dm , const char * name , const char * uuid ,
const char * target_type , int wait ,
struct logical_volume * lv , float * percent ,
uint32_t * event_nr )
2003-04-25 02:09:13 +04:00
{
2003-04-30 19:26:25 +04:00
if ( uuid & & * uuid
2003-05-06 16:00:29 +04:00
& & _percent_run ( dm , NULL , uuid , target_type , wait , lv , percent ,
event_nr ) )
2003-04-25 02:09:13 +04:00
return 1 ;
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 ;
}
2002-12-20 02:25:55 +03:00
static int _rename ( struct dev_layer * dl , char * newname )
2002-03-19 02:25:50 +03:00
{
int r = 1 ;
struct dm_task * dmt ;
log_verbose ( " Renaming %s to %s " , dl - > name , newname ) ;
2003-04-30 19:26:25 +04:00
if ( ! ( dmt = _setup_task ( dl - > name , NULL , 0 , DM_DEVICE_RENAME ) ) ) {
2002-03-19 02:25:50 +03:00
stack ;
return 0 ;
}
if ( ! dm_task_set_newname ( dmt , newname ) ) {
stack ;
r = 0 ;
goto out ;
}
if ( ! ( r = dm_task_run ( dmt ) ) )
log_error ( " Couldn't rename device '%s'. " , dl - > name ) ;
if ( r & & _get_flag ( dl , VISIBLE ) )
fs_rename_lv ( dl - > lv , newname , _find_lv_name ( dl - > name ) ) ;
dl - > name = newname ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2004-05-13 00:40:34 +04:00
static int _suspend_or_resume ( const char * name , action_t suspend )
{
int r ;
struct dm_task * dmt ;
int sus = ( suspend = = SUSPEND ) ? 1 : 0 ;
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME ;
log_very_verbose ( " %s %s " , sus ? " Suspending " : " Resuming " , name ) ;
if ( ! ( dmt = _setup_task ( name , NULL , 0 , task ) ) ) {
stack ;
return 0 ;
}
if ( ! ( r = dm_task_run ( dmt ) ) )
log_error ( " Couldn't %s device '%s' " , sus ? " suspend " : " resume " ,
name ) ;
dm_task_destroy ( dmt ) ;
return r ;
}
static int _suspend ( struct dev_layer * dl )
{
if ( ! dl - > info . exists | | dl - > info . suspended )
return 1 ;
if ( ! _suspend_or_resume ( dl - > name , SUSPEND ) ) {
stack ;
return 0 ;
}
dl - > info . suspended = 1 ;
return 1 ;
}
static int _resume ( struct dev_layer * dl )
{
if ( ! dl - > info . exists | | ! dl - > info . suspended )
return 1 ;
if ( ! _suspend_or_resume ( dl - > name , RESUME ) ) {
stack ;
return 0 ;
}
dl - > info . suspended = 0 ;
return 1 ;
}
2002-02-26 17:44:13 +03:00
static int _load ( struct dev_manager * dm , struct dev_layer * dl , int task )
2002-02-25 17:46:57 +03:00
{
2002-03-19 02:25:50 +03:00
int r = 1 ;
2002-02-25 17:46:57 +03:00
struct dm_task * dmt ;
2002-03-05 23:03:09 +03:00
log_verbose ( " Loading %s " , dl - > name ) ;
2002-03-25 21:54:59 +03:00
if ( ! ( dmt = _setup_task ( task = = DM_DEVICE_CREATE ? dl - > name : NULL ,
2003-04-30 19:26:25 +04:00
dl - > dlid , 0 , task ) ) ) {
2002-02-25 17:46:57 +03:00
stack ;
return 0 ;
}
/*
* Populate the table .
*/
2002-02-26 17:44:13 +03:00
if ( ! dl - > populate ( dm , dmt , dl ) ) {
2002-03-15 00:17:30 +03:00
log_error ( " Couldn't populate device '%s'. " , dl - > name ) ;
2002-03-19 02:25:50 +03:00
r = 0 ;
goto out ;
2002-02-25 17:46:57 +03:00
}
2002-03-26 16:41:37 +03:00
/*
2003-04-02 23:14:43 +04:00
* Do we want a specific device number ?
2002-03-26 16:41:37 +03:00
*/
2003-04-02 23:14:43 +04:00
if ( dl - > lv - > major > = 0 & & _get_flag ( dl , VISIBLE ) ) {
if ( ! dm_task_set_major ( dmt , dl - > lv - > major ) ) {
log_error ( " Failed to set major number for %s to %d "
" during activation. " , dl - > name ,
dl - > lv - > major ) ;
goto out ;
} else
log_very_verbose ( " Set major number for %s to %d. " ,
dl - > name , dl - > lv - > major ) ;
}
2002-03-26 16:41:37 +03:00
if ( dl - > lv - > minor > = 0 & & _get_flag ( dl , VISIBLE ) ) {
if ( ! dm_task_set_minor ( dmt , dl - > lv - > minor ) ) {
log_error ( " Failed to set minor number for %s to %d "
" during activation. " , dl - > name ,
dl - > lv - > minor ) ;
goto out ;
} else
log_very_verbose ( " Set minor number for %s to %d. " ,
dl - > name , dl - > lv - > minor ) ;
}
2002-03-25 21:54:59 +03:00
if ( ! _get_flag ( dl , READWRITE ) ) {
if ( ! dm_task_set_ro ( dmt ) ) {
log_error ( " Failed to set %s read-only during "
" activation. " , dl - > name ) ;
goto out ;
} else
log_very_verbose ( " Activating %s read-only " , dl - > name ) ;
}
2002-03-08 13:41:48 +03:00
2003-07-05 02:34:56 +04:00
if ( ! ( r = dm_task_run ( dmt ) ) ) {
2002-03-15 00:17:30 +03:00
log_error ( " Couldn't load device '%s'. " , dl - > name ) ;
2003-07-05 02:34:56 +04:00
if ( ( dl - > lv - > minor > = 0 | | dl - > lv - > major > = 0 ) & &
_get_flag ( dl , VISIBLE ) )
2004-05-05 01:25:57 +04:00
log_error ( " Perhaps the persistent device number "
" %d:%d is already in use? " ,
dl - > lv - > major , dl - > lv - > minor ) ;
2003-07-05 02:34:56 +04:00
}
2002-03-15 00:17:30 +03:00
if ( ! dm_task_get_info ( dmt , & dl - > info ) ) {
stack ;
2002-03-19 02:25:50 +03:00
r = 0 ;
goto out ;
2002-03-15 00:17:30 +03:00
}
2003-07-05 02:34:56 +04:00
if ( ! dl - > info . exists | | ! dl - > info . live_table ) {
stack ;
r = 0 ;
goto out ;
}
2004-05-13 00:40:34 +04:00
if ( _get_flag ( dl , RESUME_IMMEDIATE ) & & dl - > info . suspended & &
! _resume ( dl ) ) {
stack ;
r = 0 ;
goto out ;
}
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-18 16:09:27 +03:00
if ( r & & _get_flag ( dl , VISIBLE ) )
2002-02-26 14:49:17 +03:00
fs_add_lv ( dl - > lv , dl - > name ) ;
2002-03-27 21:17:43 +03:00
_clear_flag ( dl , RELOAD ) ;
2002-03-16 01:59:12 +03:00
2002-03-19 02:25:50 +03:00
out :
dm_task_destroy ( dmt ) ;
2002-02-25 17:46:57 +03:00
return r ;
}
static int _remove ( struct dev_layer * dl )
{
int r ;
struct dm_task * dmt ;
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
2003-04-30 19:26:25 +04:00
if ( ! ( dmt = _setup_task ( dl - > name , NULL , 0 , DM_DEVICE_REMOVE ) ) ) {
2002-02-25 17:46:57 +03:00
stack ;
return 0 ;
}
2002-03-16 01:59:12 +03:00
/* Suppress error message if it's still in use - we'll log it later */
log_suppress ( 1 ) ;
if ( ( r = dm_task_run ( dmt ) ) )
2002-03-15 00:17:30 +03:00
dl - > info . exists = 0 ;
2002-02-25 17:46:57 +03:00
2002-03-16 01:59:12 +03:00
log_suppress ( 0 ) ;
2002-02-25 17:46:57 +03:00
dm_task_destroy ( dmt ) ;
2002-02-26 14:49:17 +03:00
2002-03-18 16:09:27 +03:00
if ( r & & _get_flag ( dl , VISIBLE ) )
2002-02-26 14:49:17 +03:00
fs_del_lv ( dl - > lv ) ;
2002-03-16 01:59:12 +03:00
_clear_flag ( dl , ACTIVE ) ;
2002-02-25 17:46:57 +03:00
return r ;
}
2002-02-25 18:19:53 +03:00
/*
* The functions that populate the table in a dm_task as part of
* a create / reload .
*/
/*
* Emit a target for a given segment .
* FIXME : tidy this function .
*/
2003-08-20 16:53:57 +04:00
static int _emit_target_line ( struct dev_manager * dm , struct dm_task * dmt ,
struct lv_segment * seg , char * params ,
size_t paramsize )
2002-02-25 18:19:53 +03:00
{
uint64_t esize = seg - > lv - > vg - > extent_size ;
2004-05-05 01:25:57 +04:00
int w = 0 ;
2002-12-20 02:25:55 +03:00
const char * target = NULL ;
2004-05-05 01:25:57 +04:00
int r ;
2002-02-25 18:19:53 +03:00
2004-05-05 01:25:57 +04:00
if ( ! seg - > segtype - > ops - > compose_target_line ) {
2003-04-25 02:09:13 +04:00
log_error ( " _emit_target: Internal error: Can't handle "
2004-05-05 01:25:57 +04:00
" segment type %s " , seg - > segtype - > name ) ;
return 0 ;
}
if ( ( r = seg - > segtype - > ops - > compose_target_line ( dm , dm - > mem ,
dm - > cmd - > cft ,
& dm - > target_state , seg ,
params , paramsize ,
& target , & w ,
& dm - >
pvmove_mirror_count ) ) < =
0 ) {
stack ;
return r ;
}
log_debug ( " Adding target: % " PRIu64 " % " PRIu64 " %s %s " ,
esize * seg - > le , esize * seg - > len , target , params ) ;
if ( ! dm_task_add_target ( dmt , esize * seg - > le , esize * seg - > len ,
target , params ) ) {
stack ;
2003-04-25 02:09:13 +04:00
return 0 ;
2002-02-25 18:19:53 +03:00
}
2004-05-05 01:25:57 +04:00
return 1 ;
}
int compose_areas_line ( struct dev_manager * dm , struct lv_segment * seg ,
char * params , size_t paramsize , int * pos , int start_area ,
int areas )
{
uint32_t s ;
int tw = 0 ;
const char * trailing_space ;
uint64_t esize = seg - > lv - > vg - > extent_size ;
struct dev_layer * dl ;
char devbuf [ 10 ] ;
for ( s = start_area ; s < areas ; s + + , * pos + = tw ) {
2003-04-25 02:09:13 +04:00
trailing_space = ( areas - s - 1 ) ? " " : " " ;
if ( ( seg - > area [ s ] . type = = AREA_PV & &
( ! seg - > area [ s ] . u . pv . pv | | ! seg - > area [ s ] . u . pv . pv - > dev ) ) | |
( seg - > area [ s ] . type = = AREA_LV & & ! seg - > area [ s ] . u . lv . lv ) )
2004-05-05 01:25:57 +04:00
tw = lvm_snprintf ( params + * pos , paramsize - * pos ,
2003-04-25 02:09:13 +04:00
" %s 0%s " , dm - > stripe_filler ,
trailing_space ) ;
else if ( seg - > area [ s ] . type = = AREA_PV )
2004-05-05 01:25:57 +04:00
tw = lvm_snprintf ( params + * pos , paramsize - * pos ,
2002-04-16 18:42:20 +04:00
" %s % " PRIu64 " %s " ,
2003-04-25 02:09:13 +04:00
dev_name ( seg - > area [ s ] . u . pv . pv - > dev ) ,
( seg - > area [ s ] . u . pv . pv - > pe_start +
( esize * seg - > area [ s ] . u . pv . pe ) ) ,
trailing_space ) ;
2003-07-05 02:34:56 +04:00
else {
if ( ! ( dl = hash_lookup ( dm - > layers ,
seg - > area [ s ] . u . lv . lv - > lvid . s ) ) ) {
log_error ( " device layer %s missing from hash " ,
seg - > area [ s ] . u . lv . lv - > lvid . s ) ;
return 0 ;
}
2004-05-05 01:25:57 +04:00
if ( ! dm_format_dev
( devbuf , sizeof ( devbuf ) , dl - > info . major ,
dl - > info . minor ) ) {
log_error
( " Failed to format device number as dm target (%u,%u) " ,
dl - > info . major , dl - > info . minor ) ;
2003-07-05 02:34:56 +04:00
return 0 ;
}
2004-05-05 01:25:57 +04:00
tw = lvm_snprintf ( params + * pos , paramsize - * pos ,
2003-07-05 02:34:56 +04:00
" %s % " PRIu64 " %s " , devbuf ,
2003-04-25 02:09:13 +04:00
esize * seg - > area [ s ] . u . lv . le ,
trailing_space ) ;
2003-07-05 02:34:56 +04:00
}
2002-03-27 21:17:43 +03:00
2004-05-05 01:25:57 +04:00
if ( tw < 0 ) {
stack ;
return - 1 ;
}
2002-02-25 18:19:53 +03:00
}
return 1 ;
2003-08-20 16:53:57 +04:00
}
static int _emit_target ( struct dev_manager * dm , struct dm_task * dmt ,
struct lv_segment * seg )
{
char * params ;
size_t paramsize = 4096 ;
int ret ;
do {
if ( ! ( params = dbg_malloc ( paramsize ) ) ) {
log_error ( " Insufficient space for target parameters. " ) ;
return 0 ;
}
ret = _emit_target_line ( dm , dmt , seg , params , paramsize ) ;
dbg_free ( params ) ;
if ( ! ret )
stack ;
if ( ret > = 0 )
return ret ;
2004-05-05 01:25:57 +04:00
log_debug ( " Insufficient space in params[% " PRIsize_t
" ] for target parameters. " , paramsize ) ;
2003-08-20 16:53:57 +04:00
paramsize * = 2 ;
} while ( paramsize < MAX_TARGET_PARAMSIZE ) ;
log_error ( " Target parameter size too big. Aborting. " ) ;
2002-03-27 21:17:43 +03:00
return 0 ;
2002-02-25 18:19:53 +03:00
}
2002-02-26 17:44:13 +03:00
static int _populate_vanilla ( struct dev_manager * dm ,
struct dm_task * dmt , struct dev_layer * dl )
2002-02-25 18:19:53 +03:00
{
struct list * segh ;
2002-11-18 17:01:16 +03:00
struct lv_segment * seg ;
2002-02-25 18:19:53 +03:00
struct logical_volume * lv = dl - > lv ;
2003-05-06 16:00:29 +04:00
dm - > pvmove_mirror_count = 0u ;
2002-02-25 18:19:53 +03:00
list_iterate ( segh , & lv - > segments ) {
2002-11-18 17:01:16 +03:00
seg = list_item ( segh , struct lv_segment ) ;
2003-04-25 02:09:13 +04:00
if ( ! _emit_target ( dm , dmt , seg ) ) {
2002-02-25 18:19:53 +03:00
log_error ( " Unable to build table for '%s' " , lv - > name ) ;
return 0 ;
}
}
return 1 ;
}
2002-02-26 17:44:13 +03:00
static int _populate_origin ( struct dev_manager * dm ,
struct dm_task * dmt , struct dev_layer * dl )
2002-02-25 18:19:53 +03:00
{
2002-02-26 19:48:52 +03:00
char * real ;
2002-03-15 00:17:30 +03:00
char params [ PATH_MAX + 32 ] ;
2003-07-05 02:34:56 +04:00
struct dev_layer * dlr ;
2002-02-26 17:44:13 +03:00
2003-07-05 02:34:56 +04:00
if ( ! ( real = _build_dlid ( dm - > mem , dl - > lv - > lvid . s , " real " ) ) ) {
2002-02-26 19:48:52 +03:00
stack ;
return 0 ;
}
2003-07-05 02:34:56 +04:00
if ( ! ( dlr = hash_lookup ( dm - > layers , real ) ) ) {
log_error ( " Couldn't find real device layer %s in hash " , real ) ;
return 0 ;
}
if ( ! dm_format_dev ( params , sizeof ( params ) , dlr - > info . major ,
dlr - > info . minor ) ) {
2002-03-15 00:17:30 +03:00
log_error ( " Couldn't create origin device parameters for '%s'. " ,
2002-03-19 02:25:50 +03:00
real ) ;
2002-02-26 17:44:13 +03:00
return 0 ;
}
2002-02-25 18:19:53 +03:00
2002-03-15 00:17:30 +03:00
log_debug ( " Adding target: 0 % " PRIu64 " snapshot-origin %s " ,
dl - > lv - > size , params ) ;
2003-03-24 21:08:53 +03:00
if ( ! dm_task_add_target ( dmt , UINT64_C ( 0 ) , dl - > lv - > size ,
2002-02-26 17:44:13 +03:00
" snapshot-origin " , params ) ) {
2002-03-15 00:17:30 +03:00
stack ;
return 0 ;
}
2002-02-25 18:19:53 +03:00
return 1 ;
}
2002-02-26 17:44:13 +03:00
static int _populate_snapshot ( struct dev_manager * dm ,
struct dm_task * dmt , struct dev_layer * dl )
2002-02-25 18:19:53 +03:00
{
2002-02-26 17:44:13 +03:00
char * origin , * cow ;
2002-03-15 00:17:30 +03:00
char params [ PATH_MAX * 2 + 32 ] ;
2002-02-26 17:44:13 +03:00
struct snapshot * s ;
2003-07-05 02:34:56 +04:00
struct dev_layer * dlo , * dlc ;
2003-07-06 03:24:10 +04:00
char devbufo [ 10 ] , devbufc [ 10 ] ;
2002-02-26 17:44:13 +03:00
if ( ! ( s = find_cow ( dl - > lv ) ) ) {
2002-03-19 02:25:50 +03:00
log_error ( " Couldn't find snapshot for '%s'. " , dl - > lv - > name ) ;
2002-02-26 17:44:13 +03:00
return 0 ;
}
2003-07-05 02:34:56 +04:00
if ( ! ( origin = _build_dlid ( dm - > mem , s - > origin - > lvid . s , " real " ) ) ) {
2002-02-26 17:44:13 +03:00
stack ;
return 0 ;
}
2002-02-25 18:19:53 +03:00
2003-07-05 02:34:56 +04:00
if ( ! ( cow = _build_dlid ( dm - > mem , s - > cow - > lvid . s , " cow " ) ) ) {
2002-02-26 17:44:13 +03:00
stack ;
return 0 ;
}
2002-02-25 18:19:53 +03:00
2003-07-05 02:34:56 +04:00
if ( ! ( dlo = hash_lookup ( dm - > layers , origin ) ) ) {
log_error ( " Couldn't find origin device layer %s in hash " ,
origin ) ;
return 0 ;
}
if ( ! ( dlc = hash_lookup ( dm - > layers , cow ) ) ) {
log_error ( " Couldn't find cow device layer %s in hash " , cow ) ;
return 0 ;
}
2003-07-06 03:24:10 +04:00
if ( ! dm_format_dev ( devbufo , sizeof ( devbufo ) , dlo - > info . major ,
dlo - > info . minor ) ) {
log_error ( " Couldn't create origin device parameters for '%s'. " ,
s - > origin - > name ) ;
return 0 ;
}
if ( ! dm_format_dev ( devbufc , sizeof ( devbufc ) , dlc - > info . major ,
dlc - > info . minor ) ) {
log_error ( " Couldn't create cow device parameters for '%s'. " ,
s - > cow - > name ) ;
return 0 ;
}
2003-09-18 00:35:57 +04:00
if ( lvm_snprintf ( params , sizeof ( params ) , " %s %s P %d " ,
2003-08-20 16:53:57 +04:00
devbufo , devbufc , s - > chunk_size ) = = - 1 ) {
2002-03-15 00:17:30 +03:00
stack ;
return 0 ;
}
2002-02-25 18:19:53 +03:00
2002-03-15 00:17:30 +03:00
log_debug ( " Adding target: 0 % " PRIu64 " snapshot %s " ,
s - > origin - > size , params ) ;
2002-12-20 02:25:55 +03:00
if ( ! dm_task_add_target
2003-03-24 21:08:53 +03:00
( dmt , UINT64_C ( 0 ) , s - > origin - > size , " snapshot " , params ) ) {
2002-03-15 00:17:30 +03:00
stack ;
return 0 ;
}
2002-02-25 18:19:53 +03:00
return 1 ;
}
2002-02-25 15:02:33 +03:00
/*
* dev_manager implementation .
*/
2004-05-05 01:25:57 +04:00
struct dev_manager * dev_manager_create ( struct cmd_context * cmd ,
const char * vg_name )
2002-02-25 15:02:33 +03:00
{
struct pool * mem ;
struct dev_manager * dm ;
if ( ! ( mem = pool_create ( 16 * 1024 ) ) ) {
stack ;
return NULL ;
}
if ( ! ( dm = pool_alloc ( mem , sizeof ( * dm ) ) ) ) {
stack ;
goto bad ;
}
2004-05-05 01:25:57 +04:00
dm - > cmd = cmd ;
2002-02-25 15:02:33 +03:00
dm - > mem = mem ;
2004-05-05 01:25:57 +04:00
2003-04-25 02:09:13 +04:00
if ( ! stripe_filler ) {
2004-05-05 01:25:57 +04:00
stripe_filler = find_config_str ( cmd - > cft - > root ,
2003-04-25 02:09:13 +04:00
" activation/missing_stripe_filler " ,
2004-03-08 21:28:45 +03:00
DEFAULT_STRIPE_FILLER ) ;
2003-04-25 02:09:13 +04:00
}
dm - > stripe_filler = stripe_filler ;
2002-02-25 15:02:33 +03:00
if ( ! ( dm - > vg_name = pool_strdup ( dm - > mem , vg_name ) ) ) {
stack ;
goto bad ;
}
if ( ! ( dm - > layers = hash_create ( 32 ) ) ) {
stack ;
goto bad ;
}
2002-03-08 13:41:48 +03:00
list_init ( & dm - > active_list ) ;
2002-03-27 21:17:43 +03:00
list_init ( & dm - > reload_list ) ;
2002-03-11 14:27:48 +03:00
list_init ( & dm - > remove_list ) ;
2002-03-27 21:17:43 +03:00
list_init ( & dm - > suspend_list ) ;
2002-03-08 13:41:48 +03:00
2004-05-05 01:25:57 +04:00
dm - > target_state = NULL ;
2002-02-25 15:02:33 +03:00
return dm ;
2002-03-15 00:17:30 +03:00
bad :
2002-02-25 15:02:33 +03:00
pool_destroy ( mem ) ;
return NULL ;
}
void dev_manager_destroy ( struct dev_manager * dm )
{
hash_destroy ( dm - > layers ) ;
pool_destroy ( dm - > mem ) ;
}
2002-12-20 02:25:55 +03:00
int dev_manager_info ( struct dev_manager * dm , const struct logical_volume * lv ,
2003-11-13 17:11:41 +03:00
int mknodes , struct dm_info * info )
2002-02-25 17:46:57 +03:00
{
char * name ;
/*
2002-03-26 16:41:37 +03:00
* Build a name for the top layer .
*/
2002-03-07 18:29:31 +03:00
if ( ! ( name = _build_name ( dm - > mem , lv - > vg - > name , lv - > name , NULL ) ) ) {
2002-02-25 17:46:57 +03:00
stack ;
return 0 ;
}
/*
* Try and get some info on this device .
*/
2002-03-25 21:54:59 +03:00
log_debug ( " Getting device info for %s " , name ) ;
2003-11-13 17:11:41 +03:00
if ( ! _info ( name , lv - > lvid . s , mknodes , info , NULL , NULL ) ) {
2002-02-25 17:46:57 +03:00
stack ;
return 0 ;
}
return 1 ;
}
2002-05-22 18:03:45 +04:00
int dev_manager_snapshot_percent ( struct dev_manager * dm ,
struct logical_volume * lv , float * percent )
2002-05-10 01:17:57 +04:00
{
2003-04-25 02:09:13 +04:00
char * name ;
2002-05-10 01:17:57 +04:00
/*
* Build a name for the top layer .
*/
2002-05-22 18:03:45 +04:00
if ( ! ( name = _build_name ( dm - > mem , lv - > vg - > name , lv - > name , NULL ) ) ) {
2002-05-10 01:17:57 +04:00
stack ;
return 0 ;
}
/*
* Try and get some info on this device .
*/
2003-04-25 02:09:13 +04:00
log_debug ( " Getting device status percentage for %s " , name ) ;
2003-05-06 16:00:29 +04:00
if ( ! ( _percent ( dm , name , lv - > lvid . s , " snapshot " , 0 , NULL , percent ,
NULL ) ) ) {
2002-05-22 18:03:45 +04:00
stack ;
return 0 ;
2002-05-10 01:17:57 +04:00
}
2002-05-22 18:03:45 +04:00
/* FIXME pool_free ? */
2002-05-10 01:17:57 +04:00
/* If the snapshot isn't available, percent will be -1 */
2003-04-25 02:09:13 +04:00
return 1 ;
2002-05-10 01:17:57 +04:00
}
2003-04-30 19:26:25 +04: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 )
{
char * name ;
/*
* Build a name for the top layer .
*/
if ( ! ( name = _build_name ( dm - > mem , lv - > vg - > name , lv - > name , NULL ) ) ) {
stack ;
return 0 ;
}
/* FIXME pool_free ? */
log_debug ( " Getting device mirror status percentage for %s " , name ) ;
2003-05-06 16:00:29 +04:00
if ( ! ( _percent ( dm , name , lv - > lvid . s , " mirror " , wait , lv , percent ,
event_nr ) ) ) {
2003-04-30 19:26:25 +04:00
stack ;
return 0 ;
}
return 1 ;
}
2002-03-19 02:25:50 +03:00
static struct dev_layer * _create_dev ( struct dev_manager * dm , char * name ,
2002-12-20 02:25:55 +03:00
const char * dlid )
2002-02-25 15:02:33 +03:00
{
struct dev_layer * dl ;
2002-03-19 02:25:50 +03:00
char * uuid ;
2002-02-25 15:02:33 +03:00
2002-03-15 00:17:30 +03:00
if ( ! ( dl = pool_zalloc ( dm - > mem , sizeof ( * dl ) ) ) ) {
2002-02-25 15:02:33 +03:00
stack ;
return NULL ;
}
2002-03-07 20:37:38 +03:00
dl - > name = name ;
2002-02-25 15:02:33 +03:00
2002-03-25 21:54:59 +03:00
log_debug ( " Getting device info for %s " , dl - > name ) ;
2003-11-13 17:11:41 +03:00
if ( ! _info ( dl - > name , dlid , 0 , & dl - > info , dm - > mem , & uuid ) ) {
2002-02-25 17:46:57 +03:00
stack ;
return NULL ;
}
2002-03-19 02:25:50 +03:00
if ( dl - > info . exists )
dl - > dlid = uuid ;
else
dl - > dlid = dlid ;
2002-02-26 14:49:17 +03:00
list_init ( & dl - > pre_create ) ;
2003-07-05 02:34:56 +04:00
list_init ( & dl - > pre_suspend ) ;
2002-02-25 15:02:33 +03:00
2002-03-19 02:25:50 +03:00
if ( ! hash_insert ( dm - > layers , dl - > dlid , dl ) ) {
2002-03-15 00:17:30 +03:00
stack ;
return NULL ;
}
2002-02-25 15:02:33 +03:00
return dl ;
}
2002-03-25 21:54:59 +03:00
static inline int _read_only_lv ( struct logical_volume * lv )
{
2002-03-26 16:41:37 +03:00
return ( ! ( lv - > vg - > status & LVM_WRITE ) | | ! ( lv - > status & LVM_WRITE ) ) ;
2002-03-25 21:54:59 +03:00
}
2002-03-15 00:17:30 +03:00
static struct dev_layer * _create_layer ( struct dev_manager * dm ,
2002-03-07 20:37:38 +03:00
const char * layer ,
struct logical_volume * lv )
{
2002-03-19 02:25:50 +03:00
char * name , * dlid ;
2002-03-15 00:17:30 +03:00
struct dev_layer * dl ;
if ( ! ( name = _build_name ( dm - > mem , lv - > vg - > name , lv - > name , layer ) ) ) {
stack ;
return NULL ;
}
2002-03-07 20:37:38 +03:00
2002-03-19 02:25:50 +03:00
if ( ! ( dlid = _build_dlid ( dm - > mem , lv - > lvid . s , layer ) ) ) {
stack ;
return NULL ;
}
if ( ! ( dl = hash_lookup ( dm - > layers , dlid ) ) & &
! ( dl = _create_dev ( dm , name , dlid ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return NULL ;
}
2002-03-15 00:17:30 +03:00
dl - > lv = lv ;
2002-03-25 21:54:59 +03:00
if ( ! _read_only_lv ( lv ) )
_set_flag ( dl , READWRITE ) ;
2002-03-15 00:17:30 +03:00
return dl ;
2002-03-07 20:37:38 +03:00
}
2002-02-25 15:02:33 +03:00
/*
* Finds the specified layer .
*/
2002-02-25 17:46:57 +03:00
static struct dev_layer * _lookup ( struct dev_manager * dm ,
2002-03-19 02:25:50 +03:00
const char * lvid , const char * layer )
2002-02-25 15:02:33 +03:00
{
2002-03-19 02:25:50 +03:00
char * dlid ;
2002-02-25 15:02:33 +03:00
struct dev_layer * dl ;
2002-03-19 02:25:50 +03:00
if ( ! ( dlid = _build_dlid ( dm - > mem , lvid , layer ) ) ) {
2002-02-25 15:02:33 +03:00
stack ;
return NULL ;
}
2002-03-19 02:25:50 +03:00
dl = hash_lookup ( dm - > layers , dlid ) ;
pool_free ( dm - > mem , dlid ) ;
2002-02-25 15:02:33 +03:00
return dl ;
}
2003-07-05 02:34:56 +04:00
static int _expand_vanilla ( struct dev_manager * dm , struct logical_volume * lv ,
int was_origin )
2002-02-25 15:02:33 +03:00
{
/*
2002-03-07 20:37:38 +03:00
* only one layer .
2002-02-25 15:02:33 +03:00
*/
2003-07-05 02:34:56 +04:00
struct dev_layer * dl , * dlr ;
2003-04-25 02:09:13 +04:00
struct list * segh ;
struct lv_segment * seg ;
uint32_t s ;
2002-03-15 00:17:30 +03:00
if ( ! ( dl = _create_layer ( dm , NULL , lv ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return 0 ;
}
dl - > populate = _populate_vanilla ;
2003-05-06 16:00:29 +04:00
if ( lv - > status & VISIBLE_LV ) {
2003-04-25 02:09:13 +04:00
_set_flag ( dl , VISIBLE ) ;
2003-05-06 16:00:29 +04:00
_set_flag ( dl , TOPLEVEL ) ;
}
if ( lv - > status & PVMOVE )
_set_flag ( dl , TOPLEVEL ) ;
2003-04-25 02:09:13 +04:00
/* Add dependencies for any LVs that segments refer to */
list_iterate ( segh , & lv - > segments ) {
seg = list_item ( segh , struct lv_segment ) ;
for ( s = 0 ; s < seg - > area_count ; s + + ) {
if ( seg - > area [ s ] . type ! = AREA_LV )
continue ;
2003-09-18 00:35:57 +04:00
if ( ! str_list_add ( dm - > mem , & dl - > pre_create ,
_build_dlid ( dm - > mem ,
2004-05-05 01:25:57 +04:00
seg - > area [ s ] . u . lv . lv - >
lvid . s , NULL ) ) ) {
2003-04-25 02:09:13 +04:00
stack ;
return 0 ;
}
_set_flag ( dl , NOPROPAGATE ) ;
}
}
2002-02-26 17:44:13 +03:00
2003-07-05 02:34:56 +04:00
if ( ! was_origin )
return 1 ;
/* Deactivating the last snapshot */
if ( ! ( dlr = _create_layer ( dm , " real " , lv ) ) ) {
stack ;
return 0 ;
}
dlr - > populate = _populate_vanilla ;
_clear_flag ( dlr , VISIBLE ) ;
_clear_flag ( dlr , TOPLEVEL ) ;
_set_flag ( dlr , REMOVE ) ;
2004-05-05 01:25:57 +04:00
2003-07-05 02:34:56 +04:00
/* add the dependency on the real device */
2003-09-18 00:35:57 +04:00
if ( ! str_list_add ( dm - > mem , & dl - > pre_create ,
pool_strdup ( dm - > mem , dlr - > dlid ) ) ) {
2003-07-05 02:34:56 +04:00
stack ;
return 0 ;
}
2002-03-07 20:37:38 +03:00
return 1 ;
}
2002-02-26 17:44:13 +03:00
2002-03-08 13:41:48 +03:00
static int _expand_origin_real ( struct dev_manager * dm ,
struct logical_volume * lv )
2002-03-07 20:37:38 +03:00
{
struct dev_layer * dl ;
2002-12-20 02:25:55 +03:00
const char * real_dlid ;
2002-02-26 17:44:13 +03:00
2002-03-15 00:17:30 +03:00
if ( ! ( dl = _create_layer ( dm , " real " , lv ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return 0 ;
}
dl - > populate = _populate_vanilla ;
_clear_flag ( dl , VISIBLE ) ;
2003-05-06 16:00:29 +04:00
_clear_flag ( dl , TOPLEVEL ) ;
2002-02-26 17:44:13 +03:00
2004-05-13 00:40:34 +04:00
/* Size changes must take effect before tables using it are reloaded */
_set_flag ( dl , RESUME_IMMEDIATE ) ;
2002-03-19 02:25:50 +03:00
real_dlid = dl - > dlid ;
2002-02-25 15:02:33 +03:00
2002-03-15 00:17:30 +03:00
if ( ! ( dl = _create_layer ( dm , NULL , lv ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return 0 ;
}
dl - > populate = _populate_origin ;
_set_flag ( dl , VISIBLE ) ;
2003-05-06 16:00:29 +04:00
_set_flag ( dl , TOPLEVEL ) ;
2002-02-26 17:44:13 +03:00
2002-03-07 20:37:38 +03:00
/* add the dependency on the real device */
2003-09-18 00:35:57 +04:00
if ( ! str_list_add ( dm - > mem , & dl - > pre_create ,
pool_strdup ( dm - > mem , real_dlid ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return 0 ;
}
2002-02-26 19:48:52 +03:00
2002-03-07 20:37:38 +03:00
return 1 ;
}
2002-02-26 17:44:13 +03:00
2002-03-08 13:41:48 +03:00
static int _expand_origin ( struct dev_manager * dm , struct logical_volume * lv )
{
struct logical_volume * active ;
struct snapshot * s ;
struct list * sh ;
/*
* We only need to create an origin layer if one of our
2003-07-05 02:34:56 +04:00
* snapshots is in the active list
2002-03-08 13:41:48 +03:00
*/
2002-03-15 00:17:30 +03:00
list_iterate ( sh , & dm - > active_list ) {
2002-03-08 13:41:48 +03:00
active = list_item ( sh , struct lv_list ) - > lv ;
if ( ( s = find_cow ( active ) ) & & ( s - > origin = = lv ) )
return _expand_origin_real ( dm , lv ) ;
}
2003-07-05 02:34:56 +04:00
/*
* We ' re deactivating the last snapshot
*/
return _expand_vanilla ( dm , lv , 1 ) ;
2002-03-08 13:41:48 +03:00
}
2002-03-07 20:37:38 +03:00
static int _expand_snapshot ( struct dev_manager * dm , struct logical_volume * lv ,
struct snapshot * s )
{
/*
* snapshot ( org , cow )
* cow
*/
struct dev_layer * dl ;
2002-12-20 02:25:55 +03:00
const char * cow_dlid ;
2002-02-26 17:44:13 +03:00
2002-03-15 00:17:30 +03:00
if ( ! ( dl = _create_layer ( dm , " cow " , lv ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return 0 ;
}
dl - > populate = _populate_vanilla ;
_clear_flag ( dl , VISIBLE ) ;
2003-05-06 16:00:29 +04:00
_clear_flag ( dl , TOPLEVEL ) ;
2003-09-16 20:08:05 +04:00
_set_flag ( dl , READWRITE ) ;
2002-02-26 17:44:13 +03:00
2002-03-19 02:25:50 +03:00
cow_dlid = dl - > dlid ;
2002-02-26 17:44:13 +03:00
2002-03-15 00:17:30 +03:00
if ( ! ( dl = _create_layer ( dm , NULL , lv ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return 0 ;
}
dl - > populate = _populate_snapshot ;
_set_flag ( dl , VISIBLE ) ;
2003-05-06 16:00:29 +04:00
_set_flag ( dl , TOPLEVEL ) ;
2002-02-26 17:44:13 +03:00
2003-07-05 02:34:56 +04:00
/* add the dependency on the cow device */
2003-09-18 00:35:57 +04:00
if ( ! str_list_add ( dm - > mem , & dl - > pre_create ,
pool_strdup ( dm - > mem , cow_dlid ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return 0 ;
}
2002-02-26 17:44:13 +03:00
2003-07-05 02:34:56 +04:00
/* add the dependency on the real origin device */
2003-09-18 00:35:57 +04:00
if ( ! str_list_add ( dm - > mem , & dl - > pre_create ,
_build_dlid ( dm - > mem , s - > origin - > lvid . s , " real " ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return 0 ;
}
2002-02-25 15:02:33 +03:00
2003-07-05 02:34:56 +04:00
/* add the dependency on the visible origin device */
2003-09-18 00:35:57 +04:00
if ( ! str_list_add ( dm - > mem , & dl - > pre_suspend , s - > origin - > lvid . s ) ) {
2003-07-05 02:34:56 +04:00
stack ;
return 0 ;
}
2002-02-25 15:02:33 +03:00
return 1 ;
}
2002-03-07 20:37:38 +03:00
/*
* Inserts the appropriate dev_layers for a logical volume .
*/
static int _expand_lv ( struct dev_manager * dm , struct logical_volume * lv )
{
struct snapshot * s ;
/*
* FIXME : this doesn ' t cope with recursive snapshots yet .
*/
if ( ( s = find_cow ( lv ) ) )
return _expand_snapshot ( dm , lv , s ) ;
else if ( lv_is_origin ( lv ) )
return _expand_origin ( dm , lv ) ;
2003-07-05 02:34:56 +04:00
return _expand_vanilla ( dm , lv , 0 ) ;
2002-03-07 20:37:38 +03:00
}
2002-02-25 15:02:33 +03:00
/*
* Clears the mark bit on all layers .
*/
2002-03-11 23:36:04 +03:00
static void _clear_marks ( struct dev_manager * dm , int flag )
2002-02-25 15:02:33 +03:00
{
struct hash_node * hn ;
struct dev_layer * dl ;
2002-03-15 00:17:30 +03:00
hash_iterate ( hn , dm - > layers ) {
2002-02-25 15:02:33 +03:00
dl = hash_get_data ( dm - > layers , hn ) ;
2002-03-11 23:36:04 +03:00
_clear_flag ( dl , flag ) ;
2002-02-25 15:02:33 +03:00
}
}
/*
2002-03-11 23:36:04 +03:00
* Propogates marks via the pre_create dependency list .
2002-02-25 15:02:33 +03:00
*/
2002-03-11 23:36:04 +03:00
static int _trace_layer_marks ( struct dev_manager * dm , struct dev_layer * dl ,
int flag )
2002-02-25 15:02:33 +03:00
{
struct list * sh ;
2003-07-05 02:34:56 +04:00
const char * dlid ;
2002-02-25 15:02:33 +03:00
struct dev_layer * dep ;
2002-03-15 00:17:30 +03:00
list_iterate ( sh , & dl - > pre_create ) {
2002-03-19 02:25:50 +03:00
dlid = list_item ( sh , struct str_list ) - > str ;
2002-02-25 15:02:33 +03:00
2002-03-19 02:25:50 +03:00
if ( ! ( dep = hash_lookup ( dm - > layers , dlid ) ) ) {
log_error ( " Couldn't find device layer '%s'. " , dlid ) ;
2002-02-25 15:02:33 +03:00
return 0 ;
}
2002-03-11 23:36:04 +03:00
if ( _get_flag ( dep , flag ) )
2002-02-25 15:02:33 +03:00
continue ;
2003-05-06 16:00:29 +04:00
/* FIXME Only propagate LV ACTIVE dependencies for now */
2003-04-25 02:09:13 +04:00
if ( ( flag ! = ACTIVE ) & & _get_flag ( dl , NOPROPAGATE ) )
continue ;
2002-03-11 23:36:04 +03:00
_set_flag ( dep , flag ) ;
2002-02-25 15:02:33 +03:00
2002-03-11 23:36:04 +03:00
if ( ! _trace_layer_marks ( dm , dep , flag ) ) {
2002-02-25 15:02:33 +03:00
stack ;
return 0 ;
}
}
return 1 ;
}
2002-03-11 23:36:04 +03:00
/*
* Calls _trace_single for every marked layer .
*/
static int _trace_all_marks ( struct dev_manager * dm , int flag )
2002-02-25 15:02:33 +03:00
{
2002-03-11 23:36:04 +03:00
struct hash_node * hn ;
struct dev_layer * dl ;
2002-03-15 00:17:30 +03:00
hash_iterate ( hn , dm - > layers ) {
2002-03-11 23:36:04 +03:00
dl = hash_get_data ( dm - > layers , hn ) ;
if ( _get_flag ( dl , flag ) & & ! _trace_layer_marks ( dm , dl , flag ) ) {
stack ;
return 0 ;
}
}
return 1 ;
}
/*
* Marks the top layers , then traces these through the
* dependencies .
*/
static int _mark_lvs ( struct dev_manager * dm , struct list * lvs , int flag )
{
struct list * lvh ;
struct logical_volume * lv ;
struct dev_layer * dl ;
2002-03-15 00:17:30 +03:00
list_iterate ( lvh , lvs ) {
2002-03-11 23:36:04 +03:00
lv = list_item ( lvh , struct lv_list ) - > lv ;
2002-03-19 02:25:50 +03:00
if ( ! ( dl = _lookup ( dm , lv - > lvid . s , NULL ) ) ) {
2002-03-11 23:36:04 +03:00
stack ;
return 0 ;
}
_set_flag ( dl , flag ) ;
}
if ( ! _trace_all_marks ( dm , flag ) ) {
stack ;
return 0 ;
}
return 1 ;
2002-02-25 15:02:33 +03:00
}
2003-07-05 02:34:56 +04:00
static int _suspend_parents ( struct dev_manager * dm , struct dev_layer * dl )
2002-03-27 21:17:43 +03:00
{
2003-07-05 02:34:56 +04:00
struct list * sh ;
struct dev_layer * dep ;
const char * dlid ;
list_iterate ( sh , & dl - > pre_suspend ) {
dlid = list_item ( sh , struct str_list ) - > str ;
if ( ! ( dep = hash_lookup ( dm - > layers , dlid ) ) ) {
log_debug ( " _suspend_parents couldn't find device "
" layer '%s' - skipping. " , dlid ) ;
continue ;
}
if ( ! strcmp ( dep - > dlid , dl - > dlid ) ) {
log_error ( " BUG: pre-suspend loop detected (%s) " , dlid ) ;
return 0 ;
}
if ( ! _suspend_parents ( dm , dep ) ) {
stack ;
return 0 ;
}
if ( dep - > info . exists & ! _suspend ( dep ) ) {
stack ;
return 0 ;
}
}
return 1 ;
}
static int _resume_with_deps ( struct dev_manager * dm , struct dev_layer * dl )
{
struct list * sh ;
struct dev_layer * dep ;
const char * dlid ;
list_iterate ( sh , & dl - > pre_create ) {
dlid = list_item ( sh , struct str_list ) - > str ;
if ( ! ( dep = hash_lookup ( dm - > layers , dlid ) ) ) {
log_debug ( " _resume_with_deps couldn't find device "
" layer '%s' - skipping. " , dlid ) ;
continue ;
}
if ( ! strcmp ( dep - > dlid , dl - > dlid ) ) {
log_error ( " BUG: pre-create loop detected (%s) " , dlid ) ;
return 0 ;
}
if ( ! _resume_with_deps ( dm , dep ) ) {
stack ;
return 0 ;
}
}
2003-08-20 16:53:57 +04:00
if ( dl - > info . exists & ! _get_flag ( dl , SUSPENDED ) & & ! _resume ( dl ) ) {
2003-07-05 02:34:56 +04:00
stack ;
return 0 ;
}
return 1 ;
2002-03-27 21:17:43 +03:00
}
2002-02-25 15:02:33 +03:00
/*
* Recurses through the tree , ensuring that devices are created
* in correct order .
*/
2003-07-05 02:34:56 +04:00
static int _create_rec ( struct dev_manager * dm , struct dev_layer * dl )
2002-02-25 15:02:33 +03:00
{
struct list * sh ;
struct dev_layer * dep ;
2003-07-05 02:34:56 +04:00
const char * dlid ;
char * newname , * suffix ;
2002-02-25 15:02:33 +03:00
2002-03-27 21:17:43 +03:00
/* Suspend? */
2003-07-05 02:34:56 +04:00
if ( _get_flag ( dl , SUSPENDED ) & &
( ! _suspend_parents ( dm , dl ) | | ! _suspend ( dl ) ) ) {
2002-03-27 21:17:43 +03:00
stack ;
return 0 ;
}
2002-03-15 00:17:30 +03:00
list_iterate ( sh , & dl - > pre_create ) {
2002-03-19 02:25:50 +03:00
dlid = list_item ( sh , struct str_list ) - > str ;
2002-02-25 15:02:33 +03:00
2002-03-19 02:25:50 +03:00
if ( ! ( dep = hash_lookup ( dm - > layers , dlid ) ) ) {
log_error ( " Couldn't find device layer '%s'. " , dlid ) ;
2002-02-25 15:02:33 +03:00
return 0 ;
}
2002-03-19 02:25:50 +03:00
if ( ! strcmp ( dep - > dlid , dl - > dlid ) ) {
log_error ( " BUG: pre-create loop detected (%s) " , dlid ) ;
return 0 ;
}
2003-07-05 02:34:56 +04:00
if ( ! _create_rec ( dm , dep ) ) {
2002-02-25 15:02:33 +03:00
stack ;
return 0 ;
}
2002-03-16 01:59:12 +03:00
}
2002-03-08 13:41:48 +03:00
2002-03-19 02:25:50 +03:00
/* Rename? */
if ( dl - > info . exists ) {
2002-03-19 19:41:44 +03:00
if ( ( suffix = rindex ( dl - > dlid , ' - ' ) ) )
suffix + + ;
newname = _build_name ( dm - > mem , dm - > vg_name , dl - > lv - > name ,
suffix ) ;
if ( strcmp ( newname , dl - > name ) ) {
2003-07-05 02:34:56 +04:00
if ( ! _suspend_parents ( dm , dl ) | |
2002-12-20 02:25:55 +03:00
! _suspend ( dl ) | | ! _rename ( dl , newname ) ) {
2002-03-19 02:25:50 +03:00
stack ;
return 0 ;
}
}
}
2002-03-16 01:59:12 +03:00
/* Create? */
if ( ! dl - > info . exists ) {
2003-07-05 02:34:56 +04:00
if ( ! _suspend_parents ( dm , dl ) | |
2002-03-27 21:17:43 +03:00
! _load ( dm , dl , DM_DEVICE_CREATE ) ) {
2002-02-25 15:02:33 +03:00
stack ;
return 0 ;
}
2002-03-16 01:59:12 +03:00
return 1 ;
}
2002-03-27 21:17:43 +03:00
/* Reload? */
if ( _get_flag ( dl , RELOAD ) & &
2003-07-05 02:34:56 +04:00
( ! _suspend_parents ( dm , dl ) | | ! _suspend ( dl ) | |
2002-03-27 21:17:43 +03:00
! _load ( dm , dl , DM_DEVICE_RELOAD ) ) ) {
2002-03-16 01:59:12 +03:00
stack ;
return 0 ;
}
2002-02-25 15:02:33 +03:00
return 1 ;
}
2002-03-11 23:36:04 +03:00
static int _build_all_layers ( struct dev_manager * dm , struct volume_group * vg )
2002-02-25 19:53:12 +03:00
{
2002-03-11 23:36:04 +03:00
struct list * lvh ;
struct logical_volume * lvt ;
2002-02-25 19:53:12 +03:00
2002-03-11 23:36:04 +03:00
/*
* Build layers for complete vg .
*/
2002-03-15 00:17:30 +03:00
list_iterate ( lvh , & vg - > lvs ) {
2002-03-11 23:36:04 +03:00
lvt = list_item ( lvh , struct lv_list ) - > lv ;
if ( ! _expand_lv ( dm , lvt ) ) {
2002-02-25 19:53:12 +03:00
stack ;
return 0 ;
}
}
return 1 ;
}
2002-03-11 23:36:04 +03:00
static int _fill_in_remove_list ( struct dev_manager * dm )
2002-02-25 15:02:33 +03:00
{
struct hash_node * hn ;
struct dev_layer * dl ;
2002-03-11 23:36:04 +03:00
struct dl_list * dll ;
2002-02-25 15:02:33 +03:00
2002-03-15 00:17:30 +03:00
hash_iterate ( hn , dm - > layers ) {
2002-02-25 15:02:33 +03:00
dl = hash_get_data ( dm - > layers , hn ) ;
2003-07-05 02:34:56 +04:00
if ( _get_flag ( dl , REMOVE ) )
_clear_flag ( dl , ACTIVE ) ;
2002-03-11 23:36:04 +03:00
if ( ! _get_flag ( dl , ACTIVE ) ) {
dll = pool_alloc ( dm - > mem , sizeof ( * dll ) ) ;
if ( ! dll ) {
2002-02-25 15:02:33 +03:00
stack ;
return 0 ;
}
2002-03-11 23:36:04 +03:00
dll - > dl = dl ;
list_add ( & dm - > remove_list , & dll - > list ) ;
2002-02-25 15:02:33 +03:00
}
}
2002-02-25 19:53:12 +03:00
return 1 ;
}
2003-07-05 02:34:56 +04:00
static int _populate_pre_suspend_lists ( struct dev_manager * dm )
{
struct hash_node * hn ;
struct dev_layer * dl ;
struct list * sh ;
const char * dlid ;
struct dev_layer * dep ;
hash_iterate ( hn , dm - > layers ) {
dl = hash_get_data ( dm - > layers , hn ) ;
list_iterate ( sh , & dl - > pre_suspend ) {
dlid = list_item ( sh , struct str_list ) - > str ;
if ( ! ( dep = hash_lookup ( dm - > layers , dlid ) ) ) {
log_debug ( " _populate_pre_suspend_lists: "
" Couldn't find device layer '%s' - "
" skipping. " , dlid ) ;
continue ;
}
2004-05-05 01:25:57 +04:00
if ( ! str_list_add ( dm - > mem , & dep - > pre_create , dl - > dlid ) ) {
2003-07-05 02:34:56 +04:00
stack ;
return 0 ;
}
}
list_iterate ( sh , & dl - > pre_create ) {
dlid = list_item ( sh , struct str_list ) - > str ;
if ( ! ( dep = hash_lookup ( dm - > layers , dlid ) ) ) {
log_debug ( " _populate_pre_suspend_lists: "
" Couldn't find device layer '%s' - "
" skipping. " , dlid ) ;
continue ;
}
2004-05-05 01:25:57 +04:00
if ( ! str_list_add ( dm - > mem , & dep - > pre_suspend , dl - > dlid ) ) {
2003-07-05 02:34:56 +04:00
stack ;
return 0 ;
}
}
}
return 1 ;
}
2002-02-25 15:02:33 +03:00
/*
2002-03-11 23:36:04 +03:00
* Layers are removed in a top - down manner .
2002-02-25 15:02:33 +03:00
*/
2002-12-20 02:25:55 +03:00
static int _remove_old_layers ( struct dev_manager * dm )
2002-02-25 15:02:33 +03:00
{
2002-03-11 23:36:04 +03:00
int change ;
2002-03-16 01:59:12 +03:00
struct list * rh , * n ;
struct dev_layer * dl ;
2002-02-25 15:02:33 +03:00
2002-03-11 23:36:04 +03:00
do {
change = 0 ;
2002-03-15 00:17:30 +03:00
list_iterate_safe ( rh , n , & dm - > remove_list ) {
2002-03-11 23:36:04 +03:00
dl = list_item ( rh , struct dl_list ) - > dl ;
2002-02-25 15:02:33 +03:00
2002-03-15 00:17:30 +03:00
if ( ! dl - > info . exists ) {
list_del ( rh ) ;
continue ;
}
2002-02-25 15:02:33 +03:00
2002-03-16 01:59:12 +03:00
if ( _remove ( dl ) ) {
2002-03-15 00:17:30 +03:00
change = 1 ;
2002-03-11 23:36:04 +03:00
list_del ( rh ) ;
}
2002-02-25 15:02:33 +03:00
}
2002-03-15 00:17:30 +03:00
} while ( change ) ;
2002-02-26 17:44:13 +03:00
2002-03-11 23:36:04 +03:00
if ( ! list_empty ( & dm - > remove_list ) ) {
2002-03-16 01:59:12 +03:00
list_iterate ( rh , & dm - > remove_list ) {
dl = list_item ( rh , struct dl_list ) - > dl ;
log_error ( " Couldn't deactivate device %s " , dl - > name ) ;
}
2002-02-25 15:02:33 +03:00
return 0 ;
}
2002-02-25 17:46:57 +03:00
return 1 ;
}
2002-02-26 14:49:17 +03:00
/*
* The guts of the activation unit , this examines the device
* layers in the manager , and tries to issue the correct
* instructions to activate them in order .
*/
2002-03-11 23:36:04 +03:00
static int _execute ( struct dev_manager * dm , struct volume_group * vg )
2002-02-25 17:46:57 +03:00
{
2002-02-26 14:49:17 +03:00
struct hash_node * hn ;
struct dev_layer * dl ;
2002-03-11 23:36:04 +03:00
if ( ! _build_all_layers ( dm , vg ) ) {
stack ;
return 0 ;
}
/*
2002-03-27 21:17:43 +03:00
* Mark all layer that need reloading .
2002-03-11 23:36:04 +03:00
*/
2002-03-27 21:17:43 +03:00
_clear_marks ( dm , RELOAD ) ;
if ( ! _mark_lvs ( dm , & dm - > reload_list , RELOAD ) ) {
2002-02-25 17:46:57 +03:00
stack ;
return 0 ;
}
2002-02-25 15:02:33 +03:00
2002-02-26 14:49:17 +03:00
/*
2002-03-27 21:17:43 +03:00
* Mark all layers that should be active .
2002-02-26 14:49:17 +03:00
*/
2002-03-11 23:36:04 +03:00
_clear_marks ( dm , ACTIVE ) ;
if ( ! _mark_lvs ( dm , & dm - > active_list , ACTIVE ) ) {
stack ;
return 0 ;
}
2002-03-27 21:17:43 +03:00
/*
* Mark all layers that should be left suspended .
*/
_clear_marks ( dm , SUSPENDED ) ;
if ( ! _mark_lvs ( dm , & dm - > suspend_list , SUSPENDED ) ) {
stack ;
return 0 ;
}
2002-03-11 23:36:04 +03:00
if ( ! _fill_in_remove_list ( dm ) ) {
2002-02-25 15:02:33 +03:00
stack ;
return 0 ;
}
2003-07-05 02:34:56 +04:00
if ( ! _populate_pre_suspend_lists ( dm ) ) {
stack ;
return 0 ;
}
2002-02-26 14:49:17 +03:00
/*
* Now only top level devices will be unmarked .
*/
2002-03-15 00:17:30 +03:00
hash_iterate ( hn , dm - > layers ) {
2002-02-26 14:49:17 +03:00
dl = hash_get_data ( dm - > layers , hn ) ;
2003-05-06 16:00:29 +04:00
if ( _get_flag ( dl , ACTIVE ) & & _get_flag ( dl , TOPLEVEL ) )
2003-07-05 02:34:56 +04:00
if ( ! _create_rec ( dm , dl ) ) {
stack ;
return 0 ;
}
}
/* Resume devices */
hash_iterate ( hn , dm - > layers ) {
dl = hash_get_data ( dm - > layers , hn ) ;
if ( ! _resume_with_deps ( dm , dl ) ) {
stack ;
return 0 ;
}
2002-03-11 23:36:04 +03:00
}
if ( ! _remove_old_layers ( dm ) ) {
stack ;
return 0 ;
2002-02-26 14:49:17 +03:00
}
2002-02-25 15:02:33 +03:00
return 1 ;
}
2002-03-07 20:37:38 +03:00
/*
* ATM we decide which vg a layer belongs to by
* looking at the beginning of the device
* name .
*/
2002-03-19 19:41:44 +03:00
static int _belong_to_vg ( const char * vgname , const char * name )
2002-03-07 20:37:38 +03:00
{
2002-03-19 19:41:44 +03:00
const char * v = vgname , * n = name ;
while ( * v ) {
2002-03-26 16:41:37 +03:00
if ( ( * v ! = * n ) | | ( * v = = ' - ' & & * ( + + n ) ! = ' - ' ) )
2002-03-19 19:41:44 +03:00
return 0 ;
v + + , n + + ;
}
2002-03-26 16:41:37 +03:00
if ( * n = = ' - ' & & * ( n + 1 ) ! = ' - ' )
2002-03-19 19:41:44 +03:00
return 1 ;
else
return 0 ;
2002-03-07 20:37:38 +03:00
}
static int _add_existing_layer ( struct dev_manager * dm , const char * name )
{
2002-03-15 00:17:30 +03:00
struct dev_layer * dl ;
2002-03-07 20:37:38 +03:00
char * copy ;
2002-03-15 00:17:30 +03:00
log_debug ( " Found existing layer '%s' " , name ) ;
2002-03-11 14:27:48 +03:00
2002-03-07 20:37:38 +03:00
if ( ! ( copy = pool_strdup ( dm - > mem , name ) ) ) {
stack ;
return 0 ;
}
2002-03-19 02:25:50 +03:00
if ( ! ( dl = _create_dev ( dm , copy , " " ) ) ) {
2002-03-07 20:37:38 +03:00
stack ;
return 0 ;
}
return 1 ;
}
static int _scan_existing_devices ( struct dev_manager * dm )
{
2003-07-05 02:34:56 +04:00
int r = 0 ;
struct dm_names * names ;
unsigned next = 0 ;
2002-03-07 20:37:38 +03:00
2003-07-05 02:34:56 +04:00
struct dm_task * dmt ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_LIST ) ) )
2002-03-07 20:37:38 +03:00
return 0 ;
2003-07-05 02:34:56 +04:00
if ( ! dm_task_run ( dmt ) )
goto out ;
2002-03-07 20:37:38 +03:00
2003-07-05 02:34:56 +04:00
if ( ! ( names = dm_task_get_names ( dmt ) ) )
goto out ;
2002-03-07 20:37:38 +03:00
2003-07-05 02:34:56 +04:00
r = 1 ;
if ( ! names - > dev )
goto out ;
do {
names = ( void * ) names + next ;
if ( _belong_to_vg ( dm - > vg_name , names - > name ) & &
! _add_existing_layer ( dm , names - > name ) ) {
2002-03-07 20:37:38 +03:00
stack ;
r = 0 ;
break ;
}
2003-07-05 02:34:56 +04:00
next = names - > next ;
} while ( next ) ;
2002-03-07 20:37:38 +03:00
2003-07-05 02:34:56 +04:00
out :
dm_task_destroy ( dmt ) ;
2002-03-07 20:37:38 +03:00
return r ;
}
2002-03-11 23:36:04 +03:00
static int _add_lv ( struct pool * mem ,
struct list * head , struct logical_volume * lv )
2002-03-11 14:27:48 +03:00
{
struct lv_list * lvl ;
2002-03-11 23:36:04 +03:00
if ( ! ( lvl = pool_alloc ( mem , sizeof ( * lvl ) ) ) ) {
2002-03-11 14:27:48 +03:00
stack ;
return 0 ;
}
lvl - > lv = lv ;
2002-03-11 23:36:04 +03:00
list_add ( head , & lvl - > list ) ;
2002-03-11 14:27:48 +03:00
return 1 ;
}
2002-03-18 16:09:27 +03:00
static int _add_lvs ( struct pool * mem ,
struct list * head , struct logical_volume * origin )
{
struct logical_volume * lv ;
struct snapshot * s ;
struct list * lvh ;
list_iterate ( lvh , & origin - > vg - > lvs ) {
lv = list_item ( lvh , struct lv_list ) - > lv ;
if ( ( s = find_cow ( lv ) ) & & s - > origin = = origin )
if ( ! _add_lv ( mem , head , lv ) )
return 0 ;
}
return _add_lv ( mem , head , origin ) ;
}
2002-03-11 23:36:04 +03:00
static void _remove_lv ( struct list * head , struct logical_volume * lv )
{
struct list * lvh ;
struct lv_list * lvl ;
2002-03-15 00:17:30 +03:00
list_iterate ( lvh , head ) {
2002-03-11 23:36:04 +03:00
lvl = list_item ( lvh , struct lv_list ) ;
if ( lvl - > lv = = lv ) {
list_del ( lvh ) ;
break ;
}
}
}
2002-04-16 18:42:20 +04:00
static int _remove_lvs ( struct dev_manager * dm , struct logical_volume * lv )
2002-03-18 16:09:27 +03:00
{
2002-04-16 18:42:20 +04:00
struct logical_volume * active , * old_origin ;
2002-03-18 16:09:27 +03:00
struct snapshot * s ;
2002-04-16 18:42:20 +04:00
struct list * sh , * active_head ;
active_head = & dm - > active_list ;
/* Remove any snapshots with given origin */
list_iterate ( sh , active_head ) {
active = list_item ( sh , struct lv_list ) - > lv ;
2002-04-24 22:20:51 +04:00
if ( ( s = find_cow ( active ) ) & & s - > origin = = lv ) {
2002-04-16 18:42:20 +04:00
_remove_lv ( active_head , active ) ;
2002-04-24 22:20:51 +04:00
}
2002-04-16 18:42:20 +04:00
}
2002-03-18 16:09:27 +03:00
2002-04-16 18:42:20 +04:00
_remove_lv ( active_head , lv ) ;
if ( ! ( s = find_cow ( lv ) ) )
return 1 ;
old_origin = s - > origin ;
/* Was this the last active snapshot with this origin? */
list_iterate ( sh , active_head ) {
2002-03-18 16:09:27 +03:00
active = list_item ( sh , struct lv_list ) - > lv ;
2002-04-24 22:20:51 +04:00
if ( ( s = find_cow ( active ) ) & & s - > 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
}
2002-04-16 18:42:20 +04:00
return _add_lvs ( dm - > mem , & dm - > reload_list , old_origin ) ;
2002-03-18 16:09:27 +03:00
}
2003-04-25 02:09:13 +04:00
static int _remove_suspended_lvs ( struct dev_manager * dm ,
struct logical_volume * lv )
{
struct logical_volume * suspended ;
struct snapshot * s ;
struct list * sh , * suspend_head ;
suspend_head = & dm - > suspend_list ;
/* Remove from list any snapshots with given origin */
list_iterate ( sh , suspend_head ) {
suspended = list_item ( sh , struct lv_list ) - > lv ;
if ( ( s = find_cow ( suspended ) ) & & s - > origin = = lv ) {
_remove_lv ( suspend_head , suspended ) ;
}
}
_remove_lv ( suspend_head , lv ) ;
return 1 ;
}
2004-05-05 22:11:43 +04:00
static int _targets_present ( struct dev_manager * dm , struct list * lvs )
{
struct logical_volume * lv ;
struct list * lvh ;
struct segment_type * segtype ;
int snapshots = 0 , mirrors = 0 ;
list_iterate ( lvh , lvs ) {
lv = list_item ( lvh , struct lv_list ) - > lv ;
if ( ! snapshots )
if ( lv_is_cow ( lv ) | | lv_is_origin ( lv ) )
snapshots = 1 ;
if ( ! mirrors )
if ( lv - > status & PVMOVE )
mirrors = 1 ;
}
if ( mirrors ) {
if ( ! ( segtype = get_segtype_from_string ( dm - > cmd , " mirror " ) ) ) {
log_error ( " Can't expand LV: Mirror support "
" missing from tools? " ) ;
return 0 ;
}
if ( ! segtype - > ops - > target_present | |
! segtype - > ops - > target_present ( ) ) {
log_error ( " Can't expand LV: Mirror support missing "
" from kernel? " ) ;
return 0 ;
}
}
if ( snapshots ) {
if ( ! ( segtype = get_segtype_from_string ( dm - > cmd , " snapshot " ) ) ) {
log_error ( " Can't expand LV: Snapshot support "
" missing from tools? " ) ;
return 0 ;
}
if ( ! segtype - > ops - > target_present | |
! segtype - > ops - > target_present ( ) ) {
log_error ( " Can't expand LV: Snapshot support missing "
" from kernel? " ) ;
return 0 ;
}
}
return 1 ;
}
2002-03-15 00:17:30 +03:00
static int _fill_in_active_list ( struct dev_manager * dm , struct volume_group * vg )
2002-03-11 14:27:48 +03:00
{
2002-03-19 02:25:50 +03:00
char * dlid ;
2002-03-11 14:27:48 +03:00
struct list * lvh ;
struct logical_volume * lv ;
2003-04-25 02:09:13 +04:00
struct dev_layer * dl ;
2002-03-11 14:27:48 +03:00
2002-03-15 00:17:30 +03:00
list_iterate ( lvh , & vg - > lvs ) {
2002-03-11 14:27:48 +03:00
lv = list_item ( lvh , struct lv_list ) - > lv ;
2002-03-19 02:25:50 +03:00
if ( ! ( dlid = _build_dlid ( dm - > mem , lv - > lvid . s , NULL ) ) ) {
2002-03-11 14:27:48 +03:00
stack ;
return 0 ;
}
2003-04-25 02:09:13 +04:00
dl = hash_lookup ( dm - > layers , dlid ) ;
2002-03-19 02:25:50 +03:00
pool_free ( dm - > mem , dlid ) ;
2002-03-11 14:27:48 +03:00
2003-04-25 02:09:13 +04:00
if ( dl ) {
log_debug ( " Found active lv %s%s " , lv - > name ,
dl - > info . suspended ? " (suspended) " : " " ) ;
2002-03-11 23:36:04 +03:00
if ( ! _add_lv ( dm - > mem , & dm - > active_list , lv ) ) {
stack ;
return 0 ;
}
2003-04-25 02:09:13 +04:00
if ( dl - > info . suspended ) {
if ( ! _add_lv ( dm - > mem , & dm - > suspend_list , lv ) ) {
stack ;
return 0 ;
}
}
2002-03-11 14:27:48 +03:00
}
}
return 1 ;
}
2002-03-27 21:17:43 +03:00
static int _action ( struct dev_manager * dm , struct logical_volume * lv ,
action_t action )
2002-03-11 14:27:48 +03:00
{
if ( ! _scan_existing_devices ( dm ) ) {
stack ;
return 0 ;
}
if ( ! _fill_in_active_list ( dm , lv - > vg ) ) {
stack ;
return 0 ;
}
2002-03-27 21:17:43 +03:00
if ( action = = ACTIVATE | | action = = DEACTIVATE )
/* Get into known state - remove from active list if present */
2002-04-16 18:42:20 +04:00
if ( ! _remove_lvs ( dm , lv ) ) {
stack ;
return 0 ;
}
2002-03-16 01:59:12 +03:00
2002-03-27 21:17:43 +03:00
if ( action = = ACTIVATE ) {
/* Add to active & reload lists */
if ( ! _add_lvs ( dm - > mem , & dm - > reload_list , lv ) | |
2002-03-18 16:09:27 +03:00
! _add_lvs ( dm - > mem , & dm - > active_list , lv ) ) {
2002-03-16 01:59:12 +03:00
stack ;
return 0 ;
}
2002-03-11 14:27:48 +03:00
}
2003-04-25 02:09:13 +04:00
if ( action = = SUSPEND | | action = = RESUME | | action = = ACTIVATE )
/* Get into known state - remove from suspend list if present */
if ( ! _remove_suspended_lvs ( dm , lv ) ) {
stack ;
return 0 ;
}
2002-03-27 21:17:43 +03:00
if ( action = = SUSPEND ) {
if ( ! _add_lvs ( dm - > mem , & dm - > suspend_list , lv ) ) {
stack ;
return 0 ;
}
}
2004-05-05 22:11:43 +04:00
if ( ! _targets_present ( dm , & dm - > active_list ) | |
! _targets_present ( dm , & dm - > reload_list ) ) {
stack ;
return 0 ;
}
2002-03-11 23:36:04 +03:00
if ( ! _execute ( dm , lv - > vg ) ) {
2002-03-11 14:27:48 +03:00
stack ;
return 0 ;
}
return 1 ;
}
2002-03-16 01:59:12 +03:00
int dev_manager_activate ( struct dev_manager * dm , struct logical_volume * lv )
2002-03-11 14:27:48 +03:00
{
2002-03-27 21:17:43 +03:00
return _action ( dm , lv , ACTIVATE ) ;
2002-03-16 01:59:12 +03:00
}
2002-03-11 14:27:48 +03:00
2002-03-16 01:59:12 +03:00
int dev_manager_deactivate ( struct dev_manager * dm , struct logical_volume * lv )
{
2002-03-27 21:17:43 +03:00
return _action ( dm , lv , DEACTIVATE ) ;
}
int dev_manager_suspend ( struct dev_manager * dm , struct logical_volume * lv )
{
return _action ( dm , lv , SUSPEND ) ;
2002-03-11 14:27:48 +03:00
}
2003-07-05 02:34:56 +04:00
2004-03-30 18:38:57 +04:00
int dev_manager_lv_mknodes ( const struct logical_volume * lv )
2003-11-12 22:16:48 +03:00
{
char * name ;
if ( ! ( name = _build_name ( lv - > vg - > cmd - > mem , lv - > vg - > name ,
lv - > name , NULL ) ) ) {
stack ;
return 0 ;
}
return fs_add_lv ( lv , name ) ;
}
2004-03-30 18:38:57 +04:00
int dev_manager_lv_rmnodes ( const struct logical_volume * lv )
2003-11-12 22:16:48 +03:00
{
return fs_del_lv ( lv ) ;
}
2004-03-30 18:40:03 +04:00
int dev_manager_mknodes ( void )
{
struct dm_task * dmt ;
int r ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_MKNODES ) ) )
return 0 ;
r = dm_task_run ( dmt ) ;
dm_task_destroy ( dmt ) ;
return r ;
}
2003-07-05 02:34:56 +04:00
void dev_manager_exit ( void )
{
dm_lib_exit ( ) ;
}