BlockDriverState *old_bs;
BlockDriverState *new_bs;
AioContext *aio_context;
+ bool overlay_appended;
} ExternalSnapshotState;
static void external_snapshot_prepare(BlkActionState *common,
if (!state->new_bs->drv->supports_backing) {
error_setg(errp, "The snapshot does not support backing images");
+ return;
}
+
+ /* This removes our old bs and adds the new bs. This is an operation that
+ * can fail, so we need to do it in .prepare; undoing it for abort is
+ * always possible. */
+ bdrv_ref(state->new_bs);
+ bdrv_append(state->new_bs, state->old_bs, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ state->overlay_appended = true;
}
static void external_snapshot_commit(BlkActionState *common)
bdrv_set_aio_context(state->new_bs, state->aio_context);
- /* This removes our old bs and adds the new bs */
- bdrv_append(state->new_bs, state->old_bs);
/* We don't need (or want) to use the transactional
* bdrv_reopen_multiple() across all the entries at once, because we
* don't want to abort all of them if one of them fails the reopen */
ExternalSnapshotState *state =
DO_UPCAST(ExternalSnapshotState, common, common);
if (state->new_bs) {
- bdrv_unref(state->new_bs);
+ if (state->overlay_appended) {
+ bdrv_replace_node(state->new_bs, state->old_bs, &error_abort);
+ }
}
}
if (state->aio_context) {
bdrv_drained_end(state->old_bs);
aio_context_release(state->aio_context);
+ bdrv_unref(state->new_bs);
}
}
}
if (!locked || force) {
- blk_dev_change_media_cb(blk, false);
+ blk_dev_change_media_cb(blk, false, &error_abort);
}
if (locked && !force) {
Error **errp)
{
BlockBackend *blk;
+ Error *local_err = NULL;
device = has_device ? device : NULL;
id = has_id ? id : NULL;
return;
}
- blk_dev_change_media_cb(blk, true);
+ blk_dev_change_media_cb(blk, true, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
}
void qmp_x_blockdev_remove_medium(bool has_device, const char *device,
* called at all); therefore, the medium needs to be ejected here.
* Do it after blk_remove_bs() so blk_is_inserted(blk) returns the @load
* value passed here (i.e. false). */
- blk_dev_change_media_cb(blk, false);
+ blk_dev_change_media_cb(blk, false, &error_abort);
}
out:
static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
BlockDriverState *bs, Error **errp)
{
+ Error *local_err = NULL;
bool has_device;
+ int ret;
/* For BBs without a device, we can exchange the BDS tree at will */
has_device = blk_get_attached_dev(blk);
return;
}
- blk_insert_bs(blk, bs);
+ ret = blk_insert_bs(blk, bs, errp);
+ if (ret < 0) {
+ return;
+ }
if (!blk_dev_has_tray(blk)) {
/* For tray-less devices, blockdev-close-tray is a no-op (or may not be
* slot here.
* Do it after blk_insert_bs() so blk_is_inserted(blk) returns the @load
* value passed here (i.e. true). */
- blk_dev_change_media_cb(blk, true);
+ blk_dev_change_media_cb(blk, true, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ blk_remove_bs(blk);
+ return;
+ }
}
}
}
blk = blk_new(BLK_PERM_RESIZE, BLK_PERM_ALL);
- blk_insert_bs(blk, bs);
+ ret = blk_insert_bs(blk, bs, errp);
+ if (ret < 0) {
+ goto out;
+ }
/* complete all in-flight operations before resizing the device */
bdrv_drain_all();
bool has_top, const char *top,
bool has_backing_file, const char *backing_file,
bool has_speed, int64_t speed,
+ bool has_filter_node_name, const char *filter_node_name,
Error **errp)
{
BlockDriverState *bs;
if (!has_speed) {
speed = 0;
}
+ if (!has_filter_node_name) {
+ filter_node_name = NULL;
+ }
/* Important Note:
* libvirt relies on the DeviceNotFound error class in order to probe for
goto out;
}
commit_active_start(has_job_id ? job_id : NULL, bs, base_bs,
- BLOCK_JOB_DEFAULT, speed, on_error, NULL, NULL,
- &local_err, false);
+ BLOCK_JOB_DEFAULT, speed, on_error,
+ filter_node_name, NULL, NULL, &local_err, false);
} else {
BlockDriverState *overlay_bs = bdrv_find_overlay(bs, top_bs);
if (bdrv_op_is_blocked(overlay_bs, BLOCK_OP_TYPE_COMMIT_TARGET, errp)) {
}
commit_start(has_job_id ? job_id : NULL, bs, base_bs, top_bs, speed,
on_error, has_backing_file ? backing_file : NULL,
- &local_err);
+ filter_node_name, &local_err);
}
if (local_err != NULL) {
error_propagate(errp, local_err);
bool has_on_target_error,
BlockdevOnError on_target_error,
bool has_unmap, bool unmap,
+ bool has_filter_node_name,
+ const char *filter_node_name,
Error **errp)
{
if (!has_unmap) {
unmap = true;
}
+ if (!has_filter_node_name) {
+ filter_node_name = NULL;
+ }
if (granularity != 0 && (granularity < 512 || granularity > 1048576 * 64)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",
mirror_start(job_id, bs, target,
has_replaces ? replaces : NULL,
speed, granularity, buf_size, sync, backing_mode,
- on_source_error, on_target_error, unmap, errp);
+ on_source_error, on_target_error, unmap, filter_node_name,
+ errp);
}
void qmp_drive_mirror(DriveMirror *arg, Error **errp)
arg->has_on_source_error, arg->on_source_error,
arg->has_on_target_error, arg->on_target_error,
arg->has_unmap, arg->unmap,
+ false, NULL,
&local_err);
bdrv_unref(target_bs);
error_propagate(errp, local_err);
BlockdevOnError on_source_error,
bool has_on_target_error,
BlockdevOnError on_target_error,
+ bool has_filter_node_name,
+ const char *filter_node_name,
Error **errp)
{
BlockDriverState *bs;
has_on_source_error, on_source_error,
has_on_target_error, on_target_error,
true, true,
+ has_filter_node_name, filter_node_name,
&local_err);
error_propagate(errp, local_err);