diff options
-rw-r--r-- | blockdev.c | 44 | ||||
-rw-r--r-- | qapi/block-core.json | 13 | ||||
-rwxr-xr-x | tests/qemu-iotests/087 | 2 | ||||
-rw-r--r-- | tests/qemu-iotests/087.out | 4 |
4 files changed, 43 insertions, 20 deletions
diff --git a/blockdev.c b/blockdev.c index 27398b1041..0785557550 100644 --- a/blockdev.c +++ b/blockdev.c @@ -3026,17 +3026,12 @@ out: void qmp_blockdev_add(BlockdevOptions *options, Error **errp) { QmpOutputVisitor *ov = qmp_output_visitor_new(); - BlockBackend *blk; + BlockDriverState *bs; + BlockBackend *blk = NULL; QObject *obj; QDict *qdict; Error *local_err = NULL; - /* Require an ID in the top level */ - if (!options->has_id) { - error_setg(errp, "Block device needs an ID"); - goto fail; - } - /* TODO Sort it out in raw-posix and drive_new(): Reject aio=native with * cache.direct=false instead of silently switching to aio=threads, except * when called from drive_new(). @@ -3064,14 +3059,37 @@ void qmp_blockdev_add(BlockdevOptions *options, Error **errp) qdict_flatten(qdict); - blk = blockdev_init(NULL, qdict, &local_err); - if (local_err) { - error_propagate(errp, local_err); - goto fail; + if (options->has_id) { + blk = blockdev_init(NULL, qdict, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto fail; + } + + bs = blk_bs(blk); + } else { + int ret; + + if (!qdict_get_try_str(qdict, "node-name")) { + error_setg(errp, "'id' and/or 'node-name' need to be specified for " + "the root node"); + goto fail; + } + + bs = NULL; + ret = bdrv_open(&bs, NULL, NULL, qdict, BDRV_O_RDWR | BDRV_O_CACHE_WB, + errp); + if (ret < 0) { + goto fail; + } } - if (bdrv_key_required(blk_bs(blk))) { - blk_unref(blk); + if (bs && bdrv_key_required(bs)) { + if (blk) { + blk_unref(blk); + } else { + bdrv_unref(bs); + } error_setg(errp, "blockdev-add doesn't support encrypted devices"); goto fail; } diff --git a/qapi/block-core.json b/qapi/block-core.json index c04256185b..425fdab706 100644 --- a/qapi/block-core.json +++ b/qapi/block-core.json @@ -1393,9 +1393,12 @@ # # @driver: block driver name # @id: #optional id by which the new block device can be referred to. -# This is a required option on the top level of blockdev-add, and -# currently not allowed on any other level. -# @node-name: #optional the name of a block driver state node (Since 2.0) +# This option is only allowed on the top level of blockdev-add. +# A BlockBackend will be created by blockdev-add if and only if +# this option is given. +# @node-name: #optional the name of a block driver state node (Since 2.0). +# This option is required on the top level of blockdev-add if +# the @id option is not given there. # @discard: #optional discard-related options (default: ignore) # @cache: #optional cache-related options # @aio: #optional AIO backend (default: threads) @@ -1859,7 +1862,9 @@ ## # @blockdev-add: # -# Creates a new block device. +# Creates a new block device. If the @id option is given at the top level, a +# BlockBackend will be created; otherwise, @node-name is mandatory at the top +# level and no BlockBackend will be created. # # This command is still a work in progress. It doesn't support all # block drivers, it lacks a matching blockdev-del, and more. Stay diff --git a/tests/qemu-iotests/087 b/tests/qemu-iotests/087 index 8694749947..af44299e07 100755 --- a/tests/qemu-iotests/087 +++ b/tests/qemu-iotests/087 @@ -54,7 +54,7 @@ size=128M _make_test_img $size echo -echo === Missing ID === +echo === Missing ID and node-name === echo run_qemu <<EOF diff --git a/tests/qemu-iotests/087.out b/tests/qemu-iotests/087.out index c509a408e2..7d62cd5840 100644 --- a/tests/qemu-iotests/087.out +++ b/tests/qemu-iotests/087.out @@ -1,12 +1,12 @@ QA output created by 087 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 -=== Missing ID === +=== Missing ID and node-name === Testing: QMP_VERSION {"return": {}} -{"error": {"class": "GenericError", "desc": "Block device needs an ID"}} +{"error": {"class": "GenericError", "desc": "'id' and/or 'node-name' need to be specified for the root node"}} {"return": {}} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} |