#include "qemu/error-report.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
-#include "qapi/qmp/types.h"
-#include "qapi-visit.h"
+#include "qapi/qapi-commands-block.h"
+#include "qapi/qapi-commands-transaction.h"
+#include "qapi/qapi-visit-block-core.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qnum.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/error.h"
#include "qapi/qmp/qerror.h"
+#include "qapi/qmp/qlist.h"
#include "qapi/qobject-output-visitor.h"
#include "sysemu/sysemu.h"
#include "sysemu/iothread.h"
#include "block/block_int.h"
-#include "qmp-commands.h"
#include "block/trace.h"
#include "sysemu/arch_init.h"
#include "sysemu/qtest.h"
static int do_open_tray(const char *blk_name, const char *qdev_id,
bool force, Error **errp);
+static void blockdev_remove_medium(bool has_device, const char *device,
+ bool has_id, const char *id, Error **errp);
+static void blockdev_insert_medium(bool has_device, const char *device,
+ bool has_id, const char *id,
+ const char *node_name, Error **errp);
static const char *const if_name[IF_COUNT] = {
[IF_NONE] = "none",
aio_context_acquire(aio_context);
if (bs->job) {
- block_job_cancel(bs->job);
+ block_job_cancel(bs->job, false);
}
aio_context_release(aio_context);
case QTYPE_QSTRING: {
unsigned long long length;
- const char *str = qstring_get_str(qobject_to_qstring(entry->value));
+ const char *str = qstring_get_str(qobject_to(QString,
+ entry->value));
if (parse_uint_full(str, &length, 10) == 0 &&
length > 0 && length <= UINT_MAX) {
block_acct_add_interval(stats, (unsigned) length);
}
case QTYPE_QNUM: {
- int64_t length = qnum_get_int(qobject_to_qnum(entry->value));
+ int64_t length = qnum_get_int(qobject_to(QNum, entry->value));
if (length > 0 && length <= UINT_MAX) {
block_acct_add_interval(stats, (unsigned) length);
.name = "trans",
.type = QEMU_OPT_STRING,
.help = "chs translation (auto, lba, none)",
- },{
- .name = "boot",
- .type = QEMU_OPT_BOOL,
- .help = "(deprecated, ignored)",
},{
.name = "addr",
.type = QEMU_OPT_STRING,
goto fail;
}
- /* Deprecated option boot=[on|off] */
- if (qemu_opt_get(legacy_opts, "boot") != NULL) {
- fprintf(stderr, "qemu-kvm: boot=on|off is deprecated and will be "
- "ignored. Future versions will reject this parameter. Please "
- "update your scripts.\n");
- }
-
/* Other deprecated options */
if (!qtest_enabled()) {
for (i = 0; i < ARRAY_SIZE(deprecated); i++) {
if (bdrv_dirty_bitmap_frozen(state->bitmap)) {
error_setg(errp, "Cannot modify a frozen bitmap");
return;
+ } else if (bdrv_dirty_bitmap_qmp_locked(state->bitmap)) {
+ error_setg(errp, "Cannot modify a locked bitmap");
+ return;
} else if (!bdrv_dirty_bitmap_enabled(state->bitmap)) {
error_setg(errp, "Cannot clear a disabled bitmap");
return;
}
error_free(local_err);
- qmp_x_blockdev_remove_medium(has_device, device, has_id, id, errp);
+ blockdev_remove_medium(has_device, device, has_id, id, errp);
}
void qmp_block_passwd(bool has_device, const char *device,
}
}
-void qmp_x_blockdev_remove_medium(bool has_device, const char *device,
- bool has_id, const char *id, Error **errp)
+static void blockdev_remove_medium(bool has_device, const char *device,
+ bool has_id, const char *id, Error **errp)
{
BlockBackend *blk;
BlockDriverState *bs;
aio_context_release(aio_context);
}
+void qmp_blockdev_remove_medium(const char *id, Error **errp)
+{
+ blockdev_remove_medium(false, NULL, true, id, errp);
+}
+
static void qmp_blockdev_insert_anon_medium(BlockBackend *blk,
BlockDriverState *bs, Error **errp)
{
}
}
-void qmp_x_blockdev_insert_medium(bool has_device, const char *device,
- bool has_id, const char *id,
- const char *node_name, Error **errp)
+static void blockdev_insert_medium(bool has_device, const char *device,
+ bool has_id, const char *id,
+ const char *node_name, Error **errp)
{
BlockBackend *blk;
BlockDriverState *bs;
qmp_blockdev_insert_anon_medium(blk, bs, errp);
}
+void qmp_blockdev_insert_medium(const char *id, const char *node_name,
+ Error **errp)
+{
+ blockdev_insert_medium(false, NULL, true, id, node_name, errp);
+}
+
void qmp_blockdev_change_medium(bool has_device, const char *device,
bool has_id, const char *id,
const char *filename,
error_free(err);
err = NULL;
- qmp_x_blockdev_remove_medium(has_device, device, has_id, id, &err);
+ blockdev_remove_medium(has_device, device, has_id, id, &err);
if (err) {
error_propagate(errp, err);
goto fail;
if (!has_persistent) {
persistent = false;
}
- if (!has_autoload) {
- autoload = false;
- }
- if (has_autoload && !persistent) {
- error_setg(errp, "Autoload flag must be used only for persistent "
- "bitmaps");
- return;
+ if (has_autoload) {
+ warn_report("Autoload option is deprecated and its value is ignored");
}
if (persistent &&
}
bdrv_dirty_bitmap_set_persistance(bitmap, persistent);
- bdrv_dirty_bitmap_set_autoload(bitmap, autoload);
}
void qmp_block_dirty_bitmap_remove(const char *node, const char *name,
"Bitmap '%s' is currently frozen and cannot be removed",
name);
return;
+ } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) {
+ error_setg(errp,
+ "Bitmap '%s' is currently locked and cannot be removed",
+ name);
+ return;
}
if (bdrv_dirty_bitmap_get_persistance(bitmap)) {
"Bitmap '%s' is currently frozen and cannot be modified",
name);
return;
+ } else if (bdrv_dirty_bitmap_qmp_locked(bitmap)) {
+ error_setg(errp,
+ "Bitmap '%s' is currently locked and cannot be modified",
+ name);
+ return;
} else if (!bdrv_dirty_bitmap_enabled(bitmap)) {
error_setg(errp,
"Bitmap '%s' is currently disabled and cannot be cleared",
AioContext *aio_context;
QDict *options = NULL;
Error *local_err = NULL;
- int flags;
+ int flags, job_flags = BLOCK_JOB_DEFAULT;
int64_t size;
bool set_backing_hd = false;
if (!backup->has_job_id) {
backup->job_id = NULL;
}
+ if (!backup->has_auto_finalize) {
+ backup->auto_finalize = true;
+ }
+ if (!backup->has_auto_dismiss) {
+ backup->auto_dismiss = true;
+ }
if (!backup->has_compress) {
backup->compress = false;
}
bdrv_unref(target_bs);
goto out;
}
+ if (bdrv_dirty_bitmap_qmp_locked(bmap)) {
+ error_setg(errp,
+ "Bitmap '%s' is currently locked and cannot be used for "
+ "backup", backup->bitmap);
+ goto out;
+ }
+ }
+ if (!backup->auto_finalize) {
+ job_flags |= BLOCK_JOB_MANUAL_FINALIZE;
+ }
+ if (!backup->auto_dismiss) {
+ job_flags |= BLOCK_JOB_MANUAL_DISMISS;
}
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, bmap, backup->compress,
backup->on_source_error, backup->on_target_error,
- BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err);
+ job_flags, NULL, NULL, txn, &local_err);
bdrv_unref(target_bs);
if (local_err != NULL) {
error_propagate(errp, local_err);
Error *local_err = NULL;
AioContext *aio_context;
BlockJob *job = NULL;
+ int job_flags = BLOCK_JOB_DEFAULT;
if (!backup->has_speed) {
backup->speed = 0;
if (!backup->has_job_id) {
backup->job_id = NULL;
}
+ if (!backup->has_auto_finalize) {
+ backup->auto_finalize = true;
+ }
+ if (!backup->has_auto_dismiss) {
+ backup->auto_dismiss = true;
+ }
if (!backup->has_compress) {
backup->compress = false;
}
goto out;
}
}
+ if (!backup->auto_finalize) {
+ job_flags |= BLOCK_JOB_MANUAL_FINALIZE;
+ }
+ if (!backup->auto_dismiss) {
+ job_flags |= BLOCK_JOB_MANUAL_DISMISS;
+ }
job = backup_job_create(backup->job_id, bs, target_bs, backup->speed,
backup->sync, NULL, backup->compress,
backup->on_source_error, backup->on_target_error,
- BLOCK_JOB_DEFAULT, NULL, NULL, txn, &local_err);
+ job_flags, NULL, NULL, txn, &local_err);
if (local_err != NULL) {
error_propagate(errp, local_err);
}
return;
}
+ /* Early check to avoid creating target */
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_MIRROR_SOURCE, errp)) {
+ return;
+ }
+
aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context);
}
trace_qmp_block_job_cancel(job);
- block_job_cancel(job);
+ block_job_user_cancel(job, force, errp);
out:
aio_context_release(aio_context);
}
AioContext *aio_context;
BlockJob *job = find_block_job(device, &aio_context, errp);
- if (!job || block_job_user_paused(job)) {
+ if (!job) {
return;
}
trace_qmp_block_job_pause(job);
- block_job_user_pause(job);
+ block_job_user_pause(job, errp);
aio_context_release(aio_context);
}
AioContext *aio_context;
BlockJob *job = find_block_job(device, &aio_context, errp);
- if (!job || !block_job_user_paused(job)) {
+ if (!job) {
return;
}
trace_qmp_block_job_resume(job);
- block_job_user_resume(job);
+ block_job_user_resume(job, errp);
aio_context_release(aio_context);
}
aio_context_release(aio_context);
}
+void qmp_block_job_finalize(const char *id, Error **errp)
+{
+ AioContext *aio_context;
+ BlockJob *job = find_block_job(id, &aio_context, errp);
+
+ if (!job) {
+ return;
+ }
+
+ trace_qmp_block_job_finalize(job);
+ block_job_finalize(job, errp);
+ aio_context_release(aio_context);
+}
+
+void qmp_block_job_dismiss(const char *id, Error **errp)
+{
+ AioContext *aio_context;
+ BlockJob *job = find_block_job(id, &aio_context, errp);
+
+ if (!job) {
+ return;
+ }
+
+ trace_qmp_block_job_dismiss(job);
+ block_job_dismiss(&job, errp);
+ aio_context_release(aio_context);
+}
+
void qmp_change_backing_file(const char *device,
const char *image_node_name,
const char *backing_file,
QObject *obj;
Visitor *v = qobject_output_visitor_new(&obj);
QDict *qdict;
- const QDictEntry *ent;
Error *local_err = NULL;
visit_type_BlockdevOptions(v, NULL, &options, &local_err);
}
visit_complete(v, &obj);
- qdict = qobject_to_qdict(obj);
+ qdict = qobject_to(QDict, obj);
qdict_flatten(qdict);
- /*
- * Rewrite "backing": null to "backing": ""
- * TODO Rewrite "" to null instead, and perhaps not even here
- */
- for (ent = qdict_first(qdict); ent; ent = qdict_next(qdict, ent)) {
- char *dot = strrchr(ent->key, '.');
-
- if (!strcmp(dot ? dot + 1 : ent->key, "backing")
- && qobject_type(ent->value) == QTYPE_QNULL) {
- qdict_put(qdict, ent->key, qstring_new());
- }
- }
-
if (!qdict_get_try_str(qdict, "node-name")) {
error_setg(errp, "'node-name' must be specified for the root node");
goto fail;
aio_context_release(old_context);
}
+void qmp_x_block_latency_histogram_set(
+ const char *device,
+ bool has_boundaries, uint64List *boundaries,
+ bool has_boundaries_read, uint64List *boundaries_read,
+ bool has_boundaries_write, uint64List *boundaries_write,
+ bool has_boundaries_flush, uint64List *boundaries_flush,
+ Error **errp)
+{
+ BlockBackend *blk = blk_by_name(device);
+ BlockAcctStats *stats;
+
+ if (!blk) {
+ error_setg(errp, "Device '%s' not found", device);
+ return;
+ }
+ stats = blk_get_stats(blk);
+
+ if (!has_boundaries && !has_boundaries_read && !has_boundaries_write &&
+ !has_boundaries_flush)
+ {
+ block_latency_histograms_clear(stats);
+ return;
+ }
+
+ if (has_boundaries || has_boundaries_read) {
+ block_latency_histogram_set(
+ stats, BLOCK_ACCT_READ,
+ has_boundaries_read ? boundaries_read : boundaries);
+ }
+
+ if (has_boundaries || has_boundaries_write) {
+ block_latency_histogram_set(
+ stats, BLOCK_ACCT_WRITE,
+ has_boundaries_write ? boundaries_write : boundaries);
+ }
+
+ if (has_boundaries || has_boundaries_flush) {
+ block_latency_histogram_set(
+ stats, BLOCK_ACCT_FLUSH,
+ has_boundaries_flush ? boundaries_flush : boundaries);
+ }
+}
+
QemuOptsList qemu_common_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),