This is an option that is directly mapped to the blockdev-add QMP command. It works more or less like -drive, except that it doesn't create a BlockBackend and doesn't support legacy options.
This patch adds minimal documentation, the next patches will improve it. Signed-off-by: Kevin Wolf <kw...@redhat.com> --- blockdev.c | 12 +++++++++++ include/sysemu/sysemu.h | 1 + qemu-options.hx | 12 +++++++++++ vl.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+) diff --git a/blockdev.c b/blockdev.c index 76b86ab..5931383 100644 --- a/blockdev.c +++ b/blockdev.c @@ -4075,3 +4075,15 @@ QemuOptsList qemu_drive_opts = { { /* end of list */ } }, }; + +QemuOptsList qemu_blockdev_opts = { + .name = "blockdev", + .head = QTAILQ_HEAD_INITIALIZER(qemu_blockdev_opts.head), + .desc = { + /* + * no elements => accept any params + * validation will happen later + */ + { /* end of list */ } + }, +}; diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h index ee7c760..1a2013a 100644 --- a/include/sysemu/sysemu.h +++ b/include/sysemu/sysemu.h @@ -238,6 +238,7 @@ bool defaults_enabled(void); extern QemuOptsList qemu_legacy_drive_opts; extern QemuOptsList qemu_common_drive_opts; extern QemuOptsList qemu_drive_opts; +extern QemuOptsList qemu_blockdev_opts; extern QemuOptsList qemu_chardev_opts; extern QemuOptsList qemu_device_opts; extern QemuOptsList qemu_netdev_opts; diff --git a/qemu-options.hx b/qemu-options.hx index 0b621bb..542c483 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -513,6 +513,18 @@ Use @var{file} as CD-ROM image (you cannot use @option{-hdc} and using @file{/dev/cdrom} as filename (@pxref{host_drives}). ETEXI +DEF("blockdev", HAS_ARG, QEMU_OPTION_blockdev, + "-blockdev driver=driver[,node-name=n][,read-only=on|off]\n" + " [,cache.direct=on|off][,cache.no-flush=on|off]\n" + " [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n" + " [,...driver specific...]\n", QEMU_ARCH_ALL) +STEXI +@item -blockdev @var{option}[,@var{option}[,@var{option}[,...]]] +@findex -blockdev + +Define a new block driver node. +ETEXI + DEF("drive", HAS_ARG, QEMU_OPTION_drive, "-drive [file=file][,if=type][,bus=n][,unit=m][,media=d][,index=i]\n" " [,cyls=c,heads=h,secs=s[,trans=t]][,snapshot=on|off]\n" diff --git a/vl.c b/vl.c index fd321e2..f146a59 100644 --- a/vl.c +++ b/vl.c @@ -122,6 +122,9 @@ int main(int argc, char **argv) #include "sysemu/replay.h" #include "qapi/qmp/qerror.h" #include "sysemu/iothread.h" +#include "qapi-visit.h" +#include "qapi/qobject-input-visitor.h" +#include "qapi/dealloc-visitor.h" #define MAX_VIRTIO_CONSOLES 1 #define MAX_SCLP_CONSOLES 1 @@ -1169,6 +1172,42 @@ static int cleanup_add_fd(void *opaque, QemuOpts *opts, Error **errp) #define MTD_OPTS "" #define SD_OPTS "" +static int blockdev_init_func(void *opaque, QemuOpts *opts, Error **errp) +{ + BlockdevOptions *options = NULL; + Visitor *v = NULL; + Error *local_err = NULL; + + QDict *opts_dict = qemu_opts_to_qdict(opts, NULL); + QObject *crumpled = qdict_crumple(opts_dict, true, &local_err); + if (local_err) { + goto fail; + } + + v = qobject_string_input_visitor_new(crumpled); + visit_type_BlockdevOptions(v, NULL, &options, &local_err); + if (local_err) { + goto fail; + } + visit_complete(v, opts); + + qmp_blockdev_add(options, &local_err); + if (local_err) { + goto fail; + } + +fail: + qapi_free_BlockdevOptions(options); + visit_free(v); + QDECREF(opts_dict); + qobject_decref(crumpled); + + if (local_err) { + error_propagate(errp, local_err); + } + return !!local_err; +} + static int drive_init_func(void *opaque, QemuOpts *opts, Error **errp) { BlockInterfaceType *block_default_type = opaque; @@ -3027,6 +3066,7 @@ int main(int argc, char **argv, char **envp) module_call_init(MODULE_INIT_QAPI); qemu_add_opts(&qemu_drive_opts); + qemu_add_opts(&qemu_blockdev_opts); qemu_add_drive_opts(&qemu_legacy_drive_opts); qemu_add_drive_opts(&qemu_common_drive_opts); qemu_add_drive_opts(&qemu_drive_opts); @@ -3162,6 +3202,13 @@ int main(int argc, char **argv, char **envp) exit(1); } break; + case QEMU_OPTION_blockdev: + opts = qemu_opts_parse_noisily(qemu_find_opts("blockdev"), + optarg, false); + if (opts == NULL) { + exit(1); + } + break; case QEMU_OPTION_set: if (qemu_set_option(optarg) != 0) exit(1); @@ -4449,6 +4496,12 @@ int main(int argc, char **argv, char **envp) } /* open the virtual block devices */ + if (qemu_opts_foreach(qemu_find_opts("blockdev"), blockdev_init_func, + NULL, &err)) { + error_report_err(err); + exit(1); + } + if (snapshot || replay_mode != REPLAY_MODE_NONE) { qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot, NULL, NULL); -- 1.8.3.1