* [Qemu-devel] [PATCH v8 01/15] block: Add blk_remove_bs()
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-27 9:04 ` Alberto Garcia
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 02/15] block: Make bdrv_states public Max Reitz
` (14 subsequent siblings)
15 siblings, 1 reply; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
This function removes the BlockDriverState associated with the given
BlockBackend from that BB and sets the BDS pointer in the BB to NULL.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
block/block-backend.c | 12 ++++++++++++
include/sysemu/block-backend.h | 1 +
2 files changed, 13 insertions(+)
diff --git a/block/block-backend.c b/block/block-backend.c
index 19fdaae..878c448 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -334,6 +334,18 @@ void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk)
}
/*
+ * Disassociates the currently associated BlockDriverState from @blk.
+ */
+void blk_remove_bs(BlockBackend *blk)
+{
+ blk_update_root_state(blk);
+
+ blk->bs->blk = NULL;
+ bdrv_unref(blk->bs);
+ blk->bs = NULL;
+}
+
+/*
* Associates a new BlockDriverState with @blk.
*/
void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs)
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 9306a52..14a6d32 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -72,6 +72,7 @@ BlockBackend *blk_by_name(const char *name);
BlockBackend *blk_next(BlockBackend *blk);
BlockDriverState *blk_bs(BlockBackend *blk);
+void blk_remove_bs(BlockBackend *blk);
void blk_insert_bs(BlockBackend *blk, BlockDriverState *bs);
void blk_hide_on_behalf_of_hmp_drive_del(BlockBackend *blk);
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v8 01/15] block: Add blk_remove_bs()
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 01/15] block: Add blk_remove_bs() Max Reitz
@ 2015-10-27 9:04 ` Alberto Garcia
0 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-10-27 9:04 UTC (permalink / raw)
To: Max Reitz, qemu-block
Cc: Kevin Wolf, John Snow, Markus Armbruster, qemu-devel,
Stefan Hajnoczi
On Mon 26 Oct 2015 09:39:05 PM CET, Max Reitz <mreitz@redhat.com> wrote:
> +void blk_remove_bs(BlockBackend *blk)
> +{
> + blk_update_root_state(blk);
> +
> + blk->bs->blk = NULL;
> + bdrv_unref(blk->bs);
> + blk->bs = NULL;
> +}
I cannot think of any example out of the blue but I wonder if removing
the reference to the BDS (and possibly destroying it) while blk->bs is
still pointing to it could be a source of problems.
Berto
^ permalink raw reply [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 02/15] block: Make bdrv_states public
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 01/15] block: Add blk_remove_bs() Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-27 9:21 ` Alberto Garcia
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 03/15] block: Add functions for inheriting a BBRS Max Reitz
` (13 subsequent siblings)
15 siblings, 1 reply; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
When inserting a BDS tree into a BB, we will need to add the root BDS to
this list. Since we will want to do that in the blockdev-insert-medium
implementation in blockdev.c, we will need access to it there.
This patch is not exactly elegant, but bdrv_states will be removed in
the future anyway because we no longer need it since we have BBs.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
block.c | 3 +--
include/block/block_int.h | 2 ++
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/block.c b/block.c
index e9f40dc..71d5474 100644
--- a/block.c
+++ b/block.c
@@ -73,8 +73,7 @@ struct BdrvDirtyBitmap {
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
-static QTAILQ_HEAD(, BlockDriverState) bdrv_states =
- QTAILQ_HEAD_INITIALIZER(bdrv_states);
+struct BdrvStates bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states);
static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
QTAILQ_HEAD_INITIALIZER(graph_bdrv_states);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 3ceeb5a..6a3f64d 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -473,6 +473,8 @@ extern BlockDriver bdrv_file;
extern BlockDriver bdrv_raw;
extern BlockDriver bdrv_qcow2;
+extern QTAILQ_HEAD(BdrvStates, BlockDriverState) bdrv_states;
+
/**
* bdrv_setup_io_funcs:
*
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v8 02/15] block: Make bdrv_states public
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 02/15] block: Make bdrv_states public Max Reitz
@ 2015-10-27 9:21 ` Alberto Garcia
0 siblings, 0 replies; 20+ messages in thread
From: Alberto Garcia @ 2015-10-27 9:21 UTC (permalink / raw)
To: Max Reitz, qemu-block
Cc: Kevin Wolf, John Snow, Markus Armbruster, qemu-devel,
Stefan Hajnoczi
On Mon 26 Oct 2015 09:39:06 PM CET, Max Reitz wrote:
> When inserting a BDS tree into a BB, we will need to add the root BDS to
> this list. Since we will want to do that in the blockdev-insert-medium
> implementation in blockdev.c, we will need access to it there.
>
> This patch is not exactly elegant, but bdrv_states will be removed in
> the future anyway because we no longer need it since we have BBs.
>
> Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Alberto Garcia <berto@igalia.com>
Berto
^ permalink raw reply [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 03/15] block: Add functions for inheriting a BBRS
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 01/15] block: Add blk_remove_bs() Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 02/15] block: Make bdrv_states public Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 04/15] blockdev: Add blockdev-open-tray Max Reitz
` (12 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
In order to open a BDS which inherits a BB's root state,
blk_get_open_flags_from_root_state() is used to inquire the flags to be
passed to bdrv_open(), and blk_apply_root_state() is used to apply the
remaining state after the BDS has been opened.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
block/block-backend.c | 27 +++++++++++++++++++++++++++
include/sysemu/block-backend.h | 2 ++
2 files changed, 29 insertions(+)
diff --git a/block/block-backend.c b/block/block-backend.c
index 878c448..7d49539 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -1239,6 +1239,33 @@ void blk_update_root_state(BlockBackend *blk)
}
}
+/*
+ * Applies the information in the root state to the given BlockDriverState. This
+ * does not include the flags which have to be specified for bdrv_open(), use
+ * blk_get_open_flags_from_root_state() to inquire them.
+ */
+void blk_apply_root_state(BlockBackend *blk, BlockDriverState *bs)
+{
+ bs->detect_zeroes = blk->root_state.detect_zeroes;
+ if (blk->root_state.throttle_group) {
+ bdrv_io_limits_enable(bs, blk->root_state.throttle_group);
+ }
+}
+
+/*
+ * Returns the flags to be used for bdrv_open() of a BlockDriverState which is
+ * supposed to inherit the root state.
+ */
+int blk_get_open_flags_from_root_state(BlockBackend *blk)
+{
+ int bs_flags;
+
+ bs_flags = blk->root_state.read_only ? 0 : BDRV_O_RDWR;
+ bs_flags |= blk->root_state.open_flags & ~BDRV_O_RDWR;
+
+ return bs_flags;
+}
+
BlockBackendRootState *blk_get_root_state(BlockBackend *blk)
{
return &blk->root_state;
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 14a6d32..40e315b 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -167,6 +167,8 @@ void blk_io_unplug(BlockBackend *blk);
BlockAcctStats *blk_get_stats(BlockBackend *blk);
BlockBackendRootState *blk_get_root_state(BlockBackend *blk);
void blk_update_root_state(BlockBackend *blk);
+void blk_apply_root_state(BlockBackend *blk, BlockDriverState *bs);
+int blk_get_open_flags_from_root_state(BlockBackend *blk);
void *blk_aio_get(const AIOCBInfo *aiocb_info, BlockBackend *blk,
BlockCompletionFunc *cb, void *opaque);
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 04/15] blockdev: Add blockdev-open-tray
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (2 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 03/15] block: Add functions for inheriting a BBRS Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 05/15] blockdev: Add blockdev-close-tray Max Reitz
` (11 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 36 ++++++++++++++++++++++++++++++++++++
qapi/block-core.json | 32 ++++++++++++++++++++++++++++++++
qmp-commands.hx | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 116 insertions(+)
diff --git a/blockdev.c b/blockdev.c
index 18712d2..1119368 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2077,6 +2077,42 @@ out:
aio_context_release(aio_context);
}
+void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
+ Error **errp)
+{
+ BlockBackend *blk;
+ bool locked;
+
+ if (!has_force) {
+ force = false;
+ }
+
+ blk = blk_by_name(device);
+ if (!blk) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
+ return;
+ }
+
+ if (!blk_dev_has_removable_media(blk)) {
+ error_setg(errp, "Device '%s' is not removable", device);
+ return;
+ }
+
+ if (blk_dev_is_tray_open(blk)) {
+ return;
+ }
+
+ 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);
+ }
+}
+
/* throttling disk I/O limits */
void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 425fdab..b65ab81 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1876,6 +1876,38 @@
##
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
+##
+# @blockdev-open-tray:
+#
+# Opens a block device's tray. If there is a block driver state tree inserted as
+# a medium, it will become inaccessible to the guest (but it will remain
+# associated to the block device, so closing the tray will make it accessible
+# again).
+#
+# If the tray was already open before, this will be a no-op.
+#
+# Once the tray opens, a DEVICE_TRAY_MOVED event is emitted. There are cases in
+# which no such event will be generated, these include:
+# - if the guest has locked the tray, @force is false and the guest does not
+# respond to the eject request
+# - if the BlockBackend denoted by @device does not have a guest device attached
+# to it
+# - if the guest device does not have an actual tray and is empty, for instance
+# for floppy disk drives
+#
+# @device: block device name
+#
+# @force: #optional if false (the default), an eject request will be sent to
+# the guest if it has locked the tray (and the tray will not be opened
+# immediately); if true, the tray will be opened regardless of whether
+# it is locked
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-open-tray',
+ 'data': { 'device': 'str',
+ '*force': 'bool' } }
+
##
# @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d7cf0ff..0b796f9 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3936,6 +3936,54 @@ Example (2):
EQMP
{
+ .name = "blockdev-open-tray",
+ .args_type = "device:s,force:b?",
+ .mhandler.cmd_new = qmp_marshal_blockdev_open_tray,
+ },
+
+SQMP
+blockdev-open-tray
+------------------
+
+Opens a block device's tray. If there is a block driver state tree inserted as a
+medium, it will become inaccessible to the guest (but it will remain associated
+to the block device, so closing the tray will make it accessible again).
+
+If the tray was already open before, this will be a no-op.
+
+Once the tray opens, a DEVICE_TRAY_MOVED event is emitted. There are cases in
+which no such event will be generated, these include:
+- if the guest has locked the tray, @force is false and the guest does not
+ respond to the eject request
+- if the BlockBackend denoted by @device does not have a guest device attached
+ to it
+- if the guest device does not have an actual tray and is empty, for instance
+ for floppy disk drives
+
+Arguments:
+
+- "device": block device name (json-string)
+- "force": if false (the default), an eject request will be sent to the guest if
+ it has locked the tray (and the tray will not be opened immediately);
+ if true, the tray will be opened regardless of whether it is locked
+ (json-bool, optional)
+
+Example:
+
+-> { "execute": "blockdev-open-tray",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "timestamp": { "seconds": 1418751016,
+ "microseconds": 716996 },
+ "event": "DEVICE_TRAY_MOVED",
+ "data": { "device": "ide1-cd0",
+ "tray-open": true } }
+
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "query-named-block-nodes",
.args_type = "",
.mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 05/15] blockdev: Add blockdev-close-tray
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (3 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 04/15] blockdev: Add blockdev-open-tray Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 06/15] blockdev: Add blockdev-remove-medium Max Reitz
` (10 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
---
blockdev.c | 23 +++++++++++++++++++++++
qapi/block-core.json | 16 ++++++++++++++++
qmp-commands.hx | 35 +++++++++++++++++++++++++++++++++++
3 files changed, 74 insertions(+)
diff --git a/blockdev.c b/blockdev.c
index 1119368..618bfad 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2113,6 +2113,29 @@ void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
}
}
+void qmp_blockdev_close_tray(const char *device, Error **errp)
+{
+ BlockBackend *blk;
+
+ blk = blk_by_name(device);
+ if (!blk) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
+ return;
+ }
+
+ if (!blk_dev_has_removable_media(blk)) {
+ error_setg(errp, "Device '%s' is not removable", device);
+ return;
+ }
+
+ if (!blk_dev_is_tray_open(blk)) {
+ return;
+ }
+
+ blk_dev_change_media_cb(blk, true);
+}
+
/* throttling disk I/O limits */
void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index b65ab81..1cb719a 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1908,6 +1908,22 @@
'data': { 'device': 'str',
'*force': 'bool' } }
+##
+# @blockdev-close-tray:
+#
+# Closes a block device's tray. If there is a block driver state tree associated
+# with the block device (which is currently ejected), that tree will be loaded
+# as the medium.
+#
+# If the tray was already closed before, this will be a no-op.
+#
+# @device: block device name
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-close-tray',
+ 'data': { 'device': 'str' } }
+
##
# @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 0b796f9..4b16d73 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -3984,6 +3984,41 @@ Example:
EQMP
{
+ .name = "blockdev-close-tray",
+ .args_type = "device:s",
+ .mhandler.cmd_new = qmp_marshal_blockdev_close_tray,
+ },
+
+SQMP
+blockdev-close-tray
+-------------------
+
+Closes a block device's tray. If there is a block driver state tree associated
+with the block device (which is currently ejected), that tree will be loaded as
+the medium.
+
+If the tray was already closed before, this will be a no-op.
+
+Arguments:
+
+- "device": block device name (json-string)
+
+Example:
+
+-> { "execute": "blockdev-close-tray",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "timestamp": { "seconds": 1418751345,
+ "microseconds": 272147 },
+ "event": "DEVICE_TRAY_MOVED",
+ "data": { "device": "ide1-cd0",
+ "tray-open": false } }
+
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "query-named-block-nodes",
.args_type = "",
.mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 06/15] blockdev: Add blockdev-remove-medium
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (4 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 05/15] blockdev: Add blockdev-close-tray Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-27 13:44 ` Kevin Wolf
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 07/15] blockdev: Add blockdev-insert-medium Max Reitz
` (9 subsequent siblings)
15 siblings, 1 reply; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
qapi/block-core.json | 16 ++++++++++++++++
qmp-commands.hx | 45 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 112 insertions(+)
diff --git a/blockdev.c b/blockdev.c
index 618bfad..f37bd27 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2136,6 +2136,57 @@ void qmp_blockdev_close_tray(const char *device, Error **errp)
blk_dev_change_media_cb(blk, true);
}
+void qmp_blockdev_remove_medium(const char *device, Error **errp)
+{
+ BlockBackend *blk;
+ BlockDriverState *bs;
+ AioContext *aio_context;
+ bool has_device;
+
+ blk = blk_by_name(device);
+ if (!blk) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
+ return;
+ }
+
+ /* 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 '%s' is not removable", device);
+ return;
+ }
+
+ if (has_device && !blk_dev_is_tray_open(blk)) {
+ error_setg(errp, "Tray of device '%s' is not open", device);
+ 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;
+ }
+
+ /* 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;
+ }
+
+ blk_remove_bs(blk);
+
+out:
+ aio_context_release(aio_context);
+}
+
/* throttling disk I/O limits */
void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 1cb719a..e19e82c 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1924,6 +1924,22 @@
{ 'command': 'blockdev-close-tray',
'data': { 'device': 'str' } }
+##
+# @blockdev-remove-medium:
+#
+# Removes a medium (a block driver state tree) from a block device. That block
+# device's tray must currently be open (unless there is no attached guest
+# device).
+#
+# If the tray is open and there is no medium inserted, this will be a no-op.
+#
+# @device: block device name
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-remove-medium',
+ 'data': { 'device': 'str' } }
+
##
# @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 4b16d73..6165398 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4019,6 +4019,51 @@ Example:
EQMP
{
+ .name = "blockdev-remove-medium",
+ .args_type = "device:s",
+ .mhandler.cmd_new = qmp_marshal_blockdev_remove_medium,
+ },
+
+SQMP
+blockdev-remove-medium
+----------------------
+
+Removes a medium (a block driver state tree) from a block device. That block
+device's tray must currently be open (unless there is no attached guest device).
+
+If the tray is open and there is no medium inserted, this will be a no-op.
+
+Arguments:
+
+- "device": block device name (json-string)
+
+Example:
+
+-> { "execute": "blockdev-remove-medium",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "error": { "class": "GenericError",
+ "desc": "Tray of device 'ide1-cd0' is not open" } }
+
+-> { "execute": "blockdev-open-tray",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "timestamp": { "seconds": 1418751627,
+ "microseconds": 549958 },
+ "event": "DEVICE_TRAY_MOVED",
+ "data": { "device": "ide1-cd0",
+ "tray-open": true } }
+
+<- { "return": {} }
+
+-> { "execute": "blockdev-remove-medium",
+ "arguments": { "device": "ide1-cd0" } }
+
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "query-named-block-nodes",
.args_type = "",
.mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v8 06/15] blockdev: Add blockdev-remove-medium
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 06/15] blockdev: Add blockdev-remove-medium Max Reitz
@ 2015-10-27 13:44 ` Kevin Wolf
0 siblings, 0 replies; 20+ messages in thread
From: Kevin Wolf @ 2015-10-27 13:44 UTC (permalink / raw)
To: Max Reitz
Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
Markus Armbruster, Stefan Hajnoczi
Am 26.10.2015 um 21:39 hat Max Reitz geschrieben:
> Signed-off-by: Max Reitz <mreitz@redhat.com>
> + if (bdrv_op_is_blocked(bs, BLOCK_OP_TYPE_EJECT, errp)) {
> + goto out;
> + }
> +
> + /* 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;
> + }
> +
> + blk_remove_bs(blk);
Wouldn't it be nicer to move the bdrv_states update into
blk_remove_bs() and blk_insert_bs()? Can be done on top of this series,
though, if you don't need to respin for another reason.
Kevin
^ permalink raw reply [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 07/15] blockdev: Add blockdev-insert-medium
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (5 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 06/15] blockdev: Add blockdev-remove-medium Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 08/15] blockdev: Implement eject with basic operations Max Reitz
` (8 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
And a helper function for that, which directly takes a pointer to the
BDS to be inserted instead of its node-name (which will be used for
implementing 'change' using blockdev-insert-medium).
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++
qapi/block-core.json | 17 ++++++++++++++++
qmp-commands.hx | 37 ++++++++++++++++++++++++++++++++++
3 files changed, 110 insertions(+)
diff --git a/blockdev.c b/blockdev.c
index f37bd27..328843b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2187,6 +2187,62 @@ out:
aio_context_release(aio_context);
}
+static void qmp_blockdev_insert_anon_medium(const char *device,
+ BlockDriverState *bs, Error **errp)
+{
+ BlockBackend *blk;
+ bool has_device;
+
+ blk = blk_by_name(device);
+ if (!blk) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
+ return;
+ }
+
+ /* 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 '%s' is not removable", device);
+ return;
+ }
+
+ if (has_device && !blk_dev_is_tray_open(blk)) {
+ error_setg(errp, "Tray of device '%s' is not open", device);
+ return;
+ }
+
+ if (blk_bs(blk)) {
+ error_setg(errp, "There already is a medium in device '%s'", device);
+ return;
+ }
+
+ blk_insert_bs(blk, bs);
+
+ QTAILQ_INSERT_TAIL(&bdrv_states, bs, device_list);
+}
+
+void qmp_blockdev_insert_medium(const char *device, const char *node_name,
+ Error **errp)
+{
+ BlockDriverState *bs;
+
+ bs = bdrv_find_node(node_name);
+ if (!bs) {
+ error_setg(errp, "Node '%s' not found", node_name);
+ return;
+ }
+
+ if (bs->blk) {
+ error_setg(errp, "Node '%s' is already in use by '%s'", node_name,
+ blk_name(bs->blk));
+ return;
+ }
+
+ qmp_blockdev_insert_anon_medium(device, bs, errp);
+}
+
/* throttling disk I/O limits */
void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr,
diff --git a/qapi/block-core.json b/qapi/block-core.json
index e19e82c..5c4fc72 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1940,6 +1940,23 @@
{ 'command': 'blockdev-remove-medium',
'data': { 'device': 'str' } }
+##
+# @blockdev-insert-medium:
+#
+# Inserts a medium (a block driver state tree) into a block device. That block
+# device's tray must currently be open (unless there is no attached guest
+# device) and there must be no medium inserted already.
+#
+# @device: block device name
+#
+# @node-name: name of a node in the block driver state graph
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-insert-medium',
+ 'data': { 'device': 'str',
+ 'node-name': 'str'} }
+
##
# @BlockErrorAction
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6165398..1dfa809 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4064,6 +4064,43 @@ Example:
EQMP
{
+ .name = "blockdev-insert-medium",
+ .args_type = "device:s,node-name:s",
+ .mhandler.cmd_new = qmp_marshal_blockdev_insert_medium,
+ },
+
+SQMP
+blockdev-insert-medium
+----------------------
+
+Inserts a medium (a block driver state tree) into a block device. That block
+device's tray must currently be open (unless there is no attached guest device)
+and there must be no medium inserted already.
+
+Arguments:
+
+- "device": block device name (json-string)
+- "node-name": root node of the BDS tree to insert into the block device
+
+Example:
+
+-> { "execute": "blockdev-add",
+ "arguments": { "options": { "node-name": "node0",
+ "driver": "raw",
+ "file": { "driver": "file",
+ "filename": "fedora.iso" } } } }
+
+<- { "return": {} }
+
+-> { "execute": "blockdev-insert-medium",
+ "arguments": { "device": "ide1-cd0",
+ "node-name": "node0" } }
+
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "query-named-block-nodes",
.args_type = "",
.mhandler.cmd_new = qmp_marshal_query_named_block_nodes,
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 08/15] blockdev: Implement eject with basic operations
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (6 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 07/15] blockdev: Add blockdev-insert-medium Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 09/15] blockdev: Implement change " Max Reitz
` (7 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Implement 'eject' by calling blockdev-open-tray and
blockdev-remove-medium.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 328843b..2fa2d3e 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1969,16 +1969,15 @@ out:
void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
{
- BlockBackend *blk;
+ Error *local_err = NULL;
- blk = blk_by_name(device);
- if (!blk) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", device);
+ qmp_blockdev_open_tray(device, has_force, force, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
return;
}
- eject_device(blk, force, errp);
+ qmp_blockdev_remove_medium(device, errp);
}
void qmp_block_passwd(bool has_device, const char *device,
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 09/15] blockdev: Implement change with basic operations
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (7 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 08/15] blockdev: Implement eject with basic operations Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 10/15] block: Inquire tray state before tray-moved events Max Reitz
` (6 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Implement 'change' on block devices by calling blockdev-open-tray,
blockdev-remove-medium, blockdev-insert-medium (a variation of that
which does not need a node-name) and blockdev-close-tray.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 178 +++++++++++++++++++++++--------------------------------------
1 file changed, 68 insertions(+), 110 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 2fa2d3e..81fd2a2 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1929,44 +1929,6 @@ exit:
}
}
-
-static void eject_device(BlockBackend *blk, int force, Error **errp)
-{
- BlockDriverState *bs = blk_bs(blk);
- AioContext *aio_context;
-
- if (!bs) {
- /* No medium inserted, so there is nothing to do */
- 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;
- }
- if (!blk_dev_has_removable_media(blk)) {
- error_setg(errp, "Device '%s' is not removable",
- bdrv_get_device_name(bs));
- goto out;
- }
-
- if (blk_dev_is_medium_locked(blk) && !blk_dev_is_tray_open(blk)) {
- blk_dev_eject_request(blk, force);
- if (!force) {
- error_setg(errp, "Device '%s' is locked",
- bdrv_get_device_name(bs));
- goto out;
- }
- }
-
- bdrv_close(bs);
-
-out:
- aio_context_release(aio_context);
-}
-
void qmp_eject(const char *device, bool has_force, bool force, Error **errp)
{
Error *local_err = NULL;
@@ -2004,78 +1966,6 @@ void qmp_block_passwd(bool has_device, const char *device,
aio_context_release(aio_context);
}
-/* Assumes AioContext is held */
-static void qmp_bdrv_open_encrypted(BlockDriverState **pbs,
- const char *filename,
- int bdrv_flags, const char *format,
- const char *password, Error **errp)
-{
- Error *local_err = NULL;
- QDict *options = NULL;
- int ret;
-
- if (format) {
- options = qdict_new();
- qdict_put(options, "driver", qstring_from_str(format));
- }
-
- ret = bdrv_open(pbs, filename, NULL, options, bdrv_flags, &local_err);
- if (ret < 0) {
- error_propagate(errp, local_err);
- return;
- }
-
- bdrv_add_key(*pbs, password, errp);
-}
-
-void qmp_change_blockdev(const char *device, const char *filename,
- const char *format, Error **errp)
-{
- BlockBackend *blk;
- BlockDriverState *bs;
- AioContext *aio_context;
- int bdrv_flags;
- bool new_bs;
- Error *err = NULL;
-
- blk = blk_by_name(device);
- if (!blk) {
- error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
- "Device '%s' not found", device);
- return;
- }
- bs = blk_bs(blk);
- new_bs = !bs;
-
- aio_context = blk_get_aio_context(blk);
- aio_context_acquire(aio_context);
-
- eject_device(blk, 0, &err);
- if (err) {
- error_propagate(errp, err);
- goto out;
- }
-
- bdrv_flags = blk_is_read_only(blk) ? 0 : BDRV_O_RDWR;
- bdrv_flags |= blk_get_root_state(blk)->open_flags & ~BDRV_O_RDWR;
-
- qmp_bdrv_open_encrypted(&bs, filename, bdrv_flags, format, NULL, &err);
- if (err) {
- error_propagate(errp, err);
- goto out;
- }
-
- if (new_bs) {
- blk_insert_bs(blk, bs);
- /* Has been sent automatically by bdrv_open() if blk_bs(blk) was not
- * NULL */
- blk_dev_change_media_cb(blk, true);
- }
-
-out:
- aio_context_release(aio_context);
-}
-
void qmp_blockdev_open_tray(const char *device, bool has_force, bool force,
Error **errp)
{
@@ -2242,6 +2132,74 @@ void qmp_blockdev_insert_medium(const char *device, const char *node_name,
qmp_blockdev_insert_anon_medium(device, bs, errp);
}
+void qmp_change_blockdev(const char *device, const char *filename,
+ const char *format, Error **errp)
+{
+ BlockBackend *blk;
+ BlockDriverState *medium_bs = NULL;
+ int bdrv_flags, ret;
+ QDict *options = NULL;
+ Error *err = NULL;
+
+ blk = blk_by_name(device);
+ if (!blk) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device);
+ goto fail;
+ }
+
+ if (blk_bs(blk)) {
+ blk_update_root_state(blk);
+ }
+
+ bdrv_flags = blk_get_open_flags_from_root_state(blk);
+
+ if (format) {
+ options = qdict_new();
+ qdict_put(options, "driver", qstring_from_str(format));
+ }
+
+ assert(!medium_bs);
+ ret = bdrv_open(&medium_bs, filename, NULL, options, bdrv_flags, errp);
+ if (ret < 0) {
+ goto fail;
+ }
+
+ blk_apply_root_state(blk, medium_bs);
+
+ bdrv_add_key(medium_bs, NULL, &err);
+ if (err) {
+ error_propagate(errp, err);
+ goto fail;
+ }
+
+ qmp_blockdev_open_tray(device, false, false, &err);
+ if (err) {
+ error_propagate(errp, err);
+ goto fail;
+ }
+
+ qmp_blockdev_remove_medium(device, &err);
+ if (err) {
+ error_propagate(errp, err);
+ goto fail;
+ }
+
+ qmp_blockdev_insert_anon_medium(device, medium_bs, &err);
+ if (err) {
+ error_propagate(errp, err);
+ goto fail;
+ }
+
+ qmp_blockdev_close_tray(device, 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(const char *device, int64_t bps, int64_t bps_rd,
int64_t bps_wr,
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 10/15] block: Inquire tray state before tray-moved events
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (8 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 09/15] blockdev: Implement change " Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 11/15] qmp: Introduce blockdev-change-medium Max Reitz
` (5 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
blk_dev_change_media_cb() is called for all potential tray movements;
however, it is possible to request closing the tray but nothing actually
happening (on a floppy disk drive without a medium).
Thus, the actual tray status should be inquired before sending a
tray-moved event (and an event should be sent whenever the status
changed).
Checking @load is now superfluous; it was necessary because it was
possible to change a medium without having explicitly opened the tray
and closed it again (or it might have been possible, at least). This is
no longer possible, though.
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
---
block/block-backend.c | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/block/block-backend.c b/block/block-backend.c
index 7d49539..1ac6982 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -429,18 +429,15 @@ void blk_set_dev_ops(BlockBackend *blk, const BlockDevOps *ops,
void blk_dev_change_media_cb(BlockBackend *blk, bool load)
{
if (blk->dev_ops && blk->dev_ops->change_media_cb) {
- bool tray_was_closed = !blk_dev_is_tray_open(blk);
+ bool tray_was_open, tray_is_open;
+ tray_was_open = blk_dev_is_tray_open(blk);
blk->dev_ops->change_media_cb(blk->dev_opaque, load);
- if (tray_was_closed) {
- /* tray open */
- qapi_event_send_device_tray_moved(blk_name(blk),
- true, &error_abort);
- }
- if (load) {
- /* tray close */
- qapi_event_send_device_tray_moved(blk_name(blk),
- false, &error_abort);
+ tray_is_open = blk_dev_is_tray_open(blk);
+
+ if (tray_was_open != tray_is_open) {
+ qapi_event_send_device_tray_moved(blk_name(blk), tray_is_open,
+ &error_abort);
}
}
}
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 11/15] qmp: Introduce blockdev-change-medium
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (9 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 10/15] block: Inquire tray state before tray-moved events Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 12/15] hmp: Use blockdev-change-medium for change command Max Reitz
` (4 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Introduce a new QMP command 'blockdev-change-medium' which is intended
to replace the 'change' command for block devices. The existing function
qmp_change_blockdev() is accordingly renamed to
qmp_blockdev_change_medium().
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 7 ++++---
include/sysemu/blockdev.h | 2 --
qapi-schema.json | 6 ++++--
qapi/block-core.json | 23 +++++++++++++++++++++++
qmp-commands.hx | 31 +++++++++++++++++++++++++++++++
qmp.c | 2 +-
6 files changed, 63 insertions(+), 8 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 81fd2a2..e609c97 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2132,8 +2132,9 @@ void qmp_blockdev_insert_medium(const char *device, const char *node_name,
qmp_blockdev_insert_anon_medium(device, bs, errp);
}
-void qmp_change_blockdev(const char *device, const char *filename,
- const char *format, Error **errp)
+void qmp_blockdev_change_medium(const char *device, const char *filename,
+ bool has_format, const char *format,
+ Error **errp)
{
BlockBackend *blk;
BlockDriverState *medium_bs = NULL;
@@ -2154,7 +2155,7 @@ void qmp_change_blockdev(const char *device, const char *filename,
bdrv_flags = blk_get_open_flags_from_root_state(blk);
- if (format) {
+ if (has_format) {
options = qdict_new();
qdict_put(options, "driver", qstring_from_str(format));
}
diff --git a/include/sysemu/blockdev.h b/include/sysemu/blockdev.h
index a00be94..b06a060 100644
--- a/include/sysemu/blockdev.h
+++ b/include/sysemu/blockdev.h
@@ -63,8 +63,6 @@ DriveInfo *drive_new(QemuOpts *arg, BlockInterfaceType block_default_type);
/* device-hotplug */
-void qmp_change_blockdev(const char *device, const char *filename,
- const char *format, Error **errp);
void hmp_commit(Monitor *mon, const QDict *qdict);
void hmp_drive_del(Monitor *mon, const QDict *qdict);
#endif
diff --git a/qapi-schema.json b/qapi-schema.json
index f60be29..7f0c4c5 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1842,8 +1842,10 @@
# device's password. The behavior of reads and writes to the block
# device between when these calls are executed is undefined.
#
-# Notes: It is strongly recommended that this interface is not used especially
-# for changing block devices.
+# Notes: This interface is deprecated, and it is strongly recommended that you
+# avoid using it. For changing block devices, use
+# blockdev-change-medium; for changing VNC parameters, use
+# change-vnc-password.
#
# Since: 0.14.0
##
diff --git a/qapi/block-core.json b/qapi/block-core.json
index 5c4fc72..e9fa649 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1959,6 +1959,29 @@
##
+# @blockdev-change-medium:
+#
+# Changes the medium inserted into a block device by ejecting the current medium
+# and loading a new image file which is inserted as the new medium (this command
+# combines blockdev-open-tray, blockdev-remove-medium, blockdev-insert-medium
+# and blockdev-close-tray).
+#
+# @device: block device name
+#
+# @filename: filename of the new image to be loaded
+#
+# @format: #optional, format to open the new image with (defaults to
+# the probed format)
+#
+# Since: 2.5
+##
+{ 'command': 'blockdev-change-medium',
+ 'data': { 'device': 'str',
+ 'filename': 'str',
+ '*format': 'str' } }
+
+
+##
# @BlockErrorAction
#
# An enumeration of action that has been taken when a DISK I/O occurs
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 1dfa809..d6e4d7e 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4163,6 +4163,37 @@ Example:
EQMP
{
+ .name = "blockdev-change-medium",
+ .args_type = "device:B,filename:F,format:s?",
+ .mhandler.cmd_new = qmp_marshal_blockdev_change_medium,
+ },
+
+SQMP
+blockdev-change-medium
+----------------------
+
+Changes the medium inserted into a block device by ejecting the current medium
+and loading a new image file which is inserted as the new medium.
+
+Arguments:
+
+- "device": device name (json-string)
+- "filename": filename of the new image (json-string)
+- "format": format of the new image (json-string, optional)
+
+Examples:
+
+1. Change a removable medium
+
+-> { "execute": "blockdev-change-medium",
+ "arguments": { "device": "ide1-cd0",
+ "filename": "/srv/images/Fedora-12-x86_64-DVD.iso",
+ "format": "raw" } }
+<- { "return": {} }
+
+EQMP
+
+ {
.name = "query-memdev",
.args_type = "",
.mhandler.cmd_new = qmp_marshal_query_memdev,
diff --git a/qmp.c b/qmp.c
index ff54e5a..4e44f98 100644
--- a/qmp.c
+++ b/qmp.c
@@ -414,7 +414,7 @@ void qmp_change(const char *device, const char *target,
if (strcmp(device, "vnc") == 0) {
qmp_change_vnc(target, has_arg, arg, errp);
} else {
- qmp_change_blockdev(device, target, arg, errp);
+ qmp_blockdev_change_medium(device, target, has_arg, arg, errp);
}
}
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 12/15] hmp: Use blockdev-change-medium for change command
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (10 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 11/15] qmp: Introduce blockdev-change-medium Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 13/15] blockdev: read-only-mode for blockdev-change-medium Max Reitz
` (3 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Use separate code paths for the two overloaded functions of the 'change'
HMP command, and invoke the 'blockdev-change-medium' QMP command if used
on a block device (by calling qmp_blockdev_change_medium()).
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
---
hmp.c | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/hmp.c b/hmp.c
index 5048eee..b91821b 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1338,22 +1338,25 @@ void hmp_change(Monitor *mon, const QDict *qdict)
const char *arg = qdict_get_try_str(qdict, "arg");
Error *err = NULL;
- if (strcmp(device, "vnc") == 0 &&
- (strcmp(target, "passwd") == 0 ||
- strcmp(target, "password") == 0)) {
- if (!arg) {
- monitor_read_password(mon, hmp_change_read_arg, NULL);
+ if (strcmp(device, "vnc") == 0) {
+ if (strcmp(target, "passwd") == 0 ||
+ strcmp(target, "password") == 0) {
+ if (!arg) {
+ monitor_read_password(mon, hmp_change_read_arg, NULL);
+ return;
+ }
+ }
+ qmp_change("vnc", target, !!arg, arg, &err);
+ } else {
+ qmp_blockdev_change_medium(device, target, !!arg, arg, &err);
+ if (err &&
+ error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
+ error_free(err);
+ monitor_read_block_device_key(mon, device, NULL, NULL);
return;
}
}
- qmp_change(device, target, !!arg, arg, &err);
- if (err &&
- error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
- error_free(err);
- monitor_read_block_device_key(mon, device, NULL, NULL);
- return;
- }
hmp_handle_error(mon, &err);
}
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 13/15] blockdev: read-only-mode for blockdev-change-medium
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (11 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 12/15] hmp: Use blockdev-change-medium for change command Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 14/15] hmp: Add read-only-mode option to change command Max Reitz
` (2 subsequent siblings)
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Add an option to qmp_blockdev_change_medium() which allows changing the
read-only status of the block device whose medium is changed.
Some drives do not have a inherently fixed read-only status; for
instance, floppy disks can be set read-only or writable independently of
the drive. Some users may find it useful to be able to therefore change
the read-only status of a block device when changing the medium.
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
blockdev.c | 22 ++++++++++++++++++++++
hmp.c | 2 +-
qapi/block-core.json | 24 +++++++++++++++++++++++-
qmp-commands.hx | 24 +++++++++++++++++++++++-
qmp.c | 3 ++-
5 files changed, 71 insertions(+), 4 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index e609c97..aa6ea89 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2134,6 +2134,8 @@ void qmp_blockdev_insert_medium(const char *device, const char *node_name,
void qmp_blockdev_change_medium(const char *device, const char *filename,
bool has_format, const char *format,
+ bool has_read_only,
+ BlockdevChangeReadOnlyMode read_only,
Error **errp)
{
BlockBackend *blk;
@@ -2155,6 +2157,26 @@ void qmp_blockdev_change_medium(const char *device, const char *filename,
bdrv_flags = blk_get_open_flags_from_root_state(blk);
+ 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();
+ }
+
if (has_format) {
options = qdict_new();
qdict_put(options, "driver", qstring_from_str(format));
diff --git a/hmp.c b/hmp.c
index b91821b..9e6b7e5 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1348,7 +1348,7 @@ void hmp_change(Monitor *mon, const QDict *qdict)
}
qmp_change("vnc", target, !!arg, arg, &err);
} else {
- qmp_blockdev_change_medium(device, target, !!arg, arg, &err);
+ qmp_blockdev_change_medium(device, target, !!arg, arg, false, 0, &err);
if (err &&
error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
error_free(err);
diff --git a/qapi/block-core.json b/qapi/block-core.json
index e9fa649..fa08ba9 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -1959,6 +1959,24 @@
##
+# @BlockdevChangeReadOnlyMode:
+#
+# Specifies the new read-only mode of a block device subject to the
+# @blockdev-change-medium command.
+#
+# @retain: Retains the current read-only mode
+#
+# @read-only: Makes the device read-only
+#
+# @read-write: Makes the device writable
+#
+# Since: 2.3
+##
+{ 'enum': 'BlockdevChangeReadOnlyMode',
+ 'data': ['retain', 'read-only', 'read-write'] }
+
+
+##
# @blockdev-change-medium:
#
# Changes the medium inserted into a block device by ejecting the current medium
@@ -1973,12 +1991,16 @@
# @format: #optional, format to open the new image with (defaults to
# the probed format)
#
+# @read-only-mode: #optional, change the read-only mode of the device; defaults
+# to 'retain'
+#
# Since: 2.5
##
{ 'command': 'blockdev-change-medium',
'data': { 'device': 'str',
'filename': 'str',
- '*format': 'str' } }
+ '*format': 'str',
+ '*read-only-mode': 'BlockdevChangeReadOnlyMode' } }
##
diff --git a/qmp-commands.hx b/qmp-commands.hx
index d6e4d7e..707e0bd 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -4164,7 +4164,7 @@ EQMP
{
.name = "blockdev-change-medium",
- .args_type = "device:B,filename:F,format:s?",
+ .args_type = "device:B,filename:F,format:s?,read-only-mode:s?",
.mhandler.cmd_new = qmp_marshal_blockdev_change_medium,
},
@@ -4180,6 +4180,8 @@ Arguments:
- "device": device name (json-string)
- "filename": filename of the new image (json-string)
- "format": format of the new image (json-string, optional)
+- "read-only-mode": new read-only mode (json-string, optional)
+ - Possible values: "retain" (default), "read-only", "read-write"
Examples:
@@ -4191,6 +4193,26 @@ Examples:
"format": "raw" } }
<- { "return": {} }
+2. Load a read-only medium into a writable drive
+
+-> { "execute": "blockdev-change-medium",
+ "arguments": { "device": "isa-fd0",
+ "filename": "/srv/images/ro.img",
+ "format": "raw",
+ "read-only-mode": "retain" } }
+
+<- { "error":
+ { "class": "GenericError",
+ "desc": "Could not open '/srv/images/ro.img': Permission denied" } }
+
+-> { "execute": "blockdev-change-medium",
+ "arguments": { "device": "isa-fd0",
+ "filename": "/srv/images/ro.img",
+ "format": "raw",
+ "read-only-mode": "read-only" } }
+
+<- { "return": {} }
+
EQMP
{
diff --git a/qmp.c b/qmp.c
index 4e44f98..ddc63ea 100644
--- a/qmp.c
+++ b/qmp.c
@@ -414,7 +414,8 @@ void qmp_change(const char *device, const char *target,
if (strcmp(device, "vnc") == 0) {
qmp_change_vnc(target, has_arg, arg, errp);
} else {
- qmp_blockdev_change_medium(device, target, has_arg, arg, errp);
+ qmp_blockdev_change_medium(device, target, has_arg, arg, false, 0,
+ errp);
}
}
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 14/15] hmp: Add read-only-mode option to change command
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (12 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 13/15] blockdev: read-only-mode for blockdev-change-medium Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 15/15] iotests: Add test for change-related QMP commands Max Reitz
2015-10-27 14:18 ` [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Kevin Wolf
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Expose the new read-only-mode option of 'blockdev-change-medium' for the
'change' HMP command.
Signed-off-by: Max Reitz <mreitz@redhat.com>
Reviewed-by: Kevin Wolf <kwolf@redhat.com>
---
hmp-commands.hx | 20 +++++++++++++++++---
hmp.c | 22 +++++++++++++++++++++-
2 files changed, 38 insertions(+), 4 deletions(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 3a4ae39..814ea86 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -194,8 +194,8 @@ ETEXI
{
.name = "change",
- .args_type = "device:B,target:F,arg:s?",
- .params = "device filename [format]",
+ .args_type = "device:B,target:F,arg:s?,read-only-mode:s?",
+ .params = "device filename [format [read-only-mode]]",
.help = "change a removable medium, optional format",
.mhandler.cmd = hmp_change,
},
@@ -206,7 +206,7 @@ STEXI
Change the configuration of a device.
@table @option
-@item change @var{diskdevice} @var{filename} [@var{format}]
+@item change @var{diskdevice} @var{filename} [@var{format} [@var{read-only-mode}]]
Change the medium for a removable disk device to point to @var{filename}. eg
@example
@@ -215,6 +215,20 @@ Change the medium for a removable disk device to point to @var{filename}. eg
@var{format} is optional.
+@var{read-only-mode} may be used to change the read-only status of the device.
+It accepts the following values:
+
+@table @var
+@item retain
+Retains the current status; this is the default.
+
+@item read-only
+Makes the device read-only.
+
+@item read-write
+Makes the device writable.
+@end table
+
@item change vnc @var{display},@var{options}
Change the configuration of the VNC server. The valid syntax for @var{display}
and @var{options} are described at @ref{sec_invocation}. eg
diff --git a/hmp.c b/hmp.c
index 9e6b7e5..83c7c15 100644
--- a/hmp.c
+++ b/hmp.c
@@ -27,6 +27,7 @@
#include "qapi/opts-visitor.h"
#include "qapi/qmp/qerror.h"
#include "qapi/string-output-visitor.h"
+#include "qapi/util.h"
#include "qapi-visit.h"
#include "ui/console.h"
#include "block/qapi.h"
@@ -1336,9 +1337,16 @@ void hmp_change(Monitor *mon, const QDict *qdict)
const char *device = qdict_get_str(qdict, "device");
const char *target = qdict_get_str(qdict, "target");
const char *arg = qdict_get_try_str(qdict, "arg");
+ const char *read_only = qdict_get_try_str(qdict, "read-only-mode");
+ BlockdevChangeReadOnlyMode read_only_mode = 0;
Error *err = NULL;
if (strcmp(device, "vnc") == 0) {
+ if (read_only) {
+ monitor_printf(mon,
+ "Parameter 'read-only-mode' is invalid for VNC\n");
+ return;
+ }
if (strcmp(target, "passwd") == 0 ||
strcmp(target, "password") == 0) {
if (!arg) {
@@ -1348,7 +1356,19 @@ void hmp_change(Monitor *mon, const QDict *qdict)
}
qmp_change("vnc", target, !!arg, arg, &err);
} else {
- qmp_blockdev_change_medium(device, target, !!arg, arg, false, 0, &err);
+ if (read_only) {
+ read_only_mode =
+ qapi_enum_parse(BlockdevChangeReadOnlyMode_lookup,
+ read_only, BLOCKDEV_CHANGE_READ_ONLY_MODE_MAX,
+ BLOCKDEV_CHANGE_READ_ONLY_MODE_RETAIN, &err);
+ if (err) {
+ hmp_handle_error(mon, &err);
+ return;
+ }
+ }
+
+ qmp_blockdev_change_medium(device, target, !!arg, arg,
+ !!read_only, read_only_mode, &err);
if (err &&
error_get_class(err) == ERROR_CLASS_DEVICE_ENCRYPTED) {
error_free(err);
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* [Qemu-devel] [PATCH v8 15/15] iotests: Add test for change-related QMP commands
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (13 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 14/15] hmp: Add read-only-mode option to change command Max Reitz
@ 2015-10-26 20:39 ` Max Reitz
2015-10-27 14:18 ` [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Kevin Wolf
15 siblings, 0 replies; 20+ messages in thread
From: Max Reitz @ 2015-10-26 20:39 UTC (permalink / raw)
To: qemu-block
Cc: Kevin Wolf, Alberto Garcia, Markus Armbruster, qemu-devel,
Max Reitz, John Snow, Stefan Hajnoczi
Signed-off-by: Max Reitz <mreitz@redhat.com>
---
tests/qemu-iotests/118 | 720 +++++++++++++++++++++++++++++++++++++++++++++
tests/qemu-iotests/118.out | 5 +
tests/qemu-iotests/group | 1 +
3 files changed, 726 insertions(+)
create mode 100755 tests/qemu-iotests/118
create mode 100644 tests/qemu-iotests/118.out
diff --git a/tests/qemu-iotests/118 b/tests/qemu-iotests/118
new file mode 100755
index 0000000..a2bcd54
--- /dev/null
+++ b/tests/qemu-iotests/118
@@ -0,0 +1,720 @@
+#!/usr/bin/env python
+#
+# Test case for the QMP 'change' command and all other associated
+# commands
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import os
+import stat
+import time
+import iotests
+from iotests import qemu_img
+
+old_img = os.path.join(iotests.test_dir, 'test0.img')
+new_img = os.path.join(iotests.test_dir, 'test1.img')
+
+class ChangeBaseClass(iotests.QMPTestCase):
+ has_opened = False
+ has_closed = False
+
+ def process_events(self):
+ for event in self.vm.get_qmp_events(wait=False):
+ if (event['event'] == 'DEVICE_TRAY_MOVED' and
+ event['data']['device'] == 'drive0'):
+ if event['data']['tray-open'] == False:
+ self.has_closed = True
+ else:
+ self.has_opened = True
+
+ def wait_for_open(self):
+ timeout = time.clock() + 3
+ while not self.has_opened and time.clock() < timeout:
+ self.process_events()
+ if not self.has_opened:
+ self.fail('Timeout while waiting for the tray to open')
+
+ def wait_for_close(self):
+ timeout = time.clock() + 3
+ while not self.has_closed and time.clock() < timeout:
+ self.process_events()
+ if not self.has_opened:
+ self.fail('Timeout while waiting for the tray to close')
+
+class GeneralChangeTestsBaseClass(ChangeBaseClass):
+ def test_change(self):
+ result = self.vm.qmp('change', device='drive0', target=new_img,
+ arg=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_blockdev_change_medium(self):
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_eject(self):
+ result = self.vm.qmp('eject', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ def test_tray_eject_change(self):
+ result = self.vm.qmp('eject', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_tray_open_close(self):
+ result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ if self.was_empty == True:
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+ else:
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ if self.has_real_tray or not self.was_empty:
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ if self.has_real_tray or not self.was_empty:
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ else:
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ if self.was_empty == True:
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+ else:
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def test_tray_eject_close(self):
+ result = self.vm.qmp('eject', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ if self.has_real_tray:
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ if self.has_real_tray:
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ else:
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ def test_tray_open_change(self):
+ result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ if self.was_empty == True:
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+ else:
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_cycle(self):
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'new',
+ 'driver': iotests.imgfmt,
+ 'file': {'filename': new_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ if self.was_empty == True:
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+ else:
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-remove-medium', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('blockdev-insert-medium', device='drive0',
+ node_name='new')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_close_on_closed(self):
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ # Should be a no-op
+ self.assert_qmp(result, 'return', {})
+ self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+ def test_remove_on_closed(self):
+ if self.has_opened:
+ # Empty floppy drive
+ return
+
+ result = self.vm.qmp('blockdev-remove-medium', device='drive0')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ def test_insert_on_closed(self):
+ if self.has_opened:
+ # Empty floppy drive
+ return
+
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'new',
+ 'driver': iotests.imgfmt,
+ 'file': {'filename': new_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-insert-medium', device='drive0',
+ node_name='new')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+class TestInitiallyFilled(GeneralChangeTestsBaseClass):
+ was_empty = False
+
+ def setUp(self, media, interface):
+ qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
+ qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
+ self.vm = iotests.VM().add_drive(old_img, 'media=%s' % media, interface)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(old_img)
+ os.remove(new_img)
+
+ def test_insert_on_filled(self):
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'new',
+ 'driver': iotests.imgfmt,
+ 'file': {'filename': new_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-open-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('blockdev-insert-medium', device='drive0',
+ node_name='new')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+class TestInitiallyEmpty(GeneralChangeTestsBaseClass):
+ was_empty = True
+
+ def setUp(self, media, interface):
+ qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
+ self.vm = iotests.VM().add_drive(None, 'media=%s' % media, interface)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(new_img)
+
+ def test_remove_on_empty(self):
+ result = self.vm.qmp('blockdev-open-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('blockdev-remove-medium', device='drive0')
+ # Should be a no-op
+ self.assert_qmp(result, 'return', {})
+
+class TestCDInitiallyFilled(TestInitiallyFilled):
+ TestInitiallyFilled = TestInitiallyFilled
+ has_real_tray = True
+
+ def setUp(self):
+ self.TestInitiallyFilled.setUp(self, 'cdrom', 'ide')
+
+class TestCDInitiallyEmpty(TestInitiallyEmpty):
+ TestInitiallyEmpty = TestInitiallyEmpty
+ has_real_tray = True
+
+ def setUp(self):
+ self.TestInitiallyEmpty.setUp(self, 'cdrom', 'ide')
+
+class TestFloppyInitiallyFilled(TestInitiallyFilled):
+ TestInitiallyFilled = TestInitiallyFilled
+ has_real_tray = False
+
+ def setUp(self):
+ self.TestInitiallyFilled.setUp(self, 'disk', 'floppy')
+
+class TestFloppyInitiallyEmpty(TestInitiallyEmpty):
+ TestInitiallyEmpty = TestInitiallyEmpty
+ has_real_tray = False
+
+ def setUp(self):
+ self.TestInitiallyEmpty.setUp(self, 'disk', 'floppy')
+ # FDDs not having a real tray and there not being a medium inside the
+ # tray at startup means the tray will be considered open
+ self.has_opened = True
+
+class TestChangeReadOnly(ChangeBaseClass):
+ def setUp(self):
+ qemu_img('create', '-f', iotests.imgfmt, old_img, '1440k')
+ qemu_img('create', '-f', iotests.imgfmt, new_img, '1440k')
+ self.vm = iotests.VM()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.chmod(old_img, 0666)
+ os.chmod(new_img, 0666)
+ os.remove(old_img)
+ os.remove(new_img)
+
+ def test_ro_ro_retain(self):
+ os.chmod(old_img, 0444)
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_ro_rw_retain(self):
+ os.chmod(old_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_rw_ro_retain(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def test_ro_rw(self):
+ os.chmod(old_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium',
+ device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='read-write')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_rw_ro(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium',
+ device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='read-only')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_make_rw_ro(self):
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium',
+ device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='read-only')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_make_ro_rw(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium',
+ device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='read-write')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def test_make_rw_ro_by_retain(self):
+ os.chmod(old_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk,read-only=on', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ def test_make_ro_rw_by_retain(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-change-medium', device='drive0',
+ filename=new_img,
+ format=iotests.imgfmt,
+ read_only_mode='retain')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ self.assertEquals(self.vm.get_qmp_events(wait=False), [])
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def test_rw_ro_cycle(self):
+ os.chmod(new_img, 0444)
+ self.vm.add_drive(old_img, 'media=disk', 'floppy')
+ self.vm.launch()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'new',
+ 'driver': iotests.imgfmt,
+ 'read-only': True,
+ 'file': {'filename': new_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-open-tray', device='drive0', force=True)
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_open()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp(result, 'return[0]/inserted/ro', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ result = self.vm.qmp('blockdev-remove-medium', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('blockdev-insert-medium', device='drive0',
+ node_name='new')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', True)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+ result = self.vm.qmp('blockdev-close-tray', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_for_close()
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/ro', True)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+
+GeneralChangeTestsBaseClass = None
+TestInitiallyFilled = None
+TestInitiallyEmpty = None
+
+
+class TestBlockJobsAfterCycle(ChangeBaseClass):
+ def setUp(self):
+ qemu_img('create', '-f', iotests.imgfmt, old_img, '1M')
+
+ self.vm = iotests.VM()
+ self.vm.launch()
+
+ result = self.vm.qmp('blockdev-add',
+ options={'id': 'drive0',
+ 'driver': 'null-co'})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/format', 'null-co')
+
+ # For device-less BBs, calling blockdev-open-tray or blockdev-close-tray
+ # is not necessary
+ result = self.vm.qmp('blockdev-remove-medium', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp_absent(result, 'return[0]/inserted')
+
+ result = self.vm.qmp('blockdev-add',
+ options={'node-name': 'node0',
+ 'driver': iotests.imgfmt,
+ 'file': {'filename': old_img,
+ 'driver': 'file'}})
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('blockdev-insert-medium', device='drive0',
+ node_name='node0')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/tray_open', False)
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', old_img)
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(old_img)
+ try:
+ os.remove(new_img)
+ except OSError:
+ pass
+
+ def test_snapshot_and_commit(self):
+ # We need backing file support
+ if iotests.imgfmt != 'qcow2' and iotests.imgfmt != 'qed':
+ return
+
+ result = self.vm.qmp('blockdev-snapshot-sync', device='drive0',
+ snapshot_file=new_img,
+ format=iotests.imgfmt)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/inserted/image/filename', new_img)
+ self.assert_qmp(result,
+ 'return[0]/inserted/image/backing-image/filename',
+ old_img)
+
+ result = self.vm.qmp('block-commit', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.vm.event_wait(name='BLOCK_JOB_READY')
+
+ result = self.vm.qmp('query-block-jobs')
+ self.assert_qmp(result, 'return[0]/device', 'drive0')
+
+ result = self.vm.qmp('block-job-complete', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.vm.event_wait(name='BLOCK_JOB_COMPLETED')
+
+
+if __name__ == '__main__':
+ if iotests.qemu_default_machine != 'pc':
+ # We need floppy and IDE CD-ROM
+ iotests.notrun('not suitable for this machine type: %s' %
+ iotests.qemu_default_machine)
+ iotests.main()
diff --git a/tests/qemu-iotests/118.out b/tests/qemu-iotests/118.out
new file mode 100644
index 0000000..6a91713
--- /dev/null
+++ b/tests/qemu-iotests/118.out
@@ -0,0 +1,5 @@
+...........................................................
+----------------------------------------------------------------------
+Ran 59 tests
+
+OK
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 30c784e..a6a61ae 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -122,6 +122,7 @@
114 rw auto quick
115 rw auto
116 rw auto quick
+118 rw auto
119 rw auto quick
120 rw auto quick
121 rw auto
--
2.6.2
^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media
2015-10-26 20:39 [Qemu-devel] [PATCH v8 00/15] blockdev: BlockBackend and media Max Reitz
` (14 preceding siblings ...)
2015-10-26 20:39 ` [Qemu-devel] [PATCH v8 15/15] iotests: Add test for change-related QMP commands Max Reitz
@ 2015-10-27 14:18 ` Kevin Wolf
15 siblings, 0 replies; 20+ messages in thread
From: Kevin Wolf @ 2015-10-27 14:18 UTC (permalink / raw)
To: Max Reitz
Cc: Alberto Garcia, qemu-block, John Snow, qemu-devel,
Markus Armbruster, Stefan Hajnoczi
Am 26.10.2015 um 21:39 hat Max Reitz geschrieben:
> Now that the main rework part of this series is merged, these remaining
> patches here implement atomic tray/medium operations and add the
> read-only-mode parameter to change and blockdev-change-medium (which was
> the original purpose of this series!).
>
> Once again, I'd like to thank all the reviewers for sticking to this
> long series over many iterations. Thanks a lot! :-)
Thanks, applied to the block branch.
Kevin
^ permalink raw reply [flat|nested] 20+ messages in thread