diff options
Diffstat (limited to 'block.c')
-rw-r--r-- | block.c | 64 |
1 files changed, 40 insertions, 24 deletions
@@ -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 **pbs, 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); |