2002-02-25 15:02:33 +03:00
/*
* Copyright ( C ) 2002 Sistina Software ( UK ) Limited .
*
* This file is released under the LGPL .
*/
# include "dev_manager.h"
# include "pool.h"
# include "hash.h"
# include "log.h"
2002-02-25 19:53:12 +03:00
# include "lvm-string.h"
2002-02-26 14:49:17 +03:00
# include "fs.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
*
*/
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 ,
SUSPENDED = 4
2002-03-07 19:48:46 +03: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 */
char * dlid ;
2002-02-25 15:02:33 +03:00
struct logical_volume * lv ;
/*
* Devices that must be created before this one can be
* created . Holds str_lists .
*/
2002-03-15 00:17:30 +03:00
struct list pre_create ;
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 ;
} ;
2002-02-25 15:02:33 +03:00
struct dev_manager {
struct pool * mem ;
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-04-03 16:17:55 +04:00
static int _pre_list_add ( struct pool * mem , struct list * pl , char * str )
{
struct str_list * sl ;
struct list * plh ;
if ( ! str ) {
stack ;
return 0 ;
}
list_iterate ( plh , pl ) {
}
if ( ! ( sl = pool_alloc ( mem , sizeof ( * sl ) ) ) ) {
stack ;
return 0 ;
}
sl - > str = str ;
list_add ( pl , & sl - > list ) ;
return 1 ;
}
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-03-15 00:17:30 +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 ;
int len ;
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 .
*/
2002-03-25 21:54:59 +03:00
static struct dm_task * _setup_task ( const char * name , const char * uuid , 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 ) ;
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 ,
2002-03-26 16:41:37 +03:00
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 ;
2002-03-15 00:17:30 +03:00
2002-03-25 21:54:59 +03:00
if ( ! ( dmt = _setup_task ( name , uuid , DM_DEVICE_INFO ) ) ) {
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
2002-03-25 21:54:59 +03:00
static int _info ( const char * name , const char * uuid , struct dm_info * info ,
struct pool * mem , char * * uuid_out )
{
2002-03-26 16:41:37 +03:00
if ( uuid & & * uuid & & _info_run ( NULL , uuid , info , mem , uuid_out )
2002-03-25 21:54:59 +03:00
& & info - > exists )
return 1 ;
if ( name )
return _info_run ( name , NULL , info , mem , uuid_out ) ;
return 0 ;
}
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 ;
unsigned long long start , length ;
char * type = NULL ;
2002-05-10 20:06:06 +04:00
char * params = NULL ;
2002-05-10 01:17:57 +04:00
if ( ! ( dmt = _setup_task ( name , uuid , DM_DEVICE_STATUS ) ) ) {
stack ;
return 0 ;
}
if ( ! dm_task_run ( dmt ) ) {
stack ;
goto out ;
}
do {
next = dm_get_next_target ( dmt , next , & start , & length ,
& type , & params ) ;
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 ) ;
( * t ) [ t_size - 1 ] = ' \0 ' ;
strncpy ( * p , params , p_size ) ;
( * p ) [ p_size - 1 ] = ' \0 ' ;
r = 1 ;
break ;
2002-05-10 01:17:57 +04:00
}
} while ( next ) ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
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 ,
params , param_size ) )
2002-05-10 01:17:57 +04:00
return 1 ;
return 0 ;
}
2002-03-19 02:25:50 +03:00
static int _rename ( struct dev_manager * dm , struct dev_layer * dl , char * newname )
{
int r = 1 ;
struct dm_task * dmt ;
log_verbose ( " Renaming %s to %s " , dl - > name , newname ) ;
2002-03-25 21:54:59 +03:00
if ( ! ( dmt = _setup_task ( dl - > name , NULL , 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 ;
}
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 ,
dl - > dlid , 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
/*
* Do we want a specific minor number ?
*/
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
2002-02-25 17:46:57 +03:00
if ( ! ( r = dm_task_run ( dmt ) ) )
2002-03-15 00:17:30 +03:00
log_error ( " Couldn't load device '%s'. " , dl - > name ) ;
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
}
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
2002-03-25 21:54:59 +03:00
if ( ! ( dmt = _setup_task ( dl - > name , NULL , 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-03-27 21:17:43 +03:00
static int _suspend_or_resume ( const char * name , action_t suspend )
2002-02-25 17:46:57 +03:00
{
int r ;
struct dm_task * dmt ;
2002-03-16 01:59:12 +03:00
int sus = ( suspend = = SUSPEND ) ? 1 : 0 ;
2002-02-25 17:46:57 +03:00
int task = sus ? DM_DEVICE_SUSPEND : DM_DEVICE_RESUME ;
log_very_verbose ( " %s %s " , sus ? " Suspending " : " Resuming " , name ) ;
2002-03-25 21:54:59 +03:00
if ( ! ( dmt = _setup_task ( name , NULL , task ) ) ) {
2002-02-25 17:46:57 +03:00
stack ;
return 0 ;
}
if ( ! ( r = dm_task_run ( dmt ) ) )
2002-03-15 00:17:30 +03:00
log_error ( " Couldn't %s device '%s' " , sus ? " suspend " : " resume " ,
name ) ;
2002-02-25 17:46:57 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
static int _suspend ( struct dev_layer * dl )
{
if ( dl - > info . suspended )
return 1 ;
2002-03-16 01:59:12 +03:00
if ( ! _suspend_or_resume ( dl - > name , SUSPEND ) ) {
2002-02-26 14:49:17 +03:00
stack ;
return 0 ;
}
dl - > info . suspended = 1 ;
return 1 ;
2002-02-25 17:46:57 +03:00
}
static int _resume ( struct dev_layer * dl )
{
if ( ! dl - > info . suspended )
return 1 ;
2002-03-16 01:59:12 +03:00
if ( ! _suspend_or_resume ( dl - > name , RESUME ) ) {
2002-02-26 14:49:17 +03:00
stack ;
return 0 ;
}
dl - > info . suspended = 0 ;
return 1 ;
2002-02-25 17:46:57 +03:00
}
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 .
*/
static int _emit_target ( struct dm_task * dmt , struct stripe_segment * seg )
{
char params [ 1024 ] ;
uint64_t esize = seg - > lv - > vg - > extent_size ;
uint32_t s , stripes = seg - > stripes ;
2002-03-27 21:17:43 +03:00
int w = 0 , tw = 0 ;
2002-02-25 18:19:53 +03:00
char * filler = " /dev/ioerror " ;
char * target ;
if ( stripes = = 1 ) {
if ( ! seg - > area [ 0 ] . pv ) {
target = " error " ;
2002-03-27 21:17:43 +03:00
goto add_target ;
2002-03-15 00:17:30 +03:00
} else
2002-02-25 18:19:53 +03:00
target = " linear " ;
2002-03-27 21:17:43 +03:00
} else if ( stripes > 1 ) {
2002-02-25 18:19:53 +03:00
target = " striped " ;
2002-03-27 21:17:43 +03:00
if ( ( tw = lvm_snprintf ( params , sizeof ( params ) , " %u %u " ,
stripes , seg - > stripe_size ) ) < 0 )
goto error ;
2002-02-25 18:19:53 +03:00
w = tw ;
}
2002-03-27 21:17:43 +03:00
for ( s = 0 ; s < stripes ; s + + , w + = tw ) {
2002-04-30 21:12:37 +04:00
if ( ! seg - > area [ s ] . pv | | ! seg - > area [ s ] . pv - > dev )
2002-03-27 21:17:43 +03:00
tw = lvm_snprintf ( params + w , sizeof ( params ) - w ,
" %s 0%s " , filler ,
s = = ( stripes - 1 ) ? " " : " " ) ;
else
tw = lvm_snprintf ( params + w , sizeof ( params ) - w ,
2002-04-16 18:42:20 +04:00
" %s % " PRIu64 " %s " ,
dev_name ( seg - > area [ s ] . pv - > dev ) ,
( seg - > area [ s ] . pv - > pe_start +
( esize * seg - > area [ s ] . pe ) ) ,
s = = ( stripes - 1 ) ? " " : " " ) ;
2002-03-27 21:17:43 +03:00
if ( tw < 0 )
goto error ;
2002-02-25 18:19:53 +03:00
}
2002-03-27 21:17:43 +03:00
add_target :
2002-03-15 00:17:30 +03:00
log_debug ( " Adding target: % " PRIu64 " % " PRIu64 " %s %s " ,
esize * seg - > le , esize * seg - > len , target , params ) ;
2002-02-25 18:19:53 +03:00
if ( ! dm_task_add_target ( dmt , esize * seg - > le , esize * seg - > len ,
target , params ) ) {
stack ;
return 0 ;
}
return 1 ;
2002-03-27 21:17:43 +03:00
error :
log_error ( " Insufficient space to write target parameters. " ) ;
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 ;
struct stripe_segment * seg ;
struct logical_volume * lv = dl - > lv ;
list_iterate ( segh , & lv - > segments ) {
seg = list_item ( segh , struct stripe_segment ) ;
if ( ! _emit_target ( dmt , seg ) ) {
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 ] ;
2002-02-26 17:44:13 +03:00
2002-03-15 00:17:30 +03:00
if ( ! ( real = _build_name ( dm - > mem , dm - > vg_name , dl - > lv - > name , " real " ) ) ) {
2002-02-26 19:48:52 +03:00
stack ;
return 0 ;
}
2002-03-15 00:17:30 +03:00
if ( lvm_snprintf ( params , sizeof ( params ) , " %s/%s " , dm_dir ( ) , real ) = = - 1 ) {
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 ) ;
if ( ! dm_task_add_target ( dmt , 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 ;
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 ;
}
if ( ! ( origin = _build_name ( dm - > mem , dm - > vg_name ,
2002-03-01 12:07:00 +03:00
s - > origin - > name , " real " ) ) ) {
2002-02-26 17:44:13 +03:00
stack ;
return 0 ;
}
2002-02-25 18:19:53 +03:00
2002-03-15 00:17:30 +03:00
if ( ! ( cow = _build_name ( dm - > mem , dm - > vg_name , s - > cow - > name , " cow " ) ) ) {
2002-02-26 17:44:13 +03:00
stack ;
return 0 ;
}
2002-02-25 18:19:53 +03:00
2002-03-15 00:17:30 +03:00
if ( snprintf ( params , sizeof ( params ) , " %s/%s %s/%s P %d 128 " ,
2002-02-26 17:44:13 +03:00
dm_dir ( ) , origin , dm_dir ( ) , cow , 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 ) ;
if ( ! dm_task_add_target ( dmt , 0 , s - > origin - > size , " snapshot " , params ) ) {
stack ;
return 0 ;
}
2002-02-25 18:19:53 +03:00
return 1 ;
}
2002-02-25 15:02:33 +03:00
/*
* dev_manager implementation .
*/
struct dev_manager * dev_manager_create ( const char * vg_name )
{
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 ;
}
dm - > mem = mem ;
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
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-02-25 17:46:57 +03:00
int dev_manager_info ( struct dev_manager * dm , struct logical_volume * lv ,
struct dm_info * info )
{
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 ) ;
2002-03-19 02:25:50 +03:00
if ( ! _info ( name , lv - > lvid . s , info , NULL , NULL ) ) {
2002-02-25 17:46:57 +03:00
stack ;
return 0 ;
}
return 1 ;
}
2002-05-10 01:17:57 +04:00
int dev_manager_get_snapshot_use ( struct dev_manager * dm ,
struct logical_volume * lv , float * percent )
{
2002-05-10 20:06:06 +04:00
char * name , * type , * params ;
unsigned long long start , length ;
/* FIXME: Hard coded numbers can be bad, but not really sure what to
* use here . . . we don ' t really care about the type and the parameter
* should be a percentage */
uint32_t type_size = 2 ;
uint32_t param_size = 7 ;
2002-05-10 01:17:57 +04:00
2002-05-10 20:06:06 +04:00
if ( ! ( type = pool_alloc ( dm - > mem , sizeof ( * type ) * type_size ) ) ) {
stack ;
return 0 ;
}
if ( ! ( params = pool_alloc ( dm - > mem , sizeof ( * params ) * param_size ) ) ) {
2002-05-10 01:17:57 +04:00
stack ;
return 0 ;
}
/*
* Build a name for the top layer .
*/
if ( ! ( name = _build_name ( dm - > mem , lv - > vg - > name , lv - > name , NULL ) ) ) {
stack ;
return 0 ;
}
/*
* Try and get some info on this device .
*/
log_debug ( " Getting device status for %s " , name ) ;
2002-05-10 20:06:06 +04:00
if ( ! ( _status ( name , lv - > lvid . s , & start , & length , & type , type_size ,
& params , param_size ) ) ) {
2002-05-10 01:17:57 +04:00
stack ;
return 0 ;
}
/* If the snapshot isn't available, percent will be -1 */
* percent = - 1 ;
2002-05-10 20:06:06 +04:00
if ( ! params )
2002-05-10 01:17:57 +04:00
return 0 ;
2002-05-10 20:06:06 +04:00
return sscanf ( params , " %f " , percent ) ;
2002-05-10 01:17:57 +04:00
}
2002-03-19 02:25:50 +03:00
static struct dev_layer * _create_dev ( struct dev_manager * dm , char * name ,
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 ) ;
2002-03-19 02:25:50 +03:00
if ( ! _info ( dl - > name , dlid , & 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 ) ;
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 ;
}
2002-03-07 20:37:38 +03:00
static int _expand_vanilla ( struct dev_manager * dm , struct logical_volume * lv )
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
*/
2002-03-07 20:37:38 +03:00
struct dev_layer * dl ;
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 ;
_set_flag ( dl , VISIBLE ) ;
2002-02-26 17:44:13 +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_real ( struct dev_manager * dm ,
struct logical_volume * lv )
2002-03-07 20:37:38 +03:00
{
struct dev_layer * dl ;
2002-03-19 02:25:50 +03:00
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 ) ;
2002-02-26 17:44:13 +03:00
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 ) ;
2002-02-26 17:44:13 +03:00
2002-03-07 20:37:38 +03:00
/* add the dependency on the real device */
2002-04-03 16:17:55 +04:00
if ( ! _pre_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
* snapshots is in the active list .
*/
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 ) ;
}
return _expand_vanilla ( dm , lv ) ;
}
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-03-19 02:25:50 +03:00
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 ) ;
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 ) ;
2002-02-26 17:44:13 +03:00
2002-03-07 20:37:38 +03:00
/* add the dependency on the real device */
2002-04-03 16:17:55 +04:00
if ( ! _pre_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
2002-03-07 20:37:38 +03:00
/* add the dependency on the org device */
2002-04-03 16:17:55 +04:00
if ( ! _pre_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
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 ) ;
return _expand_vanilla ( dm , lv ) ;
}
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 ;
2002-03-19 02:25:50 +03:00
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 ;
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
}
2002-03-27 21:17:43 +03:00
static inline int _suspend_parent ( struct dev_layer * parent )
{
return ( ! parent | | ! parent - > info . exists | | _suspend ( parent ) ) ;
}
2002-02-25 15:02:33 +03:00
/*
* Recurses through the tree , ensuring that devices are created
* in correct order .
*/
2002-03-27 21:17:43 +03:00
int _create_rec ( struct dev_manager * dm , struct dev_layer * dl ,
struct dev_layer * parent )
2002-02-25 15:02:33 +03:00
{
struct list * sh ;
struct dev_layer * dep ;
2002-03-19 02:25:50 +03:00
char * dlid , * newname , * suffix ;
2002-02-25 15:02:33 +03:00
2002-03-27 21:17:43 +03:00
/* FIXME Create and use a _suspend_parents() function instead */
/* Suspend? */
2002-04-16 18:42:20 +04:00
if ( _get_flag ( dl , SUSPENDED ) & & ( ! _suspend_parent | | ! _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-27 21:17:43 +03:00
if ( ! _suspend_parent ( parent ) ) {
2002-02-25 15:02:33 +03:00
stack ;
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 ;
}
2002-03-27 21:17:43 +03:00
if ( ! _create_rec ( dm , dep , dl ) ) {
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 ) ) {
2002-04-16 18:42:20 +04:00
if ( ! _suspend_parent ( parent ) | |
! _suspend ( dl ) | | ! _rename ( dm , 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 ) {
2002-04-16 18:42:20 +04:00
if ( ! _suspend_parent ( parent ) | |
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 ) & &
2002-04-16 18:42:20 +04:00
( ! _suspend_parent ( parent ) | | ! _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-03-27 21:17:43 +03:00
/* Resume? */
2002-04-16 18:42:20 +04:00
if ( ! _get_flag ( dl , SUSPENDED ) & & ( ! _suspend_parent | | ! _resume ( dl ) ) ) {
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 ) ;
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 ;
}
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-03-11 23:36:04 +03:00
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 ;
}
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 ) ;
2002-03-11 23:36:04 +03:00
if ( _get_flag ( dl , ACTIVE ) & & _get_flag ( dl , VISIBLE ) )
2002-03-27 21:17:43 +03:00
_create_rec ( dm , dl , NULL ) ;
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 )
{
const char * dev_dir = dm_dir ( ) ;
2002-03-16 01:59:12 +03:00
int r = 1 ;
2002-03-07 20:37:38 +03:00
const char * name ;
2002-03-16 01:59:12 +03:00
struct dirent * dirent ;
DIR * d ;
2002-03-07 20:37:38 +03:00
2002-03-16 01:59:12 +03:00
if ( ! ( d = opendir ( dev_dir ) ) ) {
log_sys_error ( " opendir " , dev_dir ) ;
2002-03-07 20:37:38 +03:00
return 0 ;
}
2002-03-16 01:59:12 +03:00
while ( ( dirent = readdir ( d ) ) ) {
name = dirent - > d_name ;
2002-03-07 20:37:38 +03:00
if ( name [ 0 ] = = ' . ' )
continue ;
/*
* Does this layer belong to us ?
*/
if ( _belong_to_vg ( dm - > vg_name , name ) & &
! _add_existing_layer ( dm , name ) ) {
stack ;
r = 0 ;
break ;
}
}
2002-03-16 01:59:12 +03:00
if ( closedir ( d ) )
log_sys_error ( " closedir " , dev_dir ) ;
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
}
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
{
int found ;
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 ;
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 ;
}
2002-03-19 02:25:50 +03:00
found = hash_lookup ( dm - > layers , dlid ) ? 1 : 0 ;
pool_free ( dm - > mem , dlid ) ;
2002-03-11 14:27:48 +03:00
2002-03-11 23:36:04 +03:00
if ( found ) {
2002-03-16 01:59:12 +03:00
log_debug ( " Found active lv %s " , lv - > name ) ;
2002-03-11 23:36:04 +03:00
if ( ! _add_lv ( dm - > mem , & dm - > active_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
}
2002-03-27 21:17:43 +03:00
if ( action = = SUSPEND ) {
if ( ! _add_lvs ( dm - > mem , & dm - > suspend_list , lv ) ) {
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
}