[Qemu-devel] [PATCH RFC v3 5/5] block: Crude initial implementation of -blockdev

Markus Armbruster posted 5 patches 8 years, 4 months ago
[Qemu-devel] [PATCH RFC v3 5/5] block: Crude initial implementation of -blockdev
Posted by Markus Armbruster 8 years, 4 months ago
The new command line option -blockdev works like QMP command
blockdev-add.

The option argument may be given in JSON syntax, exactly as in QMP.
Example usage:

    -blockdev '{"node-name": "foo", "driver": "raw", "file": {"driver": "file", "filename": "foo.img"} }'

The JSON argument doesn't exactly blend into the existing option
syntax, so the traditional KEY=VALUE,... syntax is also supported,
using dotted keys to do the nesting:

    -blockdev node-name=foo,driver=raw,file.driver=file,file.filename=foo.img

Note that calling qmp_blockdev_add() (say via qmp_marshal_block_add())
right away would crash.  We need to stash the configuration for later
instead.  This is crudely done, and bypasses QemuOpts, even though
storing configuration is what QemuOpts is for.  Need to revamp option
infrastructure to support QAPI types like BlockdevOptions.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
---
 qemu-options.hx |  3 +++
 vl.c            | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/qemu-options.hx b/qemu-options.hx
index 9936cf3..36a38d7 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -512,6 +512,9 @@ 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 FIXME document\n", QEMU_OPTION_blockdev)
+
 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 b5d0a19..37be73c 100644
--- a/vl.c
+++ b/vl.c
@@ -95,6 +95,9 @@ int main(int argc, char **argv)
 #include "migration/colo.h"
 #include "sysemu/kvm.h"
 #include "sysemu/hax.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi/qobject-input-visitor.h"
+#include "qapi-visit.h"
 #include "qapi/qmp/qjson.h"
 #include "qemu/option.h"
 #include "qemu/config-file.h"
@@ -2954,6 +2957,12 @@ int main(int argc, char **argv, char **envp)
     Error *main_loop_err = NULL;
     Error *err = NULL;
     bool list_data_dirs = false;
+    typedef struct BlockdevOptions_queue {
+        BlockdevOptions *bdo;
+        Location loc;
+        QSIMPLEQ_ENTRY(BlockdevOptions_queue) entry;
+    } BlockdevOptions_queue;
+    QSIMPLEQ_HEAD(, BlockdevOptions_queue) bdo_queue = QSIMPLEQ_HEAD_INITIALIZER(bdo_queue);
 
     module_call_init(MODULE_INIT_TRACE);
 
@@ -3095,6 +3104,37 @@ int main(int argc, char **argv, char **envp)
                 drive_add(IF_DEFAULT, popt->index - QEMU_OPTION_hda, optarg,
                           HD_OPTS);
                 break;
+            case QEMU_OPTION_blockdev:
+                {
+                    BlockdevOptions_queue *bdo = g_new(BlockdevOptions_queue, 1);
+                    bool is_json = optarg[0] == '{';
+                    QObject *obj;
+                    QDict *args;
+                    Visitor *v;
+
+                    if (is_json) {
+                        obj = qobject_from_json(optarg);
+                        // TODO get error out of parser
+                        if (!obj) {
+                            error_report("invalid JSON");
+                            exit(1);
+                        }
+                        args = qobject_to_qdict(obj);
+                        assert(args);
+                        v = qobject_input_visitor_new(QOBJECT(args), true);
+                    } else {
+                        args = keyval_parse(optarg, "driver", &error_fatal);
+                        v = qobject_input_visitor_new_autocast(QOBJECT(args));
+                    }
+
+                    visit_type_BlockdevOptions(v, NULL, &bdo->bdo,
+                                               &error_fatal);
+                    visit_free(v);
+                    QDECREF(args);
+                    loc_save(&bdo->loc);
+                    QSIMPLEQ_INSERT_TAIL(&bdo_queue, bdo, entry);
+                    break;
+                }
             case QEMU_OPTION_drive:
                 if (drive_def(optarg) == NULL) {
                     exit(1);
@@ -4407,6 +4447,16 @@ int main(int argc, char **argv, char **envp)
         qemu_opts_foreach(qemu_find_opts("drive"), drive_enable_snapshot,
                           NULL, NULL);
     }
+    while (!QSIMPLEQ_EMPTY(&bdo_queue)) {
+        BlockdevOptions_queue *bdo = QSIMPLEQ_FIRST(&bdo_queue);
+
+        QSIMPLEQ_REMOVE_HEAD(&bdo_queue, entry);
+        loc_push_restore(&bdo->loc);
+        qmp_blockdev_add(bdo->bdo, &error_fatal);
+        loc_pop(&bdo->loc);
+        qapi_free_BlockdevOptions(bdo->bdo);
+        g_free(bdo);
+    }
     if (qemu_opts_foreach(qemu_find_opts("drive"), drive_init_func,
                           &machine_class->block_default_type, NULL)) {
         exit(1);
-- 
2.7.4


Re: [Qemu-devel] [PATCH RFC v3 5/5] block: Crude initial implementation of -blockdev
Posted by Eric Blake 8 years, 4 months ago
On 02/21/2017 03:01 PM, Markus Armbruster wrote:
> The new command line option -blockdev works like QMP command
> blockdev-add.
> 
> The option argument may be given in JSON syntax, exactly as in QMP.
> Example usage:
> 
>     -blockdev '{"node-name": "foo", "driver": "raw", "file": {"driver": "file", "filename": "foo.img"} }'
> 
> The JSON argument doesn't exactly blend into the existing option
> syntax, so the traditional KEY=VALUE,... syntax is also supported,
> using dotted keys to do the nesting:
> 
>     -blockdev node-name=foo,driver=raw,file.driver=file,file.filename=foo.img

Some of the list ideas were allowing mix-and-match or re-opening the
dict; do we want to allow any of these? (maybe as followups?)

-blockdev
node-name=foo,driver=raw,file='{"driver":"file"}',file.filename=foo.img


> 
> Note that calling qmp_blockdev_add() (say via qmp_marshal_block_add())
> right away would crash.  We need to stash the configuration for later
> instead.  This is crudely done, and bypasses QemuOpts, even though
> storing configuration is what QemuOpts is for.  Need to revamp option
> infrastructure to support QAPI types like BlockdevOptions.
> 
> Signed-off-by: Markus Armbruster <armbru@redhat.com>
> ---
>  qemu-options.hx |  3 +++
>  vl.c            | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 53 insertions(+)
> 
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 9936cf3..36a38d7 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -512,6 +512,9 @@ 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 FIXME document\n", QEMU_OPTION_blockdev)

Adequate for an RFC, but I can see how you want to improve it.

> @@ -3095,6 +3104,37 @@ int main(int argc, char **argv, char **envp)
>                  drive_add(IF_DEFAULT, popt->index - QEMU_OPTION_hda, optarg,
>                            HD_OPTS);
>                  break;
> +            case QEMU_OPTION_blockdev:
> +                {
> +                    BlockdevOptions_queue *bdo = g_new(BlockdevOptions_queue, 1);
> +                    bool is_json = optarg[0] == '{';
> +                    QObject *obj;
> +                    QDict *args;
> +                    Visitor *v;
> +
> +                    if (is_json) {
> +                        obj = qobject_from_json(optarg);
> +                        // TODO get error out of parser

Yeah, that's something we still need to improve.

> +                        if (!obj) {
> +                            error_report("invalid JSON");
> +                            exit(1);
> +                        }
> +                        args = qobject_to_qdict(obj);
> +                        assert(args);
> +                        v = qobject_input_visitor_new(QOBJECT(args), true);
> +                    } else {
> +                        args = keyval_parse(optarg, "driver", &error_fatal);
> +                        v = qobject_input_visitor_new_autocast(QOBJECT(args));
> +                    }

Pretty slick!  And answers my question: no mix-and-match of JSON and
dotted (all one or the other) within a single -blockdev argument.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org