block: Avoid second open for format probing
This fixes problems that are caused by the additional open/close cycle of the existing format probing, for example related to qemu-nbd without -t option or file descriptor passing. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
7b27245239
commit
f500a6d3c2
70
block.c
70
block.c
@ -518,22 +518,16 @@ BlockDriver *bdrv_find_protocol(const char *filename)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_image_format(const char *filename, BlockDriver **pdrv)
|
static int find_image_format(BlockDriverState *bs, const char *filename,
|
||||||
|
BlockDriver **pdrv)
|
||||||
{
|
{
|
||||||
int ret, score, score_max;
|
int score, score_max;
|
||||||
BlockDriver *drv1, *drv;
|
BlockDriver *drv1, *drv;
|
||||||
uint8_t buf[2048];
|
uint8_t buf[2048];
|
||||||
BlockDriverState *bs;
|
int ret = 0;
|
||||||
|
|
||||||
ret = bdrv_file_open(&bs, filename, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
*pdrv = NULL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
|
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
|
||||||
if (bs->sg || !bdrv_is_inserted(bs)) {
|
if (bs->sg || !bdrv_is_inserted(bs)) {
|
||||||
bdrv_delete(bs);
|
|
||||||
drv = bdrv_find_format("raw");
|
drv = bdrv_find_format("raw");
|
||||||
if (!drv) {
|
if (!drv) {
|
||||||
ret = -ENOENT;
|
ret = -ENOENT;
|
||||||
@ -543,7 +537,6 @@ static int find_image_format(const char *filename, BlockDriver **pdrv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = bdrv_pread(bs, 0, buf, sizeof(buf));
|
ret = bdrv_pread(bs, 0, buf, sizeof(buf));
|
||||||
bdrv_delete(bs);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
*pdrv = NULL;
|
*pdrv = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
@ -657,7 +650,8 @@ static int bdrv_open_flags(BlockDriverState *bs, int flags)
|
|||||||
/*
|
/*
|
||||||
* Common part for opening disk images and files
|
* Common part for opening disk images and files
|
||||||
*/
|
*/
|
||||||
static int bdrv_open_common(BlockDriverState *bs, const char *filename,
|
static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
|
||||||
|
const char *filename,
|
||||||
int flags, BlockDriver *drv)
|
int flags, BlockDriver *drv)
|
||||||
{
|
{
|
||||||
int ret, open_flags;
|
int ret, open_flags;
|
||||||
@ -691,12 +685,16 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
|
|||||||
|
|
||||||
/* Open the image, either directly or using a protocol */
|
/* Open the image, either directly or using a protocol */
|
||||||
if (drv->bdrv_file_open) {
|
if (drv->bdrv_file_open) {
|
||||||
ret = drv->bdrv_file_open(bs, filename, open_flags);
|
if (file != NULL) {
|
||||||
|
bdrv_swap(file, bs);
|
||||||
|
ret = 0;
|
||||||
} else {
|
} else {
|
||||||
ret = bdrv_file_open(&bs->file, filename, open_flags);
|
ret = drv->bdrv_file_open(bs, filename, open_flags);
|
||||||
if (ret >= 0) {
|
|
||||||
ret = drv->bdrv_open(bs, open_flags);
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
assert(file != NULL);
|
||||||
|
bs->file = file;
|
||||||
|
ret = drv->bdrv_open(bs, open_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -716,10 +714,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
free_and_fail:
|
free_and_fail:
|
||||||
if (bs->file) {
|
|
||||||
bdrv_delete(bs->file);
|
|
||||||
bs->file = NULL;
|
bs->file = NULL;
|
||||||
}
|
|
||||||
g_free(bs->opaque);
|
g_free(bs->opaque);
|
||||||
bs->opaque = NULL;
|
bs->opaque = NULL;
|
||||||
bs->drv = NULL;
|
bs->drv = NULL;
|
||||||
@ -741,7 +736,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bs = bdrv_new("");
|
bs = bdrv_new("");
|
||||||
ret = bdrv_open_common(bs, filename, flags, drv);
|
ret = bdrv_open_common(bs, NULL, filename, flags, drv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
bdrv_delete(bs);
|
bdrv_delete(bs);
|
||||||
return ret;
|
return ret;
|
||||||
@ -796,6 +791,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
|||||||
int ret;
|
int ret;
|
||||||
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
/* TODO: extra byte is a hack to ensure MAX_PATH space on Windows. */
|
||||||
char tmp_filename[PATH_MAX + 1];
|
char tmp_filename[PATH_MAX + 1];
|
||||||
|
BlockDriverState *file = NULL;
|
||||||
|
|
||||||
if (flags & BDRV_O_SNAPSHOT) {
|
if (flags & BDRV_O_SNAPSHOT) {
|
||||||
BlockDriverState *bs1;
|
BlockDriverState *bs1;
|
||||||
@ -855,25 +851,36 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
|||||||
bs->is_temporary = 1;
|
bs->is_temporary = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the right image format driver */
|
/* Open image file without format layer */
|
||||||
if (!drv) {
|
|
||||||
ret = find_image_format(filename, &drv);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!drv) {
|
|
||||||
goto unlink_and_fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags & BDRV_O_RDWR) {
|
if (flags & BDRV_O_RDWR) {
|
||||||
flags |= BDRV_O_ALLOW_RDWR;
|
flags |= BDRV_O_ALLOW_RDWR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = bdrv_file_open(&file, filename, bdrv_open_flags(bs, flags));
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find the right image format driver */
|
||||||
|
if (!drv) {
|
||||||
|
ret = find_image_format(file, filename, &drv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!drv) {
|
||||||
|
goto unlink_and_fail;
|
||||||
|
}
|
||||||
|
|
||||||
/* Open the image */
|
/* Open the image */
|
||||||
ret = bdrv_open_common(bs, filename, flags, drv);
|
ret = bdrv_open_common(bs, file, filename, flags, drv);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto unlink_and_fail;
|
goto unlink_and_fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bs->file != file) {
|
||||||
|
bdrv_delete(file);
|
||||||
|
file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/* If there is a backing file, use it */
|
/* If there is a backing file, use it */
|
||||||
if ((flags & BDRV_O_NO_BACKING) == 0) {
|
if ((flags & BDRV_O_NO_BACKING) == 0) {
|
||||||
ret = bdrv_open_backing_file(bs);
|
ret = bdrv_open_backing_file(bs);
|
||||||
@ -895,6 +902,9 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
unlink_and_fail:
|
unlink_and_fail:
|
||||||
|
if (file != NULL) {
|
||||||
|
bdrv_delete(file);
|
||||||
|
}
|
||||||
if (bs->is_temporary) {
|
if (bs->is_temporary) {
|
||||||
unlink(filename);
|
unlink(filename);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user