* Ignore default drives, because we create certain default
* drives unconditionally, then leave them unclaimed. Not the
* users fault.
- * Ignore IF_VIRTIO, because it gets desugared into -device,
- * so we can leave failing to -device.
+ * Ignore IF_VIRTIO or IF_XEN, because it gets desugared into
+ * -device, so we can leave failing to -device.
* Ignore IF_NONE, because leaving unclaimed IF_NONE remains
* available for device_add is a feature.
*/
if (dinfo->is_default || dinfo->type == IF_VIRTIO
- || dinfo->type == IF_NONE) {
+ || dinfo->type == IF_XEN || dinfo->type == IF_NONE) {
continue;
}
if (!blk_get_attached_dev(blk)) {
switch (qobject_type(entry->value)) {
case QTYPE_QSTRING: {
- unsigned long long length;
+ uint64_t length;
const char *str = qstring_get_str(qobject_to(QString,
entry->value));
- if (parse_uint_full(str, &length, 10) == 0 &&
+ if (parse_uint_full(str, 10, &length) == 0 &&
length > 0 && length <= UINT_MAX) {
block_acct_add_interval(stats, (unsigned) length);
} else {
/* Takes the ownership of bs_opts */
BlockDriverState *bds_tree_init(QDict *bs_opts, Error **errp)
{
+ BlockDriverState *bs;
int bdrv_flags = 0;
GLOBAL_STATE_CODE();
bdrv_flags |= BDRV_O_INACTIVE;
}
- return bdrv_open(NULL, NULL, bs_opts, bdrv_flags, errp);
+ aio_context_acquire(qemu_get_aio_context());
+ bs = bdrv_open(NULL, NULL, bs_opts, bdrv_flags, errp);
+ aio_context_release(qemu_get_aio_context());
+
+ return bs;
}
void blockdev_close_all_bdrv_states(void)
qemu_opt_set(devopts, "driver", "virtio-blk", &error_abort);
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
&error_abort);
+ } else if (type == IF_XEN) {
+ QemuOpts *devopts;
+ devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
+ &error_abort);
+ qemu_opt_set(devopts, "driver",
+ (media == MEDIA_CDROM) ? "xen-cdrom" : "xen-disk",
+ &error_abort);
+ qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
+ &error_abort);
}
filename = qemu_opt_get(legacy_opts, "file");
BlockDriverState *bs;
AioContext *aio_context;
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
bs = bdrv_lookup_bs(name, name, errp);
if (bs == NULL) {
return NULL;
SnapshotInfo *info = NULL;
int ret;
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
bs = qmp_get_root_bs(device, errp);
if (!bs) {
return NULL;
AioContext *aio_context;
int ret1;
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
tran_add(tran, &internal_snapshot_drv, state);
device = internal->device;
AioContext *aio_context;
Error *local_error = NULL;
+ GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
if (!state->created) {
return;
}
AioContext *aio_context;
uint64_t perm, shared;
+ /* TODO We'll eventually have to take a writer lock in this function */
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
tran_add(tran, &external_snapshot_drv, state);
/* 'blockdev-snapshot' and 'blockdev-snapshot-sync' have similar
}
qdict_put_str(options, "driver", format);
}
+ aio_context_release(aio_context);
+ aio_context_acquire(qemu_get_aio_context());
state->new_bs = bdrv_open(new_image_file, snapshot_ref, options, flags,
errp);
+ aio_context_release(qemu_get_aio_context());
+
/* We will manually add the backing_hd field to the bs later */
if (!state->new_bs) {
- goto out;
+ return;
}
+ aio_context_acquire(aio_context);
+
/*
* Allow attaching a backing file to an overlay that's already in use only
* if the parents don't assume that they are already seeing a valid image.
bool set_backing_hd = false;
int ret;
+ GLOBAL_STATE_CODE();
+
tran_add(tran, &drive_backup_drv, state);
if (!backup->has_mode) {
}
/* Early check to avoid creating target */
+ bdrv_graph_rdlock_main_loop();
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_BACKUP_SOURCE, errp)) {
+ bdrv_graph_rdunlock_main_loop();
goto out;
}
+ bdrv_graph_rdunlock_main_loop();
flags = bs->open_flags | BDRV_O_RDWR;
BlockDriverState *explicit_backing =
bdrv_skip_implicit_filters(source);
+ bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(explicit_backing);
+ bdrv_graph_rdunlock_main_loop();
+
bdrv_img_create(backup->target, format,
explicit_backing->filename,
explicit_backing->drv->format_name, NULL,
if (format) {
qdict_put_str(options, "driver", format);
}
+ aio_context_release(aio_context);
+ aio_context_acquire(qemu_get_aio_context());
target_bs = bdrv_open(backup->target, NULL, options, flags, errp);
+ aio_context_release(qemu_get_aio_context());
+
if (!target_bs) {
- goto out;
+ return;
}
/* Honor bdrv_try_change_aio_context() context acquisition requirements. */
old_context = bdrv_get_aio_context(target_bs);
- aio_context_release(aio_context);
aio_context_acquire(old_context);
ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp);
return;
}
+ bdrv_graph_co_rdlock();
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) {
error_setg(errp, QERR_DEVICE_IN_USE, device);
+ bdrv_graph_co_rdunlock();
return;
}
+ bdrv_graph_co_rdunlock();
blk = blk_co_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, errp);
if (!blk) {
Error *local_err = NULL;
int job_flags = JOB_DEFAULT;
+ GLOBAL_STATE_CODE();
+
if (base && base_node) {
error_setg(errp, "'base' and 'base-node' cannot be specified "
"at the same time");
goto out;
}
assert(bdrv_get_aio_context(base_bs) == aio_context);
+
+ bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(base_bs);
+ bdrv_graph_rdunlock_main_loop();
}
if (bottom) {
* Check for op blockers in the whole chain between bs and base (or bottom)
*/
iter_end = bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs;
+ bdrv_graph_rdlock_main_loop();
for (iter = bs; iter && iter != iter_end;
iter = bdrv_filter_or_cow_bs(iter))
{
if (bdrv_op_is_blocked(iter, BLOCK_OP_TYPE_STREAM, errp)) {
+ bdrv_graph_rdunlock_main_loop();
goto out;
}
}
+ bdrv_graph_rdunlock_main_loop();
/* if we are streaming the entire chain, the result will have no backing
* file, and specifying one is therefore an error */
int job_flags = JOB_DEFAULT;
uint64_t top_perm, top_shared;
+ /* TODO We'll eventually have to take a writer lock in this function */
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
if (!has_speed) {
speed = 0;
}
XDbgBlockGraph *qmp_x_debug_query_block_graph(Error **errp)
{
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
return bdrv_get_xdbg_block_graph(errp);
}
if (replaces) {
BlockDriverState *to_replace_bs;
+ AioContext *aio_context;
AioContext *replace_aio_context;
int64_t bs_size, replace_size;
return;
}
+ aio_context = bdrv_get_aio_context(bs);
replace_aio_context = bdrv_get_aio_context(to_replace_bs);
- aio_context_acquire(replace_aio_context);
+ /*
+ * bdrv_getlength() is a co-wrapper and uses AIO_WAIT_WHILE. Be sure not
+ * to acquire the same AioContext twice.
+ */
+ if (replace_aio_context != aio_context) {
+ aio_context_acquire(replace_aio_context);
+ }
replace_size = bdrv_getlength(to_replace_bs);
- aio_context_release(replace_aio_context);
+ if (replace_aio_context != aio_context) {
+ aio_context_release(replace_aio_context);
+ }
if (replace_size < 0) {
error_setg_errno(errp, -replace_size,
}
/* Early check to avoid creating target */
+ bdrv_graph_rdlock_main_loop();
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) {
+ bdrv_graph_rdunlock_main_loop();
return;
}
+ bdrv_graph_rdunlock_main_loop();
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
break;
case NEW_IMAGE_MODE_ABSOLUTE_PATHS:
/* create new image with backing file */
+ bdrv_graph_rdlock_main_loop();
bdrv_refresh_filename(explicit_backing);
+ bdrv_graph_rdunlock_main_loop();
+
bdrv_img_create(arg->target, format,
explicit_backing->filename,
explicit_backing->drv->format_name,
if (format) {
qdict_put_str(options, "driver", format);
}
+ aio_context_release(aio_context);
/* Mirroring takes care of copy-on-write using the source's backing
* file.
*/
+ aio_context_acquire(qemu_get_aio_context());
target_bs = bdrv_open(arg->target, NULL, options, flags, errp);
+ aio_context_release(qemu_get_aio_context());
+
if (!target_bs) {
- goto out;
+ return;
}
+ bdrv_graph_rdlock_main_loop();
zero_target = (arg->sync == MIRROR_SYNC_MODE_FULL &&
(arg->mode == NEW_IMAGE_MODE_EXISTING ||
!bdrv_has_zero_init(target_bs)));
+ bdrv_graph_rdunlock_main_loop();
/* Honor bdrv_try_change_aio_context() context acquisition requirements. */
old_context = bdrv_get_aio_context(target_bs);
- aio_context_release(aio_context);
aio_context_acquire(old_context);
ret = bdrv_try_change_aio_context(target_bs, aio_context, NULL, errp);
job_dismiss_locked(&job, errp);
}
+void qmp_block_job_change(BlockJobChangeOptions *opts, Error **errp)
+{
+ BlockJob *job;
+
+ JOB_LOCK_GUARD();
+ job = find_block_job_locked(opts->id, errp);
+
+ if (!job) {
+ return;
+ }
+
+ block_job_change_locked(job, opts, errp);
+}
+
void qmp_change_backing_file(const char *device,
const char *image_node_name,
const char *backing_file,
/* even though we are not necessarily operating on bs, we need it to
* determine if block ops are currently prohibited on the chain */
+ bdrv_graph_rdlock_main_loop();
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_CHANGE, errp)) {
+ bdrv_graph_rdunlock_main_loop();
goto out;
}
+ bdrv_graph_rdunlock_main_loop();
/* final sanity check */
if (!bdrv_chain_contains(bs, image_bs)) {
BlockDriverState *bs;
GLOBAL_STATE_CODE();
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
bs = bdrv_find_node(node_name);
if (!bs) {
aio_context_release(aio_context);
}
-static BdrvChild *bdrv_find_child(BlockDriverState *parent_bs,
- const char *child_name)
+static BdrvChild * GRAPH_RDLOCK
+bdrv_find_child(BlockDriverState *parent_bs, const char *child_name)
{
BdrvChild *child;
BlockDriverState *parent_bs, *new_bs = NULL;
BdrvChild *p_child;
+ bdrv_graph_wrlock(NULL);
+
parent_bs = bdrv_lookup_bs(parent, parent, errp);
if (!parent_bs) {
- return;
+ goto out;
}
if (!child == !node) {
} else {
error_setg(errp, "Either child or node must be specified");
}
- return;
+ goto out;
}
if (child) {
if (!p_child) {
error_setg(errp, "Node '%s' does not have child '%s'",
parent, child);
- return;
+ goto out;
}
bdrv_del_child(parent_bs, p_child, errp);
}
new_bs = bdrv_find_node(node);
if (!new_bs) {
error_setg(errp, "Node '%s' not found", node);
- return;
+ goto out;
}
bdrv_add_child(parent_bs, new_bs, errp);
}
+
+out:
+ bdrv_graph_wrunlock();
}
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
AioContext *new_context;
BlockDriverState *bs;
+ GRAPH_RDLOCK_GUARD_MAINLOOP();
+
bs = bdrv_find_node(node_name);
if (!bs) {
error_setg(errp, "Failed to find node with node-name='%s'", node_name);