@ -2612,12 +2612,15 @@ static void bdrv_replace_child_noperm(BdrvChild *child,
* If @ new_bs is not NULL , bdrv_check_perm ( ) must be called beforehand , as this
* function uses bdrv_set_perm ( ) to update the permissions according to the new
* reference that @ new_bs gets .
*
* Callers must ensure that child - > frozen is false .
*/
static void bdrv_replace_child ( BdrvChild * child , BlockDriverState * new_bs )
{
BlockDriverState * old_bs = child - > bs ;
uint64_t perm , shared_perm ;
/* Asserts that child->frozen == false */
bdrv_replace_child_noperm ( child , new_bs ) ;
/*
@ -2778,6 +2781,7 @@ static void bdrv_detach_child(BdrvChild *child)
g_free ( child ) ;
}
/* Callers must ensure that child->frozen is false. */
void bdrv_root_unref_child ( BdrvChild * child )
{
BlockDriverState * child_bs ;
@ -2815,6 +2819,7 @@ static void bdrv_unset_inherits_from(BlockDriverState *root, BdrvChild *child)
}
}
/* Callers must ensure that child->frozen is false. */
void bdrv_unref_child ( BlockDriverState * parent , BdrvChild * child )
{
if ( child = = NULL ) {
@ -2881,6 +2886,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
}
if ( bs - > backing ) {
/* Cannot be frozen, we checked that above */
bdrv_unref_child ( bs , bs - > backing ) ;
bs - > backing = NULL ;
}
@ -4387,6 +4393,7 @@ static void bdrv_close(BlockDriverState *bs)
if ( bs - > drv ) {
if ( bs - > drv - > bdrv_close ) {
/* Must unfreeze all children, so bdrv_unref_child() works */
bs - > drv - > bdrv_close ( bs ) ;
}
bs - > drv = NULL ;
@ -4762,20 +4769,22 @@ BlockDriverState *bdrv_find_base(BlockDriverState *bs)
}
/*
* Return true if at least one of the backing links between @ bs and
* @ base is frozen . @ errp is set if that ' s the case .
* Return true if at least one of the COW ( backing ) and filter links
* between @ bs and @ base is frozen . @ errp is set if that ' s the case .
* @ base must be reachable from @ bs , or NULL .
*/
bool bdrv_is_backing_chain_frozen ( BlockDriverState * bs , BlockDriverState * base ,
Error * * errp )
{
BlockDriverState * i ;
BdrvChild * child ;
for ( i = bs ; i ! = base ; i = backing_bs ( i ) ) {
if ( i - > backing & & i - > backing - > frozen ) {
for ( i = bs ; i ! = base ; i = child_bs ( child ) ) {
child = bdrv_filter_or_cow_child ( i ) ;
if ( child & & child - > frozen ) {
error_setg ( errp , " Cannot change '%s' link from '%s' to '%s' " ,
i - > backing - > name , i - > node_name ,
backing_bs ( i ) - > node_name ) ;
child - > name , i - > node_name , child - > bs - > node_name ) ;
return true ;
}
}
@ -4784,7 +4793,7 @@ bool bdrv_is_backing_chain_frozen(BlockDriverState *bs, BlockDriverState *base,
}
/*
* Freeze all backing links between @ bs and @ base .
* Freeze all COW ( backing ) and filter links between @ bs and @ base .
* If any of the links is already frozen the operation is aborted and
* none of the links are modified .
* @ base must be reachable from @ bs , or NULL .
@ -4794,22 +4803,25 @@ int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
Error * * errp )
{
BlockDriverState * i ;
BdrvChild * child ;
if ( bdrv_is_backing_chain_frozen ( bs , base , errp ) ) {
return - EPERM ;
}
for ( i = bs ; i ! = base ; i = backing_bs ( i ) ) {
if ( i - > backing & & backing_bs ( i ) - > never_freeze ) {
for ( i = bs ; i ! = base ; i = child_bs ( child ) ) {
child = bdrv_filter_or_cow_child ( i ) ;
if ( child & & child - > bs - > never_freeze ) {
error_setg ( errp , " Cannot freeze '%s' link to '%s' " ,
i - > backing - > name , backing_bs ( i ) - > node_name ) ;
child - > name , child - > bs - > node_name ) ;
return - EPERM ;
}
}
for ( i = bs ; i ! = base ; i = backing_bs ( i ) ) {
if ( i - > backing ) {
i - > backing - > frozen = true ;
for ( i = bs ; i ! = base ; i = child_bs ( child ) ) {
child = bdrv_filter_or_cow_child ( i ) ;
if ( child ) {
child - > frozen = true ;
}
}
@ -4817,18 +4829,21 @@ int bdrv_freeze_backing_chain(BlockDriverState *bs, BlockDriverState *base,
}
/*
* Unfreeze all backing links between @ bs and @ base . The caller must
* ensure that all links are frozen before using this function .
* Unfreeze all COW ( backing ) and filter links between @ bs and @ base .
* The caller must ensure that all links are frozen before using this
* function .
* @ base must be reachable from @ bs , or NULL .
*/
void bdrv_unfreeze_backing_chain ( BlockDriverState * bs , BlockDriverState * base )
{
BlockDriverState * i ;
BdrvChild * child ;
for ( i = bs ; i ! = base ; i = backing_bs ( i ) ) {
if ( i - > backing ) {
assert ( i - > backing - > frozen ) ;
i - > backing - > frozen = false ;
for ( i = bs ; i ! = base ; i = child_bs ( child ) ) {
child = bdrv_filter_or_cow_child ( i ) ;
if ( child ) {
assert ( child - > frozen ) ;
child - > frozen = false ;
}
}
}
@ -4931,8 +4946,11 @@ int bdrv_drop_intermediate(BlockDriverState *top, BlockDriverState *base,
}
}
/* Do the actual switch in the in-memory graph.
* Completes bdrv_check_update_perm ( ) transaction internally . */
/*
* Do the actual switch in the in - memory graph .
* Completes bdrv_check_update_perm ( ) transaction internally .
* c - > frozen is false , we have checked that above .
*/
bdrv_ref ( base ) ;
bdrv_replace_child ( c , base ) ;
bdrv_unref ( top ) ;