@ -1046,7 +1046,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
}
if ( ! drv - > bdrv_file_open ) {
ret = bdrv_open ( bs , filename , options , flags , drv , & local_err ) ;
ret = bdrv_open ( & bs , filename , options , flags , drv , & local_err ) ;
options = NULL ;
} else {
ret = bdrv_open_common ( bs , NULL , options , flags , drv , & local_err ) ;
@ -1115,8 +1115,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
sizeof ( backing_filename ) ) ;
}
bs - > backing_hd = bdrv_new ( " " ) ;
if ( bs - > backing_format [ 0 ] ! = ' \0 ' ) {
back_drv = bdrv_find_format ( bs - > backing_format ) ;
}
@ -1125,11 +1123,11 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
back_flags = bs - > open_flags & ~ ( BDRV_O_RDWR | BDRV_O_SNAPSHOT |
BDRV_O_COPY_ON_READ ) ;
ret = bdrv_open ( bs - > backing_hd ,
assert ( bs - > backing_hd = = NULL ) ;
ret = bdrv_open ( & bs - > backing_hd ,
* backing_filename ? backing_filename : NULL , options ,
back_flags , back_drv , & local_err ) ;
if ( ret < 0 ) {
bdrv_unref ( bs - > backing_hd ) ;
bs - > backing_hd = NULL ;
bs - > open_flags | = BDRV_O_NO_BACKING ;
error_setg ( errp , " Could not open backing file: %s " ,
@ -1166,6 +1164,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
* BlockdevRef .
*
* The BlockdevRef will be removed from the options QDict .
*
* To conform with the behavior of bdrv_open ( ) , * pbs has to be NULL .
*/
int bdrv_open_image ( BlockDriverState * * pbs , const char * filename ,
QDict * options , const char * bdref_key , int flags ,
@ -1176,6 +1176,9 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
char * bdref_key_dot ;
const char * reference ;
assert ( pbs ) ;
assert ( * pbs = = NULL ) ;
bdref_key_dot = g_strdup_printf ( " %s. " , bdref_key ) ;
qdict_extract_subqdict ( options , & image_options , bdref_key_dot ) ;
g_free ( bdref_key_dot ) ;
@ -1196,8 +1199,6 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
/* If a filename is given and the block driver should be detected
automatically ( instead of using none ) , use bdrv_open ( ) in order to do
that auto - detection . */
BlockDriverState * bs ;
if ( reference ) {
error_setg ( errp , " Cannot reference an existing block device while "
" giving a filename " ) ;
@ -1205,13 +1206,7 @@ int bdrv_open_image(BlockDriverState **pbs, const char *filename,
goto done ;
}
bs = bdrv_new ( " " ) ;
ret = bdrv_open ( bs , filename , image_options , flags , NULL , errp ) ;
if ( ret < 0 ) {
bdrv_unref ( bs ) ;
} else {
* pbs = bs ;
}
ret = bdrv_open ( pbs , filename , image_options , flags , NULL , errp ) ;
} else {
ret = bdrv_file_open ( pbs , filename , reference , image_options , flags ,
errp ) ;
@ -1229,17 +1224,28 @@ done:
* empty set of options . The reference to the QDict belongs to the block layer
* after the call ( even on failure ) , so if the caller intends to reuse the
* dictionary , it needs to use QINCREF ( ) before calling bdrv_open .
*
* If * pbs is NULL , a new BDS will be created with a pointer to it stored there .
* If it is not NULL , the referenced BDS will be reused .
*/
int bdrv_open ( BlockDriverState * bs , const char * filename , QDict * options ,
int bdrv_open ( BlockDriverState * * p bs, const char * filename , QDict * options ,
int flags , BlockDriver * drv , Error * * errp )
{
int ret ;
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
char tmp_filename [ PATH_MAX + 1 ] ;
BlockDriverState * file = NULL ;
BlockDriverState * file = NULL , * bs ;
const char * drvname ;
Error * local_err = NULL ;
assert ( pbs ) ;
if ( * pbs ) {
bs = * pbs ;
} else {
bs = bdrv_new ( " " ) ;
}
/* NULL means an empty set of options */
if ( options = = NULL ) {
options = qdict_new ( ) ;
@ -1260,12 +1266,11 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
instead of opening ' filename ' directly */
/* Get the required size from the image */
bs1 = bdrv_new ( " " ) ;
QINCREF ( options ) ;
ret = bdrv_open ( bs1 , filename , options , BDRV_O_NO_BACKING ,
bs1 = NULL ;
ret = bdrv_open ( & bs1 , filename , options , BDRV_O_NO_BACKING ,
drv , & local_err ) ;
if ( ret < 0 ) {
bdrv_unref ( bs1 ) ;
goto fail ;
}
total_size = bdrv_getlength ( bs1 ) & BDRV_SECTOR_MASK ;
@ -1322,6 +1327,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
flags | = BDRV_O_ALLOW_RDWR ;
}
assert ( file = = NULL ) ;
ret = bdrv_open_image ( & file , filename , options , " file " ,
bdrv_open_flags ( bs , flags | BDRV_O_UNMAP ) , true , true ,
& local_err ) ;
@ -1393,6 +1399,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
bdrv_dev_change_media_cb ( bs , true ) ;
}
* pbs = bs ;
return 0 ;
unlink_and_fail :
@ -1406,13 +1413,24 @@ fail:
QDECREF ( bs - > options ) ;
QDECREF ( options ) ;
bs - > options = NULL ;
if ( ! * pbs ) {
/* If *pbs is NULL, a new BDS has been created in this function and
needs to be freed now . Otherwise , it does not need to be closed ,
since it has not really been opened yet . */
bdrv_unref ( bs ) ;
}
if ( local_err ) {
error_propagate ( errp , local_err ) ;
}
return ret ;
close_and_fail :
bdrv_close ( bs ) ;
/* See fail path, but now the BDS has to be always closed */
if ( * pbs ) {
bdrv_close ( bs ) ;
} else {
bdrv_unref ( bs ) ;
}
QDECREF ( options ) ;
if ( local_err ) {
error_propagate ( errp , local_err ) ;
@ -5290,9 +5308,8 @@ void bdrv_img_create(const char *filename, const char *fmt,
back_flags =
flags & ~ ( BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING ) ;
bs = bdrv_new ( " " ) ;
ret = bdrv_open ( bs , backing_file - > value . s , NULL , back_flags ,
bs = NULL ;
ret = bdrv_open ( & bs , backing_file - > value . s , NULL , back_flags ,
backing_drv , & local_err ) ;
if ( ret < 0 ) {
error_setg_errno ( errp , - ret , " Could not open '%s': %s " ,
@ -5300,7 +5317,6 @@ void bdrv_img_create(const char *filename, const char *fmt,
error_get_pretty ( local_err ) ) ;
error_free ( local_err ) ;
local_err = NULL ;
bdrv_unref ( bs ) ;
goto out ;
}
bdrv_get_geometry ( bs , & size ) ;