2002-02-25 15:02:33 +03:00
/*
2008-01-30 17:00:02 +03:00
* Copyright ( C ) 2002 - 2004 Sistina Software , Inc . All rights reserved .
2011-06-17 18:14:19 +04:00
* Copyright ( C ) 2004 - 2011 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
2007-08-21 00:55:30 +04:00
* of the GNU Lesser General Public License v .2 .1 .
2004-03-30 23:35:44 +04:00
*
2007-08-21 00:55:30 +04:00
* You should have received a copy of the GNU Lesser General Public License
2004-03-30 23:35:44 +04:00
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2002-02-25 15:02:33 +03:00
*/
2002-11-18 17:01:16 +03:00
# include "lib.h"
2003-09-18 00:35:57 +04:00
# include "str_list.h"
2002-02-25 15:02:33 +03:00
# include "dev_manager.h"
2002-02-25 19:53:12 +03:00
# include "lvm-string.h"
2002-02-26 14:49:17 +03:00
# include "fs.h"
2003-04-25 02:09:13 +04:00
# include "defaults.h"
2004-09-16 22:40:56 +04:00
# include "segtype.h"
2004-05-05 01:25:57 +04:00
# include "display.h"
2003-11-13 21:47:22 +03:00
# include "toolcontext.h"
2004-05-05 01:25:57 +04:00
# include "targets.h"
# include "config.h"
2005-10-25 23:08:21 +04:00
# include "filter.h"
2007-01-26 00:22:30 +03:00
# include "activate.h"
2002-02-25 15:02:33 +03:00
2002-02-26 17:44:13 +03:00
# include <limits.h>
2002-03-07 20:37:38 +03:00
# include <dirent.h>
2002-02-25 15:02:33 +03:00
2003-08-20 16:53:57 +04:00
# define MAX_TARGET_PARAMSIZE 50000
2002-03-16 01:59:12 +03:00
typedef enum {
2005-11-09 01:52:26 +03:00
PRELOAD ,
2002-03-16 01:59:12 +03:00
ACTIVATE ,
2002-03-27 21:17:43 +03:00
DEACTIVATE ,
2002-03-16 01:59:12 +03:00
SUSPEND ,
2006-08-09 01:20:00 +04:00
SUSPEND_WITH_LOCKFS ,
2005-11-09 01:52:26 +03:00
CLEAN
2002-03-27 21:17:43 +03:00
} action_t ;
2002-03-16 01:59:12 +03:00
2002-02-25 15:02:33 +03:00
struct dev_manager {
2005-10-17 03:03:59 +04:00
struct dm_pool * mem ;
2002-02-25 15:02:33 +03:00
2004-05-05 01:25:57 +04:00
struct cmd_context * cmd ;
void * target_state ;
2003-05-06 16:00:29 +04:00
uint32_t pvmove_mirror_count ;
2009-05-20 13:52:37 +04:00
int flush_required ;
2011-06-11 04:03:06 +04:00
unsigned track_pvmove_deps ;
2003-04-25 02:09:13 +04:00
2002-02-25 15:02:33 +03:00
char * vg_name ;
} ;
2005-11-09 01:52:26 +03:00
struct lv_layer {
struct logical_volume * lv ;
const char * old_name ;
} ;
2002-03-07 19:48:46 +03:00
2006-04-19 19:33:07 +04:00
static int _read_only_lv ( struct logical_volume * lv )
2005-11-09 01:52:26 +03:00
{
return ( ! ( lv - > vg - > status & LVM_WRITE ) | | ! ( lv - > status & LVM_WRITE ) ) ;
}
2002-02-25 17:46:57 +03:00
/*
* Low level device - layer operations .
*/
2003-05-06 16:00:29 +04:00
static struct dm_task * _setup_task ( const char * name , const char * uuid ,
2008-12-19 18:23:03 +03:00
uint32_t * event_nr , int task ,
uint32_t major , uint32_t minor )
2002-02-25 17:46:57 +03:00
{
struct dm_task * dmt ;
2008-01-30 16:19:47 +03:00
if ( ! ( dmt = dm_task_create ( task ) ) )
return_NULL ;
2002-02-25 17:46:57 +03:00
2011-01-05 17:03:36 +03:00
if ( name & & ! dm_task_set_name ( dmt , name ) )
goto_out ;
2002-03-25 21:54:59 +03:00
2011-01-05 17:03:36 +03:00
if ( uuid & & * uuid & & ! dm_task_set_uuid ( dmt , uuid ) )
goto_out ;
2002-03-25 21:54:59 +03:00
2011-01-05 17:03:36 +03:00
if ( event_nr & & ! dm_task_set_event_nr ( dmt , * event_nr ) )
goto_out ;
2003-04-30 19:26:25 +04:00
2011-01-05 17:03:36 +03:00
if ( major & & ! dm_task_set_major_minor ( dmt , major , minor , 1 ) )
goto_out ;
2008-12-19 18:23:03 +03:00
2011-07-01 18:09:19 +04:00
if ( activation_checks ( ) & & ! dm_task_enable_checks ( dmt ) )
goto_out ;
2002-02-25 17:46:57 +03:00
return dmt ;
2011-01-05 17:03:36 +03:00
out :
dm_task_destroy ( dmt ) ;
return NULL ;
2002-02-25 17:46:57 +03:00
}
2005-10-19 17:59:18 +04:00
static int _info_run ( const char * name , const char * dlid , struct dm_info * info ,
2007-11-12 23:51:54 +03:00
uint32_t * read_ahead , int mknodes , int with_open_count ,
2008-12-19 18:23:03 +03:00
int with_read_ahead , uint32_t major , uint32_t minor )
2002-03-15 00:17:30 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
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 ;
2010-02-24 23:00:56 +03:00
if ( ! ( dmt = _setup_task ( mknodes ? name : NULL , dlid , 0 , dmtask , major , minor ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2002-03-15 00:17:30 +03:00
2005-01-13 01:58:21 +03:00
if ( ! with_open_count )
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2005-11-09 01:52:26 +03:00
if ( ! dm_task_run ( dmt ) )
goto_out ;
2002-03-15 00:17:30 +03:00
2005-11-09 01:52:26 +03:00
if ( ! dm_task_get_info ( dmt , info ) )
goto_out ;
2002-03-19 02:25:50 +03:00
2009-05-13 18:13:54 +04:00
if ( with_read_ahead & & info - > exists ) {
2007-12-03 21:00:38 +03:00
if ( ! dm_task_get_read_ahead ( dmt , read_ahead ) )
goto_out ;
} else if ( read_ahead )
2007-11-29 18:04:12 +03:00
* read_ahead = DM_READ_AHEAD_NONE ;
2007-11-12 23:51:54 +03:00
2002-03-15 00:17:30 +03:00
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2002-02-25 17:46:57 +03:00
2010-05-13 22:38:38 +04:00
int device_is_usable ( struct device * dev )
2007-01-26 00:22:30 +03:00
{
struct dm_task * dmt ;
struct dm_info info ;
2010-05-13 22:38:38 +04:00
const char * name , * uuid ;
2008-01-30 17:00:02 +03:00
uint64_t start , length ;
char * target_type = NULL ;
2010-05-14 16:03:32 +04:00
char * params , * vgname = NULL , * lvname , * layer ;
2007-01-26 02:03:48 +03:00
void * next = NULL ;
2010-10-25 14:37:34 +04:00
int only_error_target = 1 ;
2007-01-26 00:22:30 +03:00
int r = 0 ;
2011-03-18 15:17:57 +03:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_STATUS ) ) )
return_0 ;
2007-01-26 00:22:30 +03:00
2010-05-13 22:38:38 +04:00
if ( ! dm_task_set_major_minor ( dmt , MAJOR ( dev - > dev ) , MINOR ( dev - > dev ) , 1 ) )
2007-01-26 00:22:30 +03:00
goto_out ;
2011-07-01 18:09:19 +04:00
if ( activation_checks ( ) & & ! dm_task_enable_checks ( dmt ) )
goto_out ;
2007-01-26 00:22:30 +03:00
if ( ! dm_task_run ( dmt ) ) {
log_error ( " Failed to get state of mapped device " ) ;
goto out ;
}
if ( ! dm_task_get_info ( dmt , & info ) )
goto_out ;
2010-08-09 18:05:16 +04:00
if ( ! info . exists )
2007-01-26 00:22:30 +03:00
goto out ;
2007-01-26 02:03:48 +03:00
name = dm_task_get_name ( dmt ) ;
2010-05-13 22:38:38 +04:00
uuid = dm_task_get_uuid ( dmt ) ;
2007-01-26 02:03:48 +03:00
2010-10-25 14:37:34 +04:00
if ( ! info . target_count ) {
log_debug ( " %s: Empty device %s not usable. " , dev_name ( dev ) , name ) ;
goto out ;
}
2010-08-09 18:05:16 +04:00
if ( info . suspended & & ignore_suspended_devices ( ) ) {
log_debug ( " %s: Suspended device %s not usable. " , dev_name ( dev ) , name ) ;
goto out ;
}
2007-01-26 00:22:30 +03:00
/* FIXME Also check for mirror block_on_error and mpath no paths */
2007-01-26 02:03:48 +03:00
/* For now, we exclude all mirrors */
2008-01-30 17:00:02 +03:00
do {
next = dm_get_next_target ( dmt , next , & start , & length ,
& target_type , & params ) ;
/* Skip if target type doesn't match */
2010-08-09 18:05:16 +04:00
if ( target_type & & ! strcmp ( target_type , " mirror " ) & & ignore_suspended_devices ( ) ) {
log_debug ( " %s: Mirror device %s not usable. " , dev_name ( dev ) , name ) ;
2007-01-26 02:03:48 +03:00
goto out ;
2010-05-13 22:38:38 +04:00
}
2010-08-26 18:21:50 +04:00
/*
* Snapshot origin could be sitting on top of a mirror which
* could be blocking I / O . Skip snapshot origins entirely for
* now .
*
* FIXME : rather than skipping origin , check if mirror is
* underneath and if the mirror is blocking I / O .
*/
if ( target_type & & ! strcmp ( target_type , " snapshot-origin " ) & &
ignore_suspended_devices ( ) ) {
log_debug ( " %s: Snapshot-origin device %s not usable. " ,
dev_name ( dev ) , name ) ;
goto out ;
}
2010-10-24 21:36:58 +04:00
2010-10-25 14:37:34 +04:00
if ( target_type & & strcmp ( target_type , " error " ) )
only_error_target = 0 ;
2008-01-30 17:00:02 +03:00
} while ( next ) ;
2007-01-26 00:22:30 +03:00
2010-10-25 14:37:34 +04:00
/* Skip devices consisting entirely of error targets. */
/* FIXME Deal with device stacked above error targets? */
if ( only_error_target ) {
log_debug ( " %s: Error device %s not usable. " ,
dev_name ( dev ) , name ) ;
goto out ;
}
2007-01-26 00:22:30 +03:00
/* FIXME Also check dependencies? */
2010-05-13 22:38:38 +04:00
/* Check internal lvm devices */
2010-05-14 16:03:32 +04:00
if ( uuid & & ! strncmp ( uuid , UUID_PREFIX , sizeof ( UUID_PREFIX ) - 1 ) ) {
if ( ! ( vgname = dm_strdup ( name ) ) | |
! dm_split_lvm_name ( NULL , NULL , & vgname , & lvname , & layer ) )
goto_out ;
2010-05-14 16:39:52 +04:00
if ( lvname & & ( is_reserved_lvname ( lvname ) | | * layer ) ) {
2010-05-14 16:03:32 +04:00
log_debug ( " %s: Reserved internal LV device %s/%s%s%s not usable. " ,
2010-05-14 16:39:52 +04:00
dev_name ( dev ) , vgname , lvname , * layer ? " - " : " " , layer ) ;
2010-05-14 16:03:32 +04:00
goto out ;
}
2010-05-13 22:38:38 +04:00
}
2007-01-26 00:22:30 +03:00
r = 1 ;
out :
2010-05-14 16:03:32 +04:00
dm_free ( vgname ) ;
2007-01-26 00:22:30 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2010-02-24 23:00:56 +03:00
static int _info ( const char * dlid , int with_open_count , int with_read_ahead ,
2007-11-12 23:51:54 +03:00
struct dm_info * info , uint32_t * read_ahead )
2002-03-25 21:54:59 +03:00
{
2010-01-26 10:58:23 +03:00
int r = 0 ;
2010-02-24 23:00:56 +03:00
if ( ( r = _info_run ( NULL , dlid , info , read_ahead , 0 , with_open_count ,
with_read_ahead , 0 , 0 ) ) & & info - > exists )
return 1 ;
else if ( ( r = _info_run ( NULL , dlid + sizeof ( UUID_PREFIX ) - 1 , info ,
read_ahead , 0 , with_open_count ,
with_read_ahead , 0 , 0 ) ) & & info - > exists )
return 1 ;
2002-03-25 21:54:59 +03:00
2010-01-26 10:58:23 +03:00
return r ;
2002-03-25 21:54:59 +03:00
}
2008-12-19 18:23:03 +03:00
static int _info_by_dev ( uint32_t major , uint32_t minor , struct dm_info * info )
{
return _info_run ( NULL , NULL , info , NULL , 0 , 0 , 0 , major , minor ) ;
}
2010-02-24 23:00:56 +03:00
int dev_manager_info ( struct dm_pool * mem , const struct logical_volume * lv ,
2010-08-17 20:25:32 +04:00
const char * layer ,
2007-11-12 23:51:54 +03:00
int with_open_count , int with_read_ahead ,
struct dm_info * info , uint32_t * read_ahead )
2005-10-17 22:00:02 +04:00
{
2010-08-03 17:13:01 +04:00
char * dlid , * name ;
2010-02-24 23:00:56 +03:00
int r ;
2010-08-17 20:25:32 +04:00
if ( ! ( name = build_dm_name ( mem , lv - > vg - > name , lv - > name , layer ) ) ) {
2010-02-24 23:00:56 +03:00
log_error ( " name build failed for %s " , lv - > name ) ;
return 0 ;
}
2005-10-19 17:59:18 +04:00
2010-08-17 20:25:32 +04:00
if ( ! ( dlid = build_dm_uuid ( mem , lv - > lvid . s , layer ) ) ) {
log_error ( " dlid build failed for %s " , name ) ;
2005-10-19 17:59:18 +04:00
return 0 ;
}
2010-02-24 23:00:56 +03:00
log_debug ( " Getting device info for %s [%s] " , name , dlid ) ;
r = _info ( dlid , with_open_count , with_read_ahead , info , read_ahead ) ;
2010-08-03 17:13:01 +04:00
dm_pool_free ( mem , name ) ;
2010-02-24 23:00:56 +03:00
return r ;
2005-10-17 22:00:02 +04:00
}
2010-01-22 18:40:31 +03:00
static const struct dm_info * _cached_info ( struct dm_pool * mem ,
const struct logical_volume * lv ,
struct dm_tree * dtree )
{
const char * dlid ;
struct dm_tree_node * dnode ;
const struct dm_info * dinfo ;
2010-04-14 17:01:38 +04:00
if ( ! ( dlid = build_dm_uuid ( mem , lv - > lvid . s , NULL ) ) ) {
2010-01-22 18:40:31 +03:00
log_error ( " dlid build failed for %s " , lv - > name ) ;
return NULL ;
}
2010-02-09 02:28:06 +03:00
/* An activating merging origin won't have a node in the tree yet */
if ( ! ( dnode = dm_tree_find_node_by_uuid ( dtree , dlid ) ) )
2010-01-22 18:40:31 +03:00
return NULL ;
if ( ! ( dinfo = dm_tree_node_get_info ( dnode ) ) ) {
log_error ( " failed to get info from tree node for %s " , lv - > name ) ;
return NULL ;
}
if ( ! dinfo - > exists )
return NULL ;
return dinfo ;
}
2010-12-22 18:32:15 +03:00
#if 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 ;
2005-10-26 21:56:31 +04:00
struct dm_info info ;
2002-05-10 01:17:57 +04:00
void * next = NULL ;
2002-06-07 12:37:07 +04:00
uint64_t start , length ;
2002-05-10 01:17:57 +04:00
char * type = NULL ;
2002-05-10 20:06:06 +04:00
char * params = NULL ;
2002-05-10 01:17:57 +04:00
2008-12-19 18:23:03 +03:00
if ( ! ( dmt = _setup_task ( name , uuid , 0 , DM_DEVICE_STATUS , 0 , 0 ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2002-05-10 01:17:57 +04:00
2005-01-13 01:58:21 +03:00
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2005-11-09 01:52:26 +03:00
if ( ! dm_task_run ( dmt ) )
goto_out ;
2002-05-10 01:17:57 +04:00
2005-11-09 01:52:26 +03:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
goto_out ;
2005-10-26 21:56:31 +04:00
2002-05-10 01:17:57 +04:00
do {
next = dm_get_next_target ( dmt , next , & start , & length ,
& type , & params ) ;
2002-05-22 18:03:45 +04:00
if ( type ) {
2002-05-10 20:06:06 +04:00
* s = start ;
* l = length ;
/* Make sure things are null terminated */
strncpy ( * t , type , t_size ) ;
2002-05-22 18:03:45 +04:00
( * t ) [ t_size - 1 ] = ' \0 ' ;
2002-05-10 20:06:06 +04:00
strncpy ( * p , params , p_size ) ;
2002-05-22 18:03:45 +04:00
( * p ) [ p_size - 1 ] = ' \0 ' ;
2002-05-10 20:06:06 +04:00
r = 1 ;
2002-05-22 18:03:45 +04:00
/* FIXME Cope with multiple targets! */
2002-05-10 20:06:06 +04:00
break ;
2002-05-10 01:17:57 +04:00
}
2002-05-22 18:03:45 +04:00
} while ( next ) ;
2002-05-10 01:17:57 +04:00
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2003-04-25 02:09:13 +04:00
static int _status ( const char * name , const char * uuid ,
unsigned long long * start , unsigned long long * length ,
char * * type , uint32_t type_size , char * * params ,
uint32_t param_size ) __attribute__ ( ( unused ) ) ;
2002-05-10 20:06:06 +04:00
static int _status ( const char * name , const char * uuid ,
unsigned long long * start , unsigned long long * length ,
char * * type , uint32_t type_size , char * * params ,
uint32_t param_size )
2002-05-10 01:17:57 +04:00
{
2005-10-26 19:00:51 +04:00
if ( uuid & & * uuid ) {
if ( _status_run ( NULL , uuid , start , length , type ,
type_size , params , param_size ) & &
* params )
return 1 ;
2005-10-26 21:56:31 +04:00
else if ( _status_run ( NULL , uuid + sizeof ( UUID_PREFIX ) - 1 , start ,
2005-10-26 19:00:51 +04:00
length , type , type_size , params ,
param_size ) & &
* params )
return 1 ;
}
2002-05-10 01:17:57 +04:00
2002-05-10 20:06:06 +04:00
if ( name & & _status_run ( name , NULL , start , length , type , type_size ,
2002-05-22 18:03:45 +04:00
params , param_size ) )
2002-05-10 01:17:57 +04:00
return 1 ;
2002-05-22 18:03:45 +04:00
2002-05-10 01:17:57 +04:00
return 0 ;
}
2010-12-22 18:32:15 +03:00
# endif
2002-05-10 01:17:57 +04:00
2010-04-23 06:57:39 +04:00
int lv_has_target_type ( struct dm_pool * mem , struct logical_volume * lv ,
const char * layer , const char * target_type )
2010-01-13 04:54:34 +03:00
{
int r = 0 ;
char * dlid ;
struct dm_task * dmt ;
struct dm_info info ;
void * next = NULL ;
uint64_t start , length ;
char * type = NULL ;
char * params = NULL ;
2010-04-23 06:57:39 +04:00
if ( ! ( dlid = build_dm_uuid ( mem , lv - > lvid . s , layer ) ) )
2010-01-13 04:54:34 +03:00
return_0 ;
if ( ! ( dmt = _setup_task ( NULL , dlid , 0 ,
DM_DEVICE_STATUS , 0 , 0 ) ) )
return_0 ;
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
if ( ! dm_task_run ( dmt ) )
goto_out ;
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
goto_out ;
do {
next = dm_get_next_target ( dmt , next , & start , & length ,
& type , & params ) ;
if ( type & & strncmp ( type , target_type ,
strlen ( target_type ) ) = = 0 ) {
2010-01-22 16:28:54 +03:00
if ( info . live_table )
2010-01-13 04:54:34 +03:00
r = 1 ;
break ;
}
} while ( next ) ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2010-11-30 14:53:31 +03:00
static percent_range_t _combine_percent ( percent_t a , percent_t b ,
uint32_t numerator , uint32_t denominator )
2009-10-01 04:35:29 +04:00
{
if ( a = = PERCENT_INVALID | | b = = PERCENT_INVALID )
return PERCENT_INVALID ;
if ( a = = PERCENT_100 & & b = = PERCENT_100 )
return PERCENT_100 ;
if ( a = = PERCENT_0 & & b = = PERCENT_0 )
return PERCENT_0 ;
2010-11-30 14:53:31 +03:00
return make_percent ( numerator , denominator ) ;
2009-10-01 04:35:29 +04:00
}
2003-05-06 16:00:29 +04:00
static int _percent_run ( struct dev_manager * dm , const char * name ,
2005-10-19 17:59:18 +04:00
const char * dlid ,
2003-05-06 16:00:29 +04:00
const char * target_type , int wait ,
2010-11-30 14:53:31 +03:00
const struct logical_volume * lv , percent_t * overall_percent ,
2010-02-10 17:38:24 +03:00
uint32_t * event_nr , int fail_if_percent_unsupported )
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 ;
2010-01-16 01:58:25 +03:00
const struct dm_list * segh = & lv - > segments ;
2003-05-06 16:00:29 +04:00
struct lv_segment * seg = NULL ;
2004-05-05 01:25:57 +04:00
struct segment_type * segtype ;
2009-10-01 04:35:29 +04:00
int first_time = 1 ;
2010-11-30 14:53:31 +03:00
percent_t percent ;
2003-04-25 02:09:13 +04:00
uint64_t total_numerator = 0 , total_denominator = 0 ;
2010-11-30 14:53:31 +03:00
* overall_percent = PERCENT_INVALID ;
2003-04-25 02:09:13 +04:00
2005-10-19 17:59:18 +04:00
if ( ! ( dmt = _setup_task ( name , dlid , event_nr ,
2008-12-19 18:23:03 +03:00
wait ? DM_DEVICE_WAITEVENT : DM_DEVICE_STATUS , 0 , 0 ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2003-04-25 02:09:13 +04:00
2005-01-13 01:58:21 +03:00
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2005-11-09 01:52:26 +03:00
if ( ! dm_task_run ( dmt ) )
goto_out ;
2003-04-25 02:09:13 +04:00
2005-11-09 01:52:26 +03:00
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
goto_out ;
2003-04-30 19:26:25 +04:00
if ( event_nr )
* event_nr = info . event_nr ;
2003-04-25 02:09:13 +04:00
do {
next = dm_get_next_target ( dmt , next , & start , & length , & type ,
& params ) ;
2003-05-06 16:00:29 +04:00
if ( lv ) {
2008-11-04 01:14:30 +03:00
if ( ! ( segh = dm_list_next ( & lv - > segments , segh ) ) ) {
2003-05-06 16:00:29 +04:00
log_error ( " Number of segments in active LV %s "
" does not match metadata " , lv - > name ) ;
goto out ;
}
2008-11-04 01:14:30 +03:00
seg = dm_list_item ( segh , struct lv_segment ) ;
2003-05-06 16:00:29 +04:00
}
2003-04-25 02:09:13 +04:00
2010-01-15 19:35:26 +03:00
if ( ! type | | ! params )
2003-04-25 02:09:13 +04:00
continue ;
2010-01-13 04:43:32 +03:00
if ( ! ( segtype = get_segtype_from_string ( dm - > cmd , target_type ) ) )
2003-04-30 19:26:25 +04:00
continue ;
2010-01-15 19:35:26 +03:00
if ( strcmp ( type , target_type ) ) {
/* If kernel's type isn't an exact match is it compatible? */
if ( ! segtype - > ops - > target_status_compatible | |
! segtype - > ops - > target_status_compatible ( type ) )
continue ;
}
2010-12-08 22:26:35 +03:00
if ( ! segtype - > ops - > target_percent )
continue ;
if ( ! segtype - > ops - > target_percent ( & dm - > target_state ,
2010-11-30 14:53:31 +03:00
& percent , dm - > mem ,
2006-05-17 00:53:13 +04:00
dm - > cmd , seg , params ,
2004-05-05 01:25:57 +04:00
& total_numerator ,
2008-07-15 04:25:52 +04:00
& total_denominator ) )
2005-11-09 01:52:26 +03:00
goto_out ;
2004-05-05 01:25:57 +04:00
2009-10-01 04:35:29 +04:00
if ( first_time ) {
2010-11-30 14:53:31 +03:00
* overall_percent = percent ;
2009-10-01 04:35:29 +04:00
first_time = 0 ;
} else
2010-11-30 14:53:31 +03:00
* overall_percent =
_combine_percent ( * overall_percent , percent ,
total_numerator , total_denominator ) ;
2003-04-25 02:09:13 +04:00
} while ( next ) ;
2010-12-20 17:04:43 +03:00
if ( lv & & dm_list_next ( & lv - > segments , segh ) ) {
2003-05-06 16:00:29 +04:00
log_error ( " Number of segments in active LV %s does not "
" match metadata " , lv - > name ) ;
goto out ;
}
2010-11-30 14:53:31 +03:00
if ( first_time ) {
/* above ->target_percent() was not executed! */
/* FIXME why return PERCENT_100 et. al. in this case? */
* overall_percent = PERCENT_100 ;
if ( fail_if_percent_unsupported )
goto_out ;
2009-10-01 04:35:29 +04:00
}
2003-04-25 02:09:13 +04:00
2010-11-30 14:53:31 +03:00
log_debug ( " LV percent: %f " , percent_to_float ( * overall_percent ) ) ;
2003-04-25 02:09:13 +04:00
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2005-10-19 17:59:18 +04:00
static int _percent ( struct dev_manager * dm , const char * name , const char * dlid ,
2003-05-06 16:00:29 +04:00
const char * target_type , int wait ,
2010-11-30 14:53:31 +03:00
const struct logical_volume * lv , percent_t * percent ,
uint32_t * event_nr , int fail_if_percent_unsupported )
2003-04-25 02:09:13 +04:00
{
2005-10-26 19:00:51 +04:00
if ( dlid & & * dlid ) {
if ( _percent_run ( dm , NULL , dlid , target_type , wait , lv , percent ,
2010-11-30 14:53:31 +03:00
event_nr , fail_if_percent_unsupported ) )
2005-10-26 19:00:51 +04:00
return 1 ;
2005-10-26 21:56:31 +04:00
else if ( _percent_run ( dm , NULL , dlid + sizeof ( UUID_PREFIX ) - 1 ,
2005-10-26 19:00:51 +04:00
target_type , wait , lv , percent ,
2010-11-30 14:53:31 +03:00
event_nr , fail_if_percent_unsupported ) )
2005-10-26 19:00:51 +04:00
return 1 ;
}
2003-04-25 02:09:13 +04:00
2003-05-06 16:00:29 +04:00
if ( name & & _percent_run ( dm , name , NULL , target_type , wait , lv , percent ,
2010-11-30 14:53:31 +03:00
event_nr , fail_if_percent_unsupported ) )
2003-04-25 02:09:13 +04:00
return 1 ;
return 0 ;
}
2010-08-17 05:51:12 +04:00
/* FIXME Merge with the percent function */
2010-05-24 19:32:20 +04:00
int dev_manager_transient ( struct dev_manager * dm , struct logical_volume * lv )
{
int r = 0 ;
struct dm_task * dmt ;
struct dm_info info ;
void * next = NULL ;
uint64_t start , length ;
char * type = NULL ;
char * params = NULL ;
char * dlid = NULL ;
2010-08-17 20:25:32 +04:00
const char * layer = lv_is_origin ( lv ) ? " real " : NULL ;
2010-05-24 19:32:20 +04:00
const struct dm_list * segh = & lv - > segments ;
struct lv_segment * seg = NULL ;
2010-08-17 20:25:32 +04:00
if ( ! ( dlid = build_dm_uuid ( dm - > mem , lv - > lvid . s , layer ) ) )
2010-05-24 19:32:20 +04:00
return_0 ;
if ( ! ( dmt = _setup_task ( 0 , dlid , NULL , DM_DEVICE_STATUS , 0 , 0 ) ) )
return_0 ;
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
if ( ! dm_task_run ( dmt ) )
goto_out ;
if ( ! dm_task_get_info ( dmt , & info ) | | ! info . exists )
goto_out ;
do {
next = dm_get_next_target ( dmt , next , & start , & length , & type ,
& params ) ;
2010-12-01 01:28:06 +03:00
if ( ! ( segh = dm_list_next ( & lv - > segments , segh ) ) ) {
log_error ( " Number of segments in active LV %s "
" does not match metadata " , lv - > name ) ;
goto out ;
2010-05-24 19:32:20 +04:00
}
2010-12-01 01:28:06 +03:00
seg = dm_list_item ( segh , struct lv_segment ) ;
2010-05-24 19:32:20 +04:00
if ( ! type | | ! params )
continue ;
if ( seg - > segtype - > ops - > check_transient_status & &
! seg - > segtype - > ops - > check_transient_status ( seg , params ) )
goto_out ;
} while ( next ) ;
2010-12-20 17:04:43 +03:00
if ( dm_list_next ( & lv - > segments , segh ) ) {
2010-05-24 19:32:20 +04:00
log_error ( " Number of segments in active LV %s does not "
" match metadata " , lv - > name ) ;
goto out ;
}
r = 1 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2005-11-09 01:52:26 +03:00
/*
* dev_manager implementation .
*/
struct dev_manager * dev_manager_create ( struct cmd_context * cmd ,
2011-06-11 04:03:06 +04:00
const char * vg_name ,
unsigned track_pvmove_deps )
2002-03-19 02:25:50 +03:00
{
2005-11-09 01:52:26 +03:00
struct dm_pool * mem ;
struct dev_manager * dm ;
2002-03-19 02:25:50 +03:00
2008-01-30 16:19:47 +03:00
if ( ! ( mem = dm_pool_create ( " dev_manager " , 16 * 1024 ) ) )
return_NULL ;
2002-03-19 02:25:50 +03:00
2009-05-07 16:01:21 +04:00
if ( ! ( dm = dm_pool_zalloc ( mem , sizeof ( * dm ) ) ) )
2007-04-26 20:44:59 +04:00
goto_bad ;
2002-03-19 02:25:50 +03:00
2005-11-09 01:52:26 +03:00
dm - > cmd = cmd ;
dm - > mem = mem ;
2005-01-13 01:58:21 +03:00
2007-04-26 20:44:59 +04:00
if ( ! ( dm - > vg_name = dm_pool_strdup ( dm - > mem , vg_name ) ) )
goto_bad ;
2004-05-13 00:40:34 +04:00
2011-06-11 04:03:06 +04:00
/*
* When we manipulate ( normally suspend / resume ) the PVMOVE
* device directly , there ' s no need to touch the LVs above .
*/
dm - > track_pvmove_deps = track_pvmove_deps ;
2005-11-09 01:52:26 +03:00
dm - > target_state = NULL ;
2005-01-13 01:58:21 +03:00
2009-08-04 19:36:13 +04:00
dm_udev_set_sync_support ( cmd - > current_settings . udev_sync ) ;
2005-11-09 01:52:26 +03:00
return dm ;
2004-05-13 00:40:34 +04:00
2005-11-09 01:52:26 +03:00
bad :
dm_pool_destroy ( mem ) ;
return NULL ;
2004-05-13 00:40:34 +04:00
}
2005-11-09 01:52:26 +03:00
void dev_manager_destroy ( struct dev_manager * dm )
2004-05-13 00:40:34 +04:00
{
2005-11-09 01:52:26 +03:00
dm_pool_destroy ( dm - > mem ) ;
}
2004-05-13 00:40:34 +04:00
2006-05-16 20:48:31 +04:00
void dev_manager_release ( void )
{
dm_lib_release ( ) ;
}
2005-11-09 01:52:26 +03:00
void dev_manager_exit ( void )
{
dm_lib_exit ( ) ;
2004-05-13 00:40:34 +04:00
}
2005-11-09 01:52:26 +03:00
int dev_manager_snapshot_percent ( struct dev_manager * dm ,
2006-04-06 18:06:27 +04:00
const struct logical_volume * lv ,
2010-11-30 14:53:31 +03:00
percent_t * percent )
2004-05-13 00:40:34 +04:00
{
2005-11-09 01:52:26 +03:00
char * name ;
const char * dlid ;
2010-02-10 17:38:24 +03:00
int fail_if_percent_unsupported = 0 ;
if ( lv_is_merging_origin ( lv ) ) {
/*
* Set ' fail_if_percent_unsupported ' , otherwise passing
* unsupported LV types to _percent will lead to a default
* successful return with percent_range as PERCENT_100 .
* - For a merging origin , this will result in a polldaemon
* that runs infinitely ( because completion is PERCENT_0 )
* - We unfortunately don ' t yet _know_ if a snapshot - merge
* target is active ( activation is deferred if dev is open ) ;
* so we can ' t short - circuit origin devices based purely on
* existing LVM LV attributes .
*/
fail_if_percent_unsupported = 1 ;
}
2005-11-09 01:52:26 +03:00
/*
* Build a name for the top layer .
*/
if ( ! ( name = build_dm_name ( dm - > mem , lv - > vg - > name , lv - > name , NULL ) ) )
return_0 ;
2010-04-14 17:01:38 +04:00
if ( ! ( dlid = build_dm_uuid ( dm - > mem , lv - > lvid . s , NULL ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2004-05-13 00:40:34 +04:00
2005-11-09 01:52:26 +03:00
/*
* Try and get some info on this device .
*/
log_debug ( " Getting device status percentage for %s " , name ) ;
2010-02-10 17:38:24 +03:00
if ( ! ( _percent ( dm , name , dlid , " snapshot " , 0 , NULL , percent ,
2010-11-30 14:53:31 +03:00
NULL , fail_if_percent_unsupported ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2004-05-13 00:40:34 +04:00
2005-11-09 01:52:26 +03:00
/* FIXME dm_pool_free ? */
/* If the snapshot isn't available, percent will be -1 */
2004-05-13 00:40:34 +04:00
return 1 ;
}
2005-11-09 01:52:26 +03:00
/* FIXME Merge with snapshot_percent, auto-detecting target type */
/* FIXME Cope with more than one target */
int dev_manager_mirror_percent ( struct dev_manager * dm ,
2010-01-16 01:58:25 +03:00
const struct logical_volume * lv , int wait ,
2010-11-30 14:53:31 +03:00
percent_t * percent , uint32_t * event_nr )
2002-02-25 17:46:57 +03:00
{
2005-11-09 01:52:26 +03:00
char * name ;
const char * dlid ;
2010-08-17 20:25:32 +04:00
const char * layer = ( lv_is_origin ( lv ) ) ? " real " : NULL ;
2002-02-25 17:46:57 +03:00
2002-03-26 16:41:37 +03:00
/*
2005-11-09 01:52:26 +03:00
* Build a name for the top layer .
2002-03-26 16:41:37 +03:00
*/
2010-08-17 20:25:32 +04:00
if ( ! ( name = build_dm_name ( dm - > mem , lv - > vg - > name , lv - > name , layer ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2002-03-08 13:41:48 +03:00
2005-11-09 01:52:26 +03:00
/* FIXME dm_pool_free ? */
2005-01-13 01:58:21 +03:00
2010-08-17 20:25:32 +04:00
if ( ! ( dlid = build_dm_uuid ( dm - > mem , lv - > lvid . s , layer ) ) ) {
2005-11-09 01:52:26 +03:00
log_error ( " dlid build failed for %s " , lv - > name ) ;
return 0 ;
2003-07-05 02:34:56 +04:00
}
2002-03-15 00:17:30 +03:00
2005-11-09 01:52:26 +03:00
log_debug ( " Getting device mirror status percentage for %s " , name ) ;
if ( ! ( _percent ( dm , name , dlid , " mirror " , wait , lv , percent ,
2010-11-30 14:53:31 +03:00
event_nr , 0 ) ) )
2008-01-30 16:19:47 +03:00
return_0 ;
2002-03-15 00:17:30 +03:00
2005-11-09 01:52:26 +03:00
return 1 ;
}
2003-07-05 02:34:56 +04:00
2005-11-09 01:52:26 +03:00
#if 0
log_very_verbose ( " %s %s " , sus ? " Suspending " : " Resuming " , name ) ;
2004-05-13 00:40:34 +04:00
2005-11-09 01:52:26 +03:00
log_verbose ( " Loading %s " , dl - > name ) ;
log_very_verbose ( " Activating %s read-only " , dl - > name ) ;
2003-07-05 02:34:56 +04:00
log_very_verbose ( " Activated %s %s %03u:%03u " , dl - > name ,
dl - > dlid , dl - > info . major , dl - > info . minor ) ;
2002-03-16 01:59:12 +03:00
if ( _get_flag ( dl , VISIBLE ) )
2002-03-18 16:09:27 +03:00
log_verbose ( " Removing %s " , dl - > name ) ;
2002-03-16 01:59:12 +03:00
else
2002-03-18 16:09:27 +03:00
log_very_verbose ( " Removing %s " , dl - > name ) ;
2002-03-16 01:59:12 +03:00
2005-11-09 01:52:26 +03:00
log_debug ( " Adding target: % " PRIu64 " % " PRIu64 " %s %s " ,
extent_size * seg - > le , extent_size * seg - > len , target , params ) ;
2002-02-25 17:46:57 +03:00
2005-11-09 01:52:26 +03:00
log_debug ( " Adding target: 0 % " PRIu64 " snapshot-origin %s " ,
dl - > lv - > size , params ) ;
log_debug ( " Adding target: 0 % " PRIu64 " snapshot %s " , size , params ) ;
log_debug ( " Getting device info for %s " , dl - > name ) ;
2005-01-13 01:58:21 +03:00
2005-11-09 01:52:26 +03:00
/* Rename? */
2007-07-02 15:17:21 +04:00
if ( ( suffix = strrchr ( dl - > dlid + sizeof ( UUID_PREFIX ) - 1 , ' - ' ) ) )
2005-11-09 01:52:26 +03:00
suffix + + ;
2007-08-06 18:57:48 +04:00
new_name = build_dm_name ( dm - > mem , dm - > vg_name , dl - > lv - > name ,
2005-11-09 01:52:26 +03:00
suffix ) ;
2002-03-16 01:59:12 +03:00
2005-11-09 01:52:26 +03:00
static int _belong_to_vg ( const char * vgname , const char * name )
{
const char * v = vgname , * n = name ;
2002-02-25 17:46:57 +03:00
2005-11-09 01:52:26 +03:00
while ( * v ) {
if ( ( * v ! = * n ) | | ( * v = = ' - ' & & * ( + + n ) ! = ' - ' ) )
return 0 ;
v + + , n + + ;
2002-04-16 18:42:20 +04:00
}
2002-03-18 16:09:27 +03:00
2005-11-09 01:52:26 +03:00
if ( * n = = ' - ' & & * ( n + 1 ) ! = ' - ' )
return 1 ;
else
return 0 ;
}
2002-04-16 18:42:20 +04:00
2005-04-07 16:39:44 +04:00
if ( ! ( snap_seg = find_cow ( lv ) ) )
2002-04-16 18:42:20 +04:00
return 1 ;
2005-04-07 16:39:44 +04:00
old_origin = snap_seg - > origin ;
2002-04-16 18:42:20 +04:00
/* Was this the last active snapshot with this origin? */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( lvl , active_head ) {
2005-06-01 20:51:55 +04:00
active = lvl - > lv ;
2005-04-07 16:39:44 +04:00
if ( ( snap_seg = find_cow ( active ) ) & &
snap_seg - > origin = = old_origin ) {
2002-04-16 18:42:20 +04:00
return 1 ;
2002-04-24 22:20:51 +04:00
}
2002-03-18 16:09:27 +03:00
}
2005-11-09 01:52:26 +03:00
# endif
/*************************/
/* NEW CODE STARTS HERE */
/*************************/
2010-02-24 23:00:56 +03:00
static int _dev_manager_lv_mknodes ( const struct logical_volume * lv )
2005-11-09 01:52:26 +03:00
{
char * name ;
if ( ! ( name = build_dm_name ( lv - > vg - > cmd - > mem , lv - > vg - > name ,
lv - > name , NULL ) ) )
return_0 ;
return fs_add_lv ( lv , name ) ;
2002-03-18 16:09:27 +03:00
}
2010-02-24 23:00:56 +03:00
static int _dev_manager_lv_rmnodes ( const struct logical_volume * lv )
2003-04-25 02:09:13 +04:00
{
2005-11-09 01:52:26 +03:00
return fs_del_lv ( lv ) ;
}
2010-02-24 23:00:56 +03:00
int dev_manager_mknodes ( const struct logical_volume * lv )
{
struct dm_info dminfo ;
2010-08-03 17:13:01 +04:00
char * name ;
2010-02-24 23:00:56 +03:00
int r = 0 ;
if ( ! ( name = build_dm_name ( lv - > vg - > cmd - > mem , lv - > vg - > name , lv - > name , NULL ) ) )
return_0 ;
if ( ( r = _info_run ( name , NULL , & dminfo , NULL , 1 , 0 , 0 , 0 , 0 ) ) ) {
if ( dminfo . exists ) {
if ( lv_is_visible ( lv ) )
r = _dev_manager_lv_mknodes ( lv ) ;
} else
r = _dev_manager_lv_rmnodes ( lv ) ;
}
2010-08-03 17:13:01 +04:00
dm_pool_free ( lv - > vg - > cmd - > mem , name ) ;
2010-02-24 23:00:56 +03:00
return r ;
}
2010-04-23 18:16:32 +04:00
static uint16_t _get_udev_flags ( struct dev_manager * dm , struct logical_volume * lv ,
const char * layer )
{
uint16_t udev_flags = 0 ;
2011-06-17 18:50:53 +04:00
/*
* Instruct also libdevmapper to disable udev
* fallback in accordance to LVM2 settings .
*/
if ( ! dm - > cmd - > current_settings . udev_fallback )
udev_flags | = DM_UDEV_DISABLE_LIBRARY_FALLBACK ;
2010-04-23 18:16:32 +04:00
/*
* Is this top - level and visible device ?
* If not , create just the / dev / mapper content .
*/
if ( layer | | ! lv_is_visible ( lv ) )
udev_flags | = DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG |
DM_UDEV_DISABLE_DISK_RULES_FLAG |
DM_UDEV_DISABLE_OTHER_RULES_FLAG ;
/*
* There ' s no need for other udev rules to touch special LVs with
* reserved names . We don ' t need to populate / dev / disk here either .
* Even if they happen to be visible and top - level .
*/
else if ( is_reserved_lvname ( lv - > name ) )
udev_flags | = DM_UDEV_DISABLE_DISK_RULES_FLAG |
DM_UDEV_DISABLE_OTHER_RULES_FLAG ;
/*
* Snapshots and origins could have the same rule applied that will
* give symlinks exactly the same name ( e . g . a name based on
* filesystem UUID ) . We give preference to origins to make such
* naming deterministic ( e . g . symlinks in / dev / disk / by - uuid ) .
*/
if ( lv_is_cow ( lv ) )
udev_flags | = DM_UDEV_LOW_PRIORITY_FLAG ;
/*
* Finally , add flags to disable / dev / mapper and / dev / < vgname > content
* to be created by udev if it is requested by user ' s configuration .
* This is basically an explicit fallback to old node / symlink creation
* without udev .
*/
if ( ! dm - > cmd - > current_settings . udev_rules )
udev_flags | = DM_UDEV_DISABLE_DM_RULES_FLAG |
DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG ;
return udev_flags ;
}
2005-11-09 16:08:41 +03:00
static int _add_dev_to_dtree ( struct dev_manager * dm , struct dm_tree * dtree ,
2005-11-09 01:52:26 +03:00
struct logical_volume * lv , const char * layer )
{
char * dlid , * name ;
2008-12-19 18:23:03 +03:00
struct dm_info info , info2 ;
2003-04-25 02:09:13 +04:00
2005-11-09 01:52:26 +03:00
if ( ! ( name = build_dm_name ( dm - > mem , lv - > vg - > name , lv - > name , layer ) ) )
return_0 ;
2003-04-25 02:09:13 +04:00
2010-04-14 17:01:38 +04:00
if ( ! ( dlid = build_dm_uuid ( dm - > mem , lv - > lvid . s , layer ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2008-01-30 17:00:02 +03:00
log_debug ( " Getting device info for %s [%s] " , name , dlid ) ;
2010-02-24 23:00:56 +03:00
if ( ! _info ( dlid , 1 , 0 , & info , NULL ) ) {
2008-01-30 17:00:02 +03:00
log_error ( " Failed to get info for %s [%s]. " , name , dlid ) ;
return 0 ;
}
2005-11-09 01:52:26 +03:00
2008-12-19 18:23:03 +03:00
/*
* For top level volumes verify that existing device match
* requested major / minor and that major / minor pair is available for use
*/
if ( ! layer & & lv - > major ! = - 1 & & lv - > minor ! = - 1 ) {
2009-02-12 23:42:07 +03:00
/*
* FIXME compare info . major with lv - > major if multiple major support
*/
if ( info . exists & & ( info . minor ! = lv - > minor ) ) {
2008-12-19 18:23:03 +03:00
log_error ( " Volume %s (% " PRIu32 " :% " PRIu32 " ) "
" differs from already active device "
" (% " PRIu32 " :% " PRIu32 " ) " ,
lv - > name , lv - > major , lv - > minor , info . major , info . minor ) ;
return 0 ;
}
if ( ! info . exists & & _info_by_dev ( lv - > major , lv - > minor , & info2 ) & &
info2 . exists ) {
log_error ( " The requested major:minor pair "
" (% " PRIu32 " :% " PRIu32 " ) is already used " ,
lv - > major , lv - > minor ) ;
return 0 ;
}
}
2010-04-23 18:16:32 +04:00
if ( info . exists & & ! dm_tree_add_dev_with_udev_flags ( dtree , info . major , info . minor ,
_get_udev_flags ( dm , lv , layer ) ) ) {
2005-11-09 16:08:41 +03:00
log_error ( " Failed to add device (% " PRIu32 " :% " PRIu32 " ) to dtree " ,
2005-11-09 01:52:26 +03:00
info . major , info . minor ) ;
return 0 ;
2003-04-25 02:09:13 +04:00
}
2005-11-09 01:52:26 +03:00
return 1 ;
}
2010-05-21 18:47:58 +04:00
/*
* Add replicator devices
*
* Using _add_dev_to_dtree ( ) directly instead of _add_lv_to_dtree ( )
* to avoid extra checks with extensions .
*/
static int _add_partial_replicator_to_dtree ( struct dev_manager * dm ,
struct dm_tree * dtree ,
struct logical_volume * lv )
{
struct logical_volume * rlv = first_seg ( lv ) - > replicator ;
struct replicator_device * rdev ;
struct replicator_site * rsite ;
struct dm_tree_node * rep_node , * rdev_node ;
const char * uuid ;
if ( ! lv_is_active_replicator_dev ( lv ) ) {
if ( ! _add_dev_to_dtree ( dm , dtree , lv - > rdevice - > lv ,
NULL ) )
return_0 ;
return 1 ;
}
/* Add _rlog and replicator device */
if ( ! _add_dev_to_dtree ( dm , dtree , first_seg ( rlv ) - > rlog_lv , NULL ) )
return_0 ;
if ( ! _add_dev_to_dtree ( dm , dtree , rlv , NULL ) )
return_0 ;
if ( ! ( uuid = build_dm_uuid ( dm - > mem , rlv - > lvid . s , NULL ) ) )
return_0 ;
rep_node = dm_tree_find_node_by_uuid ( dtree , uuid ) ;
/* Add all related devices for replicator */
dm_list_iterate_items ( rsite , & rlv - > rsites )
dm_list_iterate_items ( rdev , & rsite - > rdevices ) {
if ( rsite - > state = = REPLICATOR_STATE_ACTIVE ) {
/* Add _rimage LV */
if ( ! _add_dev_to_dtree ( dm , dtree , rdev - > lv , NULL ) )
return_0 ;
/* Add replicator-dev LV, except of the already added one */
if ( ( lv ! = rdev - > replicator_dev - > lv ) & &
! _add_dev_to_dtree ( dm , dtree ,
rdev - > replicator_dev - > lv , NULL ) )
return_0 ;
/* If replicator exists - try connect existing heads */
if ( rep_node ) {
uuid = build_dm_uuid ( dm - > mem ,
rdev - > replicator_dev - > lv - > lvid . s ,
NULL ) ;
if ( ! uuid )
return_0 ;
rdev_node = dm_tree_find_node_by_uuid ( dtree , uuid ) ;
if ( rdev_node )
dm_tree_node_set_presuspend_node ( rdev_node ,
rep_node ) ;
}
}
if ( ! rdev - > rsite - > vg_name )
continue ;
if ( ! _add_dev_to_dtree ( dm , dtree , rdev - > lv , NULL ) )
return_0 ;
if ( rdev - > slog & &
! _add_dev_to_dtree ( dm , dtree , rdev - > slog , NULL ) )
return_0 ;
}
return 1 ;
}
2005-11-09 01:52:26 +03:00
/*
* Add LV and any known dependencies
*/
2011-06-17 18:14:19 +04:00
static int _add_lv_to_dtree ( struct dev_manager * dm , struct dm_tree * dtree , struct logical_volume * lv , int origin_only )
2005-11-09 01:52:26 +03:00
{
2011-06-11 04:03:06 +04:00
struct seg_list * sl ;
2010-08-17 20:25:32 +04:00
if ( ! origin_only & & ! _add_dev_to_dtree ( dm , dtree , lv , NULL ) )
2005-11-09 01:52:26 +03:00
return_0 ;
/* FIXME Can we avoid doing this every time? */
2005-11-09 16:08:41 +03:00
if ( ! _add_dev_to_dtree ( dm , dtree , lv , " real " ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2010-08-17 20:25:32 +04:00
if ( ! origin_only & & ! _add_dev_to_dtree ( dm , dtree , lv , " cow " ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2003-04-25 02:09:13 +04:00
2010-02-23 18:49:52 +03:00
if ( ( lv - > status & MIRRORED ) & & first_seg ( lv ) - > log_lv & &
! _add_dev_to_dtree ( dm , dtree , first_seg ( lv ) - > log_lv , NULL ) )
2006-04-28 21:01:07 +04:00
return_0 ;
2011-06-11 04:03:06 +04:00
/* Add any LVs referencing a PVMOVE LV unless told not to. */
if ( dm - > track_pvmove_deps & & lv - > status & PVMOVE )
dm_list_iterate_items ( sl , & lv - > segs_using_this_lv )
if ( ! _add_lv_to_dtree ( dm , dtree , sl - > seg - > lv , origin_only ) )
return_0 ;
2010-05-21 18:47:58 +04:00
/* Adding LV head of replicator adds all other related devs */
if ( lv_is_replicator_dev ( lv ) & &
! _add_partial_replicator_to_dtree ( dm , dtree , lv ) )
return_0 ;
2003-04-25 02:09:13 +04:00
return 1 ;
}
2011-06-17 18:14:19 +04:00
static struct dm_tree * _create_partial_dtree ( struct dev_manager * dm , struct logical_volume * lv , int origin_only )
2004-05-05 22:11:43 +04:00
{
2005-11-09 16:05:17 +03:00
struct dm_tree * dtree ;
2008-11-04 01:14:30 +03:00
struct dm_list * snh , * snht ;
2005-11-10 02:56:36 +03:00
struct lv_segment * seg ;
uint32_t s ;
2004-05-05 22:11:43 +04:00
2005-11-09 16:05:17 +03:00
if ( ! ( dtree = dm_tree_create ( ) ) ) {
2005-11-09 16:08:41 +03:00
log_error ( " Partial dtree creation failed for %s. " , lv - > name ) ;
2005-11-09 01:52:26 +03:00
return NULL ;
}
2004-05-05 22:11:43 +04:00
2011-06-30 22:25:18 +04:00
if ( ! _add_lv_to_dtree ( dm , dtree , lv , lv_is_origin ( lv ) ? origin_only : 0 ) )
2008-01-30 16:19:47 +03:00
goto_bad ;
2004-05-05 22:11:43 +04:00
2005-11-09 01:52:26 +03:00
/* Add any snapshots of this LV */
2011-06-30 22:25:18 +04:00
if ( ! origin_only & & lv_is_origin ( lv ) )
2010-08-17 20:25:32 +04:00
dm_list_iterate_safe ( snh , snht , & lv - > snapshot_segs )
if ( ! _add_lv_to_dtree ( dm , dtree , dm_list_struct_base ( snh , struct lv_segment , origin_list ) - > cow , 0 ) )
goto_bad ;
2004-05-05 22:11:43 +04:00
2005-11-10 02:56:36 +03:00
/* Add any LVs used by segments in this LV */
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments )
2005-11-10 02:56:36 +03:00
for ( s = 0 ; s < seg - > area_count ; s + + )
if ( seg_type ( seg , s ) = = AREA_LV & & seg_lv ( seg , s ) ) {
2010-08-17 20:25:32 +04:00
if ( ! _add_lv_to_dtree ( dm , dtree , seg_lv ( seg , s ) , 0 ) )
2008-01-30 16:19:47 +03:00
goto_bad ;
2005-11-10 02:56:36 +03:00
}
2005-11-09 01:52:26 +03:00
return dtree ;
2004-05-05 22:11:43 +04:00
2008-01-30 16:19:47 +03:00
bad :
2005-11-09 16:05:17 +03:00
dm_tree_free ( dtree ) ;
2005-11-09 01:52:26 +03:00
return NULL ;
2004-05-05 22:11:43 +04:00
}
2008-09-19 10:42:00 +04:00
static char * _add_error_device ( struct dev_manager * dm , struct dm_tree * dtree ,
struct lv_segment * seg , int s )
{
char * id , * name ;
char errid [ 32 ] ;
struct dm_tree_node * node ;
struct lv_segment * seg_i ;
2011-03-30 00:30:05 +04:00
int segno = - 1 , i = 0 ;
2008-09-19 10:42:00 +04:00
uint64_t size = seg - > len * seg - > lv - > vg - > extent_size ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg_i , & seg - > lv - > segments ) {
2008-09-19 10:42:00 +04:00
if ( seg = = seg_i )
segno = i ;
+ + i ;
}
if ( segno < 0 ) {
log_error ( " _add_error_device called with bad segment " ) ;
return_NULL ;
}
sprintf ( errid , " missing_%d_%d " , segno , s ) ;
2010-04-14 17:01:38 +04:00
if ( ! ( id = build_dm_uuid ( dm - > mem , seg - > lv - > lvid . s , errid ) ) )
2008-09-19 10:42:00 +04:00
return_NULL ;
if ( ! ( name = build_dm_name ( dm - > mem , seg - > lv - > vg - > name ,
seg - > lv - > name , errid ) ) )
return_NULL ;
if ( ! ( node = dm_tree_add_new_dev ( dtree , name , id , 0 , 0 , 0 , 0 , 0 ) ) )
return_NULL ;
if ( ! dm_tree_node_add_error_target ( node , size ) )
return_NULL ;
return id ;
}
static int _add_error_area ( struct dev_manager * dm , struct dm_tree_node * node ,
struct lv_segment * seg , int s )
{
char * dlid ;
uint64_t extent_size = seg - > lv - > vg - > extent_size ;
if ( ! strcmp ( dm - > cmd - > stripe_filler , " error " ) ) {
/*
* FIXME , the tree pointer is first field of dm_tree_node , but
* we don ' t have the struct definition available .
*/
struct dm_tree * * tree = ( struct dm_tree * * ) node ;
dlid = _add_error_device ( dm , * tree , seg , s ) ;
if ( ! dlid )
return_0 ;
2011-07-06 03:10:14 +04:00
if ( ! dm_tree_node_add_target_area ( node , NULL , dlid , extent_size * seg_le ( seg , s ) ) )
return_0 ;
2008-09-19 11:18:03 +04:00
} else
2011-07-06 03:10:14 +04:00
if ( ! dm_tree_node_add_target_area ( node , dm - > cmd - > stripe_filler , NULL , UINT64_C ( 0 ) ) )
return_0 ;
2008-09-19 11:18:03 +04:00
2008-09-19 10:42:00 +04:00
return 1 ;
}
2005-11-09 01:52:26 +03:00
int add_areas_line ( struct dev_manager * dm , struct lv_segment * seg ,
2006-05-10 01:23:51 +04:00
struct dm_tree_node * node , uint32_t start_area ,
uint32_t areas )
2002-03-11 14:27:48 +03:00
{
2005-11-09 01:52:26 +03:00
uint64_t extent_size = seg - > lv - > vg - > extent_size ;
uint32_t s ;
2002-03-19 02:25:50 +03:00
char * dlid ;
2011-07-06 04:29:44 +04:00
struct stat info ;
const char * name ;
2002-03-11 14:27:48 +03:00
2011-07-06 04:29:44 +04:00
/* FIXME Avoid repeating identical stat in dm_tree_node_add_target_area */
2005-11-09 01:52:26 +03:00
for ( s = start_area ; s < areas ; s + + ) {
if ( ( seg_type ( seg , s ) = = AREA_PV & &
2011-07-06 04:29:44 +04:00
( ! seg_pvseg ( seg , s ) | | ! seg_pv ( seg , s ) | | ! seg_dev ( seg , s ) | |
! ( name = dev_name ( seg_dev ( seg , s ) ) ) | | ! * name | |
stat ( name , & info ) < 0 | | ! S_ISBLK ( info . st_mode ) ) ) | |
2008-09-19 10:42:00 +04:00
( seg_type ( seg , s ) = = AREA_LV & & ! seg_lv ( seg , s ) ) ) {
2011-07-06 04:29:44 +04:00
if ( ! seg - > lv - > vg - > cmd - > partial_activation ) {
log_error ( " Aborting. LV %s is now incomplete "
" and --partial was not specified. " , seg - > lv - > name ) ;
return 0 ;
}
2008-09-19 10:42:00 +04:00
if ( ! _add_error_area ( dm , node , seg , s ) )
return_0 ;
2011-07-06 03:10:14 +04:00
} else if ( seg_type ( seg , s ) = = AREA_PV ) {
if ( ! dm_tree_node_add_target_area ( node , dev_name ( seg_dev ( seg , s ) ) , NULL ,
( seg_pv ( seg , s ) - > pe_start + ( extent_size * seg_pe ( seg , s ) ) ) ) )
return_0 ;
} else if ( seg_type ( seg , s ) = = AREA_LV ) {
if ( ! ( dlid = build_dm_uuid ( dm - > mem , seg_lv ( seg , s ) - > lvid . s , NULL ) ) )
return_0 ;
if ( ! dm_tree_node_add_target_area ( node , NULL , dlid , extent_size * seg_le ( seg , s ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
} else {
2009-12-16 22:22:11 +03:00
log_error ( INTERNAL_ERROR " Unassigned area found in LV %s. " ,
2005-11-09 01:52:26 +03:00
seg - > lv - > name ) ;
2002-03-11 14:27:48 +03:00
return 0 ;
}
2005-11-09 01:52:26 +03:00
}
2002-03-11 14:27:48 +03:00
2005-11-09 01:52:26 +03:00
return 1 ;
}
2002-03-11 14:27:48 +03:00
2005-11-09 16:08:41 +03:00
static int _add_origin_target_to_dtree ( struct dev_manager * dm ,
2005-11-09 16:05:17 +03:00
struct dm_tree_node * dnode ,
2005-11-09 01:52:26 +03:00
struct logical_volume * lv )
{
const char * real_dlid ;
2002-03-11 23:36:04 +03:00
2010-04-14 17:01:38 +04:00
if ( ! ( real_dlid = build_dm_uuid ( dm - > mem , lv - > lvid . s , " real " ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2003-04-25 02:09:13 +04:00
2005-11-09 16:05:17 +03:00
if ( ! dm_tree_node_add_snapshot_origin_target ( dnode , lv - > size , real_dlid ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2002-03-11 14:27:48 +03:00
return 1 ;
}
2010-01-13 04:43:32 +03:00
static int _add_snapshot_merge_target_to_dtree ( struct dev_manager * dm ,
struct dm_tree_node * dnode ,
struct logical_volume * lv )
{
const char * origin_dlid , * cow_dlid , * merge_dlid ;
2010-01-13 04:55:43 +03:00
struct lv_segment * merging_cow_seg = find_merging_cow ( lv ) ;
2010-01-13 04:43:32 +03:00
2010-04-14 17:01:38 +04:00
if ( ! ( origin_dlid = build_dm_uuid ( dm - > mem , lv - > lvid . s , " real " ) ) )
2010-01-13 04:43:32 +03:00
return_0 ;
2010-04-14 17:01:38 +04:00
if ( ! ( cow_dlid = build_dm_uuid ( dm - > mem , merging_cow_seg - > cow - > lvid . s , " cow " ) ) )
2010-01-13 04:43:32 +03:00
return_0 ;
2010-04-14 17:01:38 +04:00
if ( ! ( merge_dlid = build_dm_uuid ( dm - > mem , merging_cow_seg - > cow - > lvid . s , NULL ) ) )
2010-01-13 04:43:32 +03:00
return_0 ;
if ( ! dm_tree_node_add_snapshot_merge_target ( dnode , lv - > size , origin_dlid ,
cow_dlid , merge_dlid ,
2010-01-13 04:55:43 +03:00
merging_cow_seg - > chunk_size ) )
2010-01-13 04:43:32 +03:00
return_0 ;
return 1 ;
}
2005-11-09 16:08:41 +03:00
static int _add_snapshot_target_to_dtree ( struct dev_manager * dm ,
2011-06-17 18:14:19 +04:00
struct dm_tree_node * dnode ,
struct logical_volume * lv ,
struct lv_activate_opts * laopts )
2002-03-11 14:27:48 +03:00
{
2005-11-09 01:52:26 +03:00
const char * origin_dlid ;
const char * cow_dlid ;
struct lv_segment * snap_seg ;
uint64_t size ;
2002-03-11 14:27:48 +03:00
2005-11-09 01:52:26 +03:00
if ( ! ( snap_seg = find_cow ( lv ) ) ) {
log_error ( " Couldn't find snapshot for '%s'. " , lv - > name ) ;
2005-10-26 23:50:00 +04:00
return 0 ;
2002-03-11 14:27:48 +03:00
}
2010-04-14 17:01:38 +04:00
if ( ! ( origin_dlid = build_dm_uuid ( dm - > mem , snap_seg - > origin - > lvid . s , " real " ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2003-04-25 02:09:13 +04:00
2010-04-14 17:01:38 +04:00
if ( ! ( cow_dlid = build_dm_uuid ( dm - > mem , snap_seg - > cow - > lvid . s , " cow " ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2002-03-27 21:17:43 +03:00
2005-11-09 01:52:26 +03:00
size = ( uint64_t ) snap_seg - > len * snap_seg - > origin - > vg - > extent_size ;
2004-05-05 22:11:43 +04:00
2011-06-17 18:22:48 +04:00
if ( ! laopts - > no_merging & & lv_is_merging_cow ( lv ) ) {
2010-02-18 01:59:46 +03:00
/* cow is to be merged so load the error target */
if ( ! dm_tree_node_add_error_target ( dnode , size ) )
return_0 ;
}
else if ( ! dm_tree_node_add_snapshot_target ( dnode , size , origin_dlid ,
cow_dlid , 1 , snap_seg - > chunk_size ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2002-03-11 14:27:48 +03:00
return 1 ;
}
2005-11-09 16:08:41 +03:00
static int _add_target_to_dtree ( struct dev_manager * dm ,
2011-06-17 18:14:19 +04:00
struct dm_tree_node * dnode ,
struct lv_segment * seg ,
struct lv_activate_opts * laopts )
2002-03-11 14:27:48 +03:00
{
2005-11-09 01:52:26 +03:00
uint64_t extent_size = seg - > lv - > vg - > extent_size ;
if ( ! seg - > segtype - > ops - > add_target_line ) {
2009-12-16 22:22:11 +03:00
log_error ( INTERNAL_ERROR " _emit_target cannot handle "
2005-11-09 01:52:26 +03:00
" segment type %s " , seg - > segtype - > name ) ;
return 0 ;
}
2006-05-16 20:48:31 +04:00
return seg - > segtype - > ops - > add_target_line ( dm , dm - > mem , dm - > cmd ,
2005-11-09 01:52:26 +03:00
& dm - > target_state , seg ,
2011-06-17 18:14:19 +04:00
laopts , dnode ,
2005-11-09 01:52:26 +03:00
extent_size * seg - > len ,
& dm - > pvmove_mirror_count ) ;
2002-03-16 01:59:12 +03:00
}
2002-03-11 14:27:48 +03:00
2005-11-09 16:08:41 +03:00
static int _add_new_lv_to_dtree ( struct dev_manager * dm , struct dm_tree * dtree ,
2011-06-17 18:14:19 +04:00
struct logical_volume * lv ,
struct lv_activate_opts * laopts ,
const char * layer ) ;
2005-11-09 01:52:26 +03:00
2010-05-24 13:01:05 +04:00
/* Add all replicators' LVs */
static int _add_replicator_dev_target_to_dtree ( struct dev_manager * dm ,
struct dm_tree * dtree ,
2011-06-17 18:14:19 +04:00
struct lv_segment * seg ,
struct lv_activate_opts * laopts )
2010-05-24 13:01:05 +04:00
{
struct replicator_device * rdev ;
struct replicator_site * rsite ;
/* For inactive replicator add linear mapping */
if ( ! lv_is_active_replicator_dev ( seg - > lv ) ) {
2011-06-17 18:14:19 +04:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , seg - > lv - > rdevice - > lv , laopts , NULL ) )
2010-05-24 13:01:05 +04:00
return_0 ;
return 1 ;
}
/* Add rlog and replicator nodes */
if ( ! seg - > replicator | |
2011-06-17 18:14:19 +04:00
! first_seg ( seg - > replicator ) - > rlog_lv | |
2010-05-24 13:01:05 +04:00
! _add_new_lv_to_dtree ( dm , dtree ,
2011-06-17 18:14:19 +04:00
first_seg ( seg - > replicator ) - > rlog_lv ,
laopts , NULL ) | |
! _add_new_lv_to_dtree ( dm , dtree , seg - > replicator , laopts , NULL ) )
2010-05-24 13:01:05 +04:00
return_0 ;
/* Activation of one replicator_dev node activates all other nodes */
dm_list_iterate_items ( rsite , & seg - > replicator - > rsites ) {
dm_list_iterate_items ( rdev , & rsite - > rdevices ) {
if ( rdev - > lv & &
2011-06-17 18:14:19 +04:00
! _add_new_lv_to_dtree ( dm , dtree , rdev - > lv ,
laopts , NULL ) )
2010-05-24 13:01:05 +04:00
return_0 ;
if ( rdev - > slog & &
2011-06-17 18:14:19 +04:00
! _add_new_lv_to_dtree ( dm , dtree , rdev - > slog ,
laopts , NULL ) )
2010-05-24 13:01:05 +04:00
return_0 ;
}
}
/* Add remaining replicator-dev nodes in the second loop
* to avoid multiple retries for inserting all elements */
dm_list_iterate_items ( rsite , & seg - > replicator - > rsites ) {
if ( rsite - > state ! = REPLICATOR_STATE_ACTIVE )
continue ;
dm_list_iterate_items ( rdev , & rsite - > rdevices ) {
if ( rdev - > replicator_dev - > lv = = seg - > lv )
continue ;
if ( ! rdev - > replicator_dev - > lv | |
! _add_new_lv_to_dtree ( dm , dtree ,
rdev - > replicator_dev - > lv ,
2011-06-17 18:14:19 +04:00
laopts , NULL ) )
2010-05-24 13:01:05 +04:00
return_0 ;
}
}
return 1 ;
}
2005-11-09 16:08:41 +03:00
static int _add_segment_to_dtree ( struct dev_manager * dm ,
2011-06-17 18:14:19 +04:00
struct dm_tree * dtree ,
struct dm_tree_node * dnode ,
struct lv_segment * seg ,
struct lv_activate_opts * laopts ,
const char * layer )
2003-11-12 22:16:48 +03:00
{
2005-11-09 01:52:26 +03:00
uint32_t s ;
2008-11-04 01:14:30 +03:00
struct dm_list * snh ;
2006-11-20 19:45:45 +03:00
struct lv_segment * seg_present ;
2010-10-14 01:26:37 +04:00
const char * target_name ;
2003-11-12 22:16:48 +03:00
2005-11-09 01:52:26 +03:00
/* Ensure required device-mapper targets are loaded */
2006-11-20 19:45:45 +03:00
seg_present = find_cow ( seg - > lv ) ? : seg ;
2010-10-14 01:26:37 +04:00
target_name = ( seg_present - > segtype - > ops - > target_name ?
2011-06-17 18:14:19 +04:00
seg_present - > segtype - > ops - > target_name ( seg_present , laopts ) :
2010-10-14 01:26:37 +04:00
seg_present - > segtype - > name ) ;
2006-11-20 19:45:45 +03:00
log_debug ( " Checking kernel supports %s segment type for %s%s%s " ,
2010-10-14 01:26:37 +04:00
target_name , seg - > lv - > name ,
2006-11-20 19:45:45 +03:00
layer ? " - " : " " , layer ? : " " ) ;
if ( seg_present - > segtype - > ops - > target_present & &
2009-02-28 23:04:24 +03:00
! seg_present - > segtype - > ops - > target_present ( seg_present - > lv - > vg - > cmd ,
seg_present , NULL ) ) {
2010-10-14 01:26:37 +04:00
log_error ( " Can't process LV %s: %s target support missing "
" from kernel? " , seg - > lv - > name , target_name ) ;
2003-11-12 22:16:48 +03:00
return 0 ;
}
2005-11-09 01:52:26 +03:00
/* Add mirror log */
if ( seg - > log_lv & &
2011-06-17 18:14:19 +04:00
! _add_new_lv_to_dtree ( dm , dtree , seg - > log_lv , laopts , NULL ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2003-11-12 22:16:48 +03:00
2010-05-24 13:01:05 +04:00
if ( seg_is_replicator_dev ( seg ) ) {
2011-06-17 18:14:19 +04:00
if ( ! _add_replicator_dev_target_to_dtree ( dm , dtree , seg , laopts ) )
2010-05-24 13:01:05 +04:00
return_0 ;
2005-11-09 01:52:26 +03:00
/* If this is a snapshot origin, add real LV */
2010-01-14 17:39:57 +03:00
/* If this is a snapshot origin + merging snapshot, add cow + real LV */
2010-05-24 13:01:05 +04:00
} else if ( lv_is_origin ( seg - > lv ) & & ! layer ) {
2011-06-17 18:22:48 +04:00
if ( ! laopts - > no_merging & & lv_is_merging_origin ( seg - > lv ) ) {
2010-01-13 04:43:32 +03:00
if ( ! _add_new_lv_to_dtree ( dm , dtree ,
2011-06-17 18:14:19 +04:00
find_merging_cow ( seg - > lv ) - > cow , laopts , " cow " ) )
2010-01-13 04:43:32 +03:00
return_0 ;
/*
* Must also add " real " LV for use when
* snapshot - merge target is added
*/
}
2011-06-17 18:14:19 +04:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , seg - > lv , laopts , " real " ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2011-07-05 05:01:19 +04:00
} else if ( lv_is_cow ( seg - > lv ) & & ! layer ) {
2011-06-17 18:14:19 +04:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , seg - > lv , laopts , " cow " ) )
2005-11-09 01:52:26 +03:00
return_0 ;
} else {
/* Add any LVs used by this segment */
for ( s = 0 ; s < seg - > area_count ; s + + )
if ( ( seg_type ( seg , s ) = = AREA_LV ) & &
2009-12-03 13:01:30 +03:00
( ! _add_new_lv_to_dtree ( dm , dtree , seg_lv ( seg , s ) ,
2011-06-17 18:14:19 +04:00
laopts , NULL ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
}
/* Now we've added its dependencies, we can add the target itself */
if ( lv_is_origin ( seg - > lv ) & & ! layer ) {
2011-06-17 18:22:48 +04:00
if ( laopts - > no_merging | | ! lv_is_merging_origin ( seg - > lv ) ) {
2010-01-13 04:43:32 +03:00
if ( ! _add_origin_target_to_dtree ( dm , dnode , seg - > lv ) )
return_0 ;
} else {
if ( ! _add_snapshot_merge_target_to_dtree ( dm , dnode , seg - > lv ) )
return_0 ;
}
2011-07-05 05:01:19 +04:00
} else if ( lv_is_cow ( seg - > lv ) & & ! layer ) {
2011-06-17 18:14:19 +04:00
if ( ! _add_snapshot_target_to_dtree ( dm , dnode , seg - > lv , laopts ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2011-06-17 18:14:19 +04:00
} else if ( ! _add_target_to_dtree ( dm , dnode , seg , laopts ) )
2005-11-09 01:52:26 +03:00
return_0 ;
if ( lv_is_origin ( seg - > lv ) & & ! layer )
/* Add any snapshots of this LV */
2008-11-04 01:14:30 +03:00
dm_list_iterate ( snh , & seg - > lv - > snapshot_segs )
2011-06-17 18:14:19 +04:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , dm_list_struct_base ( snh , struct lv_segment , origin_list ) - > cow ,
laopts , NULL ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2003-11-12 22:16:48 +03:00
2005-11-09 01:52:26 +03:00
return 1 ;
2003-07-05 02:34:56 +04:00
}
2005-10-17 22:00:02 +04:00
2005-11-09 16:08:41 +03:00
static int _add_new_lv_to_dtree ( struct dev_manager * dm , struct dm_tree * dtree ,
2011-06-17 18:14:19 +04:00
struct logical_volume * lv , struct lv_activate_opts * laopts ,
const char * layer )
2005-10-17 22:21:05 +04:00
{
2005-11-09 01:52:26 +03:00
struct lv_segment * seg ;
struct lv_layer * lvlayer ;
2011-06-11 04:03:06 +04:00
struct seg_list * sl ;
2005-11-09 16:05:17 +03:00
struct dm_tree_node * dnode ;
2010-01-22 18:40:31 +03:00
const struct dm_info * dinfo ;
2010-02-18 01:59:46 +03:00
char * name , * dlid ;
2007-11-12 23:51:54 +03:00
uint32_t max_stripe_size = UINT32_C ( 0 ) ;
uint32_t read_ahead = lv - > read_ahead ;
2007-11-29 18:04:12 +03:00
uint32_t read_ahead_flags = UINT32_C ( 0 ) ;
2005-10-17 22:21:05 +04:00
2010-01-14 17:39:57 +03:00
/* FIXME Seek a simpler way to lay out the snapshot-merge tree. */
2010-01-13 04:55:43 +03:00
if ( lv_is_origin ( lv ) & & lv_is_merging_origin ( lv ) & & ! layer ) {
2010-01-13 04:54:34 +03:00
/*
* Clear merge attributes if merge isn ' t currently possible :
* either origin or merging snapshot are open
2010-01-22 18:40:31 +03:00
* - but use " snapshot-merge " if it is already in use
* - open_count is always retrieved ( as of dm - ioctl 4.7 .0 )
* so just use the tree ' s existing nodes ' info
2010-01-13 04:54:34 +03:00
*/
2010-01-22 18:40:31 +03:00
if ( ( ( dinfo = _cached_info ( dm - > mem , lv ,
dtree ) ) & & dinfo - > open_count ) | |
( ( dinfo = _cached_info ( dm - > mem , find_merging_cow ( lv ) - > cow ,
dtree ) ) & & dinfo - > open_count ) ) {
2010-01-22 16:28:54 +03:00
/* FIXME Is there anything simpler to check for instead? */
2010-04-23 06:57:39 +04:00
if ( ! lv_has_target_type ( dm - > mem , lv , NULL , " snapshot-merge " ) )
2011-06-17 18:22:48 +04:00
laopts - > no_merging = 1 ;
2010-01-13 04:54:34 +03:00
}
}
2010-02-18 01:59:46 +03:00
if ( ! ( name = build_dm_name ( dm - > mem , lv - > vg - > name , lv - > name , layer ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2005-10-17 22:21:05 +04:00
2010-04-14 17:01:38 +04:00
if ( ! ( dlid = build_dm_uuid ( dm - > mem , lv - > lvid . s , layer ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
/* We've already processed this node if it already has a context ptr */
2005-11-09 16:05:17 +03:00
if ( ( dnode = dm_tree_find_node_by_uuid ( dtree , dlid ) ) & &
dm_tree_node_get_context ( dnode ) )
2005-11-09 01:52:26 +03:00
return 1 ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
if ( ! ( lvlayer = dm_pool_alloc ( dm - > mem , sizeof ( * lvlayer ) ) ) ) {
2009-12-03 13:01:30 +03:00
log_error ( " _add_new_lv_to_dtree: pool alloc failed for %s %s. " ,
2010-02-18 01:59:46 +03:00
lv - > name , layer ) ;
2005-10-17 22:21:05 +04:00
return 0 ;
}
2005-11-09 01:52:26 +03:00
lvlayer - > lv = lv ;
/*
2005-11-09 16:08:41 +03:00
* Add LV to dtree .
2005-11-09 01:52:26 +03:00
* If we ' re working with precommitted metadata , clear any
* existing inactive table left behind .
* Major / minor settings only apply to the visible layer .
*/
2011-06-11 04:03:06 +04:00
/* FIXME Move the clear from here until later, so we can leave
* identical inactive tables untouched . ( For pvmove . )
*/
2009-10-22 17:00:07 +04:00
if ( ! ( dnode = dm_tree_add_new_dev_with_udev_flags ( dtree , name , dlid ,
2006-07-10 23:17:40 +04:00
layer ? UINT32_C ( 0 ) : ( uint32_t ) lv - > major ,
layer ? UINT32_C ( 0 ) : ( uint32_t ) lv - > minor ,
2005-11-09 01:52:26 +03:00
_read_only_lv ( lv ) ,
2006-05-11 21:58:58 +04:00
( lv - > vg - > status & PRECOMMITTED ) ? 1 : 0 ,
2009-10-22 17:00:07 +04:00
lvlayer ,
2010-04-23 18:16:32 +04:00
_get_udev_flags ( dm , lv , layer ) ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
/* Store existing name so we can do rename later */
2005-11-09 16:05:17 +03:00
lvlayer - > old_name = dm_tree_node_get_name ( dnode ) ;
2005-11-09 01:52:26 +03:00
/* Create table */
dm - > pvmove_mirror_count = 0u ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & lv - > segments ) {
2011-06-17 18:14:19 +04:00
if ( ! _add_segment_to_dtree ( dm , dtree , dnode , seg , laopts , layer ) )
2005-11-09 01:52:26 +03:00
return_0 ;
/* These aren't real segments in the LVM2 metadata */
if ( lv_is_origin ( lv ) & & ! layer )
break ;
2011-06-17 18:22:48 +04:00
if ( ! laopts - > no_merging & & lv_is_cow ( lv ) & & ! layer )
2005-11-09 01:52:26 +03:00
break ;
2008-06-18 15:32:14 +04:00
if ( max_stripe_size < seg - > stripe_size * seg - > area_count )
max_stripe_size = seg - > stripe_size * seg - > area_count ;
2005-11-09 01:52:26 +03:00
}
2005-10-17 22:21:05 +04:00
2007-12-05 22:24:32 +03:00
if ( read_ahead = = DM_READ_AHEAD_AUTO ) {
2008-01-08 19:47:10 +03:00
/* we need RA at least twice a whole stripe - see the comment in md/raid0.c */
read_ahead = max_stripe_size * 2 ;
2009-05-20 15:09:49 +04:00
if ( ! read_ahead )
2009-06-01 16:43:31 +04:00
lv_calculate_readahead ( lv , & read_ahead ) ;
2007-11-29 18:04:12 +03:00
read_ahead_flags = DM_READ_AHEAD_MINIMUM_FLAG ;
2007-12-05 22:24:32 +03:00
}
2007-11-12 23:51:54 +03:00
2007-11-29 18:04:12 +03:00
dm_tree_node_set_read_ahead ( dnode , read_ahead , read_ahead_flags ) ;
2007-11-12 23:51:54 +03:00
2011-06-11 04:03:06 +04:00
/* Add any LVs referencing a PVMOVE LV unless told not to */
if ( dm - > track_pvmove_deps & & ( lv - > status & PVMOVE ) )
dm_list_iterate_items ( sl , & lv - > segs_using_this_lv )
2011-06-17 18:14:19 +04:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , sl - > seg - > lv , laopts , NULL ) )
2011-06-11 04:03:06 +04:00
return_0 ;
2005-10-18 16:39:20 +04:00
return 1 ;
2005-10-17 22:21:05 +04:00
}
2007-05-15 18:42:01 +04:00
/* FIXME: symlinks should be created/destroyed at the same time
* as the kernel devices but we can ' t do that from within libdevmapper
* at present so we must walk the tree twice instead . */
2005-11-09 01:52:26 +03:00
/*
* Create LV symlinks for children of supplied root node .
*/
2005-11-09 16:05:17 +03:00
static int _create_lv_symlinks ( struct dev_manager * dm , struct dm_tree_node * root )
2005-10-17 22:21:05 +04:00
{
2005-11-09 01:52:26 +03:00
void * handle = NULL ;
2005-11-09 16:05:17 +03:00
struct dm_tree_node * child ;
2005-11-09 01:52:26 +03:00
struct lv_layer * lvlayer ;
2008-12-19 17:22:48 +03:00
char * old_vgname , * old_lvname , * old_layer ;
char * new_vgname , * new_lvname , * new_layer ;
2005-11-09 01:52:26 +03:00
const char * name ;
int r = 1 ;
2005-10-17 22:21:05 +04:00
2011-06-17 18:50:53 +04:00
/* Nothing to do if udev fallback is disabled. */
if ( ! dm - > cmd - > current_settings . udev_fallback )
return 1 ;
2005-11-09 16:05:17 +03:00
while ( ( child = dm_tree_next_child ( & handle , root , 0 ) ) ) {
2009-12-03 12:59:54 +03:00
if ( ! ( lvlayer = dm_tree_node_get_context ( child ) ) )
2005-11-09 01:52:26 +03:00
continue ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
/* Detect rename */
2005-11-09 16:05:17 +03:00
name = dm_tree_node_get_name ( child ) ;
2005-10-17 22:21:05 +04:00
2005-11-09 01:52:26 +03:00
if ( name & & lvlayer - > old_name & & * lvlayer - > old_name & & strcmp ( name , lvlayer - > old_name ) ) {
2008-12-19 17:22:48 +03:00
if ( ! dm_split_lvm_name ( dm - > mem , lvlayer - > old_name , & old_vgname , & old_lvname , & old_layer ) ) {
2008-01-30 17:00:02 +03:00
log_error ( " _create_lv_symlinks: Couldn't split up old device name %s " , lvlayer - > old_name ) ;
return 0 ;
}
2008-12-19 17:22:48 +03:00
if ( ! dm_split_lvm_name ( dm - > mem , name , & new_vgname , & new_lvname , & new_layer ) ) {
log_error ( " _create_lv_symlinks: Couldn't split up new device name %s " , name ) ;
return 0 ;
}
if ( ! fs_rename_lv ( lvlayer - > lv , name , old_vgname , old_lvname ) )
r = 0 ;
2009-05-28 05:11:29 +04:00
continue ;
}
if ( lv_is_visible ( lvlayer - > lv ) ) {
2010-02-24 23:00:56 +03:00
if ( ! _dev_manager_lv_mknodes ( lvlayer - > lv ) )
2009-05-28 05:11:29 +04:00
r = 0 ;
continue ;
}
2010-02-24 23:00:56 +03:00
if ( ! _dev_manager_lv_rmnodes ( lvlayer - > lv ) )
2005-11-09 01:52:26 +03:00
r = 0 ;
2005-10-17 22:21:05 +04:00
}
2005-11-09 01:52:26 +03:00
return r ;
}
2005-10-18 16:39:20 +04:00
2007-05-15 18:42:01 +04:00
/*
* Remove LV symlinks for children of supplied root node .
*/
static int _remove_lv_symlinks ( struct dev_manager * dm , struct dm_tree_node * root )
{
void * handle = NULL ;
struct dm_tree_node * child ;
char * vgname , * lvname , * layer ;
int r = 1 ;
2011-06-17 18:50:53 +04:00
/* Nothing to do if udev fallback is disabled. */
if ( ! dm - > cmd - > current_settings . udev_fallback )
return 1 ;
2007-05-15 18:42:01 +04:00
while ( ( child = dm_tree_next_child ( & handle , root , 0 ) ) ) {
2008-01-30 17:00:02 +03:00
if ( ! dm_split_lvm_name ( dm - > mem , dm_tree_node_get_name ( child ) , & vgname , & lvname , & layer ) ) {
2007-05-15 18:42:01 +04:00
r = 0 ;
continue ;
}
2008-06-05 16:45:55 +04:00
if ( ! * vgname )
continue ;
2007-05-15 18:42:01 +04:00
/* only top level layer has symlinks */
if ( * layer )
continue ;
2010-01-07 22:54:21 +03:00
fs_del_lv_byname ( dm - > cmd - > dev_dir , vgname , lvname ,
dm - > cmd - > current_settings . udev_rules ) ;
2007-05-15 18:42:01 +04:00
}
return r ;
}
2010-08-17 23:25:05 +04:00
static int _clean_tree ( struct dev_manager * dm , struct dm_tree_node * root , char * non_toplevel_tree_dlid )
2005-11-09 01:52:26 +03:00
{
void * handle = NULL ;
2005-11-09 16:05:17 +03:00
struct dm_tree_node * child ;
2005-11-09 01:52:26 +03:00
char * vgname , * lvname , * layer ;
const char * name , * uuid ;
2005-11-09 16:05:17 +03:00
while ( ( child = dm_tree_next_child ( & handle , root , 0 ) ) ) {
if ( ! ( name = dm_tree_node_get_name ( child ) ) )
2005-11-09 01:52:26 +03:00
continue ;
2005-11-09 16:05:17 +03:00
if ( ! ( uuid = dm_tree_node_get_uuid ( child ) ) )
2005-11-09 01:52:26 +03:00
continue ;
2008-01-30 17:00:02 +03:00
if ( ! dm_split_lvm_name ( dm - > mem , name , & vgname , & lvname , & layer ) ) {
log_error ( " _clean_tree: Couldn't split up device name %s. " , name ) ;
return 0 ;
}
2005-11-09 01:52:26 +03:00
/* Not meant to be top level? */
if ( ! * layer )
continue ;
2010-08-17 23:25:05 +04:00
/* If operation was performed on a partial tree, don't remove it */
if ( non_toplevel_tree_dlid & & ! strcmp ( non_toplevel_tree_dlid , uuid ) )
continue ;
2011-01-10 17:02:30 +03:00
if ( ! dm_tree_deactivate_children ( root , uuid , strlen ( uuid ) ) )
2009-08-03 22:01:45 +04:00
return_0 ;
2005-11-09 01:52:26 +03:00
}
return 1 ;
2005-10-17 22:21:05 +04:00
}
2010-08-17 20:25:32 +04:00
static int _tree_action ( struct dev_manager * dm , struct logical_volume * lv ,
2011-06-17 18:14:19 +04:00
struct lv_activate_opts * laopts , action_t action )
2005-10-17 22:21:05 +04:00
{
2005-11-09 16:05:17 +03:00
struct dm_tree * dtree ;
struct dm_tree_node * root ;
2005-10-18 16:39:20 +04:00
char * dlid ;
2005-10-17 22:21:05 +04:00
int r = 0 ;
2011-06-17 18:14:19 +04:00
if ( ! ( dtree = _create_partial_dtree ( dm , lv , laopts - > origin_only ) ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2005-10-17 22:21:05 +04:00
2005-11-09 16:05:17 +03:00
if ( ! ( root = dm_tree_find_node ( dtree , 0 , 0 ) ) ) {
2005-10-18 16:39:20 +04:00
log_error ( " Lost dependency tree root node " ) ;
2011-01-10 17:02:30 +03:00
goto out_no_root ;
2005-10-17 22:21:05 +04:00
}
2011-01-10 17:02:30 +03:00
/* Restore fs cookie */
dm_tree_set_cookie ( root , fs_get_cookie ( ) ) ;
2011-06-30 22:25:18 +04:00
if ( ! ( dlid = build_dm_uuid ( dm - > mem , lv - > lvid . s , ( lv_is_origin ( lv ) & & laopts - > origin_only ) ? " real " : NULL ) ) )
2005-11-09 01:52:26 +03:00
goto_out ;
2005-10-17 22:21:05 +04:00
2005-10-19 17:59:18 +04:00
/* Only process nodes with uuid of "LVM-" plus VG id. */
2005-10-25 23:08:21 +04:00
switch ( action ) {
2005-11-09 01:52:26 +03:00
case CLEAN :
/* Deactivate any unused non-toplevel nodes */
2011-06-17 18:14:19 +04:00
if ( ! _clean_tree ( dm , root , laopts - > origin_only ? dlid : NULL ) )
2005-11-09 01:52:26 +03:00
goto_out ;
break ;
2005-10-25 23:08:21 +04:00
case DEACTIVATE :
2005-11-09 01:52:26 +03:00
/* Deactivate LV and all devices it references that nothing else has open. */
2009-08-03 22:01:45 +04:00
r = dm_tree_deactivate_children ( root , dlid , ID_LEN + sizeof ( UUID_PREFIX ) - 1 ) ;
if ( ! r )
goto_out ;
2007-05-15 18:42:01 +04:00
if ( ! _remove_lv_symlinks ( dm , root ) )
log_error ( " Failed to remove all device symlinks associated with %s. " , lv - > name ) ;
2005-10-25 23:08:21 +04:00
break ;
case SUSPEND :
2006-08-09 01:20:00 +04:00
dm_tree_skip_lockfs ( root ) ;
2009-05-20 13:52:37 +04:00
if ( ! dm - > flush_required & & ( lv - > status & MIRRORED ) & & ! ( lv - > status & PVMOVE ) )
2007-01-09 23:31:08 +03:00
dm_tree_use_no_flush_suspend ( root ) ;
2011-02-28 22:53:03 +03:00
/* Fall through */
2006-08-09 01:20:00 +04:00
case SUSPEND_WITH_LOCKFS :
2005-11-09 16:05:17 +03:00
if ( ! dm_tree_suspend_children ( root , dlid , ID_LEN + sizeof ( UUID_PREFIX ) - 1 ) )
2005-11-09 01:52:26 +03:00
goto_out ;
break ;
case PRELOAD :
case ACTIVATE :
/* Add all required new devices to tree */
2011-06-30 22:25:18 +04:00
if ( ! _add_new_lv_to_dtree ( dm , dtree , lv , laopts , ( lv_is_origin ( lv ) & & laopts - > origin_only ) ? " real " : NULL ) )
2005-11-09 01:52:26 +03:00
goto_out ;
/* Preload any devices required before any suspensions */
2009-08-03 22:01:45 +04:00
r = dm_tree_preload_children ( root , dlid , ID_LEN + sizeof ( UUID_PREFIX ) - 1 ) ;
if ( ! r )
goto_out ;
2005-11-09 01:52:26 +03:00
2009-05-20 13:52:37 +04:00
if ( dm_tree_node_size_changed ( root ) )
dm - > flush_required = 1 ;
2009-07-31 22:30:31 +04:00
if ( action = = ACTIVATE ) {
2009-08-03 22:01:45 +04:00
r = dm_tree_activate_children ( root , dlid , ID_LEN + sizeof ( UUID_PREFIX ) - 1 ) ;
if ( ! r )
goto_out ;
2009-08-03 22:09:25 +04:00
if ( ! _create_lv_symlinks ( dm , root ) ) {
log_error ( " Failed to create symlinks for %s. " , lv - > name ) ;
goto out ;
}
2009-07-31 22:30:31 +04:00
}
2005-11-09 01:52:26 +03:00
2005-10-25 23:08:21 +04:00
break ;
default :
log_error ( " _tree_action: Action %u not supported. " , action ) ;
2005-10-17 22:21:05 +04:00
goto out ;
2009-12-03 12:58:30 +03:00
}
2005-10-17 22:21:05 +04:00
r = 1 ;
out :
2011-01-10 17:02:30 +03:00
/* Save fs cookie for udev settle, do not wait here */
fs_set_cookie ( dm_tree_get_cookie ( root ) ) ;
out_no_root :
2005-11-09 16:05:17 +03:00
dm_tree_free ( dtree ) ;
2005-10-17 22:21:05 +04:00
return r ;
}
2010-08-17 20:25:32 +04:00
/* origin_only may only be set if we are resuming (not activating) an origin LV */
2011-06-17 18:14:19 +04:00
int dev_manager_activate ( struct dev_manager * dm , struct logical_volume * lv ,
struct lv_activate_opts * laopts )
2005-11-09 01:52:26 +03:00
{
2011-06-17 18:14:19 +04:00
if ( ! _tree_action ( dm , lv , laopts , ACTIVATE ) )
2005-11-09 01:52:26 +03:00
return_0 ;
2011-06-17 18:14:19 +04:00
return _tree_action ( dm , lv , laopts , CLEAN ) ;
2005-11-09 01:52:26 +03:00
}
2010-08-17 20:25:32 +04:00
/* origin_only may only be set if we are resuming (not activating) an origin LV */
2009-05-20 13:52:37 +04:00
int dev_manager_preload ( struct dev_manager * dm , struct logical_volume * lv ,
2011-06-17 18:14:19 +04:00
struct lv_activate_opts * laopts , int * flush_required )
2005-11-09 01:52:26 +03:00
{
2011-06-17 18:14:19 +04:00
if ( ! _tree_action ( dm , lv , laopts , PRELOAD ) )
2009-05-20 13:52:37 +04:00
return 0 ;
* flush_required = dm - > flush_required ;
return 1 ;
2005-11-09 01:52:26 +03:00
}
2005-10-26 18:13:52 +04:00
2005-10-25 23:08:21 +04:00
int dev_manager_deactivate ( struct dev_manager * dm , struct logical_volume * lv )
{
2011-06-17 18:14:19 +04:00
struct lv_activate_opts laopts = { 0 } ;
2005-10-25 23:08:21 +04:00
int r ;
2011-06-17 18:14:19 +04:00
r = _tree_action ( dm , lv , & laopts , DEACTIVATE ) ;
2005-10-25 23:08:21 +04:00
return r ;
}
2006-08-09 01:20:00 +04:00
int dev_manager_suspend ( struct dev_manager * dm , struct logical_volume * lv ,
2011-06-17 18:14:19 +04:00
struct lv_activate_opts * laopts , int lockfs , int flush_required )
2005-10-26 18:13:52 +04:00
{
2009-05-20 13:52:37 +04:00
dm - > flush_required = flush_required ;
2011-06-17 18:14:19 +04:00
return _tree_action ( dm , lv , laopts , lockfs ? SUSPEND_WITH_LOCKFS : SUSPEND ) ;
2005-10-26 18:13:52 +04:00
}
2005-10-25 23:08:21 +04:00
/*
* Does device use VG somewhere in its construction ?
* Returns 1 if uncertain .
*/
2006-05-11 21:58:58 +04:00
int dev_manager_device_uses_vg ( struct device * dev ,
2005-10-25 23:08:21 +04:00
struct volume_group * vg )
{
2005-11-09 16:05:17 +03:00
struct dm_tree * dtree ;
struct dm_tree_node * root ;
2010-07-09 19:34:40 +04:00
char dlid [ sizeof ( UUID_PREFIX ) + sizeof ( struct id ) - 1 ] __attribute__ ( ( aligned ( 8 ) ) ) ;
2005-10-25 23:08:21 +04:00
int r = 1 ;
2005-11-09 16:05:17 +03:00
if ( ! ( dtree = dm_tree_create ( ) ) ) {
2005-11-09 16:08:41 +03:00
log_error ( " partial dtree creation failed " ) ;
2005-10-25 23:08:21 +04:00
return r ;
}
2006-05-11 21:58:58 +04:00
if ( ! dm_tree_add_dev ( dtree , ( uint32_t ) MAJOR ( dev - > dev ) , ( uint32_t ) MINOR ( dev - > dev ) ) ) {
2005-11-09 16:08:41 +03:00
log_error ( " Failed to add device %s (% " PRIu32 " :% " PRIu32 " ) to dtree " ,
2005-10-25 23:08:21 +04:00
dev_name ( dev ) , ( uint32_t ) MAJOR ( dev - > dev ) , ( uint32_t ) MINOR ( dev - > dev ) ) ;
goto out ;
}
memcpy ( dlid , UUID_PREFIX , sizeof ( UUID_PREFIX ) - 1 ) ;
memcpy ( dlid + sizeof ( UUID_PREFIX ) - 1 , & vg - > id . uuid [ 0 ] , sizeof ( vg - > id ) ) ;
2005-11-09 16:05:17 +03:00
if ( ! ( root = dm_tree_find_node ( dtree , 0 , 0 ) ) ) {
2005-10-25 23:08:21 +04:00
log_error ( " Lost dependency tree root node " ) ;
goto out ;
}
2005-11-09 16:05:17 +03:00
if ( dm_tree_children_use_uuid ( root , dlid , sizeof ( UUID_PREFIX ) + sizeof ( vg - > id ) - 1 ) )
2005-11-09 01:52:26 +03:00
goto_out ;
2005-10-25 23:08:21 +04:00
r = 0 ;
out :
2005-11-09 16:05:17 +03:00
dm_tree_free ( dtree ) ;
2005-10-25 23:08:21 +04:00
return r ;
}