#include "block/block_int.h"
#include "block/trace.h"
#include "sysemu/arch_init.h"
-#include "sysemu/qtest.h"
#include "sysemu/runstate.h"
#include "sysemu/replay.h"
#include "qemu/cutils.h"
return NULL;
}
-void drive_mark_claimed_by_board(void)
-{
- BlockBackend *blk;
- DriveInfo *dinfo;
-
- for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
- dinfo = blk_legacy_dinfo(blk);
- if (dinfo && blk_get_attached_dev(blk)) {
- dinfo->claimed_by_board = true;
- }
- }
-}
-
+/*
+ * Check board claimed all -drive that are meant to be claimed.
+ * Fatal error if any remain unclaimed.
+ */
void drive_check_orphaned(void)
{
BlockBackend *blk;
for (blk = blk_next(NULL); blk; blk = blk_next(blk)) {
dinfo = blk_legacy_dinfo(blk);
- if (dinfo->is_default || dinfo->type == IF_NONE) {
+ /*
+ * 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_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) {
continue;
}
if (!blk_get_attached_dev(blk)) {
if_name[dinfo->type], dinfo->bus, dinfo->unit);
loc_pop(&loc);
orphans = true;
- continue;
- }
- if (!dinfo->claimed_by_board && dinfo->type != IF_VIRTIO) {
- loc_push_none(&loc);
- qemu_opts_loc_restore(dinfo->opts);
- warn_report("bogus if=%s is deprecated, use if=none",
- if_name[dinfo->type]);
- loc_pop(&loc);
}
}
QemuOpts *devopts;
devopts = qemu_opts_create(qemu_find_opts("device"), NULL, 0,
&error_abort);
- if (arch_type == QEMU_ARCH_S390X) {
- qemu_opt_set(devopts, "driver", "virtio-blk-ccw", &error_abort);
- } else {
- qemu_opt_set(devopts, "driver", "virtio-blk-pci", &error_abort);
- }
+ qemu_opt_set(devopts, "driver", "virtio-blk", &error_abort);
qemu_opt_set(devopts, "drive", qdict_get_str(bs_opts, "id"),
&error_abort);
}
static void external_snapshot_prepare(BlkActionState *common,
Error **errp)
{
+ int ret;
int flags = 0;
QDict *options = NULL;
Error *local_err = NULL;
s->has_snapshot_node_name ? s->snapshot_node_name : NULL;
if (node_name && !snapshot_node_name) {
- error_setg(errp, "New overlay node name missing");
+ error_setg(errp, "New overlay node-name missing");
goto out;
}
if (snapshot_node_name &&
bdrv_lookup_bs(snapshot_node_name, snapshot_node_name, NULL)) {
- error_setg(errp, "New overlay node name already in use");
+ error_setg(errp, "New overlay node-name already in use");
goto out;
}
goto out;
}
- /* 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);
+ ret = bdrv_append(state->new_bs, state->old_bs, errp);
+ if (ret < 0) {
goto out;
}
state->overlay_appended = true;
aio_context_acquire(aio_context);
if (set_backing_hd) {
- bdrv_set_backing_hd(target_bs, source, &local_err);
- if (local_err) {
+ if (bdrv_set_backing_hd(target_bs, source, errp) < 0) {
goto unref;
}
}
job_txn_unref(block_job_txn);
}
-void qmp_block_passwd(bool has_device, const char *device,
- bool has_node_name, const char *node_name,
- const char *password, Error **errp)
-{
- error_setg(errp,
- "Setting block passwords directly is no longer supported");
-}
-
BlockDirtyBitmapSha256 *qmp_x_debug_block_dirty_bitmap_sha256(const char *node,
const char *name,
Error **errp)
return ret;
}
-void qmp_block_resize(bool has_device, const char *device,
- bool has_node_name, const char *node_name,
- int64_t size, Error **errp)
+void coroutine_fn qmp_block_resize(bool has_device, const char *device,
+ bool has_node_name, const char *node_name,
+ int64_t size, Error **errp)
{
Error *local_err = NULL;
- BlockBackend *blk = NULL;
+ BlockBackend *blk;
BlockDriverState *bs;
- AioContext *aio_context;
+ AioContext *old_ctx;
bs = bdrv_lookup_bs(has_device ? device : NULL,
has_node_name ? node_name : NULL,
return;
}
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
if (size < 0) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "size", "a >0 size");
- goto out;
+ return;
}
if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_RESIZE, NULL)) {
error_setg(errp, QERR_DEVICE_IN_USE, device);
- goto out;
+ return;
}
blk = blk_new_with_bs(bs, BLK_PERM_RESIZE, BLK_PERM_ALL, errp);
if (!blk) {
- goto out;
+ return;
}
+ bdrv_co_lock(bs);
bdrv_drained_begin(bs);
+ bdrv_co_unlock(bs);
+
+ old_ctx = bdrv_co_enter(bs);
blk_truncate(blk, size, false, PREALLOC_MODE_OFF, 0, errp);
- bdrv_drained_end(bs);
+ bdrv_co_leave(bs, old_ctx);
-out:
+ bdrv_co_lock(bs);
+ bdrv_drained_end(bs);
blk_unref(blk);
- aio_context_release(aio_context);
+ bdrv_co_unlock(bs);
}
void qmp_block_stream(bool has_job_id, const char *job_id, const char *device,
bool has_base, const char *base,
bool has_base_node, const char *base_node,
bool has_backing_file, const char *backing_file,
+ bool has_bottom, const char *bottom,
bool has_speed, int64_t speed,
bool has_on_error, BlockdevOnError on_error,
+ bool has_filter_node_name, const char *filter_node_name,
bool has_auto_finalize, bool auto_finalize,
bool has_auto_dismiss, bool auto_dismiss,
Error **errp)
{
- BlockDriverState *bs, *iter;
+ BlockDriverState *bs, *iter, *iter_end;
BlockDriverState *base_bs = NULL;
+ BlockDriverState *bottom_bs = NULL;
AioContext *aio_context;
Error *local_err = NULL;
- const char *base_name = NULL;
int job_flags = JOB_DEFAULT;
+ if (has_base && has_base_node) {
+ error_setg(errp, "'base' and 'base-node' cannot be specified "
+ "at the same time");
+ return;
+ }
+
+ if (has_base && has_bottom) {
+ error_setg(errp, "'base' and 'bottom' cannot be specified "
+ "at the same time");
+ return;
+ }
+
+ if (has_bottom && has_base_node) {
+ error_setg(errp, "'bottom' and 'base-node' cannot be specified "
+ "at the same time");
+ return;
+ }
+
if (!has_on_error) {
on_error = BLOCKDEV_ON_ERROR_REPORT;
}
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
- if (has_base && has_base_node) {
- error_setg(errp, "'base' and 'base-node' cannot be specified "
- "at the same time");
- goto out;
- }
-
if (has_base) {
base_bs = bdrv_find_backing_image(bs, base);
if (base_bs == NULL) {
- error_setg(errp, QERR_BASE_NOT_FOUND, base);
+ error_setg(errp, "Can't find '%s' in the backing chain", base);
goto out;
}
assert(bdrv_get_aio_context(base_bs) == aio_context);
- base_name = base;
}
if (has_base_node) {
}
assert(bdrv_get_aio_context(base_bs) == aio_context);
bdrv_refresh_filename(base_bs);
- base_name = base_bs->filename;
}
- /* Check for op blockers in the whole chain between bs and base */
- for (iter = bs; iter && iter != base_bs;
+ if (has_bottom) {
+ bottom_bs = bdrv_lookup_bs(NULL, bottom, errp);
+ if (!bottom_bs) {
+ goto out;
+ }
+ if (!bottom_bs->drv) {
+ error_setg(errp, "Node '%s' is not open", bottom);
+ goto out;
+ }
+ if (bottom_bs->drv->is_filter) {
+ error_setg(errp, "Node '%s' is a filter, use a non-filter node "
+ "as 'bottom'", bottom);
+ goto out;
+ }
+ if (!bdrv_chain_contains(bs, bottom_bs)) {
+ error_setg(errp, "Node '%s' is not in a chain starting from '%s'",
+ bottom, device);
+ goto out;
+ }
+ assert(bdrv_get_aio_context(bottom_bs) == aio_context);
+ }
+
+ /*
+ * Check for op blockers in the whole chain between bs and base (or bottom)
+ */
+ iter_end = has_bottom ? bdrv_filter_or_cow_bs(bottom_bs) : base_bs;
+ 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)) {
goto out;
}
- /* backing_file string overrides base bs filename */
- base_name = has_backing_file ? backing_file : base_name;
-
if (has_auto_finalize && !auto_finalize) {
job_flags |= JOB_MANUAL_FINALIZE;
}
job_flags |= JOB_MANUAL_DISMISS;
}
- stream_start(has_job_id ? job_id : NULL, bs, base_bs, base_name,
- job_flags, has_speed ? speed : 0, on_error, &local_err);
+ stream_start(has_job_id ? job_id : NULL, bs, base_bs, backing_file,
+ bottom_bs, job_flags, has_speed ? speed : 0, on_error,
+ filter_node_name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
goto out;
}
} else if (has_base && base) {
base_bs = bdrv_find_backing_image(top_bs, base);
+ if (base_bs == NULL) {
+ error_setg(errp, "Can't find '%s' in the backing chain", base);
+ goto out;
+ }
} else {
base_bs = bdrv_find_base(top_bs);
- }
-
- if (base_bs == NULL) {
- error_setg(errp, QERR_BASE_NOT_FOUND, base ? base : "NULL");
- goto out;
+ if (base_bs == NULL) {
+ error_setg(errp, "There is no backimg image");
+ goto out;
+ }
}
assert(bdrv_get_aio_context(base_bs) == aio_context);
{
BlockJob *job = NULL;
BdrvDirtyBitmap *bmap = NULL;
+ BackupPerf perf = { .max_workers = 64 };
int job_flags = JOB_DEFAULT;
if (!backup->has_speed) {
backup->compress = false;
}
+ if (backup->x_perf) {
+ if (backup->x_perf->has_use_copy_range) {
+ perf.use_copy_range = backup->x_perf->use_copy_range;
+ }
+ if (backup->x_perf->has_max_workers) {
+ perf.max_workers = backup->x_perf->max_workers;
+ }
+ if (backup->x_perf->has_max_chunk) {
+ perf.max_chunk = backup->x_perf->max_chunk;
+ }
+ }
+
if ((backup->sync == MIRROR_SYNC_MODE_BITMAP) ||
(backup->sync == MIRROR_SYNC_MODE_INCREMENTAL)) {
/* done before desugaring 'incremental' to print the right message */
backup->sync, bmap, backup->bitmap_mode,
backup->compress,
backup->filter_node_name,
+ &perf,
backup->on_source_error,
backup->on_target_error,
job_flags, NULL, NULL, txn, errp);
}
if (granularity & (granularity - 1)) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "granularity",
- "power of 2");
+ "a power of 2");
return;
}
/* Check for the selected node name */
if (!options->has_node_name) {
- error_setg(errp, "Node name not specified");
+ error_setg(errp, "node-name not specified");
goto fail;
}
bs = bdrv_find_node(options->node_name);
if (!bs) {
- error_setg(errp, "Cannot find node named '%s'", options->node_name);
+ error_setg(errp, "Failed to find node with node-name='%s'",
+ options->node_name);
goto fail;
}
bs = bdrv_find_node(node_name);
if (!bs) {
- error_setg(errp, "Cannot find node %s", node_name);
+ error_setg(errp, "Failed to find node with node-name='%s'", node_name);
return;
}
if (bdrv_has_blk(bs)) {
BlockJobInfoList *qmp_query_block_jobs(Error **errp)
{
- BlockJobInfoList *head = NULL, **p_next = &head;
+ BlockJobInfoList *head = NULL, **tail = &head;
BlockJob *job;
for (job = block_job_next(NULL); job; job = block_job_next(job)) {
- BlockJobInfoList *elem;
+ BlockJobInfo *value;
AioContext *aio_context;
if (block_job_is_internal(job)) {
continue;
}
- elem = g_new0(BlockJobInfoList, 1);
aio_context = blk_get_aio_context(job->blk);
aio_context_acquire(aio_context);
- elem->value = block_job_query(job, errp);
+ value = block_job_query(job, errp);
aio_context_release(aio_context);
- if (!elem->value) {
- g_free(elem);
+ if (!value) {
qapi_free_BlockJobInfoList(head);
return NULL;
}
- *p_next = elem;
- p_next = &elem->next;
+ QAPI_LIST_APPEND(tail, value);
}
return head;
bs = bdrv_find_node(node_name);
if (!bs) {
- error_setg(errp, "Cannot find node %s", node_name);
+ error_setg(errp, "Failed to find node with node-name='%s'", node_name);
return;
}