return 0;
open_failed:
bs->drv = NULL;
+
+ bdrv_graph_wrlock(NULL);
if (bs->file != NULL) {
- bdrv_graph_wrlock(NULL);
bdrv_unref_child(bs, bs->file);
- bdrv_graph_wrunlock();
assert(!bs->file);
}
+ bdrv_graph_wrunlock();
+
g_free(bs->opaque);
bs->opaque = NULL;
return ret;
Error *local_err = NULL;
bool ro;
+ GLOBAL_STATE_CODE();
+
+ bdrv_graph_rdlock_main_loop();
assert(bs->file == NULL);
assert(options != NULL && bs->options != options);
- GLOBAL_STATE_CODE();
+ bdrv_graph_rdunlock_main_loop();
opts = qemu_opts_create(&bdrv_runtime_opts, NULL, 0, &error_abort);
if (!qemu_opts_absorb_qdict(opts, options, errp)) {
int bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd,
Error **errp)
{
- BlockDriverState *drain_bs = bs->backing ? bs->backing->bs : bs;
+ BlockDriverState *drain_bs;
int ret;
GLOBAL_STATE_CODE();
+ bdrv_graph_rdlock_main_loop();
+ drain_bs = bs->backing ? bs->backing->bs : bs;
+ bdrv_graph_rdunlock_main_loop();
+
bdrv_ref(drain_bs);
bdrv_drained_begin(drain_bs);
bdrv_graph_wrlock(backing_hd);
Error *local_err = NULL;
GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
if (bs->backing != NULL) {
goto free_exit;
implicit_backing = !strcmp(bs->auto_backing_file, bs->backing_file);
}
- bdrv_graph_rdlock_main_loop();
backing_filename = bdrv_get_full_backing_filename(bs, &local_err);
- bdrv_graph_rdunlock_main_loop();
-
if (local_err) {
ret = -EINVAL;
error_propagate(errp, local_err);
}
if (implicit_backing) {
- bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(backing_hd);
- bdrv_graph_rdunlock_main_loop();
pstrcpy(bs->auto_backing_file, sizeof(bs->auto_backing_file),
backing_hd->filename);
}
{
BlockDriverState *bs = reopen_state->bs;
BlockDriverState *new_child_bs;
- BlockDriverState *old_child_bs = is_backing ? child_bs(bs->backing) :
- child_bs(bs->file);
+ BlockDriverState *old_child_bs;
+
const char *child_name = is_backing ? "backing" : "file";
QObject *value;
const char *str;
g_assert_not_reached();
}
+ old_child_bs = is_backing ? child_bs(bs->backing) : child_bs(bs->file);
if (old_child_bs == new_child_bs) {
ret = 0;
goto out_rdlock;
* file or if the image file has a backing file name as part of
* its metadata. Otherwise the 'backing' option can be omitted.
*/
+ bdrv_graph_rdlock_main_loop();
if (drv->supports_backing && reopen_state->backing_missing &&
(reopen_state->bs->backing || reopen_state->bs->backing_file[0])) {
error_setg(errp, "backing is missing for '%s'",
reopen_state->bs->node_name);
+ bdrv_graph_rdunlock_main_loop();
ret = -EINVAL;
goto error;
}
+ bdrv_graph_rdunlock_main_loop();
/*
* Allow changing the 'backing' option. The new value can be
QLIST_FOREACH_SAFE(child, &bs->children, next, next) {
bdrv_unref_child(bs, child);
}
- bdrv_graph_wrunlock();
assert(!bs->backing);
assert(!bs->file);
+ bdrv_graph_wrunlock();
+
g_free(bs->opaque);
bs->opaque = NULL;
qatomic_set(&bs->copy_on_read, 0);
}
/*
+ * Switch all parents of @from to point to @to instead. @from and @to must be in
+ * the same AioContext and both must be drained.
+ *
* With auto_skip=true bdrv_replace_node_common skips updating from parents
* if it creates a parent-child relation loop or if parent is block-job.
*
* With @detach_subchain=true @to must be in a backing chain of @from. In this
* case backing link of the cow-parent of @to is removed.
*/
-static int bdrv_replace_node_common(BlockDriverState *from,
- BlockDriverState *to,
- bool auto_skip, bool detach_subchain,
- Error **errp)
+static int GRAPH_WRLOCK
+bdrv_replace_node_common(BlockDriverState *from, BlockDriverState *to,
+ bool auto_skip, bool detach_subchain, Error **errp)
{
Transaction *tran = tran_new();
g_autoptr(GSList) refresh_list = NULL;
GLOBAL_STATE_CODE();
- /* Make sure that @from doesn't go away until we have successfully attached
- * all of its parents to @to. */
- bdrv_ref(from);
-
- assert(qemu_get_current_aio_context() == qemu_get_aio_context());
+ assert(from->quiesce_counter);
+ assert(to->quiesce_counter);
assert(bdrv_get_aio_context(from) == bdrv_get_aio_context(to));
- bdrv_drained_begin(from);
- bdrv_drained_begin(to);
-
- bdrv_graph_wrlock(to);
if (detach_subchain) {
assert(bdrv_chain_contains(from, to));
out:
tran_finalize(tran, ret);
- bdrv_graph_wrunlock();
-
- bdrv_drained_end(to);
- bdrv_drained_end(from);
- bdrv_unref(from);
-
return ret;
}
int bdrv_replace_node(BlockDriverState *from, BlockDriverState *to,
Error **errp)
{
- GLOBAL_STATE_CODE();
-
return bdrv_replace_node_common(from, to, true, false, errp);
}
int bdrv_drop_filter(BlockDriverState *bs, Error **errp)
{
BlockDriverState *child_bs;
+ int ret;
GLOBAL_STATE_CODE();
+
bdrv_graph_rdlock_main_loop();
child_bs = bdrv_filter_or_cow_bs(bs);
bdrv_graph_rdunlock_main_loop();
- return bdrv_replace_node_common(bs, child_bs, true, true, errp);
+ bdrv_drained_begin(child_bs);
+ bdrv_graph_wrlock(bs);
+ ret = bdrv_replace_node_common(bs, child_bs, true, true, errp);
+ bdrv_graph_wrunlock();
+ bdrv_drained_end(child_bs);
+
+ return ret;
}
/*
GLOBAL_STATE_CODE();
+ bdrv_graph_rdlock_main_loop();
assert(!bs_new->backing);
+ bdrv_graph_rdunlock_main_loop();
old_context = bdrv_get_aio_context(bs_top);
bdrv_drained_begin(bs_top);
goto fail;
}
+ /*
+ * Make sure that @bs doesn't go away until we have successfully attached
+ * all of its parents to @new_node_bs and undrained it again.
+ */
+ bdrv_ref(bs);
bdrv_drained_begin(bs);
+ bdrv_drained_begin(new_node_bs);
+ bdrv_graph_wrlock(new_node_bs);
ret = bdrv_replace_node(bs, new_node_bs, errp);
+ bdrv_graph_wrunlock();
+ bdrv_drained_end(new_node_bs);
bdrv_drained_end(bs);
+ bdrv_unref(bs);
if (ret < 0) {
error_prepend(errp, "Could not replace node: ");
* image file header
* -ENOTSUP - format driver doesn't support changing the backing file
*/
-int bdrv_change_backing_file(BlockDriverState *bs, const char *backing_file,
- const char *backing_fmt, bool require)
+int coroutine_fn
+bdrv_co_change_backing_file(BlockDriverState *bs, const char *backing_file,
+ const char *backing_fmt, bool require)
{
BlockDriver *drv = bs->drv;
int ret;
- GLOBAL_STATE_CODE();
+ IO_CODE();
if (!drv) {
return -ENOMEDIUM;
return -EINVAL;
}
- if (drv->bdrv_change_backing_file != NULL) {
- ret = drv->bdrv_change_backing_file(bs, backing_file, backing_fmt);
+ if (drv->bdrv_co_change_backing_file != NULL) {
+ ret = drv->bdrv_co_change_backing_file(bs, backing_file, backing_fmt);
} else {
ret = -ENOTSUP;
}
bdrv_ref(top);
bdrv_drained_begin(base);
- bdrv_graph_rdlock_main_loop();
+ bdrv_graph_wrlock(base);
if (!top->drv || !base->drv) {
- goto exit;
+ goto exit_wrlock;
}
/* Make sure that base is in the backing chain of top */
if (!bdrv_chain_contains(top, base)) {
- goto exit;
+ goto exit_wrlock;
}
/* If 'base' recursively inherits from 'top' then we should set
* That's a FIXME.
*/
bdrv_replace_node_common(top, base, false, false, &local_err);
+ bdrv_graph_wrunlock();
+
if (local_err) {
error_report_err(local_err);
goto exit;
}
ret = 0;
+ goto exit;
+
+exit_wrlock:
+ bdrv_graph_wrunlock();
exit:
- bdrv_graph_rdunlock_main_loop();
bdrv_drained_end(base);
bdrv_unref(top);
return ret;
/* Note: This function may return false positives; it may return true
* even if opening the backing file specified by bs's image header
* would result in exactly bs->backing. */
-static bool bdrv_backing_overridden(BlockDriverState *bs)
+static bool GRAPH_RDLOCK bdrv_backing_overridden(BlockDriverState *bs)
{
GLOBAL_STATE_CODE();
if (bs->backing) {