blockdev: 'blockdev-add' QMP command
For examples see the changes to qmp-commands.hx. Signed-off-by: Kevin Wolf <kwolf@redhat.com>
This commit is contained in:
parent
2d246f01d3
commit
d26c9a1573
57
blockdev.c
57
blockdev.c
@ -38,6 +38,8 @@
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "qapi/qmp/types.h"
|
||||
#include "qapi-visit.h"
|
||||
#include "qapi/qmp-output-visitor.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "block/block_int.h"
|
||||
#include "qmp-commands.h"
|
||||
@ -2066,6 +2068,61 @@ void qmp_block_job_complete(const char *device, Error **errp)
|
||||
block_job_complete(job, errp);
|
||||
}
|
||||
|
||||
void qmp_blockdev_add(BlockdevOptions *options, Error **errp)
|
||||
{
|
||||
QmpOutputVisitor *ov = qmp_output_visitor_new();
|
||||
QObject *obj;
|
||||
QDict *qdict;
|
||||
DriveInfo *dinfo;
|
||||
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_init: Reject aio=native with
|
||||
* cache.direct=false instead of silently switching to aio=threads, except
|
||||
* if called from drive_init.
|
||||
*
|
||||
* For now, simply forbidding the combination for all drivers will do. */
|
||||
if (options->has_aio && options->aio == BLOCKDEV_AIO_OPTIONS_NATIVE) {
|
||||
bool direct = options->cache->has_direct && options->cache->direct;
|
||||
if (!options->has_cache && !direct) {
|
||||
error_setg(errp, "aio=native requires cache.direct=true");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
visit_type_BlockdevOptions(qmp_output_get_visitor(ov),
|
||||
&options, NULL, &local_err);
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
obj = qmp_output_get_qobject(ov);
|
||||
qdict = qobject_to_qdict(obj);
|
||||
|
||||
qdict_flatten(qdict);
|
||||
|
||||
QemuOpts *opts = qemu_opts_from_qdict(&qemu_drive_opts, qdict, &local_err);
|
||||
if (error_is_set(&local_err)) {
|
||||
error_propagate(errp, local_err);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dinfo = blockdev_init(opts, IF_NONE);
|
||||
if (!dinfo) {
|
||||
error_setg(errp, "Could not open image");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
qmp_output_visitor_cleanup(ov);
|
||||
}
|
||||
|
||||
static void do_qmp_query_block_jobs_one(void *opaque, BlockDriverState *bs)
|
||||
{
|
||||
BlockJobInfoList **prev = opaque;
|
||||
|
236
qapi-schema.json
236
qapi-schema.json
@ -3952,3 +3952,239 @@
|
||||
##
|
||||
{ 'command': 'query-rx-filter', 'data': { '*name': 'str' },
|
||||
'returns': ['RxFilterInfo'] }
|
||||
|
||||
|
||||
##
|
||||
# @BlockdevDiscardOptions
|
||||
#
|
||||
# Determines how to handle discard requests.
|
||||
#
|
||||
# @ignore: Ignore the request
|
||||
# @unmap: Forward as an unmap request
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'enum': 'BlockdevDiscardOptions',
|
||||
'data': [ 'ignore', 'unmap' ] }
|
||||
|
||||
##
|
||||
# @BlockdevAioOptions
|
||||
#
|
||||
# Selects the AIO backend to handle I/O requests
|
||||
#
|
||||
# @threads: Use qemu's thread pool
|
||||
# @native: Use native AIO backend (only Linux and Windows)
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'enum': 'BlockdevAioOptions',
|
||||
'data': [ 'threads', 'native' ] }
|
||||
|
||||
##
|
||||
# @BlockdevCacheOptions
|
||||
#
|
||||
# Includes cache-related options for block devices
|
||||
#
|
||||
# @writeback: #optional enables writeback mode for any caches (default: true)
|
||||
# @direct: #optional enables use of O_DIRECT (bypass the host page cache;
|
||||
# default: false)
|
||||
# @no-flush: #optional ignore any flush requests for the device (default:
|
||||
# false)
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'type': 'BlockdevCacheOptions',
|
||||
'data': { '*writeback': 'bool',
|
||||
'*direct': 'bool',
|
||||
'*no-flush': 'bool' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsBase
|
||||
#
|
||||
# Options that are available for all block devices, independent of the block
|
||||
# driver.
|
||||
#
|
||||
# @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.
|
||||
# @discard: #optional discard-related options (default: ignore)
|
||||
# @cache: #optional cache-related options
|
||||
# @aio: #optional AIO backend (default: threads)
|
||||
# @rerror: #optional how to handle read errors on the device
|
||||
# (default: report)
|
||||
# @werror: #optional how to handle write errors on the device
|
||||
# (default: enospc)
|
||||
# @read-only: #optional whether the block device should be read-only
|
||||
# (default: false)
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'type': 'BlockdevOptionsBase',
|
||||
'data': { 'driver': 'str',
|
||||
'*id': 'str',
|
||||
'*discard': 'BlockdevDiscardOptions',
|
||||
'*cache': 'BlockdevCacheOptions',
|
||||
'*aio': 'BlockdevAioOptions',
|
||||
'*rerror': 'BlockdevOnError',
|
||||
'*werror': 'BlockdevOnError',
|
||||
'*read-only': 'bool' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsFile
|
||||
#
|
||||
# Driver specific block device options for the file backend and similar
|
||||
# protocols.
|
||||
#
|
||||
# @filename: path to the image file
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'type': 'BlockdevOptionsFile',
|
||||
'data': { 'filename': 'str' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsVVFAT
|
||||
#
|
||||
# Driver specific block device options for the vvfat protocol.
|
||||
#
|
||||
# @dir: directory to be exported as FAT image
|
||||
# @fat-type: #optional FAT type: 12, 16 or 32
|
||||
# @floppy: #optional whether to export a floppy image (true) or
|
||||
# partitioned hard disk (false; default)
|
||||
# @rw: #optional whether to allow write operations (default: false)
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'type': 'BlockdevOptionsVVFAT',
|
||||
'data': { 'dir': 'str', '*fat-type': 'int', '*floppy': 'bool',
|
||||
'*rw': 'bool' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsGenericFormat
|
||||
#
|
||||
# Driver specific block device options for image format that have no option
|
||||
# besides their data source.
|
||||
#
|
||||
# @file: reference to or definition of the data source block device
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'type': 'BlockdevOptionsGenericFormat',
|
||||
'data': { 'file': 'BlockdevRef' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsGenericCOWFormat
|
||||
#
|
||||
# Driver specific block device options for image format that have no option
|
||||
# besides their data source and an optional backing file.
|
||||
#
|
||||
# @backing: #optional reference to or definition of the backing file block
|
||||
# device (if missing, taken from the image file content). It is
|
||||
# allowed to pass an empty string here in order to disable the
|
||||
# default backing file.
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'type': 'BlockdevOptionsGenericCOWFormat',
|
||||
'base': 'BlockdevOptionsGenericFormat',
|
||||
'data': { '*backing': 'BlockdevRef' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptionsQcow2
|
||||
#
|
||||
# Driver specific block device options for qcow2.
|
||||
#
|
||||
# @lazy-refcounts: #optional whether to enable the lazy refcounts
|
||||
# feature (default is taken from the image file)
|
||||
#
|
||||
# @pass-discard-request: #optional whether discard requests to the qcow2
|
||||
# device should be forwarded to the data source
|
||||
#
|
||||
# @pass-discard-snapshot: #optional whether discard requests for the data source
|
||||
# should be issued when a snapshot operation (e.g.
|
||||
# deleting a snapshot) frees clusters in the qcow2 file
|
||||
#
|
||||
# @pass-discard-other: #optional whether discard requests for the data source
|
||||
# should be issued on other occasions where a cluster
|
||||
# gets freed
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'type': 'BlockdevOptionsQcow2',
|
||||
'base': 'BlockdevOptionsGenericCOWFormat',
|
||||
'data': { '*lazy-refcounts': 'bool',
|
||||
'*pass-discard-request': 'bool',
|
||||
'*pass-discard-snapshot': 'bool',
|
||||
'*pass-discard-other': 'bool' } }
|
||||
|
||||
##
|
||||
# @BlockdevOptions
|
||||
#
|
||||
# Options for creating a block device.
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'union': 'BlockdevOptions',
|
||||
'base': 'BlockdevOptionsBase',
|
||||
'discriminator': 'driver',
|
||||
'data': {
|
||||
'file': 'BlockdevOptionsFile',
|
||||
'http': 'BlockdevOptionsFile',
|
||||
'https': 'BlockdevOptionsFile',
|
||||
'ftp': 'BlockdevOptionsFile',
|
||||
'ftps': 'BlockdevOptionsFile',
|
||||
'tftp': 'BlockdevOptionsFile',
|
||||
# TODO gluster: Wait for structured options
|
||||
# TODO iscsi: Wait for structured options
|
||||
# TODO nbd: Should take InetSocketAddress for 'host'?
|
||||
# TODO rbd: Wait for structured options
|
||||
# TODO sheepdog: Wait for structured options
|
||||
# TODO ssh: Should take InetSocketAddress for 'host'?
|
||||
'vvfat': 'BlockdevOptionsVVFAT',
|
||||
|
||||
# TODO blkdebug: Wait for structured options
|
||||
# TODO blkverify: Wait for structured options
|
||||
|
||||
'bochs': 'BlockdevOptionsGenericFormat',
|
||||
'cloop': 'BlockdevOptionsGenericFormat',
|
||||
'cow': 'BlockdevOptionsGenericCOWFormat',
|
||||
'dmg': 'BlockdevOptionsGenericFormat',
|
||||
'parallels': 'BlockdevOptionsGenericFormat',
|
||||
'qcow': 'BlockdevOptionsGenericCOWFormat',
|
||||
'qcow2': 'BlockdevOptionsQcow2',
|
||||
'qed': 'BlockdevOptionsGenericCOWFormat',
|
||||
'raw': 'BlockdevOptionsGenericFormat',
|
||||
'vdi': 'BlockdevOptionsGenericFormat',
|
||||
'vhdx': 'BlockdevOptionsGenericFormat',
|
||||
'vmdk': 'BlockdevOptionsGenericCOWFormat',
|
||||
'vpc': 'BlockdevOptionsGenericFormat'
|
||||
} }
|
||||
|
||||
##
|
||||
# @BlockdevRef
|
||||
#
|
||||
# Reference to a block device.
|
||||
#
|
||||
# @definition: defines a new block device inline
|
||||
# @reference: references the ID of an existing block device. An
|
||||
# empty string means that no block device should be
|
||||
# referenced.
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'union': 'BlockdevRef',
|
||||
'discriminator': {},
|
||||
'data': { 'definition': 'BlockdevOptions',
|
||||
'reference': 'str' } }
|
||||
|
||||
##
|
||||
# @blockdev-add:
|
||||
#
|
||||
# Creates a new block device.
|
||||
#
|
||||
# @options: block device options for the new device
|
||||
#
|
||||
# Since: 1.7
|
||||
##
|
||||
{ 'command': 'blockdev-add', 'data': { 'options': 'BlockdevOptions' } }
|
||||
|
@ -3239,4 +3239,59 @@ Example:
|
||||
]
|
||||
}
|
||||
|
||||
EQMP
|
||||
|
||||
{
|
||||
.name = "blockdev-add",
|
||||
.args_type = "options:q",
|
||||
.mhandler.cmd_new = qmp_marshal_input_blockdev_add,
|
||||
},
|
||||
|
||||
SQMP
|
||||
blockdev-add
|
||||
------------
|
||||
|
||||
Add a block device.
|
||||
|
||||
Arguments:
|
||||
|
||||
- "options": block driver options
|
||||
|
||||
Example (1):
|
||||
|
||||
-> { "execute": "blockdev-add",
|
||||
"arguments": { "options" : { "driver": "qcow2",
|
||||
"file": { "driver": "file",
|
||||
"filename": "test.qcow2" } } } }
|
||||
<- { "return": {} }
|
||||
|
||||
Example (2):
|
||||
|
||||
-> { "execute": "blockdev-add",
|
||||
"arguments": {
|
||||
"options": {
|
||||
"driver": "qcow2",
|
||||
"id": "my_disk",
|
||||
"discard": "unmap",
|
||||
"cache": {
|
||||
"direct": true,
|
||||
"writeback": true
|
||||
},
|
||||
"file": {
|
||||
"driver": "file",
|
||||
"filename": "/tmp/test.qcow2"
|
||||
},
|
||||
"backing": {
|
||||
"driver": "raw",
|
||||
"file": {
|
||||
"driver": "file",
|
||||
"filename": "/dev/fdset/4"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<- { "return": {} }
|
||||
|
||||
EQMP
|
||||
|
Loading…
Reference in New Issue
Block a user