diff options
Diffstat (limited to 'block.c')
-rw-r--r-- | block.c | 150 |
1 files changed, 80 insertions, 70 deletions
@@ -85,8 +85,7 @@ static QLIST_HEAD(, BlockDriver) bdrv_drivers = static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, const char *reference, QDict *options, int flags, BlockDriverState *parent, - const BdrvChildRole *child_role, - BlockDriver *drv, Error **errp); + const BdrvChildRole *child_role, Error **errp); static void bdrv_dirty_bitmap_truncate(BlockDriverState *bs); /* If non-zero, use only whitelisted block drivers */ @@ -314,13 +313,6 @@ static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only) return 0; } -BlockDriver *bdrv_find_whitelisted_format(const char *format_name, - bool read_only) -{ - BlockDriver *drv = bdrv_find_format(format_name); - return drv && bdrv_is_whitelisted(drv, read_only) ? drv : NULL; -} - typedef struct CreateCo { BlockDriver *drv; char *filename; @@ -997,13 +989,13 @@ static QDict *parse_json_filename(const char *filename, Error **errp) * block driver has been specified explicitly. */ static int bdrv_fill_options(QDict **options, const char **pfilename, - int *flags, BlockDriver *drv, Error **errp) + int *flags, Error **errp) { const char *filename = *pfilename; const char *drvname; bool protocol = *flags & BDRV_O_PROTOCOL; bool parse_filename = false; - BlockDriver *tmp_drv; + BlockDriver *drv = NULL; Error *local_err = NULL; /* Parse json: pseudo-protocol */ @@ -1022,15 +1014,15 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, } drvname = qdict_get_try_str(*options, "driver"); - - /* If the user has explicitly specified the driver, this choice should - * override the BDRV_O_PROTOCOL flag */ - tmp_drv = drv; - if (!tmp_drv && drvname) { - tmp_drv = bdrv_find_format(drvname); - } - if (tmp_drv) { - protocol = tmp_drv->bdrv_file_open; + if (drvname) { + drv = bdrv_find_format(drvname); + if (!drv) { + error_setg(errp, "Unknown driver '%s'", drvname); + return -ENOENT; + } + /* If the user has explicitly specified the driver, this choice should + * override the BDRV_O_PROTOCOL flag */ + protocol = drv->bdrv_file_open; } if (protocol) { @@ -1054,33 +1046,18 @@ static int bdrv_fill_options(QDict **options, const char **pfilename, /* Find the right block driver */ filename = qdict_get_try_str(*options, "filename"); - if (drv) { - if (drvname) { - error_setg(errp, "Driver specified twice"); - return -EINVAL; - } - drvname = drv->format_name; - qdict_put(*options, "driver", qstring_from_str(drvname)); - } else { - if (!drvname && protocol) { - if (filename) { - drv = bdrv_find_protocol(filename, parse_filename, errp); - if (!drv) { - return -EINVAL; - } - - drvname = drv->format_name; - qdict_put(*options, "driver", qstring_from_str(drvname)); - } else { - error_setg(errp, "Must specify either driver or file"); - return -EINVAL; - } - } else if (drvname) { - drv = bdrv_find_format(drvname); + if (!drvname && protocol) { + if (filename) { + drv = bdrv_find_protocol(filename, parse_filename, errp); if (!drv) { - error_setg(errp, "Unknown driver '%s'", drvname); - return -ENOENT; + return -EINVAL; } + + drvname = drv->format_name; + qdict_put(*options, "driver", qstring_from_str(drvname)); + } else { + error_setg(errp, "Must specify either driver or file"); + return -EINVAL; } } @@ -1227,8 +1204,7 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp) assert(bs->backing_hd == NULL); ret = bdrv_open_inherit(&backing_hd, *backing_filename ? backing_filename : NULL, - NULL, options, 0, bs, &child_backing, - NULL, &local_err); + NULL, options, 0, bs, &child_backing, &local_err); if (ret < 0) { bdrv_unref(backing_hd); backing_hd = NULL; @@ -1291,7 +1267,7 @@ BdrvChild *bdrv_open_child(const char *filename, bs = NULL; ret = bdrv_open_inherit(&bs, filename, reference, image_options, 0, - parent, child_role, NULL, errp); + parent, child_role, errp); if (ret < 0) { goto done; } @@ -1385,11 +1361,13 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp) qstring_from_str("file")); qdict_put(snapshot_options, "file.filename", qstring_from_str(tmp_filename)); + qdict_put(snapshot_options, "driver", + qstring_from_str("qcow2")); bs_snapshot = bdrv_new(); ret = bdrv_open(&bs_snapshot, NULL, NULL, snapshot_options, - flags, &bdrv_qcow2, &local_err); + flags, &local_err); if (ret < 0) { error_propagate(errp, local_err); goto out; @@ -1420,11 +1398,11 @@ out: static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, const char *reference, QDict *options, int flags, BlockDriverState *parent, - const BdrvChildRole *child_role, - BlockDriver *drv, Error **errp) + const BdrvChildRole *child_role, Error **errp) { int ret; BlockDriverState *file = NULL, *bs; + BlockDriver *drv = NULL; const char *drvname; Error *local_err = NULL; int snapshot_flags = 0; @@ -1474,13 +1452,12 @@ static int bdrv_open_inherit(BlockDriverState **pbs, const char *filename, flags = child_role->inherit_flags(parent->open_flags); } - ret = bdrv_fill_options(&options, &filename, &flags, drv, &local_err); + ret = bdrv_fill_options(&options, &filename, &flags, &local_err); if (local_err) { goto fail; } /* Find the right image format driver */ - drv = NULL; drvname = qdict_get_try_str(options, "driver"); if (drvname) { drv = bdrv_find_format(drvname); @@ -1635,11 +1612,10 @@ close_and_fail: } int bdrv_open(BlockDriverState **pbs, const char *filename, - const char *reference, QDict *options, int flags, - BlockDriver *drv, Error **errp) + const char *reference, QDict *options, int flags, Error **errp) { return bdrv_open_inherit(pbs, filename, reference, options, flags, NULL, - NULL, drv, errp); + NULL, errp); } typedef struct BlockReopenQueueEntry { @@ -1660,6 +1636,9 @@ typedef struct BlockReopenQueueEntry { * * bs is the BlockDriverState to add to the reopen queue. * + * options contains the changed options for the associated bs + * (the BlockReopenQueue takes ownership) + * * flags contains the open flags for the associated bs * * returns a pointer to bs_queue, which is either the newly allocated @@ -1667,18 +1646,28 @@ typedef struct BlockReopenQueueEntry { * */ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, - BlockDriverState *bs, int flags) + BlockDriverState *bs, + QDict *options, int flags) { assert(bs != NULL); BlockReopenQueueEntry *bs_entry; BdrvChild *child; + QDict *old_options; if (bs_queue == NULL) { bs_queue = g_new0(BlockReopenQueue, 1); QSIMPLEQ_INIT(bs_queue); } + if (!options) { + options = qdict_new(); + } + + old_options = qdict_clone_shallow(bs->options); + qdict_join(options, old_options, false); + QDECREF(old_options); + /* bdrv_open() masks this flag out */ flags &= ~BDRV_O_PROTOCOL; @@ -1690,13 +1679,15 @@ BlockReopenQueue *bdrv_reopen_queue(BlockReopenQueue *bs_queue, } child_flags = child->role->inherit_flags(flags); - bdrv_reopen_queue(bs_queue, child->bs, child_flags); + /* TODO Pass down child flags (backing.*, extents.*, ...) */ + bdrv_reopen_queue(bs_queue, child->bs, NULL, child_flags); } bs_entry = g_new0(BlockReopenQueueEntry, 1); QSIMPLEQ_INSERT_TAIL(bs_queue, bs_entry, entry); bs_entry->state.bs = bs; + bs_entry->state.options = options; bs_entry->state.flags = flags; return bs_queue; @@ -1749,6 +1740,7 @@ cleanup: if (ret && bs_entry->prepared) { bdrv_reopen_abort(&bs_entry->state); } + QDECREF(bs_entry->state.options); g_free(bs_entry); } g_free(bs_queue); @@ -1761,7 +1753,7 @@ int bdrv_reopen(BlockDriverState *bs, int bdrv_flags, Error **errp) { int ret = -1; Error *local_err = NULL; - BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, bdrv_flags); + BlockReopenQueue *queue = bdrv_reopen_queue(NULL, bs, NULL, bdrv_flags); ret = bdrv_reopen_multiple(queue, &local_err); if (local_err != NULL) { @@ -1837,6 +1829,26 @@ int bdrv_reopen_prepare(BDRVReopenState *reopen_state, BlockReopenQueue *queue, goto error; } + /* Options that are not handled are only okay if they are unchanged + * compared to the old state. It is expected that some options are only + * used for the initial open, but not reopen (e.g. filename) */ + if (qdict_size(reopen_state->options)) { + const QDictEntry *entry = qdict_first(reopen_state->options); + + do { + QString *new_obj = qobject_to_qstring(entry->value); + const char *new = qstring_get_str(new_obj); + const char *old = qdict_get_try_str(reopen_state->bs->options, + entry->key); + + if (!old || strcmp(new, old)) { + error_setg(errp, "Cannot change the option '%s'", entry->key); + ret = -EINVAL; + goto error; + } + } while ((entry = qdict_next(reopen_state->options, entry))); + } + ret = 0; error: @@ -3739,7 +3751,6 @@ void bdrv_img_create(const char *filename, const char *fmt, const char *backing_fmt, *backing_file; int64_t size; BlockDriver *drv, *proto_drv; - BlockDriver *backing_drv = NULL; Error *local_err = NULL; int ret = 0; @@ -3813,14 +3824,6 @@ void bdrv_img_create(const char *filename, const char *fmt, } backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT); - if (backing_fmt) { - backing_drv = bdrv_find_format(backing_fmt); - if (!backing_drv) { - error_setg(errp, "Unknown backing file format '%s'", - backing_fmt); - goto out; - } - } // The size for the image must always be specified, with one exception: // If we are using a backing file, we can obtain the size from there @@ -3831,6 +3834,7 @@ void bdrv_img_create(const char *filename, const char *fmt, char *full_backing = g_new0(char, PATH_MAX); int64_t size; int back_flags; + QDict *backing_options = NULL; bdrv_get_full_backing_filename_from_filename(filename, backing_file, full_backing, PATH_MAX, @@ -3844,9 +3848,15 @@ void bdrv_img_create(const char *filename, const char *fmt, back_flags = flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); + if (backing_fmt) { + backing_options = qdict_new(); + qdict_put(backing_options, "driver", + qstring_from_str(backing_fmt)); + } + bs = NULL; - ret = bdrv_open(&bs, full_backing, NULL, NULL, back_flags, - backing_drv, &local_err); + ret = bdrv_open(&bs, full_backing, NULL, backing_options, + back_flags, &local_err); g_free(full_backing); if (ret < 0) { goto out; |