aboutsummaryrefslogtreecommitdiff
path: root/blockdev.c
diff options
context:
space:
mode:
Diffstat (limited to 'blockdev.c')
-rw-r--r--blockdev.c64
1 files changed, 58 insertions, 6 deletions
diff --git a/blockdev.c b/blockdev.c
index 07cfe25e1e..be4ca44ab2 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -50,6 +50,9 @@
#include "trace.h"
#include "sysemu/arch_init.h"
+static QTAILQ_HEAD(, BlockDriverState) monitor_bdrv_states =
+ QTAILQ_HEAD_INITIALIZER(monitor_bdrv_states);
+
static const char *const if_name[IF_COUNT] = {
[IF_NONE] = "none",
[IF_IDE] = "ide",
@@ -702,6 +705,19 @@ fail:
return NULL;
}
+void blockdev_close_all_bdrv_states(void)
+{
+ BlockDriverState *bs, *next_bs;
+
+ QTAILQ_FOREACH_SAFE(bs, &monitor_bdrv_states, monitor_list, next_bs) {
+ AioContext *ctx = bdrv_get_aio_context(bs);
+
+ aio_context_acquire(ctx);
+ bdrv_unref(bs);
+ aio_context_release(ctx);
+ }
+}
+
static void qemu_opt_rename(QemuOpts *opts, const char *from, const char *to,
Error **errp)
{
@@ -2304,6 +2320,11 @@ void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
return;
}
+ if (!blk_dev_has_tray(blk)) {
+ /* Ignore this command on tray-less devices */
+ return;
+ }
+
if (blk_dev_is_tray_open(blk)) {
return;
}
@@ -2334,6 +2355,11 @@ void qmp_blockdev_close_tray(const char *device, Error **errp)
return;
}
+ if (!blk_dev_has_tray(blk)) {
+ /* Ignore this command on tray-less devices */
+ return;
+ }
+
if (!blk_dev_is_tray_open(blk)) {
return;
}
@@ -2363,7 +2389,7 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp)
return;
}
- if (has_device && !blk_dev_is_tray_open(blk)) {
+ if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
error_setg(errp, "Tray of device '%s' is not open", device);
return;
}
@@ -2382,12 +2408,19 @@ void qmp_x_blockdev_remove_medium(const char *device, Error **errp)
/* This follows the convention established by bdrv_make_anon() */
if (bs->device_list.tqe_prev) {
- QTAILQ_REMOVE(&bdrv_states, bs, device_list);
- bs->device_list.tqe_prev = NULL;
+ bdrv_device_remove(bs);
}
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);
+ }
+
out:
aio_context_release(aio_context);
}
@@ -2413,7 +2446,7 @@ static void qmp_blockdev_insert_anon_medium(const char *device,
return;
}
- if (has_device && !blk_dev_is_tray_open(blk)) {
+ if (has_device && blk_dev_has_tray(blk) && !blk_dev_is_tray_open(blk)) {
error_setg(errp, "Tray of device '%s' is not open", device);
return;
}
@@ -2426,6 +2459,15 @@ static void qmp_blockdev_insert_anon_medium(const char *device,
blk_insert_bs(blk, bs);
QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
+
+ 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);
+ }
}
void qmp_x_blockdev_insert_medium(const char *device, const char *node_name,
@@ -2765,7 +2807,7 @@ void hmp_drive_del(Monitor *mon, const QDict *qdict)
return;
}
- bdrv_close(bs);
+ blk_remove_bs(blk);
}
/* if we have a device attached to this BlockDriverState
@@ -3848,12 +3890,15 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
if (!bs) {
goto fail;
}
+
+ QTAILQ_INSERT_TAIL(&monitor_bdrv_states, bs, monitor_list);
}
if (bs && bdrv_key_required(bs)) {
if (blk) {
blk_unref(blk);
} else {
+ QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
bdrv_unref(bs);
}
error_setg(errp, "blockdev-add doesn't support encrypted devices");
@@ -3913,7 +3958,13 @@ void qmp_x_blockdev_del(bool has_id, const char *id,
goto out;
}
- if (bs->refcnt > 1 || !QLIST_EMPTY(&bs->parents)) {
+ if (!blk && !bs->monitor_list.tqe_prev) {
+ error_setg(errp, "Node %s is not owned by the monitor",
+ bs->node_name);
+ goto out;
+ }
+
+ if (bs->refcnt > 1) {
error_setg(errp, "Block device %s is in use",
bdrv_get_device_or_node_name(bs));
goto out;
@@ -3923,6 +3974,7 @@ void qmp_x_blockdev_del(bool has_id, const char *id,
if (blk) {
blk_unref(blk);
} else {
+ QTAILQ_REMOVE(&monitor_bdrv_states, bs, monitor_list);
bdrv_unref(bs);
}