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:
Kevin Wolf 2012-11-12 17:35:27 +01:00
parent 7b27245239
commit f500a6d3c2

70
block.c
View File

@ -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);
} }