From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, peter.maydell@linaro.org, qemu-devel@nongnu.org
Subject: [PULL 09/29] block: Move system emulator QMP commands to block/qapi-sysemu.c
Date: Fri, 6 Mar 2020 18:14:38 +0100 [thread overview]
Message-ID: <20200306171458.1848-10-kwolf@redhat.com> (raw)
In-Reply-To: <20200306171458.1848-1-kwolf@redhat.com>
These commands make only sense for system emulators and their
implementations call functions that don't exist in tools (e.g. to
resolve qdev IDs). Move them out so that blockdev.c can be linked to
qemu-storage-daemon.
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
Message-Id: <20200224143008.13362-4-kwolf@redhat.com>
Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
block/qapi-sysemu.c | 590 ++++++++++++++++++++++++++++++++++++++++++++
blockdev.c | 559 -----------------------------------------
block/Makefile.objs | 2 +
3 files changed, 592 insertions(+), 559 deletions(-)
create mode 100644 block/qapi-sysemu.c
diff --git a/block/qapi-sysemu.c b/block/qapi-sysemu.c
new file mode 100644
index 0000000000..8498402ad4
--- /dev/null
+++ b/block/qapi-sysemu.c
@@ -0,0 +1,590 @@
+/*
+ * QMP command handlers specific to the system emulators
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * later. See the COPYING file in the top-level directory.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+
+#include "qapi/error.h"
+#include "qapi/qapi-commands-block.h"
+#include "qapi/qmp/qdict.h"
+#include "sysemu/block-backend.h"
+#include "sysemu/blockdev.h"
+
+static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id,
+ Error **errp)
+{
+ BlockBackend *blk;
+
+ if (!blk_name == !qdev_id) {
+ error_setg(errp, "Need exactly one of 'device' and 'id'");
+ return NULL;
+ }
+
+ if (qdev_id) {
+ blk = blk_by_qdev_id(qdev_id, errp);
+ } else {
+ blk = blk_by_name(blk_name);
+ if (blk == NULL) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", blk_name);
+ }
+ }
+
+ return blk;
+}
+
+/*
+ * Attempt to open the tray of @device.
+ * If @force, ignore its tray lock.
+ * Else, if the tray is locked, don't open it, but ask the guest to open it.
+ * On error, store an error through @errp and return -errno.
+ * If @device does not exist, return -ENODEV.
+ * If it has no removable media, return -ENOTSUP.
+ * If it has no tray, return -ENOSYS.
+ * If the guest was asked to open the tray, return -EINPROGRESS.
+ * Else, return 0.
+ */
+static int do_open_tray(const char *blk_name, const char *qdev_id,
+ bool force, Error **errp)
+{
+ BlockBackend *blk;
+ const char *device = qdev_id ?: blk_name;
+ bool locked;
+
+ blk = qmp_get_blk(blk_name, qdev_id, errp);
+ if (!blk) {
+ return -ENODEV;
+ }
+
+ if (!blk_dev_has_removable_media(blk)) {
+ error_setg(errp, "Device '%s' is not removable", device);
+ return -ENOTSUP;
+ }
+
+ if (!blk_dev_has_tray(blk)) {
+ error_setg(errp, "Device '%s' does not have a tray", device);
+ return -ENOSYS;
+ }
+
+ if (blk_dev_is_tray_open(blk)) {
+ return 0;
+ }
+
+ locked = blk_dev_is_medium_locked(blk);
+ if (locked) {
+ blk_dev_eject_request(blk, force);
+ }
+
+ if (!locked || force) {
+ blk_dev_change_media_cb(blk, false, &error_abort);
+ }
+
+ if (locked && !force) {
+ error_setg(errp, "Device '%s' is locked and force was not specified, "
+ "wait for tray to open and try again", device);
+ return -EINPROGRESS;
+ }
+
+ return 0;
+}
+
+void qmp_blockdev_open_tray(bool has_device, const char *device,
+ bool has_id, const char *id,
+ bool has_force, bool force,
+ Error **errp)
+{
+ Error *local_err = NULL;
+ int rc;
+
+ if (!has_force) {
+ force = false;
+ }
+ rc = do_open_tray(has_device ? device : NULL,
+ has_id ? id : NULL,
+ force, &local_err);
+ if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ error_free(local_err);
+}
+
+void qmp_blockdev_close_tray(bool has_device, const char *device,
+ bool has_id, const char *id,
+ Error **errp)
+{
+ BlockBackend *blk;
+ Error *local_err = NULL;
+
+ device = has_device ? device : NULL;
+ id = has_id ? id : NULL;
+
+ blk = qmp_get_blk(device, id, errp);
+ if (!blk) {
+ return;
+ }
+
+ if (!blk_dev_has_removable_media(blk)) {
+ error_setg(errp, "Device '%s' is not removable", device ?: id);
+ return;
+ }
+
+ if (!blk_dev_has_tray(blk)) {
+ /* Ignore this command on tray-less devices */
+ return;
+ }
+
+ if (!blk_dev_is_tray_open(blk)) {
+ return;
+ }
+
+ blk_dev_change_media_cb(blk, true, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+}
+
+static void blockdev_remove_medium(bool has_device, const char *device,
+ bool has_id, const char *id, Error **errp)
+{
+ BlockBackend *blk;
+ BlockDriverState *bs;
+ AioContext *aio_context;
+ bool has_attached_device;
+
+ device = has_device ? device : NULL;
+ id = has_id ? id : NULL;
+
+ blk = qmp_get_blk(device, id, errp);
+ if (!blk) {
+ return;
+ }
+
+ /* For BBs without a device, we can exchange the BDS tree at will */
+ has_attached_device = blk_get_attached_dev(blk);
+
+ if (has_attached_device && !blk_dev_has_removable_media(blk)) {
+ error_setg(errp, "Device '%s' is not removable", device ?: id);
+ return;
+ }
+
+ if (has_attached_device && blk_dev_has_tray(blk) &&
+ !blk_dev_is_tray_open(blk))
+ {
+ error_setg(errp, "Tray of device '%s' is not open", device ?: id);
+ return;
+ }
+
+ bs = blk_bs(blk);
+ if (!bs) {
+ return;
+ }
+
+ aio_context = bdrv_get_aio_context(bs);
+ aio_context_acquire(aio_context);
+
+ if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
+ goto out;
+ }
+
+ blk_remove_bs(blk);
+
+ if (!blk_dev_has_tray(blk)) {
+ /* For tray-less devices, blockdev-open-tray is a no-op (or may not be
+ * 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, &error_abort);
+ }
+
+out:
+ 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)
+{
+ 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);
+
+ if (has_device && !blk_dev_has_removable_media(blk)) {
+ error_setg(errp, "Device is not removable");
+ return;
+ }
+
+ if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
+ error_setg(errp, "Tray of the device is not open");
+ return;
+ }
+
+ if (blk_bs(blk)) {
+ error_setg(errp, "There already is a medium in the device");
+ return;
+ }
+
+ 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
+ * called at all); therefore, the medium needs to be pushed into the
+ * 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, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ blk_remove_bs(blk);
+ return;
+ }
+ }
+}
+
+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;
+
+ blk = qmp_get_blk(has_device ? device : NULL,
+ has_id ? id : NULL,
+ errp);
+ if (!blk) {
+ return;
+ }
+
+ bs = bdrv_find_node(node_name);
+ if (!bs) {
+ error_setg(errp, "Node '%s' not found", node_name);
+ return;
+ }
+
+ if (bdrv_has_blk(bs)) {
+ error_setg(errp, "Node '%s' is already in use", node_name);
+ return;
+ }
+
+ 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,
+ bool has_format, const char *format,
+ bool has_read_only,
+ BlockdevChangeReadOnlyMode read_only,
+ Error **errp)
+{
+ BlockBackend *blk;
+ BlockDriverState *medium_bs = NULL;
+ int bdrv_flags;
+ bool detect_zeroes;
+ int rc;
+ QDict *options = NULL;
+ Error *err = NULL;
+
+ blk = qmp_get_blk(has_device ? device : NULL,
+ has_id ? id : NULL,
+ errp);
+ if (!blk) {
+ goto fail;
+ }
+
+ if (blk_bs(blk)) {
+ blk_update_root_state(blk);
+ }
+
+ bdrv_flags = blk_get_open_flags_from_root_state(blk);
+ bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
+ BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
+
+ if (!has_read_only) {
+ read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
+ }
+
+ switch (read_only) {
+ case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
+ break;
+
+ case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
+ bdrv_flags &= ~BDRV_O_RDWR;
+ break;
+
+ case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
+ bdrv_flags |= BDRV_O_RDWR;
+ break;
+
+ default:
+ abort();
+ }
+
+ options = qdict_new();
+ detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
+ qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
+
+ if (has_format) {
+ qdict_put_str(options, "driver", format);
+ }
+
+ medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
+ if (!medium_bs) {
+ goto fail;
+ }
+
+ rc = do_open_tray(has_device ? device : NULL,
+ has_id ? id : NULL,
+ false, &err);
+ if (rc && rc != -ENOSYS) {
+ error_propagate(errp, err);
+ goto fail;
+ }
+ error_free(err);
+ err = NULL;
+
+ blockdev_remove_medium(has_device, device, has_id, id, &err);
+ if (err) {
+ error_propagate(errp, err);
+ goto fail;
+ }
+
+ qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
+ if (err) {
+ error_propagate(errp, err);
+ goto fail;
+ }
+
+ qmp_blockdev_close_tray(has_device, device, has_id, id, errp);
+
+fail:
+ /* If the medium has been inserted, the device has its own reference, so
+ * ours must be relinquished; and if it has not been inserted successfully,
+ * the reference must be relinquished anyway */
+ bdrv_unref(medium_bs);
+}
+
+void qmp_eject(bool has_device, const char *device,
+ bool has_id, const char *id,
+ bool has_force, bool force, Error **errp)
+{
+ Error *local_err = NULL;
+ int rc;
+
+ if (!has_force) {
+ force = false;
+ }
+
+ rc = do_open_tray(has_device ? device : NULL,
+ has_id ? id : NULL,
+ force, &local_err);
+ if (rc && rc != -ENOSYS) {
+ error_propagate(errp, local_err);
+ return;
+ }
+ error_free(local_err);
+
+ blockdev_remove_medium(has_device, device, has_id, id, errp);
+}
+
+/* throttling disk I/O limits */
+void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
+{
+ ThrottleConfig cfg;
+ BlockDriverState *bs;
+ BlockBackend *blk;
+ AioContext *aio_context;
+
+ blk = qmp_get_blk(arg->has_device ? arg->device : NULL,
+ arg->has_id ? arg->id : NULL,
+ errp);
+ if (!blk) {
+ return;
+ }
+
+ aio_context = blk_get_aio_context(blk);
+ aio_context_acquire(aio_context);
+
+ bs = blk_bs(blk);
+ if (!bs) {
+ error_setg(errp, "Device has no medium");
+ goto out;
+ }
+
+ throttle_config_init(&cfg);
+ cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
+ cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd;
+ cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
+
+ cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
+ cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd;
+ cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
+
+ if (arg->has_bps_max) {
+ cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
+ }
+ if (arg->has_bps_rd_max) {
+ cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
+ }
+ if (arg->has_bps_wr_max) {
+ cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
+ }
+ if (arg->has_iops_max) {
+ cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
+ }
+ if (arg->has_iops_rd_max) {
+ cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
+ }
+ if (arg->has_iops_wr_max) {
+ cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
+ }
+
+ if (arg->has_bps_max_length) {
+ cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
+ }
+ if (arg->has_bps_rd_max_length) {
+ cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
+ }
+ if (arg->has_bps_wr_max_length) {
+ cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
+ }
+ if (arg->has_iops_max_length) {
+ cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
+ }
+ if (arg->has_iops_rd_max_length) {
+ cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
+ }
+ if (arg->has_iops_wr_max_length) {
+ cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
+ }
+
+ if (arg->has_iops_size) {
+ cfg.op_size = arg->iops_size;
+ }
+
+ if (!throttle_is_valid(&cfg, errp)) {
+ goto out;
+ }
+
+ if (throttle_enabled(&cfg)) {
+ /* Enable I/O limits if they're not enabled yet, otherwise
+ * just update the throttling group. */
+ if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
+ blk_io_limits_enable(blk,
+ arg->has_group ? arg->group :
+ arg->has_device ? arg->device :
+ arg->id);
+ } else if (arg->has_group) {
+ blk_io_limits_update_group(blk, arg->group);
+ }
+ /* Set the new throttling configuration */
+ blk_set_io_limits(blk, &cfg);
+ } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
+ /* If all throttling settings are set to 0, disable I/O limits */
+ blk_io_limits_disable(blk);
+ }
+
+out:
+ aio_context_release(aio_context);
+}
+
+void qmp_block_latency_histogram_set(
+ const char *id,
+ 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 = qmp_get_blk(NULL, id, errp);
+ BlockAcctStats *stats;
+ int ret;
+
+ if (!blk) {
+ 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) {
+ ret = block_latency_histogram_set(
+ stats, BLOCK_ACCT_READ,
+ has_boundaries_read ? boundaries_read : boundaries);
+ if (ret) {
+ error_setg(errp, "Device '%s' set read boundaries fail", id);
+ return;
+ }
+ }
+
+ if (has_boundaries || has_boundaries_write) {
+ ret = block_latency_histogram_set(
+ stats, BLOCK_ACCT_WRITE,
+ has_boundaries_write ? boundaries_write : boundaries);
+ if (ret) {
+ error_setg(errp, "Device '%s' set write boundaries fail", id);
+ return;
+ }
+ }
+
+ if (has_boundaries || has_boundaries_flush) {
+ ret = block_latency_histogram_set(
+ stats, BLOCK_ACCT_FLUSH,
+ has_boundaries_flush ? boundaries_flush : boundaries);
+ if (ret) {
+ error_setg(errp, "Device '%s' set flush boundaries fail", id);
+ return;
+ }
+ }
+}
diff --git a/blockdev.c b/blockdev.c
index 011dcfec27..3e44fa766b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -67,14 +67,6 @@
static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
-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",
[IF_IDE] = "ide",
@@ -1047,29 +1039,6 @@ static BlockDriverState *qmp_get_root_bs(const char *name, Error **errp)
return bs;
}
-static BlockBackend *qmp_get_blk(const char *blk_name, const char *qdev_id,
- Error **errp)
-{
- BlockBackend *blk;
-
- if (!blk_name == !qdev_id) {
- error_setg(errp, "Need exactly one of 'device' and 'id'");
- return NULL;
- }
-
- if (qdev_id) {
- blk = blk_by_qdev_id(qdev_id, errp);
- } else {
- blk = blk_by_name(blk_name);
- if (blk == NULL) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", blk_name);
- }
- }
-
- return blk;
-}
-
void hmp_commit(Monitor *mon, const QDict *qdict)
{
const char *device = qdict_get_str(qdict, "device");
@@ -2508,29 +2477,6 @@ exit:
job_txn_unref(block_job_txn);
}
-void qmp_eject(bool has_device, const char *device,
- bool has_id, const char *id,
- bool has_force, bool force, Error **errp)
-{
- Error *local_err = NULL;
- int rc;
-
- if (!has_force) {
- force = false;
- }
-
- rc = do_open_tray(has_device ? device : NULL,
- has_id ? id : NULL,
- force, &local_err);
- if (rc && rc != -ENOSYS) {
- error_propagate(errp, local_err);
- return;
- }
- error_free(local_err);
-
- blockdev_remove_medium(has_device, device, has_id, id, errp);
-}
-
void qmp_block_passwd(bool has_device, const char *device,
bool has_node_name, const char *node_name,
const char *password, Error **errp)
@@ -2539,455 +2485,6 @@ void qmp_block_passwd(bool has_device, const char *device,
"Setting block passwords directly is no longer supported");
}
-/*
- * Attempt to open the tray of @device.
- * If @force, ignore its tray lock.
- * Else, if the tray is locked, don't open it, but ask the guest to open it.
- * On error, store an error through @errp and return -errno.
- * If @device does not exist, return -ENODEV.
- * If it has no removable media, return -ENOTSUP.
- * If it has no tray, return -ENOSYS.
- * If the guest was asked to open the tray, return -EINPROGRESS.
- * Else, return 0.
- */
-static int do_open_tray(const char *blk_name, const char *qdev_id,
- bool force, Error **errp)
-{
- BlockBackend *blk;
- const char *device = qdev_id ?: blk_name;
- bool locked;
-
- blk = qmp_get_blk(blk_name, qdev_id, errp);
- if (!blk) {
- return -ENODEV;
- }
-
- if (!blk_dev_has_removable_media(blk)) {
- error_setg(errp, "Device '%s' is not removable", device);
- return -ENOTSUP;
- }
-
- if (!blk_dev_has_tray(blk)) {
- error_setg(errp, "Device '%s' does not have a tray", device);
- return -ENOSYS;
- }
-
- if (blk_dev_is_tray_open(blk)) {
- return 0;
- }
-
- locked = blk_dev_is_medium_locked(blk);
- if (locked) {
- blk_dev_eject_request(blk, force);
- }
-
- if (!locked || force) {
- blk_dev_change_media_cb(blk, false, &error_abort);
- }
-
- if (locked && !force) {
- error_setg(errp, "Device '%s' is locked and force was not specified, "
- "wait for tray to open and try again", device);
- return -EINPROGRESS;
- }
-
- return 0;
-}
-
-void qmp_blockdev_open_tray(bool has_device, const char *device,
- bool has_id, const char *id,
- bool has_force, bool force,
- Error **errp)
-{
- Error *local_err = NULL;
- int rc;
-
- if (!has_force) {
- force = false;
- }
- rc = do_open_tray(has_device ? device : NULL,
- has_id ? id : NULL,
- force, &local_err);
- if (rc && rc != -ENOSYS && rc != -EINPROGRESS) {
- error_propagate(errp, local_err);
- return;
- }
- error_free(local_err);
-}
-
-void qmp_blockdev_close_tray(bool has_device, const char *device,
- bool has_id, const char *id,
- Error **errp)
-{
- BlockBackend *blk;
- Error *local_err = NULL;
-
- device = has_device ? device : NULL;
- id = has_id ? id : NULL;
-
- blk = qmp_get_blk(device, id, errp);
- if (!blk) {
- return;
- }
-
- if (!blk_dev_has_removable_media(blk)) {
- error_setg(errp, "Device '%s' is not removable", device ?: id);
- return;
- }
-
- if (!blk_dev_has_tray(blk)) {
- /* Ignore this command on tray-less devices */
- return;
- }
-
- if (!blk_dev_is_tray_open(blk)) {
- return;
- }
-
- blk_dev_change_media_cb(blk, true, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- return;
- }
-}
-
-static void blockdev_remove_medium(bool has_device, const char *device,
- bool has_id, const char *id, Error **errp)
-{
- BlockBackend *blk;
- BlockDriverState *bs;
- AioContext *aio_context;
- bool has_attached_device;
-
- device = has_device ? device : NULL;
- id = has_id ? id : NULL;
-
- blk = qmp_get_blk(device, id, errp);
- if (!blk) {
- return;
- }
-
- /* For BBs without a device, we can exchange the BDS tree at will */
- has_attached_device = blk_get_attached_dev(blk);
-
- if (has_attached_device && !blk_dev_has_removable_media(blk)) {
- error_setg(errp, "Device '%s' is not removable", device ?: id);
- return;
- }
-
- if (has_attached_device && blk_dev_has_tray(blk) &&
- !blk_dev_is_tray_open(blk))
- {
- error_setg(errp, "Tray of device '%s' is not open", device ?: id);
- return;
- }
-
- bs = blk_bs(blk);
- if (!bs) {
- return;
- }
-
- aio_context = bdrv_get_aio_context(bs);
- aio_context_acquire(aio_context);
-
- if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
- goto out;
- }
-
- blk_remove_bs(blk);
-
- if (!blk_dev_has_tray(blk)) {
- /* For tray-less devices, blockdev-open-tray is a no-op (or may not be
- * 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, &error_abort);
- }
-
-out:
- 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)
-{
- 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);
-
- if (has_device && !blk_dev_has_removable_media(blk)) {
- error_setg(errp, "Device is not removable");
- return;
- }
-
- if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
- error_setg(errp, "Tray of the device is not open");
- return;
- }
-
- if (blk_bs(blk)) {
- error_setg(errp, "There already is a medium in the device");
- return;
- }
-
- 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
- * called at all); therefore, the medium needs to be pushed into the
- * 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, &local_err);
- if (local_err) {
- error_propagate(errp, local_err);
- blk_remove_bs(blk);
- return;
- }
- }
-}
-
-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;
-
- blk = qmp_get_blk(has_device ? device : NULL,
- has_id ? id : NULL,
- errp);
- if (!blk) {
- return;
- }
-
- bs = bdrv_find_node(node_name);
- if (!bs) {
- error_setg(errp, "Node '%s' not found", node_name);
- return;
- }
-
- if (bdrv_has_blk(bs)) {
- error_setg(errp, "Node '%s' is already in use", node_name);
- return;
- }
-
- 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,
- bool has_format, const char *format,
- bool has_read_only,
- BlockdevChangeReadOnlyMode read_only,
- Error **errp)
-{
- BlockBackend *blk;
- BlockDriverState *medium_bs = NULL;
- int bdrv_flags;
- bool detect_zeroes;
- int rc;
- QDict *options = NULL;
- Error *err = NULL;
-
- blk = qmp_get_blk(has_device ? device : NULL,
- has_id ? id : NULL,
- errp);
- if (!blk) {
- goto fail;
- }
-
- if (blk_bs(blk)) {
- blk_update_root_state(blk);
- }
-
- bdrv_flags = blk_get_open_flags_from_root_state(blk);
- bdrv_flags &= ~(BDRV_O_TEMPORARY | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING |
- BDRV_O_PROTOCOL | BDRV_O_AUTO_RDONLY);
-
- if (!has_read_only) {
- read_only = BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN;
- }
-
- switch (read_only) {
- case BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN:
- break;
-
- case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_ONLY:
- bdrv_flags &= ~BDRV_O_RDWR;
- break;
-
- case BLOCKDEV_CHANGE_READ_ONLY_MODE_READ_WRITE:
- bdrv_flags |= BDRV_O_RDWR;
- break;
-
- default:
- abort();
- }
-
- options = qdict_new();
- detect_zeroes = blk_get_detect_zeroes_from_root_state(blk);
- qdict_put_str(options, "detect-zeroes", detect_zeroes ? "on" : "off");
-
- if (has_format) {
- qdict_put_str(options, "driver", format);
- }
-
- medium_bs = bdrv_open(filename, NULL, options, bdrv_flags, errp);
- if (!medium_bs) {
- goto fail;
- }
-
- rc = do_open_tray(has_device ? device : NULL,
- has_id ? id : NULL,
- false, &err);
- if (rc && rc != -ENOSYS) {
- error_propagate(errp, err);
- goto fail;
- }
- error_free(err);
- err = NULL;
-
- blockdev_remove_medium(has_device, device, has_id, id, &err);
- if (err) {
- error_propagate(errp, err);
- goto fail;
- }
-
- qmp_blockdev_insert_anon_medium(blk, medium_bs, &err);
- if (err) {
- error_propagate(errp, err);
- goto fail;
- }
-
- qmp_blockdev_close_tray(has_device, device, has_id, id, errp);
-
-fail:
- /* If the medium has been inserted, the device has its own reference, so
- * ours must be relinquished; and if it has not been inserted successfully,
- * the reference must be relinquished anyway */
- bdrv_unref(medium_bs);
-}
-
-/* throttling disk I/O limits */
-void qmp_block_set_io_throttle(BlockIOThrottle *arg, Error **errp)
-{
- ThrottleConfig cfg;
- BlockDriverState *bs;
- BlockBackend *blk;
- AioContext *aio_context;
-
- blk = qmp_get_blk(arg->has_device ? arg->device : NULL,
- arg->has_id ? arg->id : NULL,
- errp);
- if (!blk) {
- return;
- }
-
- aio_context = blk_get_aio_context(blk);
- aio_context_acquire(aio_context);
-
- bs = blk_bs(blk);
- if (!bs) {
- error_setg(errp, "Device has no medium");
- goto out;
- }
-
- throttle_config_init(&cfg);
- cfg.buckets[THROTTLE_BPS_TOTAL].avg = arg->bps;
- cfg.buckets[THROTTLE_BPS_READ].avg = arg->bps_rd;
- cfg.buckets[THROTTLE_BPS_WRITE].avg = arg->bps_wr;
-
- cfg.buckets[THROTTLE_OPS_TOTAL].avg = arg->iops;
- cfg.buckets[THROTTLE_OPS_READ].avg = arg->iops_rd;
- cfg.buckets[THROTTLE_OPS_WRITE].avg = arg->iops_wr;
-
- if (arg->has_bps_max) {
- cfg.buckets[THROTTLE_BPS_TOTAL].max = arg->bps_max;
- }
- if (arg->has_bps_rd_max) {
- cfg.buckets[THROTTLE_BPS_READ].max = arg->bps_rd_max;
- }
- if (arg->has_bps_wr_max) {
- cfg.buckets[THROTTLE_BPS_WRITE].max = arg->bps_wr_max;
- }
- if (arg->has_iops_max) {
- cfg.buckets[THROTTLE_OPS_TOTAL].max = arg->iops_max;
- }
- if (arg->has_iops_rd_max) {
- cfg.buckets[THROTTLE_OPS_READ].max = arg->iops_rd_max;
- }
- if (arg->has_iops_wr_max) {
- cfg.buckets[THROTTLE_OPS_WRITE].max = arg->iops_wr_max;
- }
-
- if (arg->has_bps_max_length) {
- cfg.buckets[THROTTLE_BPS_TOTAL].burst_length = arg->bps_max_length;
- }
- if (arg->has_bps_rd_max_length) {
- cfg.buckets[THROTTLE_BPS_READ].burst_length = arg->bps_rd_max_length;
- }
- if (arg->has_bps_wr_max_length) {
- cfg.buckets[THROTTLE_BPS_WRITE].burst_length = arg->bps_wr_max_length;
- }
- if (arg->has_iops_max_length) {
- cfg.buckets[THROTTLE_OPS_TOTAL].burst_length = arg->iops_max_length;
- }
- if (arg->has_iops_rd_max_length) {
- cfg.buckets[THROTTLE_OPS_READ].burst_length = arg->iops_rd_max_length;
- }
- if (arg->has_iops_wr_max_length) {
- cfg.buckets[THROTTLE_OPS_WRITE].burst_length = arg->iops_wr_max_length;
- }
-
- if (arg->has_iops_size) {
- cfg.op_size = arg->iops_size;
- }
-
- if (!throttle_is_valid(&cfg, errp)) {
- goto out;
- }
-
- if (throttle_enabled(&cfg)) {
- /* Enable I/O limits if they're not enabled yet, otherwise
- * just update the throttling group. */
- if (!blk_get_public(blk)->throttle_group_member.throttle_state) {
- blk_io_limits_enable(blk,
- arg->has_group ? arg->group :
- arg->has_device ? arg->device :
- arg->id);
- } else if (arg->has_group) {
- blk_io_limits_update_group(blk, arg->group);
- }
- /* Set the new throttling configuration */
- blk_set_io_limits(blk, &cfg);
- } else if (blk_get_public(blk)->throttle_group_member.throttle_state) {
- /* If all throttling settings are set to 0, disable I/O limits */
- blk_io_limits_disable(blk);
- }
-
-out:
- aio_context_release(aio_context);
-}
-
void qmp_block_dirty_bitmap_add(const char *node, const char *name,
bool has_granularity, uint32_t granularity,
bool has_persistent, bool persistent,
@@ -4595,62 +4092,6 @@ void qmp_x_blockdev_set_iothread(const char *node_name, StrOrNull *iothread,
aio_context_release(old_context);
}
-void qmp_block_latency_histogram_set(
- const char *id,
- 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 = qmp_get_blk(NULL, id, errp);
- BlockAcctStats *stats;
- int ret;
-
- if (!blk) {
- 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) {
- ret = block_latency_histogram_set(
- stats, BLOCK_ACCT_READ,
- has_boundaries_read ? boundaries_read : boundaries);
- if (ret) {
- error_setg(errp, "Device '%s' set read boundaries fail", id);
- return;
- }
- }
-
- if (has_boundaries || has_boundaries_write) {
- ret = block_latency_histogram_set(
- stats, BLOCK_ACCT_WRITE,
- has_boundaries_write ? boundaries_write : boundaries);
- if (ret) {
- error_setg(errp, "Device '%s' set write boundaries fail", id);
- return;
- }
- }
-
- if (has_boundaries || has_boundaries_flush) {
- ret = block_latency_histogram_set(
- stats, BLOCK_ACCT_FLUSH,
- has_boundaries_flush ? boundaries_flush : boundaries);
- if (ret) {
- error_setg(errp, "Device '%s' set flush boundaries fail", id);
- return;
- }
- }
-}
-
QemuOptsList qemu_common_drive_opts = {
.name = "drive",
.head = QTAILQ_HEAD_INITIALIZER(qemu_common_drive_opts.head),
diff --git a/block/Makefile.objs b/block/Makefile.objs
index 3bcb35c81d..e06cf0b284 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -48,6 +48,8 @@ block-obj-y += filter-compress.o
common-obj-y += stream.o
+common-obj-y += qapi-sysemu.o
+
nfs.o-libs := $(LIBNFS_LIBS)
iscsi.o-cflags := $(LIBISCSI_CFLAGS)
iscsi.o-libs := $(LIBISCSI_LIBS)
--
2.20.1
next prev parent reply other threads:[~2020-03-06 17:35 UTC|newest]
Thread overview: 36+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-06 17:14 [PULL 00/29] Block layer patches Kevin Wolf
2020-03-06 17:14 ` [PULL 01/29] qcow2: Fix alloc_cluster_abort() for pre-existing clusters Kevin Wolf
2020-03-06 17:14 ` [PULL 02/29] iotests/026: Test EIO on preallocated zero cluster Kevin Wolf
2020-03-06 17:14 ` [PULL 03/29] iotests/026: Test EIO on allocation in a data-file Kevin Wolf
2020-03-06 17:14 ` [PULL 04/29] block: Fix leak in bdrv_create_file_fallback() Kevin Wolf
2020-03-06 17:14 ` [PULL 05/29] block: Introduce 'bdrv_reopen_commit_post' step Kevin Wolf
2020-03-06 17:14 ` [PULL 06/29] block/qcow2: Move bitmap reopen into bdrv_reopen_commit_post Kevin Wolf
2020-03-06 17:14 ` [PULL 07/29] qemu-storage-daemon: Add barebone tool Kevin Wolf
2020-03-06 17:14 ` [PULL 08/29] stubs: Add arch_type Kevin Wolf
2020-03-06 17:14 ` Kevin Wolf [this message]
2020-03-06 17:14 ` [PULL 10/29] block: Move common QMP commands to block-core QAPI module Kevin Wolf
2020-03-06 17:14 ` [PULL 11/29] block: Move sysemu QMP commands to QAPI block module Kevin Wolf
2020-03-06 17:14 ` [PULL 12/29] qemu-storage-daemon: Add --blockdev option Kevin Wolf
2020-03-06 17:14 ` [PULL 13/29] qapi: Flatten object-add Kevin Wolf
2020-07-08 15:48 ` Paolo Bonzini
2020-07-08 16:05 ` Kevin Wolf
2020-07-08 16:12 ` Paolo Bonzini
2020-07-09 10:26 ` Markus Armbruster
2020-03-06 17:14 ` [PULL 14/29] qemu-storage-daemon: Add --object option Kevin Wolf
2020-03-06 17:14 ` [PULL 15/29] qemu-storage-daemon: Add --nbd-server option Kevin Wolf
2020-03-06 17:14 ` [PULL 16/29] blockdev-nbd: Boxed argument type for nbd-server-add Kevin Wolf
2020-03-06 17:14 ` [PULL 17/29] qemu-storage-daemon: Add --export option Kevin Wolf
2020-03-06 17:14 ` [PULL 18/29] qemu-storage-daemon: Add main loop Kevin Wolf
2020-03-06 17:14 ` [PULL 19/29] qemu-storage-daemon: Add --chardev option Kevin Wolf
2020-03-06 17:14 ` [PULL 20/29] stubs: Update monitor stubs for qemu-storage-daemon Kevin Wolf
2020-03-06 17:14 ` [PULL 21/29] qapi: Create 'pragma' module Kevin Wolf
2020-03-06 17:14 ` [PULL 22/29] monitor: Create QAPIfied monitor_init() Kevin Wolf
2020-03-06 17:14 ` [PULL 23/29] qmp: Fail gracefully if chardev is already in use Kevin Wolf
2020-03-06 17:14 ` [PULL 24/29] hmp: " Kevin Wolf
2020-03-06 17:14 ` [PULL 25/29] monitor: Add allow_hmp parameter to monitor_init() Kevin Wolf
2020-03-06 17:14 ` [PULL 26/29] qemu-storage-daemon: Add --monitor option Kevin Wolf
2020-03-06 17:14 ` [PULL 27/29] block/rbd: Add support for ceph namespaces Kevin Wolf
2020-03-06 17:14 ` [PULL 28/29] iotests: Refactor blockdev-reopen test for iothreads Kevin Wolf
2020-03-06 17:14 ` [PULL 29/29] block: bdrv_reopen() with backing file in different AioContext Kevin Wolf
2020-03-06 19:16 ` [PULL 00/29] Block layer patches no-reply
2020-03-06 19:26 ` Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200306171458.1848-10-kwolf@redhat.com \
--to=kwolf@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).