2005-10-16 14:33:22 +00:00
/*
2014-01-27 05:29:35 -06:00
* Copyright ( C ) 2005 - 2014 Red Hat , Inc . All rights reserved .
2005-10-16 14:33:22 +00: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 18:59:59 +00:00
# include "dmlib.h"
2005-10-16 14:33:22 +00:00
# include "libdm-targets.h"
# include "libdm-common.h"
# include "kdev_t.h"
2014-07-30 21:55:11 +01:00
# include "dm-ioctl.h"
2005-10-16 14:33:22 +00:00
# include <stdarg.h>
# include <sys/param.h>
2009-08-13 16:31:01 +00:00
# include <sys/utsname.h>
2005-10-16 14:33:22 +00:00
2005-11-08 22:50:11 +00:00
# define MAX_TARGET_PARAMSIZE 500000
2010-05-21 12:24:15 +00:00
# define REPLICATOR_LOCAL_SITE 0
2005-11-08 22:50:11 +00:00
/* Supported segment types */
enum {
2014-01-27 05:29:35 -06:00
SEG_CACHE ,
2009-06-09 16:10:20 +00:00
SEG_CRYPT ,
SEG_ERROR ,
2005-11-08 22:50:11 +00:00
SEG_LINEAR ,
SEG_MIRRORED ,
2010-05-21 12:24:15 +00:00
SEG_REPLICATOR ,
SEG_REPLICATOR_DEV ,
2005-11-08 22:50:11 +00:00
SEG_SNAPSHOT ,
SEG_SNAPSHOT_ORIGIN ,
2010-01-13 01:39:44 +00:00
SEG_SNAPSHOT_MERGE ,
2005-11-08 22:50:11 +00:00
SEG_STRIPED ,
SEG_ZERO ,
2011-09-29 08:53:48 +00:00
SEG_THIN_POOL ,
SEG_THIN ,
2011-08-02 22:07:20 +00:00
SEG_RAID1 ,
2012-08-24 15:34:19 -05:00
SEG_RAID10 ,
2011-08-02 22:07:20 +00:00
SEG_RAID4 ,
SEG_RAID5_LA ,
SEG_RAID5_RA ,
SEG_RAID5_LS ,
SEG_RAID5_RS ,
SEG_RAID6_ZR ,
SEG_RAID6_NR ,
SEG_RAID6_NC ,
2005-11-08 22:50:11 +00:00
} ;
2005-11-09 14:10:50 +00:00
2005-11-08 22:50:11 +00:00
/* FIXME Add crypt and multipath support */
2014-04-04 22:34:22 +02:00
static const struct {
2005-11-08 22:50:11 +00:00
unsigned type ;
2014-04-04 22:34:22 +02:00
const char target [ 16 ] ;
} _dm_segtypes [ ] = {
2014-01-27 05:29:35 -06:00
{ SEG_CACHE , " cache " } ,
2009-06-09 16:10:20 +00:00
{ SEG_CRYPT , " crypt " } ,
2005-11-08 22:50:11 +00:00
{ SEG_ERROR , " error " } ,
{ SEG_LINEAR , " linear " } ,
{ SEG_MIRRORED , " mirror " } ,
2010-05-21 12:24:15 +00:00
{ SEG_REPLICATOR , " replicator " } ,
{ SEG_REPLICATOR_DEV , " replicator-dev " } ,
2005-11-08 22:50:11 +00:00
{ SEG_SNAPSHOT , " snapshot " } ,
{ SEG_SNAPSHOT_ORIGIN , " snapshot-origin " } ,
2010-01-13 01:39:44 +00:00
{ SEG_SNAPSHOT_MERGE , " snapshot-merge " } ,
2005-11-08 22:50:11 +00:00
{ SEG_STRIPED , " striped " } ,
{ SEG_ZERO , " zero " } ,
2011-09-29 08:53:48 +00:00
{ SEG_THIN_POOL , " thin-pool " } ,
{ SEG_THIN , " thin " } ,
2011-08-02 22:07:20 +00:00
{ SEG_RAID1 , " raid1 " } ,
2012-08-24 15:34:19 -05:00
{ SEG_RAID10 , " raid10 " } ,
2011-08-02 22:07:20 +00:00
{ SEG_RAID4 , " raid4 " } ,
{ SEG_RAID5_LA , " raid5_la " } ,
{ SEG_RAID5_RA , " raid5_ra " } ,
{ SEG_RAID5_LS , " raid5_ls " } ,
{ SEG_RAID5_RS , " raid5_rs " } ,
{ SEG_RAID6_ZR , " raid6_zr " } ,
{ SEG_RAID6_NR , " raid6_nr " } ,
{ SEG_RAID6_NC , " raid6_nc " } ,
2011-09-29 08:50:54 +00:00
/*
* WARNING : Since ' raid ' target overloads this 1 : 1 mapping table
* for search do not add new enum elements past them !
*/
2011-08-02 22:07:20 +00:00
{ SEG_RAID5_LS , " raid5 " } , /* same as "raid5_ls" (default for MD also) */
{ SEG_RAID6_ZR , " raid6 " } , /* same as "raid6_zr" */
2005-11-08 22:50:11 +00:00
} ;
/* Some segment types have a list of areas of other devices attached */
struct seg_area {
2008-11-03 22:14:30 +00:00
struct dm_list list ;
2005-11-08 22:50:11 +00:00
2005-11-09 14:10:50 +00:00
struct dm_tree_node * dev_node ;
2005-11-08 22:50:11 +00:00
uint64_t offset ;
2010-05-21 12:24:15 +00: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 */
} ;
2011-11-03 14:45:01 +00:00
struct dm_thin_message {
dm_thin_message_t type ;
union {
struct {
uint32_t device_id ;
uint32_t origin_id ;
} m_create_snap ;
struct {
uint32_t device_id ;
} m_create_thin ;
struct {
uint32_t device_id ;
} m_delete ;
struct {
uint64_t current_id ;
uint64_t new_id ;
} m_set_transaction_id ;
} u ;
} ;
2011-10-17 14:16:25 +00:00
struct thin_message {
struct dm_list list ;
struct dm_thin_message message ;
2011-10-19 16:36:01 +00:00
int expected_errno ;
2011-10-17 14:16:25 +00:00
} ;
2010-05-21 12:24:15 +00:00
/* 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-08 22:50:11 +00:00
} ;
/* Per-segment properties */
struct load_segment {
2008-11-03 22:14:30 +00:00
struct dm_list list ;
2005-11-08 22:50:11 +00:00
unsigned type ;
uint64_t size ;
2010-05-21 12:24:15 +00:00
unsigned area_count ; /* Linear + Striped + Mirrored + Crypt + Replicator */
struct dm_list areas ; /* Linear + Striped + Mirrored + Crypt + Replicator */
2005-11-08 22:50:11 +00:00
2011-08-02 22:07:20 +00:00
uint32_t stripe_size ; /* Striped + raid */
2005-11-08 22:50:11 +00:00
int persistent ; /* Snapshot */
2014-01-27 05:29:35 -06:00
uint32_t chunk_size ; /* Snapshot + cache */
2005-11-09 14:10:50 +00:00
struct dm_tree_node * cow ; /* Snapshot */
2014-01-27 05:29:35 -06:00
struct dm_tree_node * origin ; /* Snapshot + Snapshot origin + Cache */
2010-01-13 01:39:44 +00:00
struct dm_tree_node * merge ; /* Snapshot */
2005-11-08 22:50:11 +00:00
2010-05-21 12:24:15 +00:00
struct dm_tree_node * log ; /* Mirror + Replicator */
2011-08-02 22:07:20 +00:00
uint32_t region_size ; /* Mirror + raid */
2005-11-08 22:50:11 +00:00
unsigned clustered ; /* Mirror */
unsigned mirror_area_count ; /* Mirror */
2014-01-27 05:29:35 -06:00
uint32_t flags ; /* Mirror + raid + Cache */
2006-02-06 20:18:10 +00:00
char * uuid ; /* Clustered mirror log */
2009-06-09 16:10:20 +00:00
2014-04-01 14:41:29 +02:00
const char * policy_name ; /* Cache */
2014-02-14 22:33:09 +01:00
unsigned policy_argc ; /* Cache */
2014-11-10 23:41:03 +01:00
struct dm_config_node * policy_settings ; /* Cache */
2014-01-27 05:29:35 -06:00
2009-06-09 16:10:20 +00: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 12:24:15 +00: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 */
2011-08-18 19:41:21 +00:00
2013-05-31 11:25:52 -05:00
uint64_t rebuilds ; /* raid */
uint64_t writemostly ; /* raid */
uint32_t writebehind ; /* raid */
uint32_t max_recovery_rate ; /* raid kB/sec/disk */
uint32_t min_recovery_rate ; /* raid kB/sec/disk */
2011-09-29 08:53:48 +00:00
2014-01-27 05:29:35 -06:00
struct dm_tree_node * metadata ; /* Thin_pool + Cache */
2011-09-29 08:53:48 +00:00
struct dm_tree_node * pool ; /* Thin_pool, Thin */
2012-02-04 13:49:40 +01:00
struct dm_tree_node * external ; /* Thin */
2011-10-17 14:16:25 +00:00
struct dm_list thin_messages ; /* Thin_pool */
2011-10-30 22:04:57 +00:00
uint64_t transaction_id ; /* Thin_pool */
2011-10-20 10:33:30 +00:00
uint64_t low_water_mark ; /* Thin_pool */
2011-10-03 18:34:52 +00:00
uint32_t data_block_size ; /* Thin_pool */
2011-10-04 16:22:38 +00:00
unsigned skip_block_zeroing ; /* Thin_pool */
2012-08-07 18:34:30 +01:00
unsigned ignore_discard ; /* Thin_pool target vsn 1.1 */
unsigned no_discard_passdown ; /* Thin_pool target vsn 1.1 */
2015-01-13 15:23:03 +01:00
unsigned error_if_no_space ; /* Thin pool target vsn 1.10 */
2011-09-29 08:53:48 +00:00
uint32_t device_id ; /* Thin */
2005-11-08 22:50:11 +00:00
} ;
/* Per-device properties */
struct load_properties {
int read_only ;
uint32_t major ;
uint32_t minor ;
2007-11-27 20:57:05 +00:00
uint32_t read_ahead ;
uint32_t read_ahead_flags ;
2005-11-08 22:50:11 +00:00
unsigned segment_count ;
2008-09-18 18:34:53 +00:00
unsigned size_changed ;
2008-11-03 22:14:30 +00:00
struct dm_list segs ;
2005-11-08 22:50:11 +00:00
const char * new_name ;
2010-06-21 08:54:32 +00: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 .
*/
2011-06-11 00:03:06 +00:00
unsigned immediate_dev_node ;
/*
* If the device size changed from zero and this is set ,
* don ' t resume the device immediately , even if the device
* has parents . This works provided the parents do not
* validate the device size and is required by pvmove to
* avoid starting the mirror resync operation too early .
*/
unsigned delay_resume_if_new ;
2011-10-30 22:04:57 +00:00
/* Send messages for this node in preload */
unsigned send_messages ;
2005-11-08 22:50:11 +00:00
} ;
/* Two of these used to join two nodes with uses and used_by. */
2005-11-09 14:10:50 +00:00
struct dm_tree_link {
2008-11-03 22:14:30 +00:00
struct dm_list list ;
2005-11-09 14:10:50 +00:00
struct dm_tree_node * node ;
2005-11-08 22:50:11 +00:00
} ;
2005-11-09 14:10:50 +00:00
struct dm_tree_node {
struct dm_tree * dtree ;
2005-10-16 14:33:22 +00:00
2011-08-19 17:02:48 +00:00
const char * name ;
const char * uuid ;
struct dm_info info ;
2005-10-16 14:33:22 +00:00
2011-08-19 17:02:48 +00:00
struct dm_list uses ; /* Nodes this node uses */
struct dm_list used_by ; /* Nodes that use this node */
2005-11-08 22:50:11 +00:00
2005-11-22 20:00:35 +00:00
int activation_priority ; /* 0 gets activated first */
2014-04-07 20:21:20 +02:00
int implicit_deps ; /* 1 device only implicitly referenced */
2005-11-22 20:00:35 +00:00
2009-10-22 13:00:07 +00:00
uint16_t udev_flags ; /* Udev control flags */
2005-11-08 22:50:11 +00:00
void * context ; /* External supplied context */
struct load_properties props ; /* For creation/table (re)load */
2010-05-21 12:27:02 +00:00
/*
* If presuspend of child node is needed
* Note : only direct child is allowed
*/
struct dm_tree_node * presuspend_node ;
2012-03-02 17:31:21 +00:00
/* Callback */
dm_node_callback_fn callback ;
void * callback_data ;
2014-01-15 12:42:47 +01:00
/*
* TODO :
* Add advanced code which tracks of send ioctls and their
* proper revert operation for more advanced recovery
* Current code serves mostly only to recovery when
* thin pool metadata check fails and command would
* have left active thin data and metadata subvolumes .
*/
struct dm_list activated ; /* Head of activated nodes for preload revert */
struct dm_list activated_list ; /* List of activated nodes for preload revert */
2005-10-16 14:33:22 +00:00
} ;
2005-11-09 14:10:50 +00:00
struct dm_tree {
2005-10-16 22:57:20 +00:00
struct dm_pool * mem ;
struct dm_hash_table * devs ;
2005-11-08 22:50:11 +00:00
struct dm_hash_table * uuids ;
2005-11-09 14:10:50 +00:00
struct dm_tree_node root ;
2006-01-30 23:36:04 +00:00
int skip_lockfs ; /* 1 skips lockfs (for non-snapshots) */
2011-09-22 17:36:50 +00:00
int no_flush ; /* 1 sets noflush (mirrors/multipath) */
int retry_remove ; /* 1 retries remove if not successful */
2009-07-31 18:30:31 +00:00
uint32_t cookie ;
2014-07-30 21:55:11 +01:00
const char * * optional_uuid_suffixes ; /* uuid suffixes ignored when matching */
2005-10-16 14:33:22 +00:00
} ;
2012-01-23 17:46:31 +00:00
/*
* Tree functions .
*/
2005-11-09 14:10:50 +00:00
struct dm_tree * dm_tree_create ( void )
2005-10-16 14:33:22 +00:00
{
2011-10-14 13:34:19 +00:00
struct dm_pool * dmem ;
2005-11-09 14:10:50 +00:00
struct dm_tree * dtree ;
2005-10-16 14:33:22 +00:00
2011-10-14 13:34:19 +00:00
if ( ! ( dmem = dm_pool_create ( " dtree " , 1024 ) ) | |
! ( dtree = dm_pool_zalloc ( dmem , sizeof ( * dtree ) ) ) ) {
log_error ( " Failed to allocate dtree. " ) ;
if ( dmem )
dm_pool_destroy ( dmem ) ;
2005-10-16 14:33:22 +00:00
return NULL ;
}
2005-11-09 14:10:50 +00:00
dtree - > root . dtree = dtree ;
2008-11-03 22:14:30 +00:00
dm_list_init ( & dtree - > root . uses ) ;
dm_list_init ( & dtree - > root . used_by ) ;
2014-01-15 12:42:47 +01:00
dm_list_init ( & dtree - > root . activated ) ;
2006-01-30 23:36:04 +00:00
dtree - > skip_lockfs = 0 ;
2007-01-09 19:44:07 +00:00
dtree - > no_flush = 0 ;
2011-10-14 13:34:19 +00:00
dtree - > mem = dmem ;
2014-07-30 21:55:11 +01:00
dtree - > optional_uuid_suffixes = NULL ;
2005-10-16 14:33:22 +00:00
2005-11-09 14:10:50 +00:00
if ( ! ( dtree - > devs = dm_hash_create ( 8 ) ) ) {
log_error ( " dtree hash creation failed " ) ;
dm_pool_destroy ( dtree - > mem ) ;
2005-10-16 14:33:22 +00:00
return NULL ;
}
2005-11-09 14:10:50 +00: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 ) ;
2005-11-08 22:50:11 +00:00
return NULL ;
}
2005-11-09 14:10:50 +00:00
return dtree ;
2005-10-16 14:33:22 +00:00
}
2005-11-09 14:10:50 +00:00
void dm_tree_free ( struct dm_tree * dtree )
2005-10-16 14:33:22 +00:00
{
2005-11-09 14:10:50 +00:00
if ( ! dtree )
2005-10-16 14:33:22 +00:00
return ;
2005-11-09 14:10:50 +00:00
dm_hash_destroy ( dtree - > uuids ) ;
dm_hash_destroy ( dtree - > devs ) ;
dm_pool_destroy ( dtree - > mem ) ;
2005-10-16 14:33:22 +00:00
}
2012-01-23 17:46:31 +00: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 ;
}
void dm_tree_skip_lockfs ( struct dm_tree_node * dnode )
{
dnode - > dtree - > skip_lockfs = 1 ;
}
void dm_tree_use_no_flush_suspend ( struct dm_tree_node * dnode )
{
dnode - > dtree - > no_flush = 1 ;
}
void dm_tree_retry_remove ( struct dm_tree_node * dnode )
{
dnode - > dtree - > retry_remove = 1 ;
}
/*
* Node functions .
*/
2010-01-14 10:15:23 +00:00
static int _nodes_are_linked ( const struct dm_tree_node * parent ,
const struct dm_tree_node * child )
2005-10-16 14:33:22 +00:00
{
2005-11-09 14:10:50 +00:00
struct dm_tree_link * dlink ;
2005-10-16 14:33:22 +00:00
2008-11-03 22:14:30 +00:00
dm_list_iterate_items ( dlink , & parent - > uses )
2005-10-16 14:33:22 +00:00
if ( dlink - > node = = child )
return 1 ;
return 0 ;
}
2008-11-03 22:14:30 +00:00
static int _link ( struct dm_list * list , struct dm_tree_node * node )
2005-10-16 14:33:22 +00:00
{
2005-11-09 14:10:50 +00:00
struct dm_tree_link * dlink ;
2005-10-16 14:33:22 +00:00
2005-11-09 14:10:50 +00:00
if ( ! ( dlink = dm_pool_alloc ( node - > dtree - > mem , sizeof ( * dlink ) ) ) ) {
log_error ( " dtree link allocation failed " ) ;
2005-10-16 14:33:22 +00:00
return 0 ;
}
dlink - > node = node ;
2008-11-03 22:14:30 +00:00
dm_list_add ( list , & dlink - > list ) ;
2005-10-16 14:33:22 +00:00
return 1 ;
}
2005-11-09 14:10:50 +00:00
static int _link_nodes ( struct dm_tree_node * parent ,
struct dm_tree_node * child )
2005-10-16 14:33:22 +00: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-03 22:14:30 +00:00
static void _unlink ( struct dm_list * list , struct dm_tree_node * node )
2005-10-16 14:33:22 +00:00
{
2005-11-09 14:10:50 +00:00
struct dm_tree_link * dlink ;
2005-10-16 14:33:22 +00:00
2008-11-03 22:14:30 +00:00
dm_list_iterate_items ( dlink , list )
2005-10-16 14:33:22 +00:00
if ( dlink - > node = = node ) {
2008-11-03 22:14:30 +00:00
dm_list_del ( & dlink - > list ) ;
2005-10-16 14:33:22 +00:00
break ;
}
}
2005-11-09 14:10:50 +00:00
static void _unlink_nodes ( struct dm_tree_node * parent ,
struct dm_tree_node * child )
2005-10-16 14:33:22 +00:00
{
if ( ! _nodes_are_linked ( parent , child ) )
return ;
_unlink ( & parent - > uses , child ) ;
_unlink ( & child - > used_by , parent ) ;
}
2005-11-09 14:10:50 +00:00
static int _add_to_toplevel ( struct dm_tree_node * node )
2005-11-08 22:50:11 +00:00
{
2005-11-09 14:10:50 +00:00
return _link_nodes ( & node - > dtree - > root , node ) ;
2005-11-08 22:50:11 +00:00
}
2005-11-09 14:10:50 +00:00
static void _remove_from_toplevel ( struct dm_tree_node * node )
2005-10-16 14:33:22 +00:00
{
2009-12-11 13:16:37 +00:00
_unlink_nodes ( & node - > dtree - > root , node ) ;
2005-10-16 14:33:22 +00:00
}
2005-11-09 14:10:50 +00:00
static int _add_to_bottomlevel ( struct dm_tree_node * node )
2005-10-16 14:33:22 +00:00
{
2005-11-09 14:10:50 +00:00
return _link_nodes ( node , & node - > dtree - > root ) ;
2005-10-16 14:33:22 +00:00
}
2005-11-09 14:10:50 +00:00
static void _remove_from_bottomlevel ( struct dm_tree_node * node )
2005-11-08 22:50:11 +00:00
{
2009-12-11 13:16:37 +00:00
_unlink_nodes ( node , & node - > dtree - > root ) ;
2005-11-08 22:50:11 +00:00
}
2005-11-09 14:10:50 +00:00
static int _link_tree_nodes ( struct dm_tree_node * parent , struct dm_tree_node * child )
2005-11-08 22:50:11 +00:00
{
/* Don't link to root node if child already has a parent */
2011-03-29 20:19:03 +00:00
if ( parent = = & parent - > dtree - > root ) {
2005-11-09 14:10:50 +00:00
if ( dm_tree_node_num_children ( child , 1 ) )
2005-11-08 22:50:11 +00:00
return 1 ;
} else
_remove_from_toplevel ( child ) ;
2011-03-29 20:19:03 +00:00
if ( child = = & child - > dtree - > root ) {
2005-11-09 14:10:50 +00:00
if ( dm_tree_node_num_children ( parent , 0 ) )
2005-11-08 22:50:11 +00:00
return 1 ;
} else
_remove_from_bottomlevel ( parent ) ;
return _link_nodes ( parent , child ) ;
}
2005-11-09 14:10:50 +00:00
static struct dm_tree_node * _create_dm_tree_node ( struct dm_tree * dtree ,
2005-10-16 14:33:22 +00:00
const char * name ,
const char * uuid ,
2005-11-08 22:50:11 +00:00
struct dm_info * info ,
2009-10-22 13:00:07 +00:00
void * context ,
uint16_t udev_flags )
2005-10-16 14:33:22 +00:00
{
2005-11-09 14:10:50 +00:00
struct dm_tree_node * node ;
2012-06-21 12:55:30 +02:00
dev_t dev ;
2005-10-16 14:33:22 +00:00
2005-11-09 14:10:50 +00:00
if ( ! ( node = dm_pool_zalloc ( dtree - > mem , sizeof ( * node ) ) ) ) {
log_error ( " _create_dm_tree_node alloc failed " ) ;
2005-10-16 14:33:22 +00:00
return NULL ;
}
2005-11-09 14:10:50 +00:00
node - > dtree = dtree ;
2005-10-16 14:33:22 +00:00
node - > name = name ;
node - > uuid = uuid ;
node - > info = * info ;
2005-11-08 22:50:11 +00:00
node - > context = context ;
2009-10-22 13:00:07 +00:00
node - > udev_flags = udev_flags ;
2005-10-16 14:33:22 +00:00
2008-11-03 22:14:30 +00:00
dm_list_init ( & node - > uses ) ;
dm_list_init ( & node - > used_by ) ;
2014-01-15 12:42:47 +01:00
dm_list_init ( & node - > activated ) ;
2008-11-03 22:14:30 +00:00
dm_list_init ( & node - > props . segs ) ;
2005-10-16 14:33:22 +00:00
2012-08-16 20:06:07 +02:00
dev = MKDEV ( ( dev_t ) info - > major , info - > minor ) ;
2005-10-16 14:33:22 +00:00
2005-11-09 14:10:50 +00:00
if ( ! dm_hash_insert_binary ( dtree - > devs , ( const char * ) & dev ,
2005-10-16 14:33:22 +00:00
sizeof ( dev ) , node ) ) {
2005-11-09 14:10:50 +00:00
log_error ( " dtree node hash insertion failed " ) ;
dm_pool_free ( dtree - > mem , node ) ;
2005-10-16 14:33:22 +00:00
return NULL ;
}
2005-11-08 22:50:11 +00:00
if ( uuid & & * uuid & &
2005-11-09 14:10:50 +00: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-08 22:50:11 +00:00
sizeof ( dev ) ) ;
2005-11-09 14:10:50 +00:00
dm_pool_free ( dtree - > mem , node ) ;
2005-11-08 22:50:11 +00:00
return NULL ;
}
2005-10-16 14:33:22 +00:00
return node ;
}
2005-11-09 14:10:50 +00:00
static struct dm_tree_node * _find_dm_tree_node ( struct dm_tree * dtree ,
2005-10-16 14:33:22 +00:00
uint32_t major , uint32_t minor )
{
2012-08-16 20:06:07 +02:00
dev_t dev = MKDEV ( ( dev_t ) major , minor ) ;
2005-10-16 14:33:22 +00:00
2005-11-09 14:10:50 +00:00
return dm_hash_lookup_binary ( dtree - > devs , ( const char * ) & dev ,
2014-02-14 20:46:55 +01:00
sizeof ( dev ) ) ;
2005-10-16 14:33:22 +00:00
}
2014-07-30 21:55:11 +01:00
void dm_tree_set_optional_uuid_suffixes ( struct dm_tree * dtree , const char * * optional_uuid_suffixes )
{
dtree - > optional_uuid_suffixes = optional_uuid_suffixes ;
}
2005-11-09 14:10:50 +00:00
static struct dm_tree_node * _find_dm_tree_node_by_uuid ( struct dm_tree * dtree ,
2005-11-08 22:50:11 +00:00
const char * uuid )
{
2005-11-12 22:46:48 +00:00
struct dm_tree_node * node ;
2012-01-10 02:03:31 +00:00
const char * default_uuid_prefix ;
size_t default_uuid_prefix_len ;
2014-07-30 21:55:11 +01:00
const char * suffix , * suffix_position ;
char uuid_without_suffix [ DM_UUID_LEN ] ;
unsigned i = 0 ;
const char * * suffix_list = dtree - > optional_uuid_suffixes ;
2005-11-12 22:46:48 +00:00
2014-07-30 21:55:11 +01:00
if ( ( node = dm_hash_lookup ( dtree - > uuids , uuid ) ) ) {
log_debug ( " Matched uuid %s in deptree. " , uuid ) ;
2005-11-12 22:46:48 +00:00
return node ;
2014-07-30 21:55:11 +01:00
}
2005-11-12 22:46:48 +00:00
2012-01-10 02:03:31 +00:00
default_uuid_prefix = dm_uuid_prefix ( ) ;
default_uuid_prefix_len = strlen ( default_uuid_prefix ) ;
2014-07-30 21:55:11 +01:00
if ( suffix_list & & ( suffix_position = rindex ( uuid , ' - ' ) ) ) {
while ( ( suffix = suffix_list [ i + + ] ) ) {
if ( strcmp ( suffix_position + 1 , suffix ) )
continue ;
( void ) strncpy ( uuid_without_suffix , uuid , sizeof ( uuid_without_suffix ) ) ;
uuid_without_suffix [ suffix_position - uuid ] = ' \0 ' ;
if ( ( node = dm_hash_lookup ( dtree - > uuids , uuid_without_suffix ) ) ) {
log_debug ( " Matched uuid %s (missing suffix -%s) in deptree. " , uuid_without_suffix , suffix ) ;
return node ;
}
break ;
} ;
}
2012-01-10 02:03:31 +00:00
if ( strncmp ( uuid , default_uuid_prefix , default_uuid_prefix_len ) )
2005-11-12 22:46:48 +00:00
return NULL ;
2014-07-30 21:55:11 +01:00
if ( ( node = dm_hash_lookup ( dtree - > uuids , uuid + default_uuid_prefix_len ) ) ) {
log_debug ( " Matched uuid %s (missing prefix) in deptree. " , uuid + default_uuid_prefix_len ) ;
return node ;
}
log_debug ( " Not matched uuid %s in deptree. " , uuid + default_uuid_prefix_len ) ;
return NULL ;
2005-11-08 22:50:11 +00:00
}
2012-01-23 17:46:31 +00:00
void dm_tree_node_set_udev_flags ( struct dm_tree_node * dnode , uint16_t udev_flags )
{
struct dm_info * dinfo = & dnode - > info ;
if ( udev_flags ! = dnode - > udev_flags )
2013-01-07 22:30:29 +00:00
log_debug_activation ( " Resetting %s (% " PRIu32 " :% " PRIu32
" ) udev_flags from 0x%x to 0x%x " ,
dnode - > name , dinfo - > major , dinfo - > minor ,
dnode - > udev_flags , udev_flags ) ;
2012-01-23 17:46:31 +00:00
dnode - > udev_flags = udev_flags ;
}
void dm_tree_node_set_read_ahead ( struct dm_tree_node * dnode ,
uint32_t read_ahead ,
uint32_t read_ahead_flags )
{
dnode - > props . read_ahead = read_ahead ;
dnode - > props . read_ahead_flags = read_ahead_flags ;
}
void dm_tree_node_set_presuspend_node ( struct dm_tree_node * node ,
struct dm_tree_node * presuspend_node )
{
node - > presuspend_node = presuspend_node ;
}
const char * dm_tree_node_get_name ( const struct dm_tree_node * node )
{
return node - > info . exists ? node - > name : " " ;
}
const char * dm_tree_node_get_uuid ( const struct dm_tree_node * node )
{
return node - > info . exists ? node - > uuid : " " ;
}
const struct dm_info * dm_tree_node_get_info ( const struct dm_tree_node * node )
{
return & node - > info ;
}
void * dm_tree_node_get_context ( const struct dm_tree_node * node )
{
return node - > context ;
}
int dm_tree_node_size_changed ( const struct dm_tree_node * dnode )
{
return dnode - > props . size_changed ;
}
int dm_tree_node_num_children ( const struct dm_tree_node * node , uint32_t inverted )
{
if ( inverted ) {
if ( _nodes_are_linked ( & node - > dtree - > root , node ) )
return 0 ;
return dm_list_size ( & node - > used_by ) ;
}
if ( _nodes_are_linked ( node , & node - > dtree - > root ) )
return 0 ;
return dm_list_size ( & node - > uses ) ;
}
/*
* Returns 1 if no prefix supplied
*/
static int _uuid_prefix_matches ( const char * uuid , const char * uuid_prefix , size_t uuid_prefix_len )
{
const char * default_uuid_prefix = dm_uuid_prefix ( ) ;
size_t default_uuid_prefix_len = strlen ( default_uuid_prefix ) ;
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 ;
if ( ! strncmp ( uuid , default_uuid_prefix , default_uuid_prefix_len ) )
return 0 ;
if ( strncmp ( uuid_prefix , default_uuid_prefix , default_uuid_prefix_len ) )
return 0 ;
if ( ! strncmp ( uuid , uuid_prefix + default_uuid_prefix_len , uuid_prefix_len - default_uuid_prefix_len ) )
return 1 ;
return 0 ;
}
/*
* Returns 1 if no children .
*/
static int _children_suspended ( struct dm_tree_node * node ,
uint32_t inverted ,
const char * uuid_prefix ,
size_t uuid_prefix_len )
{
struct dm_list * list ;
struct dm_tree_link * dlink ;
const struct dm_info * dinfo ;
const char * uuid ;
if ( inverted ) {
if ( _nodes_are_linked ( & node - > dtree - > root , node ) )
return 1 ;
list = & node - > used_by ;
} else {
if ( _nodes_are_linked ( node , & node - > dtree - > root ) )
return 1 ;
list = & node - > uses ;
}
dm_list_iterate_items ( dlink , list ) {
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 ;
/* Ignore if parent node wants to presuspend this node */
if ( dlink - > node - > presuspend_node = = node )
continue ;
2013-07-01 11:27:11 +02:00
if ( ! ( dinfo = dm_tree_node_get_info ( dlink - > node ) ) )