@ -447,6 +447,41 @@ int bdrv_snapshot_load_tmp_by_id_or_name(BlockDriverState *bs,
return ret ;
}
static int bdrv_all_get_snapshot_devices ( bool has_devices , strList * devices ,
GList * * all_bdrvs ,
Error * * errp )
{
g_autoptr ( GList ) bdrvs = NULL ;
if ( has_devices ) {
if ( ! devices ) {
error_setg ( errp , " At least one device is required for snapshot " ) ;
return - 1 ;
}
while ( devices ) {
BlockDriverState * bs = bdrv_find_node ( devices - > value ) ;
if ( ! bs ) {
error_setg ( errp , " No block device node '%s' " , devices - > value ) ;
return - 1 ;
}
bdrvs = g_list_append ( bdrvs , bs ) ;
devices = devices - > next ;
}
} else {
BlockDriverState * bs ;
BdrvNextIterator it ;
for ( bs = bdrv_first ( & it ) ; bs ; bs = bdrv_next ( & it ) ) {
bdrvs = g_list_append ( bdrvs , bs ) ;
}
}
* all_bdrvs = g_steal_pointer ( & bdrvs ) ;
return 0 ;
}
static bool bdrv_all_snapshots_includes_bs ( BlockDriverState * bs )
{
if ( ! bdrv_is_inserted ( bs ) | | bdrv_is_read_only ( bs ) ) {
@ -462,43 +497,59 @@ static bool bdrv_all_snapshots_includes_bs(BlockDriverState *bs)
* These functions will properly handle dataplane ( take aio_context_acquire
* when appropriate for appropriate block drivers ) */
bool bdrv_all_can_snapshot ( Error * * errp )
bool bdrv_all_can_snapshot ( bool has_devices , strList * devices ,
Error * * errp )
{
BlockDriverState * bs ;
BdrvNextIterator it ;
g_autoptr ( GList ) bdrvs = NULL ;
GList * iterbdrvs ;
for ( bs = bdrv_first ( & it ) ; bs ; bs = bdrv_next ( & it ) ) {
if ( bdrv_all_get_snapshot_devices ( has_devices , devices , & bdrvs , errp ) < 0 ) {
return false ;
}
iterbdrvs = bdrvs ;
while ( iterbdrvs ) {
BlockDriverState * bs = iterbdrvs - > data ;
AioContext * ctx = bdrv_get_aio_context ( bs ) ;
bool ok = true ;
aio_context_acquire ( ctx ) ;
if ( bdrv_all_snapshots_includes_bs ( bs ) ) {
if ( devices | | bdrv_all_snapshots_includes_bs ( bs ) ) {
ok = bdrv_can_snapshot ( bs ) ;
}
aio_context_release ( ctx ) ;
if ( ! ok ) {
error_setg ( errp , " Device '%s' is writable but does not support "
" snapshots " , bdrv_get_device_or_node_name ( bs ) ) ;
bdrv_next_cleanup ( & it ) ;
return false ;
}
iterbdrvs = iterbdrvs - > next ;
}
return true ;
}
int bdrv_all_delete_snapshot ( const char * name , Error * * errp )
int bdrv_all_delete_snapshot ( const char * name ,
bool has_devices , strList * devices ,
Error * * errp )
{
BlockDriverState * bs ;
BdrvNextIterator it ;
QEMUSnapshotInfo sn1 , * snapshot = & sn1 ;
g_autoptr ( GList ) bdrvs = NULL ;
GList * iterbdrvs ;
if ( bdrv_all_get_snapshot_devices ( has_devices , devices , & bdrvs , errp ) < 0 ) {
return - 1 ;
}
for ( bs = bdrv_first ( & it ) ; bs ; bs = bdrv_next ( & it ) ) {
iterbdrvs = bdrvs ;
while ( iterbdrvs ) {
BlockDriverState * bs = iterbdrvs - > data ;
AioContext * ctx = bdrv_get_aio_context ( bs ) ;
QEMUSnapshotInfo sn1 , * snapshot = & sn1 ;
int ret = 0 ;
aio_context_acquire ( ctx ) ;
if ( bdrv_all_snapshots_includes_bs ( bs ) & &
if ( ( devices | | bdrv_all_snapshots_includes_bs ( bs ) ) & &
bdrv_snapshot_find ( bs , snapshot , name ) > = 0 )
{
ret = bdrv_snapshot_delete ( bs , snapshot - > id_str ,
@ -508,61 +559,80 @@ int bdrv_all_delete_snapshot(const char *name, Error **errp)
if ( ret < 0 ) {
error_prepend ( errp , " Could not delete snapshot '%s' on '%s': " ,
name , bdrv_get_device_or_node_name ( bs ) ) ;
bdrv_next_cleanup ( & it ) ;
return - 1 ;
}
iterbdrvs = iterbdrvs - > next ;
}
return 0 ;
}
int bdrv_all_goto_snapshot ( const char * name , Error * * errp )
int bdrv_all_goto_snapshot ( const char * name ,
bool has_devices , strList * devices ,
Error * * errp )
{
BlockDriverState * bs ;
BdrvNextIterator it ;
g_autoptr ( GList ) bdrvs = NULL ;
GList * iterbdrvs ;
for ( bs = bdrv_first ( & it ) ; bs ; bs = bdrv_next ( & it ) ) {
if ( bdrv_all_get_snapshot_devices ( has_devices , devices , & bdrvs , errp ) < 0 ) {
return - 1 ;
}
iterbdrvs = bdrvs ;
while ( iterbdrvs ) {
BlockDriverState * bs = iterbdrvs - > data ;
AioContext * ctx = bdrv_get_aio_context ( bs ) ;
int ret = 0 ;
aio_context_acquire ( ctx ) ;
if ( bdrv_all_snapshots_includes_bs ( bs ) ) {
if ( devices | | bdrv_all_snapshots_includes_bs ( bs ) ) {
ret = bdrv_snapshot_goto ( bs , name , errp ) ;
}
aio_context_release ( ctx ) ;
if ( ret < 0 ) {
error_prepend ( errp , " Could not load snapshot '%s' on '%s': " ,
name , bdrv_get_device_or_node_name ( bs ) ) ;
bdrv_next_cleanup ( & it ) ;
return - 1 ;
}
iterbdrvs = iterbdrvs - > next ;
}
return 0 ;
}
int bdrv_all_find_snapshot ( const char * name , Error * * errp )
int bdrv_all_find_snapshot ( const char * name ,
bool has_devices , strList * devices ,
Error * * errp )
{
QEMUSnapshotInfo sn ;
BlockDriverState * bs ;
BdrvNextIterator it ;
g_autoptr ( GList ) bdrvs = NULL ;
GList * iterbdrvs ;
if ( bdrv_all_get_snapshot_devices ( has_devices , devices , & bdrvs , errp ) < 0 ) {
return - 1 ;
}
for ( bs = bdrv_first ( & it ) ; bs ; bs = bdrv_next ( & it ) ) {
iterbdrvs = bdrvs ;
while ( iterbdrvs ) {
BlockDriverState * bs = iterbdrvs - > data ;
AioContext * ctx = bdrv_get_aio_context ( bs ) ;
QEMUSnapshotInfo sn ;
int ret = 0 ;
aio_context_acquire ( ctx ) ;
if ( bdrv_all_snapshots_includes_bs ( bs ) ) {
if ( devices | | bdrv_all_snapshots_includes_bs ( bs ) ) {
ret = bdrv_snapshot_find ( bs , & sn , name ) ;
}
aio_context_release ( ctx ) ;
if ( ret < 0 ) {
error_setg ( errp , " Could not find snapshot '%s' on '%s' " ,
name , bdrv_get_device_or_node_name ( bs ) ) ;
bdrv_next_cleanup ( & it ) ;
return - 1 ;
}
iterbdrvs = iterbdrvs - > next ;
}
return 0 ;
@ -571,12 +641,19 @@ int bdrv_all_find_snapshot(const char *name, Error **errp)
int bdrv_all_create_snapshot ( QEMUSnapshotInfo * sn ,
BlockDriverState * vm_state_bs ,
uint64_t vm_state_size ,
bool has_devices , strList * devices ,
Error * * errp )
{
BlockDriverState * bs ;
BdrvNextIterator it ;
g_autoptr ( GList ) bdrvs = NULL ;
GList * iterbdrvs ;
if ( bdrv_all_get_snapshot_devices ( has_devices , devices , & bdrvs , errp ) < 0 ) {
return - 1 ;
}
for ( bs = bdrv_first ( & it ) ; bs ; bs = bdrv_next ( & it ) ) {
iterbdrvs = bdrvs ;
while ( iterbdrvs ) {
BlockDriverState * bs = iterbdrvs - > data ;
AioContext * ctx = bdrv_get_aio_context ( bs ) ;
int ret = 0 ;
@ -584,7 +661,7 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
if ( bs = = vm_state_bs ) {
sn - > vm_state_size = vm_state_size ;
ret = bdrv_snapshot_create ( bs , sn ) ;
} else if ( bdrv_all_snapshots_includes_bs ( bs ) ) {
} else if ( devices | | bdrv_all_snapshots_includes_bs ( bs ) ) {
sn - > vm_state_size = 0 ;
ret = bdrv_snapshot_create ( bs , sn ) ;
}
@ -592,34 +669,43 @@ int bdrv_all_create_snapshot(QEMUSnapshotInfo *sn,
if ( ret < 0 ) {
error_setg ( errp , " Could not create snapshot '%s' on '%s' " ,
sn - > name , bdrv_get_device_or_node_name ( bs ) ) ;
bdrv_next_cleanup ( & it ) ;
return - 1 ;
}
iterbdrvs = iterbdrvs - > next ;
}
return 0 ;
}
BlockDriverState * bdrv_all_find_vmstate_bs ( Error * * errp )
BlockDriverState * bdrv_all_find_vmstate_bs ( bool has_devices , strList * devices ,
Error * * errp )
{
BlockDriverState * bs ;
BdrvNextIterator it ;
g_autoptr ( GList ) bdrvs = NULL ;
GList * iterbdrvs ;
for ( bs = bdrv_first ( & it ) ; bs ; bs = bdrv_next ( & it ) ) {
if ( bdrv_all_get_snapshot_devices ( has_devices , devices , & bdrvs , errp ) < 0 ) {
return NULL ;
}
iterbdrvs = bdrvs ;
while ( iterbdrvs ) {
BlockDriverState * bs = iterbdrvs - > data ;
AioContext * ctx = bdrv_get_aio_context ( bs ) ;
bool found ;
bool found = false ;
aio_context_acquire ( ctx ) ;
found = bdrv_all_snapshots_includes_bs ( bs ) & & bdrv_can_snapshot ( bs ) ;
found = ( devices | | bdrv_all_snapshots_includes_bs ( bs ) ) & &
bdrv_can_snapshot ( bs ) ;
aio_context_release ( ctx ) ;
if ( found ) {
bdrv_next_cleanup ( & it ) ;
break ;
return bs ;
}
iterbdrvs = iterbdrvs - > next ;
}
if ( ! bs ) {
error_setg ( errp , " No block device supports snapshots " ) ;
}
return bs ;
error_setg ( errp , " No block device supports snapshots " ) ;
return NULL ;
}