static void update_options_from_flags(QDict *options, int flags)
{
if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) {
- qdict_put(options, BDRV_OPT_CACHE_DIRECT,
- qbool_from_bool(flags & BDRV_O_NOCACHE));
+ qdict_put_bool(options, BDRV_OPT_CACHE_DIRECT, flags & BDRV_O_NOCACHE);
}
if (!qdict_haskey(options, BDRV_OPT_CACHE_NO_FLUSH)) {
- qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
- qbool_from_bool(flags & BDRV_O_NO_FLUSH));
+ qdict_put_bool(options, BDRV_OPT_CACHE_NO_FLUSH,
+ flags & BDRV_O_NO_FLUSH);
}
if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
- qdict_put(options, BDRV_OPT_READ_ONLY,
- qbool_from_bool(!(flags & BDRV_O_RDWR)));
+ qdict_put_bool(options, BDRV_OPT_READ_ONLY, !(flags & BDRV_O_RDWR));
}
}
if (file != NULL) {
filename = blk_bs(file)->filename;
} else {
+ /*
+ * Caution: while qdict_get_try_str() is fine, getting
+ * non-string types would require more care. When @options
+ * come from -blockdev or blockdev_add, its members are typed
+ * according to the QAPI schema, but when they come from
+ * -drive, they're all QString.
+ */
filename = qdict_get_try_str(options, "filename");
}
- if (drv->bdrv_needs_filename && !filename) {
+ if (drv->bdrv_needs_filename && (!filename || !filename[0])) {
error_setg(errp, "The '%s' block driver requires a file name",
drv->format_name);
ret = -EINVAL;
BlockDriver *drv = NULL;
Error *local_err = NULL;
+ /*
+ * Caution: while qdict_get_try_str() is fine, getting non-string
+ * types would require more care. When @options come from
+ * -blockdev or blockdev_add, its members are typed according to
+ * the QAPI schema, but when they come from -drive, they're all
+ * QString.
+ */
drvname = qdict_get_try_str(*options, "driver");
if (drvname) {
drv = bdrv_find_format(drvname);
/* Fetch the file name from the options QDict if necessary */
if (protocol && filename) {
if (!qdict_haskey(*options, "filename")) {
- qdict_put(*options, "filename", qstring_from_str(filename));
+ qdict_put_str(*options, "filename", filename);
parse_filename = true;
} else {
error_setg(errp, "Can't specify 'file' and 'filename' options at "
}
/* Find the right block driver */
+ /* See cautionary note on accessing @options above */
filename = qdict_get_try_str(*options, "filename");
if (!drvname && protocol) {
}
drvname = drv->format_name;
- qdict_put(*options, "driver", qstring_from_str(drvname));
+ qdict_put_str(*options, "driver", drvname);
} else {
error_setg(errp, "Must specify either driver or file");
return -EINVAL;
return 0;
}
+static int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
+ GSList *ignore_children, Error **errp);
+static void bdrv_child_abort_perm_update(BdrvChild *c);
+static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared);
+
/*
* Check whether permissions on this node can be changed in a way that
* @cumulative_perms and @cumulative_shared_perms are the new cumulative
/* Needs to be followed by a call to either bdrv_child_set_perm() or
* bdrv_child_abort_perm_update(). */
-int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
- GSList *ignore_children, Error **errp)
+static int bdrv_child_check_perm(BdrvChild *c, uint64_t perm, uint64_t shared,
+ GSList *ignore_children, Error **errp)
{
int ret;
return ret;
}
-void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared)
+static void bdrv_child_set_perm(BdrvChild *c, uint64_t perm, uint64_t shared)
{
uint64_t cumulative_perms, cumulative_shared_perms;
bdrv_set_perm(c->bs, cumulative_perms, cumulative_shared_perms);
}
-void bdrv_child_abort_perm_update(BdrvChild *c)
+static void bdrv_child_abort_perm_update(BdrvChild *c)
{
bdrv_abort_perm_update(c->bs);
}
{
BlockDriverState *old_bs = child->bs;
+ if (old_bs && new_bs) {
+ assert(bdrv_get_aio_context(old_bs) == bdrv_get_aio_context(new_bs));
+ }
if (old_bs) {
if (old_bs->quiesce_counter && child->role->drained_end) {
child->role->drained_end(child);
}
}
-static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs,
- bool check_new_perm)
+/*
+ * Updates @child to change its reference to point to @new_bs, including
+ * checking and applying the necessary permisson updates both to the old node
+ * and to @new_bs.
+ *
+ * NULL is passed as @new_bs for removing the reference before freeing @child.
+ *
+ * If @new_bs is not NULL, bdrv_check_perm() must be called beforehand, as this
+ * function uses bdrv_set_perm() to update the permissions according to the new
+ * reference that @new_bs gets.
+ */
+static void bdrv_replace_child(BdrvChild *child, BlockDriverState *new_bs)
{
BlockDriverState *old_bs = child->bs;
uint64_t perm, shared_perm;
if (new_bs) {
bdrv_get_cumulative_perm(new_bs, &perm, &shared_perm);
- if (check_new_perm) {
- bdrv_check_perm(new_bs, perm, shared_perm, NULL, &error_abort);
- }
bdrv_set_perm(new_bs, perm, shared_perm);
}
}
};
/* This performs the matching bdrv_set_perm() for the above check. */
- bdrv_replace_child(child, child_bs, false);
+ bdrv_replace_child(child, child_bs);
return child;
}
bdrv_get_cumulative_perm(parent_bs, &perm, &shared_perm);
assert(parent_bs->drv);
+ assert(bdrv_get_aio_context(parent_bs) == bdrv_get_aio_context(child_bs));
parent_bs->drv->bdrv_child_perm(parent_bs, NULL, child_role,
perm, shared_perm, &perm, &shared_perm);
child->next.le_prev = NULL;
}
- bdrv_replace_child(child, NULL, false);
+ bdrv_replace_child(child, NULL);
g_free(child->name);
g_free(child);
bdrv_unref(backing_hd);
}
+ bdrv_refresh_filename(bs);
+
out:
bdrv_refresh_limits(bs, NULL);
}
qdict_extract_subqdict(parent_options, &options, bdref_key_dot);
g_free(bdref_key_dot);
+ /*
+ * Caution: while qdict_get_try_str() is fine, getting non-string
+ * types would require more care. When @parent_options come from
+ * -blockdev or blockdev_add, its members are typed according to
+ * the QAPI schema, but when they come from -drive, they're all
+ * QString.
+ */
reference = qdict_get_try_str(parent_options, bdref_key);
if (reference || qdict_haskey(options, "file.filename")) {
backing_filename[0] = '\0';
}
if (bs->backing_format[0] != '\0' && !qdict_haskey(options, "driver")) {
- qdict_put(options, "driver", qstring_from_str(bs->backing_format));
+ qdict_put_str(options, "driver", bs->backing_format);
}
backing_hd = bdrv_open_inherit(*backing_filename ? backing_filename : NULL,
bdrv_set_backing_hd(bs, backing_hd, &local_err);
bdrv_unref(backing_hd);
if (local_err) {
+ error_propagate(errp, local_err);
ret = -EINVAL;
goto free_exit;
}
qdict_extract_subqdict(options, &image_options, bdref_key_dot);
g_free(bdref_key_dot);
+ /*
+ * Caution: while qdict_get_try_str() is fine, getting non-string
+ * types would require more care. When @options come from
+ * -blockdev or blockdev_add, its members are typed according to
+ * the QAPI schema, but when they come from -drive, they're all
+ * QString.
+ */
reference = qdict_get_try_str(options, bdref_key);
if (!filename && !reference && !qdict_size(image_options)) {
if (!allow_none) {
}
/* Prepare options QDict for the temporary file */
- qdict_put(snapshot_options, "file.driver",
- qstring_from_str("file"));
- qdict_put(snapshot_options, "file.filename",
- qstring_from_str(tmp_filename));
- qdict_put(snapshot_options, "driver",
- qstring_from_str("qcow2"));
+ qdict_put_str(snapshot_options, "file.driver", "file");
+ qdict_put_str(snapshot_options, "file.filename", tmp_filename);
+ qdict_put_str(snapshot_options, "driver", "qcow2");
bs_snapshot = bdrv_open(NULL, NULL, snapshot_options, flags, errp);
snapshot_options = NULL;
goto fail;
}
- /* Set the BDRV_O_RDWR and BDRV_O_ALLOW_RDWR flags.
- * FIXME: we're parsing the QDict to avoid having to create a
- * QemuOpts just for this, but neither option is optimal. */
+ /*
+ * Set the BDRV_O_RDWR and BDRV_O_ALLOW_RDWR flags.
+ * Caution: getting a boolean member of @options requires care.
+ * When @options come from -blockdev or blockdev_add, members are
+ * typed according to the QAPI schema, but when they come from
+ * -drive, they're all QString.
+ */
if (g_strcmp0(qdict_get_try_str(options, BDRV_OPT_READ_ONLY), "on") &&
!qdict_get_try_bool(options, BDRV_OPT_READ_ONLY, false)) {
flags |= (BDRV_O_RDWR | BDRV_O_ALLOW_RDWR);
options = qdict_clone_shallow(options);
/* Find the right image format driver */
+ /* See cautionary note on accessing @options above */
drvname = qdict_get_try_str(options, "driver");
if (drvname) {
drv = bdrv_find_format(drvname);
assert(drvname || !(flags & BDRV_O_PROTOCOL));
+ /* See cautionary note on accessing @options above */
backing = qdict_get_try_str(options, "backing");
if (backing && *backing == '\0') {
flags |= BDRV_O_NO_BACKING;
goto fail;
}
- qdict_put(options, "file",
- qstring_from_str(bdrv_get_node_name(file_bs)));
+ qdict_put_str(options, "file", bdrv_get_node_name(file_bs));
}
}
* sure to update both bs->options (which has the full effective
* options for bs) and options (which has file.* already removed).
*/
- qdict_put(bs->options, "driver", qstring_from_str(drv->format_name));
- qdict_put(options, "driver", qstring_from_str(drv->format_name));
+ qdict_put_str(bs->options, "driver", drv->format_name);
+ qdict_put_str(options, "driver", drv->format_name);
} else if (!drv) {
error_setg(errp, "Must specify either driver or file");
goto fail;
* that they are checked at the end of this function. */
value = qemu_opt_get(opts, "node-name");
if (value) {
- qdict_put(reopen_state->options, "node-name", qstring_from_str(value));
+ qdict_put_str(reopen_state->options, "node-name", value);
}
value = qemu_opt_get(opts, "driver");
if (value) {
- qdict_put(reopen_state->options, "driver", qstring_from_str(value));
+ qdict_put_str(reopen_state->options, "driver", value);
}
/* if we are to stay read-only, do not allow permission change
do {
QString *new_obj = qobject_to_qstring(entry->value);
const char *new = qstring_get_str(new_obj);
+ /*
+ * Caution: while qdict_get_try_str() is fine, getting
+ * non-string types would require more care. When
+ * bs->options come from -blockdev or blockdev_add, its
+ * members are typed according to the QAPI schema, but
+ * when they come from -drive, they're all QString.
+ */
const char *old = qdict_get_try_str(reopen_state->bs->options,
entry->key);
/**
* Truncate file to 'offset' bytes (needed only for file protocols)
*/
-int bdrv_truncate(BdrvChild *child, int64_t offset)
+int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
{
BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv;
int ret;
- assert(child->perm & BLK_PERM_RESIZE);
+ /* FIXME: Some format block drivers use this function instead of implicitly
+ * growing their file by writing beyond its end.
+ * See bdrv_aligned_pwritev() for an explanation why we currently
+ * cannot assert this permission in that case. */
+ // assert(child->perm & BLK_PERM_RESIZE);
- if (!drv)
+ if (!drv) {
+ error_setg(errp, "No medium inserted");
return -ENOMEDIUM;
- if (!drv->bdrv_truncate)
+ }
+ if (!drv->bdrv_truncate) {
+ error_setg(errp, "Image format driver does not support resize");
return -ENOTSUP;
- if (bs->read_only)
+ }
+ if (bs->read_only) {
+ error_setg(errp, "Image is read-only");
return -EACCES;
+ }
ret = drv->bdrv_truncate(bs, offset);
if (ret == 0) {
bdrv_dirty_bitmap_truncate(bs);
bdrv_parent_cb_resize(bs);
++bs->write_gen;
+ } else {
+ error_setg_errno(errp, -ret, "Failed to resize image");
}
return ret;
}
return retval;
}
-int bdrv_get_backing_file_depth(BlockDriverState *bs)
-{
- if (!bs->drv) {
- return 0;
- }
-
- if (!bs->backing) {
- return 0;
- }
-
- return 1 + bdrv_get_backing_file_depth(bs->backing->bs);
-}
-
void bdrv_init(void)
{
module_call_init(MODULE_INIT_BLOCK);
if (backing_fmt) {
backing_options = qdict_new();
- qdict_put(backing_options, "driver",
- qstring_from_str(backing_fmt));
+ qdict_put_str(backing_options, "driver", backing_fmt);
}
bs = bdrv_open(full_backing, NULL, backing_options, back_flags,
return bs->aio_context;
}
+void bdrv_coroutine_enter(BlockDriverState *bs, Coroutine *co)
+{
+ aio_co_enter(bdrv_get_aio_context(bs), co);
+}
+
static void bdrv_do_remove_aio_context_notifier(BdrvAioNotifier *ban)
{
QLIST_REMOVE(ban, list);
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context)
{
+ AioContext *ctx = bdrv_get_aio_context(bs);
+
+ aio_disable_external(ctx);
+ bdrv_parent_drained_begin(bs);
bdrv_drain(bs); /* ensure there are no in-flight requests */
+ while (aio_poll(ctx, false)) {
+ /* wait for all bottom halves to execute */
+ }
+
bdrv_detach_aio_context(bs);
/* This function executes in the old AioContext so acquire the new one in
*/
aio_context_acquire(new_context);
bdrv_attach_aio_context(bs, new_context);
+ bdrv_parent_drained_end(bs);
+ aio_enable_external(ctx);
aio_context_release(new_context);
}
* contain a representation of the filename, therefore the following
* suffices without querying the (exact_)filename of this BDS. */
if (bs->file->bs->full_open_options) {
- qdict_put_obj(opts, "driver",
- QOBJECT(qstring_from_str(drv->format_name)));
+ qdict_put_str(opts, "driver", drv->format_name);
QINCREF(bs->file->bs->full_open_options);
- qdict_put_obj(opts, "file",
- QOBJECT(bs->file->bs->full_open_options));
+ qdict_put(opts, "file", bs->file->bs->full_open_options);
bs->full_open_options = opts;
} else {
opts = qdict_new();
append_open_options(opts, bs);
- qdict_put_obj(opts, "driver",
- QOBJECT(qstring_from_str(drv->format_name)));
+ qdict_put_str(opts, "driver", drv->format_name);
if (bs->exact_filename[0]) {
/* This may not work for all block protocol drivers (some may
* needs some special format of the options QDict, it needs to
* implement the driver-specific bdrv_refresh_filename() function.
*/
- qdict_put_obj(opts, "filename",
- QOBJECT(qstring_from_str(bs->exact_filename)));
+ qdict_put_str(opts, "filename", bs->exact_filename);
}
bs->full_open_options = opts;