2005-10-16 18:33:22 +04:00
/*
2010-05-24 13:04:27 +04:00
* Copyright ( C ) 2005 - 2010 Red Hat , Inc . All rights reserved .
2005-10-16 18:33:22 +04:00
*
* This file is part of the device - mapper userspace tools .
*
* This copyrighted material is made available to anyone wishing to use ,
* modify , copy , or redistribute it subject to the terms and conditions
* of the GNU Lesser General Public License v .2 .1 .
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program ; if not , write to the Free Software Foundation ,
* Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
2008-11-03 21:59:59 +03:00
# include "dmlib.h"
2005-10-16 18:33:22 +04:00
# include "libdm-targets.h"
# include "libdm-common.h"
# include "kdev_t.h"
2008-11-01 05:19:19 +03:00
# include "dm-ioctl.h"
2005-10-16 18:33:22 +04:00
# include <stdarg.h>
# include <sys/param.h>
2009-08-13 20:31:01 +04:00
# include <sys/utsname.h>
2005-10-16 18:33:22 +04:00
2005-11-09 01:50:11 +03:00
# define MAX_TARGET_PARAMSIZE 500000
2005-11-13 01:46:48 +03:00
/* FIXME Fix interface so this is used only by LVM */
# define UUID_PREFIX "LVM-"
2010-05-21 16:24:15 +04:00
# define REPLICATOR_LOCAL_SITE 0
2005-11-09 01:50:11 +03:00
/* Supported segment types */
enum {
2009-06-09 20:10:20 +04:00
SEG_CRYPT ,
SEG_ERROR ,
2005-11-09 01:50:11 +03:00
SEG_LINEAR ,
SEG_MIRRORED ,
2010-05-21 16:24:15 +04:00
SEG_REPLICATOR ,
SEG_REPLICATOR_DEV ,
2005-11-09 01:50:11 +03:00
SEG_SNAPSHOT ,
SEG_SNAPSHOT_ORIGIN ,
2010-01-13 04:39:44 +03:00
SEG_SNAPSHOT_MERGE ,
2005-11-09 01:50:11 +03:00
SEG_STRIPED ,
SEG_ZERO ,
} ;
2005-11-09 17:10:50 +03:00
2005-11-09 01:50:11 +03:00
/* FIXME Add crypt and multipath support */
struct {
unsigned type ;
const char * target ;
} dm_segtypes [ ] = {
2009-06-09 20:10:20 +04:00
{ SEG_CRYPT , " crypt " } ,
2005-11-09 01:50:11 +03:00
{ SEG_ERROR , " error " } ,
{ SEG_LINEAR , " linear " } ,
{ SEG_MIRRORED , " mirror " } ,
2010-05-21 16:24:15 +04:00
{ SEG_REPLICATOR , " replicator " } ,
{ SEG_REPLICATOR_DEV , " replicator-dev " } ,
2005-11-09 01:50:11 +03:00
{ SEG_SNAPSHOT , " snapshot " } ,
{ SEG_SNAPSHOT_ORIGIN , " snapshot-origin " } ,
2010-01-13 04:39:44 +03:00
{ SEG_SNAPSHOT_MERGE , " snapshot-merge " } ,
2005-11-09 01:50:11 +03:00
{ SEG_STRIPED , " striped " } ,
{ SEG_ZERO , " zero " } ,
} ;
/* Some segment types have a list of areas of other devices attached */
struct seg_area {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2005-11-09 01:50:11 +03:00
2005-11-09 17:10:50 +03:00
struct dm_tree_node * dev_node ;
2005-11-09 01:50:11 +03:00
uint64_t offset ;
2010-05-21 16:24:15 +04:00
unsigned rsite_index ; /* Replicator site index */
struct dm_tree_node * slog ; /* Replicator sync log node */
uint64_t region_size ; /* Replicator sync log size */
uint32_t flags ; /* Replicator sync log flags */
} ;
/* Replicator-log has a list of sites */
/* FIXME: maybe move to seg_area too? */
struct replicator_site {
struct dm_list list ;
unsigned rsite_index ;
dm_replicator_mode_t mode ;
uint32_t async_timeout ;
uint32_t fall_behind_ios ;
uint64_t fall_behind_data ;
2005-11-09 01:50:11 +03:00
} ;
/* Per-segment properties */
struct load_segment {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2005-11-09 01:50:11 +03:00
unsigned type ;
uint64_t size ;
2010-05-21 16:24:15 +04:00
unsigned area_count ; /* Linear + Striped + Mirrored + Crypt + Replicator */
struct dm_list areas ; /* Linear + Striped + Mirrored + Crypt + Replicator */
2005-11-09 01:50:11 +03:00
uint32_t stripe_size ; /* Striped */
int persistent ; /* Snapshot */
uint32_t chunk_size ; /* Snapshot */
2005-11-09 17:10:50 +03:00
struct dm_tree_node * cow ; /* Snapshot */
struct dm_tree_node * origin ; /* Snapshot + Snapshot origin */
2010-01-13 04:39:44 +03:00
struct dm_tree_node * merge ; /* Snapshot */
2005-11-09 01:50:11 +03:00
2010-05-21 16:24:15 +04:00
struct dm_tree_node * log ; /* Mirror + Replicator */
2005-11-09 01:50:11 +03:00
uint32_t region_size ; /* Mirror */
unsigned clustered ; /* Mirror */
unsigned mirror_area_count ; /* Mirror */
2005-12-13 18:49:27 +03:00
uint32_t flags ; /* Mirror log */
2006-02-06 23:18:10 +03:00
char * uuid ; /* Clustered mirror log */
2009-06-09 20:10:20 +04:00
const char * cipher ; /* Crypt */
const char * chainmode ; /* Crypt */
const char * iv ; /* Crypt */
uint64_t iv_offset ; /* Crypt */
const char * key ; /* Crypt */
2010-05-21 16:24:15 +04:00
const char * rlog_type ; /* Replicator */
struct dm_list rsites ; /* Replicator */
unsigned rsite_count ; /* Replicator */
unsigned rdevice_count ; /* Replicator */
struct dm_tree_node * replicator ; /* Replicator-dev */
uint64_t rdevice_index ; /* Replicator-dev */
2005-11-09 01:50:11 +03:00
} ;
/* Per-device properties */
struct load_properties {
int read_only ;
uint32_t major ;
uint32_t minor ;
2007-11-27 23:57:05 +03:00
uint32_t read_ahead ;
uint32_t read_ahead_flags ;
2005-11-09 01:50:11 +03:00
unsigned segment_count ;
2008-09-18 22:34:53 +04:00
unsigned size_changed ;
2008-11-04 01:14:30 +03:00
struct dm_list segs ;
2005-11-09 01:50:11 +03:00
const char * new_name ;
2010-06-21 12:54:32 +04:00
/* If immediate_dev_node is set to 1, try to create the dev node
* as soon as possible ( e . g . in preload stage even during traversal
* and processing of dm tree ) . This will also flush all stacked dev
* node operations , synchronizing with udev .
*/
int immediate_dev_node ;
2005-11-09 01:50:11 +03:00
} ;
/* Two of these used to join two nodes with uses and used_by. */
2005-11-09 17:10:50 +03:00
struct dm_tree_link {
2008-11-04 01:14:30 +03:00
struct dm_list list ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node * node ;
2005-11-09 01:50:11 +03:00
} ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node {
struct dm_tree * dtree ;
2005-10-16 18:33:22 +04:00
const char * name ;
const char * uuid ;
struct dm_info info ;
2008-11-04 01:14:30 +03:00
struct dm_list uses ; /* Nodes this node uses */
struct dm_list used_by ; /* Nodes that use this node */
2005-11-09 01:50:11 +03:00
2005-11-22 23:00:35 +03:00
int activation_priority ; /* 0 gets activated first */
2009-10-22 17:00:07 +04:00
uint16_t udev_flags ; /* Udev control flags */
2005-11-09 01:50:11 +03:00
void * context ; /* External supplied context */
struct load_properties props ; /* For creation/table (re)load */
2010-05-21 16:27:02 +04:00
/*
* If presuspend of child node is needed
* Note : only direct child is allowed
*/
struct dm_tree_node * presuspend_node ;
2005-10-16 18:33:22 +04:00
} ;
2005-11-09 17:10:50 +03:00
struct dm_tree {
2005-10-17 02:57:20 +04:00
struct dm_pool * mem ;
struct dm_hash_table * devs ;
2005-11-09 01:50:11 +03:00
struct dm_hash_table * uuids ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node root ;
2006-01-31 02:36:04 +03:00
int skip_lockfs ; /* 1 skips lockfs (for non-snapshots) */
2007-01-09 22:44:07 +03:00
int no_flush ; /* 1 sets noflush (mirrors/multipath) */
2009-07-31 22:30:31 +04:00
uint32_t cookie ;
2005-10-16 18:33:22 +04:00
} ;
2005-11-09 17:10:50 +03:00
struct dm_tree * dm_tree_create ( void )
2005-10-16 18:33:22 +04:00
{
2005-11-09 17:10:50 +03:00
struct dm_tree * dtree ;
2005-10-16 18:33:22 +04:00
2010-10-01 01:06:50 +04:00
if ( ! ( dtree = dm_zalloc ( sizeof ( * dtree ) ) ) ) {
2005-11-09 17:10:50 +03:00
log_error ( " dm_tree_create malloc failed " ) ;
2005-10-16 18:33:22 +04:00
return NULL ;
}
2005-11-09 17:10:50 +03:00
dtree - > root . dtree = dtree ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & dtree - > root . uses ) ;
dm_list_init ( & dtree - > root . used_by ) ;
2006-01-31 02:36:04 +03:00
dtree - > skip_lockfs = 0 ;
2007-01-09 22:44:07 +03:00
dtree - > no_flush = 0 ;
2005-10-16 18:33:22 +04:00
2005-11-09 17:10:50 +03:00
if ( ! ( dtree - > mem = dm_pool_create ( " dtree " , 1024 ) ) ) {
log_error ( " dtree pool creation failed " ) ;
dm_free ( dtree ) ;
2005-10-16 18:33:22 +04:00
return NULL ;
}
2005-11-09 17:10:50 +03:00
if ( ! ( dtree - > devs = dm_hash_create ( 8 ) ) ) {
log_error ( " dtree hash creation failed " ) ;
dm_pool_destroy ( dtree - > mem ) ;
dm_free ( dtree ) ;
2005-10-16 18:33:22 +04:00
return NULL ;
}
2005-11-09 17:10:50 +03:00
if ( ! ( dtree - > uuids = dm_hash_create ( 32 ) ) ) {
log_error ( " dtree uuid hash creation failed " ) ;
dm_hash_destroy ( dtree - > devs ) ;
dm_pool_destroy ( dtree - > mem ) ;
dm_free ( dtree ) ;
2005-11-09 01:50:11 +03:00
return NULL ;
}
2005-11-09 17:10:50 +03:00
return dtree ;
2005-10-16 18:33:22 +04:00
}
2005-11-09 17:10:50 +03:00
void dm_tree_free ( struct dm_tree * dtree )
2005-10-16 18:33:22 +04:00
{
2005-11-09 17:10:50 +03:00
if ( ! dtree )
2005-10-16 18:33:22 +04:00
return ;
2005-11-09 17:10:50 +03:00
dm_hash_destroy ( dtree - > uuids ) ;
dm_hash_destroy ( dtree - > devs ) ;
dm_pool_destroy ( dtree - > mem ) ;
dm_free ( dtree ) ;
2005-10-16 18:33:22 +04:00
}
2010-01-14 13:15:23 +03:00
static int _nodes_are_linked ( const struct dm_tree_node * parent ,
const struct dm_tree_node * child )
2005-10-16 18:33:22 +04:00
{
2005-11-09 17:10:50 +03:00
struct dm_tree_link * dlink ;
2005-10-16 18:33:22 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( dlink , & parent - > uses )
2005-10-16 18:33:22 +04:00
if ( dlink - > node = = child )
return 1 ;
return 0 ;
}
2008-11-04 01:14:30 +03:00
static int _link ( struct dm_list * list , struct dm_tree_node * node )
2005-10-16 18:33:22 +04:00
{
2005-11-09 17:10:50 +03:00
struct dm_tree_link * dlink ;
2005-10-16 18:33:22 +04:00
2005-11-09 17:10:50 +03:00
if ( ! ( dlink = dm_pool_alloc ( node - > dtree - > mem , sizeof ( * dlink ) ) ) ) {
log_error ( " dtree link allocation failed " ) ;
2005-10-16 18:33:22 +04:00
return 0 ;
}
dlink - > node = node ;
2008-11-04 01:14:30 +03:00
dm_list_add ( list , & dlink - > list ) ;
2005-10-16 18:33:22 +04:00
return 1 ;
}
2005-11-09 17:10:50 +03:00
static int _link_nodes ( struct dm_tree_node * parent ,
struct dm_tree_node * child )
2005-10-16 18:33:22 +04:00
{
if ( _nodes_are_linked ( parent , child ) )
return 1 ;
if ( ! _link ( & parent - > uses , child ) )
return 0 ;
if ( ! _link ( & child - > used_by , parent ) )
return 0 ;
return 1 ;
}
2008-11-04 01:14:30 +03:00
static void _unlink ( struct dm_list * list , struct dm_tree_node * node )
2005-10-16 18:33:22 +04:00
{
2005-11-09 17:10:50 +03:00
struct dm_tree_link * dlink ;
2005-10-16 18:33:22 +04:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( dlink , list )
2005-10-16 18:33:22 +04:00
if ( dlink - > node = = node ) {
2008-11-04 01:14:30 +03:00
dm_list_del ( & dlink - > list ) ;
2005-10-16 18:33:22 +04:00
break ;
}
}
2005-11-09 17:10:50 +03:00
static void _unlink_nodes ( struct dm_tree_node * parent ,
struct dm_tree_node * child )
2005-10-16 18:33:22 +04:00
{
if ( ! _nodes_are_linked ( parent , child ) )
return ;
_unlink ( & parent - > uses , child ) ;
_unlink ( & child - > used_by , parent ) ;
}
2005-11-09 17:10:50 +03:00
static int _add_to_toplevel ( struct dm_tree_node * node )
2005-11-09 01:50:11 +03:00
{
2005-11-09 17:10:50 +03:00
return _link_nodes ( & node - > dtree - > root , node ) ;
2005-11-09 01:50:11 +03:00
}
2005-11-09 17:10:50 +03:00
static void _remove_from_toplevel ( struct dm_tree_node * node )
2005-10-16 18:33:22 +04:00
{
2009-12-11 16:16:37 +03:00
_unlink_nodes ( & node - > dtree - > root , node ) ;
2005-10-16 18:33:22 +04:00
}
2005-11-09 17:10:50 +03:00
static int _add_to_bottomlevel ( struct dm_tree_node * node )
2005-10-16 18:33:22 +04:00
{
2005-11-09 17:10:50 +03:00
return _link_nodes ( node , & node - > dtree - > root ) ;
2005-10-16 18:33:22 +04:00
}
2005-11-09 17:10:50 +03:00
static void _remove_from_bottomlevel ( struct dm_tree_node * node )
2005-11-09 01:50:11 +03:00
{
2009-12-11 16:16:37 +03:00
_unlink_nodes ( node , & node - > dtree - > root ) ;
2005-11-09 01:50:11 +03:00
}
2005-11-09 17:10:50 +03:00
static int _link_tree_nodes ( struct dm_tree_node * parent , struct dm_tree_node * child )
2005-11-09 01:50:11 +03:00
{
/* Don't link to root node if child already has a parent */
2005-11-09 17:10:50 +03:00
if ( ( parent = = & parent - > dtree - > root ) ) {
if ( dm_tree_node_num_children ( child , 1 ) )
2005-11-09 01:50:11 +03:00
return 1 ;
} else
_remove_from_toplevel ( child ) ;
2005-11-09 17:10:50 +03:00
if ( ( child = = & child - > dtree - > root ) ) {
if ( dm_tree_node_num_children ( parent , 0 ) )
2005-11-09 01:50:11 +03:00
return 1 ;
} else
_remove_from_bottomlevel ( parent ) ;
return _link_nodes ( parent , child ) ;
}
2005-11-09 17:10:50 +03:00
static struct dm_tree_node * _create_dm_tree_node ( struct dm_tree * dtree ,
2005-10-16 18:33:22 +04:00
const char * name ,
const char * uuid ,
2005-11-09 01:50:11 +03:00
struct dm_info * info ,
2009-10-22 17:00:07 +04:00
void * context ,
uint16_t udev_flags )
2005-10-16 18:33:22 +04:00
{
2005-11-09 17:10:50 +03:00
struct dm_tree_node * node ;
2005-10-16 18:33:22 +04:00
uint64_t dev ;
2005-11-09 17:10:50 +03:00
if ( ! ( node = dm_pool_zalloc ( dtree - > mem , sizeof ( * node ) ) ) ) {
log_error ( " _create_dm_tree_node alloc failed " ) ;
2005-10-16 18:33:22 +04:00
return NULL ;
}
2005-11-09 17:10:50 +03:00
node - > dtree = dtree ;
2005-10-16 18:33:22 +04:00
node - > name = name ;
node - > uuid = uuid ;
node - > info = * info ;
2005-11-09 01:50:11 +03:00
node - > context = context ;
2009-10-22 17:00:07 +04:00
node - > udev_flags = udev_flags ;
2005-11-22 23:00:35 +03:00
node - > activation_priority = 0 ;
2005-10-16 18:33:22 +04:00
2008-11-04 01:14:30 +03:00
dm_list_init ( & node - > uses ) ;
dm_list_init ( & node - > used_by ) ;
dm_list_init ( & node - > props . segs ) ;
2005-10-16 18:33:22 +04:00
dev = MKDEV ( info - > major , info - > minor ) ;
2005-11-09 17:10:50 +03:00
if ( ! dm_hash_insert_binary ( dtree - > devs , ( const char * ) & dev ,
2005-10-16 18:33:22 +04:00
sizeof ( dev ) , node ) ) {
2005-11-09 17:10:50 +03:00
log_error ( " dtree node hash insertion failed " ) ;
dm_pool_free ( dtree - > mem , node ) ;
2005-10-16 18:33:22 +04:00
return NULL ;
}
2005-11-09 01:50:11 +03:00
if ( uuid & & * uuid & &
2005-11-09 17:10:50 +03:00
! dm_hash_insert ( dtree - > uuids , uuid , node ) ) {
log_error ( " dtree uuid hash insertion failed " ) ;
dm_hash_remove_binary ( dtree - > devs , ( const char * ) & dev ,
2005-11-09 01:50:11 +03:00
sizeof ( dev ) ) ;
2005-11-09 17:10:50 +03:00
dm_pool_free ( dtree - > mem , node ) ;
2005-11-09 01:50:11 +03:00
return NULL ;
}
2005-10-16 18:33:22 +04:00
return node ;
}
2005-11-09 17:10:50 +03:00
static struct dm_tree_node * _find_dm_tree_node ( struct dm_tree * dtree ,
2005-10-16 18:33:22 +04:00
uint32_t major , uint32_t minor )
{
uint64_t dev = MKDEV ( major , minor ) ;
2005-11-09 17:10:50 +03:00
return dm_hash_lookup_binary ( dtree - > devs , ( const char * ) & dev ,
2005-10-16 18:33:22 +04:00
sizeof ( dev ) ) ;
}
2005-11-09 17:10:50 +03:00
static struct dm_tree_node * _find_dm_tree_node_by_uuid ( struct dm_tree * dtree ,
2005-11-09 01:50:11 +03:00
const char * uuid )
{
2005-11-13 01:46:48 +03:00
struct dm_tree_node * node ;
if ( ( node = dm_hash_lookup ( dtree - > uuids , uuid ) ) )
return node ;
if ( strncmp ( uuid , UUID_PREFIX , sizeof ( UUID_PREFIX ) - 1 ) )
return NULL ;
return dm_hash_lookup ( dtree - > uuids , uuid + sizeof ( UUID_PREFIX ) - 1 ) ;
2005-11-09 01:50:11 +03:00
}
2005-10-17 02:57:20 +04:00
static int _deps ( struct dm_task * * dmt , struct dm_pool * mem , uint32_t major , uint32_t minor ,
2005-10-16 18:33:22 +04:00
const char * * name , const char * * uuid ,
struct dm_info * info , struct dm_deps * * deps )
{
memset ( info , 0 , sizeof ( * info ) ) ;
if ( ! dm_is_dm_major ( major ) ) {
* name = " " ;
* uuid = " " ;
* deps = NULL ;
info - > major = major ;
info - > minor = minor ;
info - > exists = 0 ;
2005-11-09 01:50:11 +03:00
info - > live_table = 0 ;
info - > inactive_table = 0 ;
info - > read_only = 0 ;
2005-10-16 18:33:22 +04:00
return 1 ;
}
if ( ! ( * dmt = dm_task_create ( DM_DEVICE_DEPS ) ) ) {
log_error ( " deps dm_task creation failed " ) ;
return 0 ;
}
2005-11-09 17:10:50 +03:00
if ( ! dm_task_set_major ( * dmt , major ) ) {
log_error ( " _deps: failed to set major for (% " PRIu32 " :% " PRIu32 " ) " ,
major , minor ) ;
2005-10-16 18:33:22 +04:00
goto failed ;
2005-11-09 17:10:50 +03:00
}
2005-10-16 18:33:22 +04:00
2005-11-09 17:10:50 +03:00
if ( ! dm_task_set_minor ( * dmt , minor ) ) {
log_error ( " _deps: failed to set minor for (% " PRIu32 " :% " PRIu32 " ) " ,
major , minor ) ;
2005-10-16 18:33:22 +04:00
goto failed ;
2005-11-09 17:10:50 +03:00
}
2005-10-16 18:33:22 +04:00
2005-11-09 17:10:50 +03:00
if ( ! dm_task_run ( * dmt ) ) {
log_error ( " _deps: task run failed for (% " PRIu32 " :% " PRIu32 " ) " ,
major , minor ) ;
2005-10-16 18:33:22 +04:00
goto failed ;
2005-11-09 17:10:50 +03:00
}
2005-10-16 18:33:22 +04:00
2005-11-09 17:10:50 +03:00
if ( ! dm_task_get_info ( * dmt , info ) ) {
log_error ( " _deps: failed to get info for (% " PRIu32 " :% " PRIu32 " ) " ,
major , minor ) ;
2005-10-16 18:33:22 +04:00
goto failed ;
2005-11-09 17:10:50 +03:00
}
2005-10-16 18:33:22 +04:00
if ( ! info - > exists ) {
* name = " " ;
* uuid = " " ;
* deps = NULL ;
} else {
if ( info - > major ! = major ) {
2005-11-09 17:10:50 +03:00
log_error ( " Inconsistent dtree major number: %u != %u " ,
2005-10-16 18:33:22 +04:00
major , info - > major ) ;
goto failed ;
}
if ( info - > minor ! = minor ) {
2005-11-09 17:10:50 +03:00
log_error ( " Inconsistent dtree minor number: %u != %u " ,
2005-10-16 18:33:22 +04:00
minor , info - > minor ) ;
goto failed ;
}
2005-10-17 02:57:20 +04:00
if ( ! ( * name = dm_pool_strdup ( mem , dm_task_get_name ( * dmt ) ) ) ) {
2005-10-16 18:33:22 +04:00
log_error ( " name pool_strdup failed " ) ;
goto failed ;
}
2005-10-17 02:57:20 +04:00
if ( ! ( * uuid = dm_pool_strdup ( mem , dm_task_get_uuid ( * dmt ) ) ) ) {
2005-10-16 18:33:22 +04:00
log_error ( " uuid pool_strdup failed " ) ;
goto failed ;
}
* deps = dm_task_get_deps ( * dmt ) ;
}
return 1 ;
failed :
dm_task_destroy ( * dmt ) ;
return 0 ;
}
2005-11-09 17:10:50 +03:00
static struct dm_tree_node * _add_dev ( struct dm_tree * dtree ,
struct dm_tree_node * parent ,
2010-01-07 22:54:21 +03:00
uint32_t major , uint32_t minor ,
uint16_t udev_flags )
2005-10-16 18:33:22 +04:00
{
struct dm_task * dmt = NULL ;
struct dm_info info ;
struct dm_deps * deps = NULL ;
const char * name = NULL ;
const char * uuid = NULL ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node * node = NULL ;
2005-10-16 18:33:22 +04:00
uint32_t i ;
int new = 0 ;
/* Already in tree? */
2005-11-09 17:10:50 +03:00
if ( ! ( node = _find_dm_tree_node ( dtree , major , minor ) ) ) {
if ( ! _deps ( & dmt , dtree - > mem , major , minor , & name , & uuid , & info , & deps ) )
return_NULL ;
2005-10-16 18:33:22 +04:00
2009-10-22 17:00:07 +04:00
if ( ! ( node = _create_dm_tree_node ( dtree , name , uuid , & info ,
2010-01-07 22:54:21 +03:00
NULL , udev_flags ) ) )
2005-11-09 17:10:50 +03:00
goto_out ;
2005-10-16 18:33:22 +04:00
new = 1 ;
}
2005-11-09 01:50:11 +03:00
if ( ! _link_tree_nodes ( parent , node ) ) {
node = NULL ;
2005-11-09 17:10:50 +03:00
goto_out ;
2005-11-09 01:50:11 +03:00
}
2005-10-16 18:33:22 +04:00
/* If node was already in tree, no need to recurse. */
if ( ! new )
2005-11-09 01:50:11 +03:00
goto out ;
2005-10-16 18:33:22 +04:00
/* Can't recurse if not a mapped device or there are no dependencies */
if ( ! node - > info . exists | | ! deps - > count ) {
2005-11-09 17:10:50 +03:00
if ( ! _add_to_bottomlevel ( node ) ) {
stack ;
2005-11-09 01:50:11 +03:00
node = NULL ;
2005-11-09 17:10:50 +03:00
}
2005-11-09 01:50:11 +03:00
goto out ;
2005-10-16 18:33:22 +04:00
}
/* Add dependencies to tree */
for ( i = 0 ; i < deps - > count ; i + + )
2005-11-09 17:10:50 +03:00
if ( ! _add_dev ( dtree , node , MAJOR ( deps - > device [ i ] ) ,
2010-01-07 22:54:21 +03:00
MINOR ( deps - > device [ i ] ) , udev_flags ) ) {
2005-11-09 01:50:11 +03:00
node = NULL ;
2005-11-09 17:10:50 +03:00
goto_out ;
2005-11-09 01:50:11 +03:00
}
2005-10-16 18:33:22 +04:00
out :
if ( dmt )
dm_task_destroy ( dmt ) ;
2005-11-09 01:50:11 +03:00
return node ;
}
2005-11-09 17:10:50 +03:00
static int _node_clear_table ( struct dm_tree_node * dnode )
2005-11-09 01:50:11 +03:00
{
struct dm_task * dmt ;
struct dm_info * info ;
const char * name ;
int r ;
if ( ! ( info = & dnode - > info ) ) {
2005-11-09 17:10:50 +03:00
log_error ( " _node_clear_table failed: missing info " ) ;
2005-11-09 01:50:11 +03:00
return 0 ;
}
2005-11-09 17:10:50 +03:00
if ( ! ( name = dm_tree_node_get_name ( dnode ) ) ) {
log_error ( " _node_clear_table failed: missing name " ) ;
2005-11-09 01:50:11 +03:00
return 0 ;
}
/* Is there a table? */
if ( ! info - > exists | | ! info - > inactive_table )
return 1 ;
log_verbose ( " Clearing inactive table %s (% " PRIu32 " :% " PRIu32 " ) " ,
name , info - > major , info - > minor ) ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_CLEAR ) ) ) {
log_error ( " Table clear dm_task creation failed for %s " , name ) ;
return 0 ;
}
if ( ! dm_task_set_major ( dmt , info - > major ) | |
! dm_task_set_minor ( dmt , info - > minor ) ) {
log_error ( " Failed to set device number for %s table clear " , name ) ;
dm_task_destroy ( dmt ) ;
return 0 ;
}
r = dm_task_run ( dmt ) ;
if ( ! dm_task_get_info ( dmt , info ) ) {
2005-11-09 17:10:50 +03:00
log_error ( " _node_clear_table failed: info missing after running task for %s " , name ) ;
2005-11-09 01:50:11 +03:00
r = 0 ;
}
dm_task_destroy ( dmt ) ;
2005-10-16 18:33:22 +04:00
return r ;
}
2005-11-09 17:10:50 +03:00
struct dm_tree_node * dm_tree_add_new_dev ( struct dm_tree * dtree ,
2005-11-09 01:50:11 +03:00
const char * name ,
const char * uuid ,
uint32_t major , uint32_t minor ,
int read_only ,
int clear_inactive ,
void * context )
{
2005-11-09 17:10:50 +03:00
struct dm_tree_node * dnode ;
2005-11-09 01:50:11 +03:00
struct dm_info info ;
const char * name2 ;
const char * uuid2 ;
/* Do we need to add node to tree? */
2005-11-09 17:10:50 +03:00
if ( ! ( dnode = dm_tree_find_node_by_uuid ( dtree , uuid ) ) ) {
if ( ! ( name2 = dm_pool_strdup ( dtree - > mem , name ) ) ) {
2005-11-09 01:50:11 +03:00
log_error ( " name pool_strdup failed " ) ;
return NULL ;
}
2005-11-09 17:10:50 +03:00
if ( ! ( uuid2 = dm_pool_strdup ( dtree - > mem , uuid ) ) ) {
2005-11-09 01:50:11 +03:00
log_error ( " uuid pool_strdup failed " ) ;
return NULL ;
}
info . major = 0 ;
info . minor = 0 ;
info . exists = 0 ;
info . live_table = 0 ;
info . inactive_table = 0 ;
info . read_only = 0 ;
2009-10-22 17:00:07 +04:00
if ( ! ( dnode = _create_dm_tree_node ( dtree , name2 , uuid2 , & info ,
context , 0 ) ) )
2005-11-09 17:10:50 +03:00
return_NULL ;
2005-11-09 01:50:11 +03:00
/* Attach to root node until a table is supplied */
2005-11-09 17:10:50 +03:00
if ( ! _add_to_toplevel ( dnode ) | | ! _add_to_bottomlevel ( dnode ) )
return_NULL ;
2005-11-09 01:50:11 +03:00
dnode - > props . major = major ;
dnode - > props . minor = minor ;
dnode - > props . new_name = NULL ;
2008-09-18 22:34:53 +04:00
dnode - > props . size_changed = 0 ;
2005-11-09 01:50:11 +03:00
} else if ( strcmp ( name , dnode - > name ) ) {
/* Do we need to rename node? */
2005-11-09 17:10:50 +03:00
if ( ! ( dnode - > props . new_name = dm_pool_strdup ( dtree - > mem , name ) ) ) {
2005-11-09 01:50:11 +03:00
log_error ( " name pool_strdup failed " ) ;
return 0 ;
}
}
dnode - > props . read_only = read_only ? 1 : 0 ;
2007-11-27 23:57:05 +03:00
dnode - > props . read_ahead = DM_READ_AHEAD_AUTO ;
dnode - > props . read_ahead_flags = 0 ;
2005-11-09 01:50:11 +03:00
2005-11-09 17:10:50 +03:00
if ( clear_inactive & & ! _node_clear_table ( dnode ) )
return_NULL ;
2005-11-09 01:50:11 +03:00
dnode - > context = context ;
2009-10-22 17:00:07 +04:00
dnode - > udev_flags = 0 ;
2005-11-09 01:50:11 +03:00
return dnode ;
}
2009-10-22 17:00:07 +04:00
struct dm_tree_node * dm_tree_add_new_dev_with_udev_flags ( struct dm_tree * dtree ,
const char * name ,
const char * uuid ,
uint32_t major ,
uint32_t minor ,
int read_only ,
int clear_inactive ,
void * context ,
uint16_t udev_flags )
{
struct dm_tree_node * node ;
if ( ( node = dm_tree_add_new_dev ( dtree , name , uuid , major , minor , read_only ,
clear_inactive , context ) ) )
node - > udev_flags = udev_flags ;
return node ;
}
2007-11-27 23:57:05 +03:00
void dm_tree_node_set_read_ahead ( struct dm_tree_node * dnode ,
uint32_t read_ahead ,
uint32_t read_ahead_flags )
2009-12-03 12:58:30 +03:00
{
2007-11-27 23:57:05 +03:00
dnode - > props . read_ahead = read_ahead ;
dnode - > props . read_ahead_flags = read_ahead_flags ;
}
2010-05-21 16:27:02 +04:00
void dm_tree_node_set_presuspend_node ( struct dm_tree_node * node ,
struct dm_tree_node * presuspend_node )
{
node - > presuspend_node = presuspend_node ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_add_dev ( struct dm_tree * dtree , uint32_t major , uint32_t minor )
2005-10-16 18:33:22 +04:00
{
2010-01-07 22:54:21 +03:00
return _add_dev ( dtree , & dtree - > root , major , minor , 0 ) ? 1 : 0 ;
}
int dm_tree_add_dev_with_udev_flags ( struct dm_tree * dtree , uint32_t major ,
uint32_t minor , uint16_t udev_flags )
{
return _add_dev ( dtree , & dtree - > root , major , minor , udev_flags ) ? 1 : 0 ;
2005-10-16 18:33:22 +04:00
}
2010-01-14 13:15:23 +03:00
const char * dm_tree_node_get_name ( const struct dm_tree_node * node )
2005-10-16 18:33:22 +04:00
{
return node - > info . exists ? node - > name : " " ;
}
2010-01-14 13:15:23 +03:00
const char * dm_tree_node_get_uuid ( const struct dm_tree_node * node )
2005-10-16 18:33:22 +04:00
{
return node - > info . exists ? node - > uuid : " " ;
}
2010-01-14 13:15:23 +03:00
const struct dm_info * dm_tree_node_get_info ( const struct dm_tree_node * node )
2005-10-16 18:33:22 +04:00
{
return & node - > info ;
}
2010-01-14 13:15:23 +03:00
void * dm_tree_node_get_context ( const struct dm_tree_node * node )
2005-11-09 01:50:11 +03:00
{
return node - > context ;
}
2010-01-14 13:15:23 +03:00
int dm_tree_node_size_changed ( const struct dm_tree_node * dnode )
2009-05-20 13:52:37 +04:00
{
return dnode - > props . size_changed ;
}
2010-01-14 13:15:23 +03:00
int dm_tree_node_num_children ( const struct dm_tree_node * node , uint32_t inverted )
2005-10-16 18:33:22 +04:00
{
if ( inverted ) {
2005-11-09 17:10:50 +03:00
if ( _nodes_are_linked ( & node - > dtree - > root , node ) )
2005-10-16 18:33:22 +04:00
return 0 ;
2008-11-04 01:14:30 +03:00
return dm_list_size ( & node - > used_by ) ;
2005-10-16 18:33:22 +04:00
}
2005-11-09 17:10:50 +03:00
if ( _nodes_are_linked ( node , & node - > dtree - > root ) )
2005-10-16 18:33:22 +04:00
return 0 ;
2008-11-04 01:14:30 +03:00
return dm_list_size ( & node - > uses ) ;
2005-10-16 18:33:22 +04:00
}
2005-10-26 19:21:13 +04:00
/*
* Returns 1 if no prefix supplied
*/
static int _uuid_prefix_matches ( const char * uuid , const char * uuid_prefix , size_t uuid_prefix_len )
{
if ( ! uuid_prefix )
return 1 ;
if ( ! strncmp ( uuid , uuid_prefix , uuid_prefix_len ) )
return 1 ;
/* Handle transition: active device uuids might be missing the prefix */
if ( uuid_prefix_len < = 4 )
return 0 ;
2005-11-13 01:46:48 +03:00
if ( ! strncmp ( uuid , UUID_PREFIX , sizeof ( UUID_PREFIX ) - 1 ) )
2005-10-26 22:33:47 +04:00
return 0 ;
2005-11-13 01:46:48 +03:00
if ( strncmp ( uuid_prefix , UUID_PREFIX , sizeof ( UUID_PREFIX ) - 1 ) )
2005-10-26 19:21:13 +04:00
return 0 ;
2005-11-13 01:46:48 +03:00
if ( ! strncmp ( uuid , uuid_prefix + sizeof ( UUID_PREFIX ) - 1 , uuid_prefix_len - ( sizeof ( UUID_PREFIX ) - 1 ) ) )
2005-10-26 19:21:13 +04:00
return 1 ;
return 0 ;
}
2005-10-26 18:08:24 +04:00
/*
* Returns 1 if no children .
*/
2005-11-09 17:10:50 +03:00
static int _children_suspended ( struct dm_tree_node * node ,
2005-10-26 18:08:24 +04:00
uint32_t inverted ,
const char * uuid_prefix ,
size_t uuid_prefix_len )
{
2008-11-04 01:14:30 +03:00
struct dm_list * list ;
2005-11-09 17:10:50 +03:00
struct dm_tree_link * dlink ;
2005-10-26 18:08:24 +04:00
const struct dm_info * dinfo ;
const char * uuid ;
if ( inverted ) {
2005-11-09 17:10:50 +03:00
if ( _nodes_are_linked ( & node - > dtree - > root , node ) )
2005-10-26 18:08:24 +04:00
return 1 ;
list = & node - > used_by ;
} else {
2005-11-09 17:10:50 +03:00
if ( _nodes_are_linked ( node , & node - > dtree - > root ) )
2005-10-26 18:08:24 +04:00
return 1 ;
list = & node - > uses ;
}
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( dlink , list ) {
2005-11-09 17:10:50 +03:00
if ( ! ( uuid = dm_tree_node_get_uuid ( dlink - > node ) ) ) {
2005-10-26 18:08:24 +04:00
stack ;
continue ;
}
/* Ignore if it doesn't belong to this VG */
2005-10-26 19:21:13 +04:00
if ( ! _uuid_prefix_matches ( uuid , uuid_prefix , uuid_prefix_len ) )
2005-10-26 18:08:24 +04:00
continue ;
2010-05-21 16:27:02 +04:00
/* Ignore if parent node wants to presuspend this node */
if ( dlink - > node - > presuspend_node = = node )
continue ;
2005-11-09 17:10:50 +03:00
if ( ! ( dinfo = dm_tree_node_get_info ( dlink - > node ) ) ) {
stack ; /* FIXME Is this normal? */
2005-10-26 18:08:24 +04:00
return 0 ;
}
if ( ! dinfo - > suspended )
return 0 ;
}
return 1 ;
}
2005-10-16 18:33:22 +04:00
/*
* Set major and minor to zero for root of tree .
*/
2005-11-09 17:10:50 +03:00
struct dm_tree_node * dm_tree_find_node ( struct dm_tree * dtree ,
2005-10-16 18:33:22 +04:00
uint32_t major ,
uint32_t minor )
{
if ( ! major & & ! minor )
2005-11-09 17:10:50 +03:00
return & dtree - > root ;
2005-10-16 18:33:22 +04:00
2005-11-09 17:10:50 +03:00
return _find_dm_tree_node ( dtree , major , minor ) ;
2005-10-16 18:33:22 +04:00
}
2005-11-09 01:50:11 +03:00
/*
* Set uuid to NULL for root of tree .
*/
2005-11-09 17:10:50 +03:00
struct dm_tree_node * dm_tree_find_node_by_uuid ( struct dm_tree * dtree ,
2005-11-09 01:50:11 +03:00
const char * uuid )
{
if ( ! uuid | | ! * uuid )
2005-11-09 17:10:50 +03:00
return & dtree - > root ;
2005-11-09 01:50:11 +03:00
2005-11-09 17:10:50 +03:00
return _find_dm_tree_node_by_uuid ( dtree , uuid ) ;
2005-11-09 01:50:11 +03:00
}
2005-10-16 18:33:22 +04:00
/*
* First time set * handle to NULL .
* Set inverted to invert the tree .
*/
2005-11-09 17:10:50 +03:00
struct dm_tree_node * dm_tree_next_child ( void * * handle ,
2010-01-14 13:15:23 +03:00
const struct dm_tree_node * parent ,
uint32_t inverted )
2005-10-16 18:33:22 +04:00
{
2008-11-04 01:14:30 +03:00
struct dm_list * * dlink = ( struct dm_list * * ) handle ;
2010-01-14 13:15:23 +03:00
const struct dm_list * use_list ;
2005-10-16 18:33:22 +04:00
if ( inverted )
use_list = & parent - > used_by ;
else
use_list = & parent - > uses ;
if ( ! * dlink )
2008-11-04 01:14:30 +03:00
* dlink = dm_list_first ( use_list ) ;
2005-10-16 18:33:22 +04:00
else
2008-11-04 01:14:30 +03:00
* dlink = dm_list_next ( use_list , * dlink ) ;
2005-10-16 18:33:22 +04:00
2008-11-04 01:14:30 +03:00
return ( * dlink ) ? dm_list_item ( * dlink , struct dm_tree_link ) - > node : NULL ;
2005-10-16 18:33:22 +04:00
}
2005-10-18 16:37:53 +04:00
/*
2005-10-18 17:57:11 +04:00
* Deactivate a device with its dependencies if the uuid prefix matches .
2005-10-18 16:37:53 +04:00
*/
2005-10-25 23:09:41 +04:00
static int _info_by_dev ( uint32_t major , uint32_t minor , int with_open_count ,
struct dm_info * info )
2005-10-18 16:37:53 +04:00
{
struct dm_task * dmt ;
int r ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_INFO ) ) ) {
log_error ( " _info_by_dev: dm_task creation failed " ) ;
return 0 ;
}
if ( ! dm_task_set_major ( dmt , major ) | | ! dm_task_set_minor ( dmt , minor ) ) {
log_error ( " _info_by_dev: Failed to set device number " ) ;
dm_task_destroy ( dmt ) ;
return 0 ;
}
2005-10-25 23:09:41 +04:00
if ( ! with_open_count & & ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2005-10-18 16:37:53 +04:00
if ( ( r = dm_task_run ( dmt ) ) )
r = dm_task_get_info ( dmt , info ) ;
dm_task_destroy ( dmt ) ;
return r ;
}
2010-05-21 16:30:35 +04:00
/* Check if all parent nodes of given node have open_count == 0 */
static int _node_has_closed_parents ( struct dm_tree_node * node ,
const char * uuid_prefix ,
size_t uuid_prefix_len )
{
struct dm_tree_link * dlink ;
const struct dm_info * dinfo ;
struct dm_info info ;
const char * uuid ;
/* Iterate through parents of this node */
dm_list_iterate_items ( dlink , & node - > used_by ) {
if ( ! ( uuid = dm_tree_node_get_uuid ( dlink - > node ) ) ) {
stack ;
continue ;
}
/* Ignore if it doesn't belong to this VG */
if ( ! _uuid_prefix_matches ( uuid , uuid_prefix , uuid_prefix_len ) )
continue ;
if ( ! ( dinfo = dm_tree_node_get_info ( dlink - > node ) ) ) {
stack ; /* FIXME Is this normal? */
return 0 ;
}
/* Refresh open_count */
if ( ! _info_by_dev ( dinfo - > major , dinfo - > minor , 1 , & info ) | |
! info . exists )
continue ;
if ( info . open_count )
return 0 ;
}
return 1 ;
}
2009-10-22 17:00:07 +04:00
static int _deactivate_node ( const char * name , uint32_t major , uint32_t minor ,
uint32_t * cookie , uint16_t udev_flags )
2005-10-18 16:37:53 +04:00
{
struct dm_task * dmt ;
2009-07-31 22:30:31 +04:00
int r = 0 ;
2005-10-18 16:37:53 +04:00
log_verbose ( " Removing %s (% " PRIu32 " :% " PRIu32 " ) " , name , major , minor ) ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_REMOVE ) ) ) {
log_error ( " Deactivation dm_task creation failed for %s " , name ) ;
return 0 ;
}
if ( ! dm_task_set_major ( dmt , major ) | | ! dm_task_set_minor ( dmt , minor ) ) {
log_error ( " Failed to set device number for %s deactivation " , name ) ;
2009-07-31 22:30:31 +04:00
goto out ;
2005-10-18 16:37:53 +04:00
}
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2009-10-22 17:00:07 +04:00
if ( ! dm_task_set_cookie ( dmt , cookie , udev_flags ) )
2009-07-31 22:30:31 +04:00
goto out ;
2005-10-18 16:37:53 +04:00
r = dm_task_run ( dmt ) ;
2005-11-09 01:50:11 +03:00
/* FIXME Until kernel returns actual name so dm-ioctl.c can handle it */
2010-01-07 22:54:21 +03:00
rm_dev_node ( name , dmt - > cookie_set & &
! ( udev_flags & DM_UDEV_DISABLE_DM_RULES_FLAG ) ) ;
2005-11-09 01:50:11 +03:00
2005-10-25 23:09:41 +04:00
/* FIXME Remove node from tree or mark invalid? */
2009-07-31 22:30:31 +04:00
out :
2005-10-25 23:09:41 +04:00
dm_task_destroy ( dmt ) ;
return r ;
}
2009-07-31 22:30:31 +04:00
static int _rename_node ( const char * old_name , const char * new_name , uint32_t major ,
2009-10-22 17:00:07 +04:00
uint32_t minor , uint32_t * cookie , uint16_t udev_flags )
2005-11-09 01:50:11 +03:00
{
struct dm_task * dmt ;
int r = 0 ;
log_verbose ( " Renaming %s (% " PRIu32 " :% " PRIu32 " ) to %s " , old_name , major , minor , new_name ) ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_RENAME ) ) ) {
log_error ( " Rename dm_task creation failed for %s " , old_name ) ;
return 0 ;
}
if ( ! dm_task_set_name ( dmt , old_name ) ) {
log_error ( " Failed to set name for %s rename. " , old_name ) ;
goto out ;
}
2005-11-09 17:10:50 +03:00
if ( ! dm_task_set_newname ( dmt , new_name ) )
goto_out ;
2005-11-09 01:50:11 +03:00
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2009-10-22 17:00:07 +04:00
if ( ! dm_task_set_cookie ( dmt , cookie , udev_flags ) )
2009-07-31 22:30:31 +04:00
goto out ;
2005-11-09 01:50:11 +03:00
r = dm_task_run ( dmt ) ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
/* FIXME Merge with _suspend_node? */
static int _resume_node ( const char * name , uint32_t major , uint32_t minor ,
2007-11-27 23:57:05 +03:00
uint32_t read_ahead , uint32_t read_ahead_flags ,
2009-10-22 17:00:07 +04:00
struct dm_info * newinfo , uint32_t * cookie ,
uint16_t udev_flags )
2005-11-09 01:50:11 +03:00
{
struct dm_task * dmt ;
2009-07-31 22:30:31 +04:00
int r = 0 ;
2005-11-09 01:50:11 +03:00
log_verbose ( " Resuming %s (% " PRIu32 " :% " PRIu32 " ) " , name , major , minor ) ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_RESUME ) ) ) {
log_error ( " Suspend dm_task creation failed for %s " , name ) ;
return 0 ;
}
2007-12-04 01:48:36 +03:00
/* FIXME Kernel should fill in name on return instead */
if ( ! dm_task_set_name ( dmt , name ) ) {
log_error ( " Failed to set readahead device name for %s " , name ) ;
2009-07-31 22:30:31 +04:00
goto out ;
2007-12-04 01:48:36 +03:00
}
2005-11-09 01:50:11 +03:00
if ( ! dm_task_set_major ( dmt , major ) | | ! dm_task_set_minor ( dmt , minor ) ) {
log_error ( " Failed to set device number for %s resumption. " , name ) ;
2009-07-31 22:30:31 +04:00
goto out ;
2005-11-09 01:50:11 +03:00
}
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2007-11-27 23:57:05 +03:00
if ( ! dm_task_set_read_ahead ( dmt , read_ahead , read_ahead_flags ) )
log_error ( " Failed to set read ahead " ) ;
2009-10-22 17:00:07 +04:00
if ( ! dm_task_set_cookie ( dmt , cookie , udev_flags ) )
2009-07-31 22:30:31 +04:00
goto out ;
2005-11-09 01:50:11 +03:00
if ( ( r = dm_task_run ( dmt ) ) )
r = dm_task_get_info ( dmt , newinfo ) ;
2009-07-31 22:30:31 +04:00
out :
2005-11-09 01:50:11 +03:00
dm_task_destroy ( dmt ) ;
return r ;
}
2005-10-25 23:09:41 +04:00
static int _suspend_node ( const char * name , uint32_t major , uint32_t minor ,
2007-01-09 22:44:07 +03:00
int skip_lockfs , int no_flush , struct dm_info * newinfo )
2005-10-25 23:09:41 +04:00
{
struct dm_task * dmt ;
int r ;
2007-01-09 22:44:07 +03:00
log_verbose ( " Suspending %s (% " PRIu32 " :% " PRIu32 " )%s%s " ,
name , major , minor ,
skip_lockfs ? " " : " with filesystem sync " ,
2008-06-25 18:24:17 +04:00
no_flush ? " " : " with device flush " ) ;
2005-10-25 23:09:41 +04:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_SUSPEND ) ) ) {
log_error ( " Suspend dm_task creation failed for %s " , name ) ;
return 0 ;
}
if ( ! dm_task_set_major ( dmt , major ) | | ! dm_task_set_minor ( dmt , minor ) ) {
log_error ( " Failed to set device number for %s suspension. " , name ) ;
dm_task_destroy ( dmt ) ;
return 0 ;
}
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2006-01-31 02:36:04 +03:00
if ( skip_lockfs & & ! dm_task_skip_lockfs ( dmt ) )
log_error ( " Failed to set skip_lockfs flag. " ) ;
2007-01-09 22:44:07 +03:00
if ( no_flush & & ! dm_task_no_flush ( dmt ) )
log_error ( " Failed to set no_flush flag. " ) ;
2005-10-25 23:09:41 +04:00
if ( ( r = dm_task_run ( dmt ) ) )
r = dm_task_get_info ( dmt , newinfo ) ;
2005-10-18 16:37:53 +04:00
dm_task_destroy ( dmt ) ;
return r ;
}
2010-04-08 03:51:34 +04:00
/*
* FIXME Don ' t attempt to deactivate known internal dependencies .
*/
static int _dm_tree_deactivate_children ( struct dm_tree_node * dnode ,
const char * uuid_prefix ,
size_t uuid_prefix_len ,
unsigned level )
2005-10-18 16:37:53 +04:00
{
2010-01-06 00:06:26 +03:00
int r = 1 ;
2005-10-18 16:37:53 +04:00
void * handle = NULL ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node * child = dnode ;
2005-10-18 16:37:53 +04:00
struct dm_info info ;
const struct dm_info * dinfo ;
const char * name ;
const char * uuid ;
2005-11-09 17:10:50 +03:00
while ( ( child = dm_tree_next_child ( & handle , dnode , 0 ) ) ) {
if ( ! ( dinfo = dm_tree_node_get_info ( child ) ) ) {
2005-10-18 16:37:53 +04:00
stack ;
continue ;
}
2005-11-09 17:10:50 +03:00
if ( ! ( name = dm_tree_node_get_name ( child ) ) ) {
2005-10-18 16:37:53 +04:00
stack ;
continue ;
}
2005-11-09 17:10:50 +03:00
if ( ! ( uuid = dm_tree_node_get_uuid ( child ) ) ) {
2005-10-18 16:37:53 +04:00
stack ;
continue ;
}
/* Ignore if it doesn't belong to this VG */
2005-10-26 19:21:13 +04:00
if ( ! _uuid_prefix_matches ( uuid , uuid_prefix , uuid_prefix_len ) )
2005-10-18 16:37:53 +04:00
continue ;
/* Refresh open_count */
2005-10-25 23:09:41 +04:00
if ( ! _info_by_dev ( dinfo - > major , dinfo - > minor , 1 , & info ) | |
2010-04-08 00:04:41 +04:00
! info . exists )
2005-10-18 16:37:53 +04:00
continue ;
2010-05-21 16:30:35 +04:00
/* Also checking open_count in parent nodes of presuspend_node */
if ( info . open_count | |
( child - > presuspend_node & &
! _node_has_closed_parents ( child - > presuspend_node ,
uuid_prefix , uuid_prefix_len ) ) ) {
2010-04-08 03:51:34 +04:00
/* Only report error from (likely non-internal) dependency at top level */
if ( ! level ) {
log_error ( " Unable to deactivate open %s (% " PRIu32
" :% " PRIu32 " ) " , name , info . major ,
info . minor ) ;
r = 0 ;
}
2010-04-08 00:04:41 +04:00
continue ;
}
2010-05-21 16:27:02 +04:00
/* Suspend child node first if requested */
if ( child - > presuspend_node & &
! dm_tree_suspend_children ( child , uuid_prefix , uuid_prefix_len ) )
continue ;
2009-10-22 17:00:07 +04:00
if ( ! _deactivate_node ( name , info . major , info . minor ,
2009-11-13 15:43:21 +03:00
& child - > dtree - > cookie , child - > udev_flags ) ) {
2005-10-18 16:37:53 +04:00
log_error ( " Unable to deactivate %s (% " PRIu32
" :% " PRIu32 " ) " , name , info . major ,
info . minor ) ;
2010-01-06 00:06:26 +03:00
r = 0 ;
2005-10-18 16:37:53 +04:00
continue ;
}
2010-04-08 03:51:34 +04:00
if ( dm_tree_node_num_children ( child , 0 ) ) {
if ( ! _dm_tree_deactivate_children ( child , uuid_prefix , uuid_prefix_len , level + 1 ) )
2010-01-06 00:06:26 +03:00
return_0 ;
2010-04-08 03:51:34 +04:00
}
2005-10-18 16:37:53 +04:00
}
2010-01-06 00:06:26 +03:00
return r ;
2005-10-18 16:37:53 +04:00
}
2005-10-25 23:09:41 +04:00
2010-04-08 03:51:34 +04:00
int dm_tree_deactivate_children ( struct dm_tree_node * dnode ,
const char * uuid_prefix ,
size_t uuid_prefix_len )
{
return _dm_tree_deactivate_children ( dnode , uuid_prefix , uuid_prefix_len , 0 ) ;
}
2006-01-31 02:36:04 +03:00
void dm_tree_skip_lockfs ( struct dm_tree_node * dnode )
{
dnode - > dtree - > skip_lockfs = 1 ;
}
2007-01-09 22:44:07 +03:00
void dm_tree_use_no_flush_suspend ( struct dm_tree_node * dnode )
{
dnode - > dtree - > no_flush = 1 ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_suspend_children ( struct dm_tree_node * dnode ,
2009-12-03 12:58:30 +03:00
const char * uuid_prefix ,
size_t uuid_prefix_len )
2005-10-25 23:09:41 +04:00
{
2010-01-06 00:05:40 +03:00
int r = 1 ;
2005-10-25 23:09:41 +04:00
void * handle = NULL ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node * child = dnode ;
2005-10-25 23:09:41 +04:00
struct dm_info info , newinfo ;
const struct dm_info * dinfo ;
const char * name ;
const char * uuid ;
2005-10-26 18:08:24 +04:00
/* Suspend nodes at this level of the tree */
2005-11-09 17:10:50 +03:00
while ( ( child = dm_tree_next_child ( & handle , dnode , 0 ) ) ) {
if ( ! ( dinfo = dm_tree_node_get_info ( child ) ) ) {
2005-10-25 23:09:41 +04:00
stack ;
continue ;
}
2005-11-09 17:10:50 +03:00
if ( ! ( name = dm_tree_node_get_name ( child ) ) ) {
2005-10-25 23:09:41 +04:00
stack ;
continue ;
}
2005-11-09 17:10:50 +03:00
if ( ! ( uuid = dm_tree_node_get_uuid ( child ) ) ) {
2005-10-25 23:09:41 +04:00
stack ;
continue ;
}
/* Ignore if it doesn't belong to this VG */
2005-10-26 19:21:13 +04:00
if ( ! _uuid_prefix_matches ( uuid , uuid_prefix , uuid_prefix_len ) )
2005-10-25 23:09:41 +04:00
continue ;
2005-10-26 18:08:24 +04:00
/* Ensure immediate parents are already suspended */
if ( ! _children_suspended ( child , 1 , uuid_prefix , uuid_prefix_len ) )
continue ;
2005-10-25 23:09:41 +04:00
if ( ! _info_by_dev ( dinfo - > major , dinfo - > minor , 0 , & info ) | |
2006-10-13 18:03:35 +04:00
! info . exists | | info . suspended )
2005-10-25 23:09:41 +04:00
continue ;
2006-01-31 02:36:04 +03:00
if ( ! _suspend_node ( name , info . major , info . minor ,
2007-01-09 22:44:07 +03:00
child - > dtree - > skip_lockfs ,
child - > dtree - > no_flush , & newinfo ) ) {
2005-10-25 23:09:41 +04:00
log_error ( " Unable to suspend %s (% " PRIu32
" :% " PRIu32 " ) " , name , info . major ,
info . minor ) ;
2010-01-06 00:05:40 +03:00
r = 0 ;
2005-10-25 23:09:41 +04:00
continue ;
}
/* Update cached info */
child - > info = newinfo ;
2005-10-26 18:08:24 +04:00
}
/* Then suspend any child nodes */
handle = NULL ;
2005-11-09 17:10:50 +03:00
while ( ( child = dm_tree_next_child ( & handle , dnode , 0 ) ) ) {
if ( ! ( uuid = dm_tree_node_get_uuid ( child ) ) ) {
2005-10-26 18:08:24 +04:00
stack ;
continue ;
}
/* Ignore if it doesn't belong to this VG */
2005-11-13 01:46:48 +03:00
if ( ! _uuid_prefix_matches ( uuid , uuid_prefix , uuid_prefix_len ) )
2005-10-26 18:08:24 +04:00
continue ;
2005-10-25 23:09:41 +04:00
2005-11-09 17:10:50 +03:00
if ( dm_tree_node_num_children ( child , 0 ) )
2010-01-06 00:05:40 +03:00
if ( ! dm_tree_suspend_children ( child , uuid_prefix , uuid_prefix_len ) )
return_0 ;
2005-10-25 23:09:41 +04:00
}
2010-01-06 00:05:40 +03:00
return r ;
2005-10-25 23:09:41 +04:00
}
2005-11-09 17:10:50 +03:00
int dm_tree_activate_children ( struct dm_tree_node * dnode ,
2005-10-25 23:09:41 +04:00
const char * uuid_prefix ,
size_t uuid_prefix_len )
{
2010-01-06 00:04:37 +03:00
int r = 1 ;
2005-10-25 23:09:41 +04:00
void * handle = NULL ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node * child = dnode ;
2005-11-09 01:50:11 +03:00
struct dm_info newinfo ;
const char * name ;
2005-10-25 23:09:41 +04:00
const char * uuid ;
2005-11-22 23:00:35 +03:00
int priority ;
2005-10-25 23:09:41 +04:00
2005-11-09 01:50:11 +03:00
/* Activate children first */
2005-11-09 17:10:50 +03:00
while ( ( child = dm_tree_next_child ( & handle , dnode , 0 ) ) ) {
if ( ! ( uuid = dm_tree_node_get_uuid ( child ) ) ) {
2005-11-09 01:50:11 +03:00
stack ;
continue ;
2005-10-25 23:09:41 +04:00
}
2005-11-09 18:41:42 +03:00
if ( ! _uuid_prefix_matches ( uuid , uuid_prefix , uuid_prefix_len ) )
continue ;
2005-10-25 23:09:41 +04:00
2005-11-09 17:10:50 +03:00
if ( dm_tree_node_num_children ( child , 0 ) )
2010-01-06 00:04:37 +03:00
if ( ! dm_tree_activate_children ( child , uuid_prefix , uuid_prefix_len ) )
return_0 ;
2005-11-22 23:00:35 +03:00
}
2005-11-09 01:50:11 +03:00
2005-11-22 23:00:35 +03:00
handle = NULL ;
2005-11-09 01:50:11 +03:00
2010-01-13 04:39:44 +03:00
for ( priority = 0 ; priority < 3 ; priority + + ) {
2005-11-22 23:00:35 +03:00
while ( ( child = dm_tree_next_child ( & handle , dnode , 0 ) ) ) {
if ( ! ( uuid = dm_tree_node_get_uuid ( child ) ) ) {
stack ;
continue ;
2005-11-09 01:50:11 +03:00
}
2005-11-22 23:00:35 +03:00
if ( ! _uuid_prefix_matches ( uuid , uuid_prefix , uuid_prefix_len ) )
continue ;
2005-11-09 01:50:11 +03:00
2005-11-22 23:00:35 +03:00
if ( priority ! = child - > activation_priority )
continue ;
2005-11-09 01:50:11 +03:00
2005-11-22 23:00:35 +03:00
if ( ! ( name = dm_tree_node_get_name ( child ) ) ) {
stack ;
continue ;
}
/* Rename? */
if ( child - > props . new_name ) {
2009-07-31 22:30:31 +04:00
if ( ! _rename_node ( name , child - > props . new_name , child - > info . major ,
2009-10-22 17:00:07 +04:00
child - > info . minor , & child - > dtree - > cookie ,
child - > udev_flags ) ) {
2005-11-22 23:00:35 +03:00
log_error ( " Failed to rename %s (% " PRIu32
" :% " PRIu32 " ) to %s " , name , child - > info . major ,
child - > info . minor , child - > props . new_name ) ;
return 0 ;
}
child - > name = child - > props . new_name ;
child - > props . new_name = NULL ;
}
if ( ! child - > info . inactive_table & & ! child - > info . suspended )
continue ;
2007-12-14 20:57:04 +03:00
if ( ! _resume_node ( child - > name , child - > info . major , child - > info . minor ,
2009-07-31 22:30:31 +04:00
child - > props . read_ahead , child - > props . read_ahead_flags ,
2009-10-22 17:00:07 +04:00
& newinfo , & child - > dtree - > cookie , child - > udev_flags ) ) {
2005-11-22 23:00:35 +03:00
log_error ( " Unable to resume %s (% " PRIu32
2007-12-14 20:57:04 +03:00
" :% " PRIu32 " ) " , child - > name , child - > info . major ,
2005-11-22 23:00:35 +03:00
child - > info . minor ) ;
2010-01-06 00:04:37 +03:00
r = 0 ;
2005-11-22 23:00:35 +03:00
continue ;
}
/* Update cached info */
child - > info = newinfo ;
}
2005-10-25 23:09:41 +04:00
}
2005-11-09 01:50:11 +03:00
handle = NULL ;
2010-01-06 00:04:37 +03:00
return r ;
2005-11-09 01:50:11 +03:00
}
2005-11-09 17:10:50 +03:00
static int _create_node ( struct dm_tree_node * dnode )
2005-11-09 01:50:11 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
log_verbose ( " Creating %s " , dnode - > name ) ;
if ( ! ( dmt = dm_task_create ( DM_DEVICE_CREATE ) ) ) {
log_error ( " Create dm_task creation failed for %s " , dnode - > name ) ;
return 0 ;
}
if ( ! dm_task_set_name ( dmt , dnode - > name ) ) {
log_error ( " Failed to set device name for %s " , dnode - > name ) ;
goto out ;
}
if ( ! dm_task_set_uuid ( dmt , dnode - > uuid ) ) {
log_error ( " Failed to set uuid for %s " , dnode - > name ) ;
goto out ;
}
if ( dnode - > props . major & &
( ! dm_task_set_major ( dmt , dnode - > props . major ) | |
! dm_task_set_minor ( dmt , dnode - > props . minor ) ) ) {
log_error ( " Failed to set device number for %s creation. " , dnode - > name ) ;
goto out ;
}
if ( dnode - > props . read_only & & ! dm_task_set_ro ( dmt ) ) {
log_error ( " Failed to set read only flag for %s " , dnode - > name ) ;
goto out ;
}
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
if ( ( r = dm_task_run ( dmt ) ) )
r = dm_task_get_info ( dmt , & dnode - > info ) ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2005-11-09 17:10:50 +03:00
static int _build_dev_string ( char * devbuf , size_t bufsize , struct dm_tree_node * node )
2005-11-09 01:50:11 +03:00
{
if ( ! dm_format_dev ( devbuf , bufsize , node - > info . major , node - > info . minor ) ) {
log_error ( " Failed to format %s device number for %s as dm "
" target (%u,%u) " ,
node - > name , node - > uuid , node - > info . major , node - > info . minor ) ;
return 0 ;
}
return 1 ;
}
2008-12-11 19:25:51 +03:00
/* simplify string emiting code */
# define EMIT_PARAMS(p, str...)\
2008-12-12 21:45:58 +03:00
do { \
int w ; \
if ( ( w = dm_snprintf ( params + p , paramsize - ( size_t ) p , str ) ) < 0 ) { \
stack ; /* Out of space */ \
return - 1 ; \
} \
p + = w ; \
} while ( 0 )
2008-12-11 19:25:51 +03:00
2009-09-22 20:26:59 +04:00
/*
* _emit_areas_line
*
* Returns : 1 on success , 0 on failure
*/
2010-07-09 19:34:40 +04:00
static int _emit_areas_line ( struct dm_task * dmt __attribute__ ( ( unused ) ) ,
2007-01-22 18:03:57 +03:00
struct load_segment * seg , char * params ,
size_t paramsize , int * pos )
2005-11-09 01:50:11 +03:00
{
struct seg_area * area ;
2008-09-02 16:16:07 +04:00
char devbuf [ DM_FORMAT_DEV_BUFSIZE ] ;
2009-07-07 20:36:05 +04:00
unsigned first_time = 1 ;
2010-07-03 01:16:50 +04:00
const char * logtype , * synctype ;
2010-05-21 16:24:15 +04:00
unsigned log_parm_count ;
2005-11-09 01:50:11 +03:00
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( area , & seg - > areas ) {
2005-11-09 17:10:50 +03:00
if ( ! _build_dev_string ( devbuf , sizeof ( devbuf ) , area - > dev_node ) )
return_0 ;
2005-11-09 01:50:11 +03:00
2010-05-21 16:24:15 +04:00
switch ( seg - > type ) {
case SEG_REPLICATOR_DEV :
EMIT_PARAMS ( * pos , " %d 1 %s " , area - > rsite_index , devbuf ) ;
if ( first_time )
EMIT_PARAMS ( * pos , " nolog 0 " ) ;
else {
/* Remote devices */
log_parm_count = ( area - > flags &
( DM_NOSYNC | DM_FORCESYNC ) ) ? 2 : 1 ;
if ( ! area - > slog ) {
devbuf [ 0 ] = 0 ; /* Only core log parameters */
logtype = " core " ;
} else {
devbuf [ 0 ] = ' ' ; /* Extra space before device name */
if ( ! _build_dev_string ( devbuf + 1 ,
sizeof ( devbuf ) - 1 ,
area - > slog ) )
return_0 ;
logtype = " disk " ;
log_parm_count + + ; /* Extra sync log device name parameter */
}
EMIT_PARAMS ( * pos , " %s %u%s % " PRIu64 , logtype ,
log_parm_count , devbuf , area - > region_size ) ;
2010-07-03 01:16:50 +04:00
synctype = ( area - > flags & DM_NOSYNC ) ?
" nosync " : ( area - > flags & DM_FORCESYNC ) ?
" sync " : NULL ;
2010-05-21 16:24:15 +04:00
2010-07-03 01:16:50 +04:00
if ( synctype )
EMIT_PARAMS ( * pos , " %s " , synctype ) ;
2010-05-21 16:24:15 +04:00
}
break ;
default :
EMIT_PARAMS ( * pos , " %s%s % " PRIu64 , first_time ? " " : " " ,
devbuf , area - > offset ) ;
}
2009-07-07 20:36:05 +04:00
first_time = 0 ;
2005-11-09 01:50:11 +03:00
}
return 1 ;
}
2010-05-21 16:24:15 +04:00
static int _replicator_emit_segment_line ( const struct load_segment * seg , char * params ,
size_t paramsize , int * pos )
{
const struct load_segment * rlog_seg ;
struct replicator_site * rsite ;
char rlogbuf [ DM_FORMAT_DEV_BUFSIZE ] ;
unsigned parm_count ;
if ( ! seg - > log | | ! _build_dev_string ( rlogbuf , sizeof ( rlogbuf ) , seg - > log ) )
return_0 ;
rlog_seg = dm_list_item ( dm_list_last ( & seg - > log - > props . segs ) ,
struct load_segment ) ;
EMIT_PARAMS ( * pos , " %s 4 %s 0 auto % " PRIu64 ,
seg - > rlog_type , rlogbuf , rlog_seg - > size ) ;
dm_list_iterate_items ( rsite , & seg - > rsites ) {
parm_count = ( rsite - > fall_behind_data
| | rsite - > fall_behind_ios
| | rsite - > async_timeout ) ? 4 : 2 ;
EMIT_PARAMS ( * pos , " blockdev %u %u %s " , parm_count , rsite - > rsite_index ,
( rsite - > mode = = DM_REPLICATOR_SYNC ) ? " synchronous " : " asynchronous " ) ;
if ( rsite - > fall_behind_data )
EMIT_PARAMS ( * pos , " data % " PRIu64 , rsite - > fall_behind_data ) ;
else if ( rsite - > fall_behind_ios )
EMIT_PARAMS ( * pos , " ios % " PRIu32 , rsite - > fall_behind_ios ) ;
else if ( rsite - > async_timeout )
EMIT_PARAMS ( * pos , " timeout % " PRIu32 , rsite - > async_timeout ) ;
}
return 1 ;
}
2009-09-22 20:26:59 +04:00
/*
* Returns : 1 on success , 0 on failure
*/
2009-09-25 22:30:27 +04:00
static int _mirror_emit_segment_line ( struct dm_task * dmt , uint32_t major ,
uint32_t minor , struct load_segment * seg ,
uint64_t * seg_start , char * params ,
size_t paramsize )
2005-11-09 01:50:11 +03:00
{
2009-08-13 20:31:01 +04:00
int block_on_error = 0 ;
int handle_errors = 0 ;
int dm_log_userspace = 0 ;
struct utsname uts ;
2005-12-13 18:49:27 +03:00
unsigned log_parm_count ;
2008-12-11 19:25:51 +03:00
int pos = 0 ;
2008-09-02 16:16:07 +04:00
char logbuf [ DM_FORMAT_DEV_BUFSIZE ] ;
2005-12-13 18:49:27 +03:00
const char * logtype ;
2010-05-25 03:11:34 +04:00
unsigned kmaj , kmin , krel ;
2005-11-09 01:50:11 +03:00
2010-05-25 12:40:36 +04:00
if ( uname ( & uts ) = = - 1 | | sscanf ( uts . release , " %u.%u.%u " , & kmaj , & kmin , & krel ) ! = 3 ) {
log_error ( " Cannot read kernel release version " ) ;
return 0 ;
}
2006-02-06 23:18:10 +03:00
2009-08-13 20:31:01 +04:00
if ( ( seg - > flags & DM_BLOCK_ON_ERROR ) ) {
/*
* Originally , block_on_error was an argument to the log
* portion of the mirror CTR table . It was renamed to
* " handle_errors " and now resides in the ' features '
* section of the mirror CTR table ( i . e . at the end ) .
*
* We can identify whether to use " block_on_error " or
* " handle_errors " by the dm - mirror module ' s version
* number ( > = 1.12 ) or by the kernel version ( > = 2.6 .22 ) .
*/
2010-05-25 03:11:34 +04:00
if ( KERNEL_VERSION ( kmaj , kmin , krel ) > = KERNEL_VERSION ( 2 , 6 , 22 ) )
2009-08-13 20:31:01 +04:00
handle_errors = 1 ;
else
block_on_error = 1 ;
}
if ( seg - > clustered ) {
/* Cluster mirrors require a UUID */
if ( ! seg - > uuid )
return_0 ;
/*
* Cluster mirrors used to have their own log
* types . Now they are accessed through the
* userspace log type .
*
* The dm - log - userspace module was added to the
* 2.6 .31 kernel .
*/
2010-05-25 03:11:34 +04:00
if ( KERNEL_VERSION ( kmaj , kmin , krel ) > = KERNEL_VERSION ( 2 , 6 , 31 ) )
2009-08-13 20:31:01 +04:00
dm_log_userspace = 1 ;
}
/* Region size */
log_parm_count = 1 ;
/* [no]sync, block_on_error etc. */
log_parm_count + = hweight32 ( seg - > flags ) ;
2006-05-16 20:20:29 +04:00
2009-08-13 20:31:01 +04:00
/* "handle_errors" is a feature arg now */
if ( handle_errors )
log_parm_count - - ;
/* DM_CORELOG does not count in the param list */
if ( seg - > flags & DM_CORELOG )
log_parm_count - - ;
if ( seg - > clustered ) {
log_parm_count + + ; /* For UUID */
if ( ! dm_log_userspace )
2008-12-11 19:25:51 +03:00
EMIT_PARAMS ( pos , " clustered- " ) ;
2010-01-15 19:00:23 +03:00
else
/* For clustered-* type field inserted later */
log_parm_count + + ;
2009-08-13 20:31:01 +04:00
}
2005-12-13 18:49:27 +03:00
2009-08-13 20:31:01 +04:00
if ( ! seg - > log )
logtype = " core " ;
else {
logtype = " disk " ;
log_parm_count + + ;
if ( ! _build_dev_string ( logbuf , sizeof ( logbuf ) , seg - > log ) )
return_0 ;
}
2005-12-13 18:49:27 +03:00
2009-08-13 20:31:01 +04:00
if ( dm_log_userspace )
EMIT_PARAMS ( pos , " userspace %u %s clustered-%s " ,
log_parm_count , seg - > uuid , logtype ) ;
else
2008-12-11 19:25:51 +03:00
EMIT_PARAMS ( pos , " %s %u " , logtype , log_parm_count ) ;
2005-12-13 18:49:27 +03:00
2009-08-13 20:31:01 +04:00
if ( seg - > log )
EMIT_PARAMS ( pos , " %s " , logbuf ) ;
EMIT_PARAMS ( pos , " %u " , seg - > region_size ) ;
2005-12-13 18:49:27 +03:00
2009-08-13 20:31:01 +04:00
if ( seg - > clustered & & ! dm_log_userspace )
EMIT_PARAMS ( pos , " %s " , seg - > uuid ) ;
2006-02-06 23:18:10 +03:00
2009-08-13 20:31:01 +04:00
if ( ( seg - > flags & DM_NOSYNC ) )
EMIT_PARAMS ( pos , " nosync " ) ;
else if ( ( seg - > flags & DM_FORCESYNC ) )
EMIT_PARAMS ( pos , " sync " ) ;
2005-12-13 18:49:27 +03:00
2009-08-13 20:31:01 +04:00
if ( block_on_error )
EMIT_PARAMS ( pos , " block_on_error " ) ;
EMIT_PARAMS ( pos , " %u " , seg - > mirror_area_count ) ;
2010-11-29 15:42:10 +03:00
if ( _emit_areas_line ( dmt , seg , params , paramsize , & pos ) < = 0 )
2009-09-22 20:26:59 +04:00
return_0 ;
2005-12-13 18:49:27 +03:00
2009-08-13 20:31:01 +04:00
if ( handle_errors )
EMIT_PARAMS ( pos , " 1 handle_errors " ) ;
2008-12-11 19:25:51 +03:00
2009-09-22 20:26:59 +04:00
return 1 ;
2009-08-13 20:31:01 +04:00
}
static int _emit_segment_line ( struct dm_task * dmt , uint32_t major ,
uint32_t minor , struct load_segment * seg ,
uint64_t * seg_start , char * params ,
size_t paramsize )
{
int pos = 0 ;
int r ;
char originbuf [ DM_FORMAT_DEV_BUFSIZE ] , cowbuf [ DM_FORMAT_DEV_BUFSIZE ] ;
2005-12-13 18:49:27 +03:00
2009-08-13 20:31:01 +04:00
switch ( seg - > type ) {
case SEG_ERROR :
case SEG_ZERO :
case SEG_LINEAR :
break ;
case SEG_MIRRORED :
/* Mirrors are pretty complicated - now in separate function */
2009-09-25 22:30:27 +04:00
r = _mirror_emit_segment_line ( dmt , major , minor , seg , seg_start ,
params , paramsize ) ;
2009-09-22 20:26:59 +04:00
if ( ! r )
return_0 ;
2005-11-09 01:50:11 +03:00
break ;
2010-05-21 16:24:15 +04:00
case SEG_REPLICATOR :
if ( ( r = _replicator_emit_segment_line ( seg , params , paramsize ,
& pos ) ) < = 0 ) {
stack ;
return r ;
}
break ;
case SEG_REPLICATOR_DEV :
if ( ! seg - > replicator | | ! _build_dev_string ( originbuf ,
sizeof ( originbuf ) ,
seg - > replicator ) )
return_0 ;
EMIT_PARAMS ( pos , " %s % " PRIu64 , originbuf , seg - > rdevice_index ) ;
break ;
2005-11-09 01:50:11 +03:00
case SEG_SNAPSHOT :
2010-01-13 04:39:44 +03:00
case SEG_SNAPSHOT_MERGE :
2005-11-09 17:10:50 +03:00
if ( ! _build_dev_string ( originbuf , sizeof ( originbuf ) , seg - > origin ) )
return_0 ;
if ( ! _build_dev_string ( cowbuf , sizeof ( cowbuf ) , seg - > cow ) )
return_0 ;
2008-12-11 19:25:51 +03:00
EMIT_PARAMS ( pos , " %s %s %c %d " , originbuf , cowbuf ,
seg - > persistent ? ' P ' : ' N ' , seg - > chunk_size ) ;
2005-11-09 01:50:11 +03:00
break ;
case SEG_SNAPSHOT_ORIGIN :
2005-11-09 17:10:50 +03:00
if ( ! _build_dev_string ( originbuf , sizeof ( originbuf ) , seg - > origin ) )
return_0 ;
2008-12-11 19:25:51 +03:00
EMIT_PARAMS ( pos , " %s " , originbuf ) ;
2005-11-09 01:50:11 +03:00
break ;
case SEG_STRIPED :
2009-07-07 20:36:05 +04:00
EMIT_PARAMS ( pos , " %u %u " , seg - > area_count , seg - > stripe_size ) ;
2005-11-09 01:50:11 +03:00
break ;
2009-06-09 20:10:20 +04:00
case SEG_CRYPT :
2009-07-07 20:36:05 +04:00
EMIT_PARAMS ( pos , " %s%s%s%s%s %s % " PRIu64 " " , seg - > cipher ,
2009-06-09 20:10:20 +04:00
seg - > chainmode ? " - " : " " , seg - > chainmode ? : " " ,
seg - > iv ? " - " : " " , seg - > iv ? : " " , seg - > key ,
seg - > iv_offset ! = DM_CRYPT_IV_DEFAULT ?
seg - > iv_offset : * seg_start ) ;
break ;
2005-11-09 01:50:11 +03:00
}
switch ( seg - > type ) {
case SEG_ERROR :
2010-05-21 16:24:15 +04:00
case SEG_REPLICATOR :
2005-11-09 01:50:11 +03:00
case SEG_SNAPSHOT :
case SEG_SNAPSHOT_ORIGIN :
2010-01-13 04:39:44 +03:00
case SEG_SNAPSHOT_MERGE :
2005-11-09 01:50:11 +03:00
case SEG_ZERO :
break ;
2009-06-09 20:10:20 +04:00
case SEG_CRYPT :
2005-11-09 01:50:11 +03:00
case SEG_LINEAR :
2010-05-21 16:24:15 +04:00
case SEG_REPLICATOR_DEV :
2005-11-09 01:50:11 +03:00
case SEG_STRIPED :
if ( ( r = _emit_areas_line ( dmt , seg , params , paramsize , & pos ) ) < = 0 ) {
stack ;
return r ;
}
break ;
}
2009-07-03 16:45:55 +04:00
log_debug ( " Adding target to (% " PRIu32 " :% " PRIu32 " ): % " PRIu64
" % " PRIu64 " %s %s " , major , minor ,
2005-11-09 01:50:11 +03:00
* seg_start , seg - > size , dm_segtypes [ seg - > type ] . target , params ) ;
2005-11-09 17:10:50 +03:00
if ( ! dm_task_add_target ( dmt , * seg_start , seg - > size , dm_segtypes [ seg - > type ] . target , params ) )
return_0 ;
2005-11-09 01:50:11 +03:00
* seg_start + = seg - > size ;
return 1 ;
}
2008-12-11 19:25:51 +03:00
# undef EMIT_PARAMS
2009-07-03 16:45:55 +04:00
static int _emit_segment ( struct dm_task * dmt , uint32_t major , uint32_t minor ,
struct load_segment * seg , uint64_t * seg_start )
2005-11-09 01:50:11 +03:00
{
char * params ;
size_t paramsize = 4096 ;
int ret ;
do {
if ( ! ( params = dm_malloc ( paramsize ) ) ) {
log_error ( " Insufficient space for target parameters. " ) ;
return 0 ;
}
2008-06-05 23:10:35 +04:00
params [ 0 ] = ' \0 ' ;
2009-07-03 16:45:55 +04:00
ret = _emit_segment_line ( dmt , major , minor , seg , seg_start ,
params , paramsize ) ;
2005-11-09 01:50:11 +03:00
dm_free ( params ) ;
if ( ! ret )
stack ;
if ( ret > = 0 )
return ret ;
log_debug ( " Insufficient space in params[% " PRIsize_t
" ] for target parameters. " , paramsize ) ;
paramsize * = 2 ;
} while ( paramsize < MAX_TARGET_PARAMSIZE ) ;
log_error ( " Target parameter size too big. Aborting. " ) ;
return 0 ;
}
2005-11-09 17:10:50 +03:00
static int _load_node ( struct dm_tree_node * dnode )
2005-11-09 01:50:11 +03:00
{
int r = 0 ;
struct dm_task * dmt ;
struct load_segment * seg ;
uint64_t seg_start = 0 ;
2009-07-03 16:45:55 +04:00
log_verbose ( " Loading %s table (% " PRIu32 " :% " PRIu32 " ) " , dnode - > name ,
dnode - > info . major , dnode - > info . minor ) ;
2005-11-09 01:50:11 +03:00
if ( ! ( dmt = dm_task_create ( DM_DEVICE_RELOAD ) ) ) {
log_error ( " Reload dm_task creation failed for %s " , dnode - > name ) ;
return 0 ;
}
if ( ! dm_task_set_major ( dmt , dnode - > info . major ) | |
! dm_task_set_minor ( dmt , dnode - > info . minor ) ) {
log_error ( " Failed to set device number for %s reload. " , dnode - > name ) ;
goto out ;
}
if ( dnode - > props . read_only & & ! dm_task_set_ro ( dmt ) ) {
log_error ( " Failed to set read only flag for %s " , dnode - > name ) ;
goto out ;
}
if ( ! dm_task_no_open_count ( dmt ) )
log_error ( " Failed to disable open_count " ) ;
2008-11-04 01:14:30 +03:00
dm_list_iterate_items ( seg , & dnode - > props . segs )
2009-07-03 16:45:55 +04:00
if ( ! _emit_segment ( dmt , dnode - > info . major , dnode - > info . minor ,
seg , & seg_start ) )
2005-11-09 17:10:50 +03:00
goto_out ;
2005-11-09 01:50:11 +03:00
2005-11-22 21:43:12 +03:00
if ( ! dm_task_suppress_identical_reload ( dmt ) )
log_error ( " Failed to suppress reload of identical tables. " ) ;
if ( ( r = dm_task_run ( dmt ) ) ) {
2005-11-09 01:50:11 +03:00
r = dm_task_get_info ( dmt , & dnode - > info ) ;
2005-11-22 21:43:12 +03:00
if ( r & & ! dnode - > info . inactive_table )
log_verbose ( " Suppressed %s identical table reload. " ,
dnode - > name ) ;
2008-09-18 22:34:53 +04:00
if ( ( dnode - > props . size_changed =
( dm_task_get_existing_table_size ( dmt ) = = seg_start ) ? 0 : 1 ) )
log_debug ( " Table size changed from % " PRIu64 " to % "
PRIu64 " for %s " ,
dm_task_get_existing_table_size ( dmt ) ,
seg_start , dnode - > name ) ;
2005-11-22 21:43:12 +03:00
}
2005-11-09 01:50:11 +03:00
dnode - > props . segment_count = 0 ;
out :
dm_task_destroy ( dmt ) ;
return r ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_preload_children ( struct dm_tree_node * dnode ,
2008-09-18 22:34:53 +04:00
const char * uuid_prefix ,
size_t uuid_prefix_len )
2005-11-09 01:50:11 +03:00
{
2010-01-06 00:04:37 +03:00
int r = 1 ;
2005-11-09 01:50:11 +03:00
void * handle = NULL ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node * child ;
2005-11-09 01:50:11 +03:00
struct dm_info newinfo ;
2010-06-21 12:54:32 +04:00
int update_devs_flag = 0 ;
2005-11-09 01:50:11 +03:00
/* Preload children first */
2005-11-09 17:10:50 +03:00
while ( ( child = dm_tree_next_child ( & handle , dnode , 0 ) ) ) {
2005-11-09 01:50:11 +03:00
/* Skip existing non-device-mapper devices */
if ( ! child - > info . exists & & child - > info . major )
continue ;
/* Ignore if it doesn't belong to this VG */
2005-11-13 01:46:48 +03:00
if ( child - > info . exists & &
! _uuid_prefix_matches ( child - > uuid , uuid_prefix , uuid_prefix_len ) )
2005-11-09 01:50:11 +03:00
continue ;
2005-11-09 17:10:50 +03:00
if ( dm_tree_node_num_children ( child , 0 ) )
2010-01-06 00:04:37 +03:00
if ( ! dm_tree_preload_children ( child , uuid_prefix , uuid_prefix_len ) )
return_0 ;
2005-11-09 01:50:11 +03:00
/* FIXME Cope if name exists with no uuid? */
if ( ! child - > info . exists ) {
if ( ! _create_node ( child ) ) {
stack ;
return 0 ;
}
}
if ( ! child - > info . inactive_table & & child - > props . segment_count ) {
if ( ! _load_node ( child ) ) {
stack ;
return 0 ;
}
}
2009-05-20 13:52:37 +04:00
/* Propagate device size change change */
if ( child - > props . size_changed )
dnode - > props . size_changed = 1 ;
2008-09-18 22:34:53 +04:00
/* Resume device immediately if it has parents and its size changed */
2008-09-19 02:55:33 +04:00
if ( ! dm_tree_node_num_children ( child , 1 ) | | ! child - > props . size_changed )
2005-11-09 01:50:11 +03:00
continue ;
2005-11-22 22:31:20 +03:00
if ( ! child - > info . inactive_table & & ! child - > info . suspended )
continue ;
2007-12-14 22:49:27 +03:00
if ( ! _resume_node ( child - > name , child - > info . major , child - > info . minor ,
2009-07-31 22:30:31 +04:00
child - > props . read_ahead , child - > props . read_ahead_flags ,
2009-10-22 17:00:07 +04:00
& newinfo , & child - > dtree - > cookie , child - > udev_flags ) ) {
2005-11-09 01:50:11 +03:00
log_error ( " Unable to resume %s (% " PRIu32
2007-12-14 22:49:27 +03:00
" :% " PRIu32 " ) " , child - > name , child - > info . major ,
2005-11-09 01:50:11 +03:00
child - > info . minor ) ;
2010-01-06 00:04:37 +03:00
r = 0 ;
2005-11-09 01:50:11 +03:00
continue ;
}
/* Update cached info */
child - > info = newinfo ;
2010-06-21 12:54:32 +04:00
/*
* Prepare for immediate synchronization with udev and flush all stacked
* dev node operations if requested by immediate_dev_node property . But
* finish processing current level in the tree first .
*/
if ( child - > props . immediate_dev_node )
update_devs_flag = 1 ;
2005-11-09 01:50:11 +03:00
}
handle = NULL ;
2010-06-21 12:54:32 +04:00
if ( update_devs_flag ) {
if ( ! dm_udev_wait ( dm_tree_get_cookie ( dnode ) ) )
stack ;
dm_tree_set_cookie ( dnode , 0 ) ;
dm_task_update_nodes ( ) ;
}
2010-01-06 00:04:37 +03:00
return r ;
2005-11-09 01:50:11 +03:00
}
/*
* Returns 1 if unsure .
*/
2005-11-09 17:10:50 +03:00
int dm_tree_children_use_uuid ( struct dm_tree_node * dnode ,
2005-11-09 01:50:11 +03:00
const char * uuid_prefix ,
size_t uuid_prefix_len )
{
void * handle = NULL ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node * child = dnode ;
2005-11-09 01:50:11 +03:00
const char * uuid ;
2005-11-09 17:10:50 +03:00
while ( ( child = dm_tree_next_child ( & handle , dnode , 0 ) ) ) {
if ( ! ( uuid = dm_tree_node_get_uuid ( child ) ) ) {
log_error ( " Failed to get uuid for dtree node. " ) ;
2005-11-09 01:50:11 +03:00
return 1 ;
}
2005-11-13 01:46:48 +03:00
if ( _uuid_prefix_matches ( uuid , uuid_prefix , uuid_prefix_len ) )
2005-11-09 01:50:11 +03:00
return 1 ;
2005-11-09 17:10:50 +03:00
if ( dm_tree_node_num_children ( child , 0 ) )
dm_tree_children_use_uuid ( child , uuid_prefix , uuid_prefix_len ) ;
2005-11-09 01:50:11 +03:00
}
return 0 ;
}
/*
* Target functions
*/
2005-11-09 17:10:50 +03:00
static struct load_segment * _add_segment ( struct dm_tree_node * dnode , unsigned type , uint64_t size )
2005-11-09 01:50:11 +03:00
{
struct load_segment * seg ;
2005-11-09 17:10:50 +03:00
if ( ! ( seg = dm_pool_zalloc ( dnode - > dtree - > mem , sizeof ( * seg ) ) ) ) {
log_error ( " dtree node segment allocation failed " ) ;
2005-11-09 01:50:11 +03:00
return NULL ;
}
seg - > type = type ;
seg - > size = size ;
seg - > area_count = 0 ;
2008-11-04 01:14:30 +03:00
dm_list_init ( & seg - > areas ) ;
2005-11-09 01:50:11 +03:00
seg - > stripe_size = 0 ;
seg - > persistent = 0 ;
seg - > chunk_size = 0 ;
seg - > cow = NULL ;
seg - > origin = NULL ;
2010-01-13 04:39:44 +03:00
seg - > merge = NULL ;
2005-11-09 01:50:11 +03:00
2008-11-04 01:14:30 +03:00
dm_list_add ( & dnode - > props . segs , & seg - > list ) ;
2005-11-09 01:50:11 +03:00
dnode - > props . segment_count + + ;
return seg ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_node_add_snapshot_origin_target ( struct dm_tree_node * dnode ,
2005-11-09 01:50:11 +03:00
uint64_t size ,
const char * origin_uuid )
{
struct load_segment * seg ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node * origin_node ;
2005-11-09 01:50:11 +03:00
2005-11-09 17:10:50 +03:00
if ( ! ( seg = _add_segment ( dnode , SEG_SNAPSHOT_ORIGIN , size ) ) )
return_0 ;
2005-11-09 01:50:11 +03:00
2005-11-09 17:10:50 +03:00
if ( ! ( origin_node = dm_tree_find_node_by_uuid ( dnode - > dtree , origin_uuid ) ) ) {
2005-11-09 01:50:11 +03:00
log_error ( " Couldn't find snapshot origin uuid %s. " , origin_uuid ) ;
return 0 ;
}
seg - > origin = origin_node ;
2005-11-09 17:10:50 +03:00
if ( ! _link_tree_nodes ( dnode , origin_node ) )
return_0 ;
2005-11-09 01:50:11 +03:00
2005-11-22 23:00:35 +03:00
/* Resume snapshot origins after new snapshots */
dnode - > activation_priority = 1 ;
2005-11-09 01:50:11 +03:00
return 1 ;
}
2010-01-13 04:39:44 +03:00
static int _add_snapshot_target ( struct dm_tree_node * node ,
uint64_t size ,
const char * origin_uuid ,
const char * cow_uuid ,
const char * merge_uuid ,
int persistent ,
uint32_t chunk_size )
2005-11-09 01:50:11 +03:00
{
struct load_segment * seg ;
2010-01-13 04:39:44 +03:00
struct dm_tree_node * origin_node , * cow_node , * merge_node ;
unsigned seg_type ;
seg_type = ! merge_uuid ? SEG_SNAPSHOT : SEG_SNAPSHOT_MERGE ;
2005-11-09 01:50:11 +03:00
2010-01-13 04:39:44 +03:00
if ( ! ( seg = _add_segment ( node , seg_type , size ) ) )
2005-11-09 17:10:50 +03:00
return_0 ;
2005-11-09 01:50:11 +03:00
2005-11-09 17:10:50 +03:00
if ( ! ( origin_node = dm_tree_find_node_by_uuid ( node - > dtree , origin_uuid ) ) ) {
2005-11-09 01:50:11 +03:00
log_error ( " Couldn't find snapshot origin uuid %s. " , origin_uuid ) ;
return 0 ;
}
seg - > origin = origin_node ;
2005-11-09 17:10:50 +03:00
if ( ! _link_tree_nodes ( node , origin_node ) )
return_0 ;
2005-11-09 01:50:11 +03:00
2005-11-09 17:10:50 +03:00
if ( ! ( cow_node = dm_tree_find_node_by_uuid ( node - > dtree , cow_uuid ) ) ) {
2010-01-13 04:39:44 +03:00
log_error ( " Couldn't find snapshot COW device uuid %s. " , cow_uuid ) ;
2005-11-09 01:50:11 +03:00
return 0 ;
}
seg - > cow = cow_node ;
2005-11-09 17:10:50 +03:00
if ( ! _link_tree_nodes ( node , cow_node ) )
return_0 ;
2005-11-09 01:50:11 +03:00
seg - > persistent = persistent ? 1 : 0 ;
seg - > chunk_size = chunk_size ;
2010-01-13 04:39:44 +03:00
if ( merge_uuid ) {
if ( ! ( merge_node = dm_tree_find_node_by_uuid ( node - > dtree , merge_uuid ) ) ) {
/* not a pure error, merging snapshot may have been deactivated */
log_verbose ( " Couldn't find merging snapshot uuid %s. " , merge_uuid ) ;
} else {
seg - > merge = merge_node ;
/* must not link merging snapshot, would undermine activation_priority below */
}
/* Resume snapshot-merge (acting origin) after other snapshots */
node - > activation_priority = 1 ;
if ( seg - > merge ) {
/* Resume merging snapshot after snapshot-merge */
seg - > merge - > activation_priority = 2 ;
}
}
2005-11-09 01:50:11 +03:00
return 1 ;
}
2010-01-13 04:39:44 +03:00
int dm_tree_node_add_snapshot_target ( struct dm_tree_node * node ,
uint64_t size ,
const char * origin_uuid ,
const char * cow_uuid ,
int persistent ,
uint32_t chunk_size )
{
return _add_snapshot_target ( node , size , origin_uuid , cow_uuid ,
NULL , persistent , chunk_size ) ;
}
int dm_tree_node_add_snapshot_merge_target ( struct dm_tree_node * node ,
uint64_t size ,
const char * origin_uuid ,
const char * cow_uuid ,
const char * merge_uuid ,
uint32_t chunk_size )
{
return _add_snapshot_target ( node , size , origin_uuid , cow_uuid ,
merge_uuid , 1 , chunk_size ) ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_node_add_error_target ( struct dm_tree_node * node ,
2005-11-09 01:50:11 +03:00
uint64_t size )
{
2005-11-09 17:10:50 +03:00
if ( ! _add_segment ( node , SEG_ERROR , size ) )
return_0 ;
2005-11-09 01:50:11 +03:00
return 1 ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_node_add_zero_target ( struct dm_tree_node * node ,
2005-11-09 01:50:11 +03:00
uint64_t size )
{
2005-11-09 17:10:50 +03:00
if ( ! _add_segment ( node , SEG_ZERO , size ) )
return_0 ;
2005-11-09 01:50:11 +03:00
return 1 ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_node_add_linear_target ( struct dm_tree_node * node ,
2005-11-09 01:50:11 +03:00
uint64_t size )
{
2005-11-09 17:10:50 +03:00
if ( ! _add_segment ( node , SEG_LINEAR , size ) )
return_0 ;
2005-11-09 01:50:11 +03:00
return 1 ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_node_add_striped_target ( struct dm_tree_node * node ,
2005-11-09 01:50:11 +03:00
uint64_t size ,
uint32_t stripe_size )
{
struct load_segment * seg ;
2005-11-09 17:10:50 +03:00
if ( ! ( seg = _add_segment ( node , SEG_STRIPED , size ) ) )
return_0 ;
2005-11-09 01:50:11 +03:00
seg - > stripe_size = stripe_size ;
return 1 ;
}
2009-06-09 20:10:20 +04:00
int dm_tree_node_add_crypt_target ( struct dm_tree_node * node ,
uint64_t size ,
const char * cipher ,
const char * chainmode ,
const char * iv ,
uint64_t iv_offset ,
const char * key )
{
struct load_segment * seg ;
if ( ! ( seg = _add_segment ( node , SEG_CRYPT , size ) ) )
return_0 ;
seg - > cipher = cipher ;
seg - > chainmode = chainmode ;
seg - > iv = iv ;
seg - > iv_offset = iv_offset ;
seg - > key = key ;
return 1 ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_node_add_mirror_target_log ( struct dm_tree_node * node ,
2005-11-09 01:50:11 +03:00
uint32_t region_size ,
2009-12-03 12:58:30 +03:00
unsigned clustered ,
2005-11-09 01:50:11 +03:00
const char * log_uuid ,
2005-12-20 00:03:17 +03:00
unsigned area_count ,
uint32_t flags )
2005-11-09 01:50:11 +03:00
{
2005-11-09 18:41:42 +03:00
struct dm_tree_node * log_node = NULL ;
2005-11-09 01:50:11 +03:00
struct load_segment * seg ;
if ( ! node - > props . segment_count ) {
2010-03-25 21:22:04 +03:00
log_error ( INTERNAL_ERROR " Attempt to add target area to missing segment. " ) ;
2005-11-09 01:50:11 +03:00
return 0 ;
}
2008-11-04 01:14:30 +03:00
seg = dm_list_item ( dm_list_last ( & node - > props . segs ) , struct load_segment ) ;
2005-11-09 01:50:11 +03:00
2005-11-09 20:32:31 +03:00
if ( log_uuid ) {
2006-02-06 23:18:10 +03:00
if ( ! ( seg - > uuid = dm_pool_strdup ( node - > dtree - > mem , log_uuid ) ) ) {
log_error ( " log uuid pool_strdup failed " ) ;
return 0 ;
}
2006-05-11 23:10:55 +04:00
if ( ! ( flags & DM_CORELOG ) ) {
if ( ! ( log_node = dm_tree_find_node_by_uuid ( node - > dtree , log_uuid ) ) ) {
log_error ( " Couldn't find mirror log uuid %s. " , log_uuid ) ;
return 0 ;
}
2010-06-21 12:54:32 +04:00
if ( clustered )
log_node - > props . immediate_dev_node = 1 ;
2006-05-11 23:10:55 +04:00
if ( ! _link_tree_nodes ( node , log_node ) )
return_0 ;
}
2005-11-09 01:50:11 +03:00
}
seg - > log = log_node ;
seg - > region_size = region_size ;
seg - > clustered = clustered ;
seg - > mirror_area_count = area_count ;
2005-12-13 18:49:27 +03:00
seg - > flags = flags ;
2005-11-09 01:50:11 +03:00
return 1 ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_node_add_mirror_target ( struct dm_tree_node * node ,
2005-11-09 01:50:11 +03:00
uint64_t size )
{
2010-11-29 14:26:00 +03:00
if ( ! _add_segment ( node , SEG_MIRRORED , size ) )
2005-11-09 17:10:50 +03:00
return_0 ;
2005-11-09 01:50:11 +03:00
return 1 ;
}
2010-05-21 16:24:15 +04:00
int dm_tree_node_add_replicator_target ( struct dm_tree_node * node ,
uint64_t size ,
const char * rlog_uuid ,
const char * rlog_type ,
unsigned rsite_index ,
dm_replicator_mode_t mode ,
uint32_t async_timeout ,
uint64_t fall_behind_data ,
uint32_t fall_behind_ios )
{
struct load_segment * rseg ;
struct replicator_site * rsite ;
/* Local site0 - adds replicator segment and links rlog device */
if ( rsite_index = = REPLICATOR_LOCAL_SITE ) {
if ( node - > props . segment_count ) {
log_error ( INTERNAL_ERROR " Attempt to add replicator segment to already used node. " ) ;
return 0 ;
}
if ( ! ( rseg = _add_segment ( node , SEG_REPLICATOR , size ) ) )
return_0 ;
if ( ! ( rseg - > log = dm_tree_find_node_by_uuid ( node - > dtree , rlog_uuid ) ) ) {
log_error ( " Missing replicator log uuid %s. " , rlog_uuid ) ;
return 0 ;
}
if ( ! _link_tree_nodes ( node , rseg - > log ) )
return_0 ;
if ( strcmp ( rlog_type , " ringbuffer " ) ! = 0 ) {
log_error ( " Unsupported replicator log type %s. " , rlog_type ) ;
return 0 ;
}
if ( ! ( rseg - > rlog_type = dm_pool_strdup ( node - > dtree - > mem , rlog_type ) ) )
return_0 ;
dm_list_init ( & rseg - > rsites ) ;
rseg - > rdevice_count = 0 ;
node - > activation_priority = 1 ;
}
/* Add site to segment */
if ( mode = = DM_REPLICATOR_SYNC
& & ( async_timeout | | fall_behind_ios | | fall_behind_data ) ) {
log_error ( " Async parameters passed for synchronnous replicator. " ) ;
return 0 ;
}
if ( node - > props . segment_count ! = 1 ) {
log_error ( INTERNAL_ERROR " Attempt to add remote site area before setting replicator log. " ) ;
return 0 ;
}
rseg = dm_list_item ( dm_list_last ( & node - > props . segs ) , struct load_segment ) ;
if ( rseg - > type ! = SEG_REPLICATOR ) {
log_error ( INTERNAL_ERROR " Attempt to use non replicator segment %s. " ,
dm_segtypes [ rseg - > type ] . target ) ;
return 0 ;
}
if ( ! ( rsite = dm_pool_zalloc ( node - > dtree - > mem , sizeof ( * rsite ) ) ) ) {
log_error ( " Failed to allocate remote site segment. " ) ;
return 0 ;
}
dm_list_add ( & rseg - > rsites , & rsite - > list ) ;
rseg - > rsite_count + + ;
rsite - > mode = mode ;
rsite - > async_timeout = async_timeout ;
rsite - > fall_behind_data = fall_behind_data ;
rsite - > fall_behind_ios = fall_behind_ios ;
rsite - > rsite_index = rsite_index ;
return 1 ;
}
/* Appends device node to Replicator */
int dm_tree_node_add_replicator_dev_target ( struct dm_tree_node * node ,
uint64_t size ,
const char * replicator_uuid ,
uint64_t rdevice_index ,
const char * rdev_uuid ,
unsigned rsite_index ,
const char * slog_uuid ,
uint32_t slog_flags ,
uint32_t slog_region_size )
{
struct seg_area * area ;
struct load_segment * rseg ;
struct load_segment * rep_seg ;
if ( rsite_index = = REPLICATOR_LOCAL_SITE ) {
/* Site index for local target */
if ( ! ( rseg = _add_segment ( node , SEG_REPLICATOR_DEV , size ) ) )
return_0 ;
if ( ! ( rseg - > replicator = dm_tree_find_node_by_uuid ( node - > dtree , replicator_uuid ) ) ) {
log_error ( " Missing replicator uuid %s. " , replicator_uuid ) ;
return 0 ;
}
/* Local slink0 for replicator must be always initialized first */
if ( rseg - > replicator - > props . segment_count ! = 1 ) {
log_error ( INTERNAL_ERROR " Attempt to use non replicator segment. " ) ;
return 0 ;
}
rep_seg = dm_list_item ( dm_list_last ( & rseg - > replicator - > props . segs ) , struct load_segment ) ;
if ( rep_seg - > type ! = SEG_REPLICATOR ) {
log_error ( INTERNAL_ERROR " Attempt to use non replicator segment %s. " ,
dm_segtypes [ rep_seg - > type ] . target ) ;
return 0 ;
}
rep_seg - > rdevice_count + + ;
if ( ! _link_tree_nodes ( node , rseg - > replicator ) )
return_0 ;
rseg - > rdevice_index = rdevice_index ;
} else {
/* Local slink0 for replicator must be always initialized first */
if ( node - > props . segment_count ! = 1 ) {
log_error ( INTERNAL_ERROR " Attempt to use non replicator-dev segment. " ) ;
return 0 ;
}
rseg = dm_list_item ( dm_list_last ( & node - > props . segs ) , struct load_segment ) ;
if ( rseg - > type ! = SEG_REPLICATOR_DEV ) {
log_error ( INTERNAL_ERROR " Attempt to use non replicator-dev segment %s. " ,
dm_segtypes [ rseg - > type ] . target ) ;
return 0 ;
}
}
if ( ! ( slog_flags & DM_CORELOG ) & & ! slog_uuid ) {
log_error ( " Unspecified sync log uuid. " ) ;
return 0 ;
}
if ( ! dm_tree_node_add_target_area ( node , NULL , rdev_uuid , 0 ) )
return_0 ;
area = dm_list_item ( dm_list_last ( & rseg - > areas ) , struct seg_area ) ;
if ( ! ( slog_flags & DM_CORELOG ) ) {
if ( ! ( area - > slog = dm_tree_find_node_by_uuid ( node - > dtree , slog_uuid ) ) ) {
log_error ( " Couldn't find sync log uuid %s. " , slog_uuid ) ;
return 0 ;
}
if ( ! _link_tree_nodes ( node , area - > slog ) )
return_0 ;
}
area - > flags = slog_flags ;
area - > region_size = slog_region_size ;
area - > rsite_index = rsite_index ;
return 1 ;
}
2005-11-09 17:10:50 +03:00
static int _add_area ( struct dm_tree_node * node , struct load_segment * seg , struct dm_tree_node * dev_node , uint64_t offset )
2005-11-09 01:50:11 +03:00
{
struct seg_area * area ;
2005-11-09 17:10:50 +03:00
if ( ! ( area = dm_pool_zalloc ( node - > dtree - > mem , sizeof ( * area ) ) ) ) {
2005-11-09 01:50:11 +03:00
log_error ( " Failed to allocate target segment area. " ) ;
return 0 ;
}
area - > dev_node = dev_node ;
area - > offset = offset ;
2008-11-04 01:14:30 +03:00
dm_list_add ( & seg - > areas , & area - > list ) ;
2005-11-09 01:50:11 +03:00
seg - > area_count + + ;
return 1 ;
}
2005-11-09 17:10:50 +03:00
int dm_tree_node_add_target_area ( struct dm_tree_node * node ,
2005-11-09 01:50:11 +03:00
const char * dev_name ,
const char * uuid ,
uint64_t offset )
{
struct load_segment * seg ;
struct stat info ;
2005-11-09 17:10:50 +03:00
struct dm_tree_node * dev_node ;
2005-11-09 01:50:11 +03:00
if ( ( ! dev_name | | ! * dev_name ) & & ( ! uuid | | ! * uuid ) ) {
2005-11-09 17:10:50 +03:00
log_error ( " dm_tree_node_add_target_area called without device " ) ;
2005-11-09 01:50:11 +03:00
return 0 ;
}
if ( uuid ) {
2005-11-09 17:10:50 +03:00
if ( ! ( dev_node = dm_tree_find_node_by_uuid ( node - > dtree , uuid ) ) ) {
2005-11-09 01:50:11 +03:00
log_error ( " Couldn't find area uuid %s. " , uuid ) ;
return 0 ;
}
2005-11-09 17:10:50 +03:00
if ( ! _link_tree_nodes ( node , dev_node ) )
return_0 ;
2005-11-09 01:50:11 +03:00
} else {
if ( stat ( dev_name , & info ) < 0 ) {
log_error ( " Device %s not found. " , dev_name ) ;
return 0 ;
}
if ( ! S_ISBLK ( info . st_mode ) ) {
log_error ( " Device %s is not a block device. " , dev_name ) ;
return 0 ;
}
/* FIXME Check correct macro use */
2010-01-07 22:54:21 +03:00
if ( ! ( dev_node = _add_dev ( node - > dtree , node , MAJOR ( info . st_rdev ) ,
MINOR ( info . st_rdev ) , 0 ) ) )
2005-11-09 17:10:50 +03:00
return_0 ;
2005-11-09 01:50:11 +03:00
}
if ( ! node - > props . segment_count ) {
2010-03-25 21:22:04 +03:00
log_error ( INTERNAL_ERROR " Attempt to add target area to missing segment. " ) ;
2005-11-09 01:50:11 +03:00
return 0 ;
}
2008-11-04 01:14:30 +03:00
seg = dm_list_item ( dm_list_last ( & node - > props . segs ) , struct load_segment ) ;
2005-11-09 01:50:11 +03:00
2005-11-09 17:10:50 +03:00
if ( ! _add_area ( node , seg , dev_node , offset ) )
return_0 ;
2005-11-09 01:50:11 +03:00
return 1 ;
2005-10-25 23:09:41 +04:00
}
2009-07-31 22:30:31 +04:00
void dm_tree_set_cookie ( struct dm_tree_node * node , uint32_t cookie )
{
node - > dtree - > cookie = cookie ;
}
uint32_t dm_tree_get_cookie ( struct dm_tree_node * node )
{
return node - > dtree - > cookie ;
}