From: "Daniel P. Berrange" <berrange@redhat.com>
To: qemu-devel@nongnu.org
Cc: qemu-block@nongnu.org, "Markus Armbruster" <armbru@redhat.com>,
"Max Reitz" <mreitz@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Andreas Färber" <afaerber@suse.de>,
"Daniel P. Berrange" <berrange@redhat.com>
Subject: [Qemu-devel] [PATCH v14 03/19] option: allow qemu_opts_to_qdict to merge repeated options
Date: Tue, 27 Sep 2016 14:13:05 +0100 [thread overview]
Message-ID: <1474982001-20878-4-git-send-email-berrange@redhat.com> (raw)
In-Reply-To: <1474982001-20878-1-git-send-email-berrange@redhat.com>
If given an option string such as
size=1024,nodes=10,nodes=4-5,nodes=1-2,policy=bind
the qemu_opts_to_qdict() method will currently overwrite
the values for repeated option keys, so only the last
value is in the returned dict:
size=1024
nodes=1-2
policy=bind
This adds the ability for the caller to ask that the
repeated keys be turned into list indexes:
size=1024
nodes.0=10
nodes.1=4-5
nodes.2=1-2
policy=bind
Note that the conversion has no way of knowing whether
any given key is expected to be a list upfront - it can
only figure that out when seeing the first duplicated
key. Thus the caller has to be prepared to deal with the
fact that if a key 'foo' is a list, then the returned
qdict may contain either 'foo' (if only a single instance
of the key was seen) or 'foo.NN' (if multiple instances
of the key were seen).
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
---
blockdev.c | 7 ++++---
include/qemu/option.h | 8 +++++++-
monitor.c | 3 ++-
qemu-img.c | 4 +++-
qemu-io-cmds.c | 3 ++-
qemu-io.c | 6 ++++--
qemu-nbd.c | 3 ++-
qom/object_interfaces.c | 3 ++-
tests/test-qemu-opts.c | 40 ++++++++++++++++++++++++++++++++++++++++
tests/test-replication.c | 9 ++++++---
util/qemu-option.c | 41 ++++++++++++++++++++++++++++++++++++++---
11 files changed, 110 insertions(+), 17 deletions(-)
diff --git a/blockdev.c b/blockdev.c
index 3010393..5ef3193 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -911,7 +911,8 @@ DriveInfo *drive_new(QemuOpts *all_opts, BlockInterfaceType block_default_type)
/* Get a QDict for processing the options */
bs_opts = qdict_new();
- qemu_opts_to_qdict(all_opts, bs_opts);
+ qemu_opts_to_qdict(all_opts, bs_opts,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
legacy_opts = qemu_opts_create(&qemu_legacy_drive_opts, NULL, 0,
&error_abort);
@@ -3758,8 +3759,8 @@ void hmp_drive_add_node(Monitor *mon, const char *optstr)
return;
}
- qdict = qemu_opts_to_qdict(opts, NULL);
-
+ qdict = qemu_opts_to_qdict(opts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
if (!qdict_get_try_str(qdict, "node-name")) {
QDECREF(qdict);
error_report("'node-name' needs to be specified");
diff --git a/include/qemu/option.h b/include/qemu/option.h
index 2a5266f..328c468 100644
--- a/include/qemu/option.h
+++ b/include/qemu/option.h
@@ -125,7 +125,13 @@ void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
int permit_abbrev);
QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
Error **errp);
-QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict);
+typedef enum {
+ QEMU_OPTS_REPEAT_POLICY_LAST,
+ QEMU_OPTS_REPEAT_POLICY_LIST,
+} QemuOptsRepeatPolicy;
+
+QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict,
+ QemuOptsRepeatPolicy repeatPolicy);
void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp);
typedef int (*qemu_opts_loopfunc)(void *opaque, QemuOpts *opts, Error **errp);
diff --git a/monitor.c b/monitor.c
index 83c4edf..7dcd66b 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2642,7 +2642,8 @@ static QDict *monitor_parse_arguments(Monitor *mon,
if (!opts) {
goto fail;
}
- qemu_opts_to_qdict(opts, qdict);
+ qemu_opts_to_qdict(opts, qdict,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
qemu_opts_del(opts);
}
break;
diff --git a/qemu-img.c b/qemu-img.c
index ceffefe..b399ae5 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -273,7 +273,9 @@ static BlockBackend *img_open_opts(const char *optstr,
QDict *options;
Error *local_err = NULL;
BlockBackend *blk;
- options = qemu_opts_to_qdict(opts, NULL);
+ options = qemu_opts_to_qdict(opts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
+
blk = blk_new_open(NULL, NULL, options, flags, &local_err);
if (!blk) {
error_reportf_err(local_err, "Could not open '%s': ", optstr);
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 3a3838a..e14beed 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -1952,7 +1952,8 @@ static int reopen_f(BlockBackend *blk, int argc, char **argv)
}
qopts = qemu_opts_find(&reopen_opts, NULL);
- opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
+ opts = qopts ? qemu_opts_to_qdict(qopts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST) : NULL;
qemu_opts_reset(&reopen_opts);
brq = bdrv_reopen_queue(NULL, bs, opts, flags);
diff --git a/qemu-io.c b/qemu-io.c
index db129ea..b295afa 100644
--- a/qemu-io.c
+++ b/qemu-io.c
@@ -207,7 +207,8 @@ static int open_f(BlockBackend *blk, int argc, char **argv)
}
qopts = qemu_opts_find(&empty_opts, NULL);
- opts = qopts ? qemu_opts_to_qdict(qopts, NULL) : NULL;
+ opts = qopts ? qemu_opts_to_qdict(qopts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST) : NULL;
qemu_opts_reset(&empty_opts);
if (optind == argc - 1) {
@@ -593,7 +594,8 @@ int main(int argc, char **argv)
if (!qopts) {
exit(1);
}
- opts = qemu_opts_to_qdict(qopts, NULL);
+ opts = qemu_opts_to_qdict(qopts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
openfile(NULL, flags, writethrough, opts);
} else {
if (format) {
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 99297a5..54eb3ce 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -859,7 +859,8 @@ int main(int argc, char **argv)
qemu_opts_reset(&file_opts);
exit(EXIT_FAILURE);
}
- options = qemu_opts_to_qdict(opts, NULL);
+ options = qemu_opts_to_qdict(opts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
qemu_opts_reset(&file_opts);
blk = blk_new_open(NULL, NULL, options, flags, &local_err);
} else {
diff --git a/qom/object_interfaces.c b/qom/object_interfaces.c
index bf59846..48edf2f 100644
--- a/qom/object_interfaces.c
+++ b/qom/object_interfaces.c
@@ -161,7 +161,8 @@ Object *user_creatable_add_opts(QemuOpts *opts, Error **errp)
Object *obj = NULL;
v = opts_visitor_new(opts);
- pdict = qemu_opts_to_qdict(opts, NULL);
+ pdict = qemu_opts_to_qdict(opts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
obj = user_creatable_add(pdict, v, errp);
visit_free(v);
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
index a505a3e..b68ef74 100644
--- a/tests/test-qemu-opts.c
+++ b/tests/test-qemu-opts.c
@@ -421,6 +421,45 @@ static void test_qemu_opts_set(void)
g_assert(opts == NULL);
}
+
+static void test_qemu_opts_to_qdict(void)
+{
+ QemuOpts *opts;
+ QDict *dict;
+
+ /* dynamically initialized (parsed) opts */
+ opts = qemu_opts_parse(&opts_list_03,
+ "size=1024,nodes=10,nodes=4-5,nodes=1-2,policy=bind",
+ false, NULL);
+ g_assert(opts);
+
+ dict = qemu_opts_to_qdict(opts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
+ g_assert(dict);
+
+ g_assert_cmpstr(qdict_get_str(dict, "size"), ==, "1024");
+ g_assert_cmpstr(qdict_get_str(dict, "nodes"), ==, "1-2");
+ g_assert(!qdict_haskey(dict, "nodes.0"));
+ g_assert(!qdict_haskey(dict, "nodes.1"));
+ g_assert(!qdict_haskey(dict, "nodes.2"));
+ g_assert_cmpstr(qdict_get_str(dict, "policy"), ==, "bind");
+ QDECREF(dict);
+
+ dict = qemu_opts_to_qdict(opts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LIST);
+ g_assert(dict);
+
+ g_assert_cmpstr(qdict_get_str(dict, "size"), ==, "1024");
+ g_assert(!qdict_haskey(dict, "nodes"));
+ g_assert_cmpstr(qdict_get_str(dict, "nodes.0"), ==, "10");
+ g_assert_cmpstr(qdict_get_str(dict, "nodes.1"), ==, "4-5");
+ g_assert_cmpstr(qdict_get_str(dict, "nodes.2"), ==, "1-2");
+ g_assert_cmpstr(qdict_get_str(dict, "policy"), ==, "bind");
+ QDECREF(dict);
+
+ qemu_opts_del(opts);
+}
+
int main(int argc, char *argv[])
{
register_opts();
@@ -435,6 +474,7 @@ int main(int argc, char *argv[])
g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset);
g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset);
g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set);
+ g_test_add_func("/qemu-opts/to_qdict", test_qemu_opts_to_qdict);
g_test_run();
return 0;
}
diff --git a/tests/test-replication.c b/tests/test-replication.c
index 0997bd8..6165ac9 100644
--- a/tests/test-replication.c
+++ b/tests/test-replication.c
@@ -181,7 +181,8 @@ static BlockBackend *start_primary(void)
opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false);
g_free(cmdline);
- qdict = qemu_opts_to_qdict(opts, NULL);
+ qdict = qemu_opts_to_qdict(opts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
@@ -311,7 +312,8 @@ static BlockBackend *start_secondary(void)
opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false);
g_free(cmdline);
- qdict = qemu_opts_to_qdict(opts, NULL);
+ qdict = qemu_opts_to_qdict(opts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
@@ -336,7 +338,8 @@ static BlockBackend *start_secondary(void)
opts = qemu_opts_parse_noisily(&qemu_drive_opts, cmdline, false);
g_free(cmdline);
- qdict = qemu_opts_to_qdict(opts, NULL);
+ qdict = qemu_opts_to_qdict(opts, NULL,
+ QEMU_OPTS_REPEAT_POLICY_LAST);
qdict_set_default_str(qdict, BDRV_OPT_CACHE_DIRECT, "off");
qdict_set_default_str(qdict, BDRV_OPT_CACHE_NO_FLUSH, "off");
diff --git a/util/qemu-option.c b/util/qemu-option.c
index 41b356c..ad28d4e 100644
--- a/util/qemu-option.c
+++ b/util/qemu-option.c
@@ -1058,10 +1058,12 @@ void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
* TODO We'll want to use types appropriate for opt->desc->type, but
* this is enough for now.
*/
-QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
+QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict,
+ QemuOptsRepeatPolicy repeatPolicy)
{
QemuOpt *opt;
- QObject *val;
+ QObject *val, *prevval;
+ QDict *lists = qdict_new();
if (!qdict) {
qdict = qdict_new();
@@ -1070,9 +1072,42 @@ QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
qdict_put(qdict, "id", qstring_from_str(opts->id));
}
QTAILQ_FOREACH(opt, &opts->head, next) {
+ gchar *key = NULL;
val = QOBJECT(qstring_from_str(opt->str));
- qdict_put_obj(qdict, opt->name, val);
+ switch (repeatPolicy) {
+ case QEMU_OPTS_REPEAT_POLICY_LIST:
+ if (qdict_haskey(lists, opt->name)) {
+ /* Current val goes into 'foo.N' */
+ int64_t max = qdict_get_int(lists, opt->name);
+ max++;
+ key = g_strdup_printf("%s.%" PRId64, opt->name, max);
+ qdict_put_obj(lists, opt->name, QOBJECT(qint_from_int(max)));
+ qdict_put_obj(qdict, key, val);
+ } else if (qdict_haskey(qdict, opt->name)) {
+ /* Move previous val from 'foo' to 'foo.0' */
+ prevval = qdict_get(qdict, opt->name);
+ qobject_incref(prevval);
+ qdict_del(qdict, opt->name);
+ key = g_strdup_printf("%s.0", opt->name);
+ qdict_put_obj(qdict, key, prevval);
+ g_free(key);
+
+ /* Current val goes into 'foo.1' */
+ key = g_strdup_printf("%s.1", opt->name);
+ qdict_put_obj(lists, opt->name, QOBJECT(qint_from_int(1)));
+ qdict_put_obj(qdict, key, val);
+ } else {
+ qdict_put_obj(qdict, key ? key : opt->name, val);
+ }
+ break;
+
+ case QEMU_OPTS_REPEAT_POLICY_LAST:
+ qdict_put_obj(qdict, key ? key : opt->name, val);
+ break;
+ }
+ g_free(key);
}
+ QDECREF(lists);
return qdict;
}
--
2.7.4
next prev parent reply other threads:[~2016-09-27 13:13 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-27 13:13 [Qemu-devel] [PATCH v14 00/19] QAPI/QOM work for non-scalar object properties Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 01/19] qdict: implement a qdict_crumple method for un-flattening a dict Daniel P. Berrange
2016-09-27 21:22 ` Eric Blake
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 02/19] option: make parse_option_bool/number non-static Daniel P. Berrange
2016-09-27 13:13 ` Daniel P. Berrange [this message]
2016-09-27 22:03 ` [Qemu-devel] [PATCH v14 03/19] option: allow qemu_opts_to_qdict to merge repeated options Eric Blake
2016-09-28 9:35 ` Daniel P. Berrange
2016-09-28 13:44 ` Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 04/19] qapi: add trace events for visitor Daniel P. Berrange
2016-09-27 22:05 ` Eric Blake
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 05/19] qapi: rename QmpInputVisitor to QObjectInputVisitor Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 06/19] qapi: rename QmpOutputVisitor to QObjectOutputVisitor Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 07/19] qapi: don't pass two copies of TestInputVisitorData to tests Daniel P. Berrange
2016-09-27 22:10 ` Eric Blake
2016-09-27 22:12 ` Eric Blake
2016-09-28 9:35 ` Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 08/19] qapi: permit scalar type conversions in QObjectInputVisitor Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 09/19] qapi: permit auto-creating single element lists Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 10/19] qapi: permit auto-creating nested structs Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 11/19] qapi: add integer range support for QObjectInputVisitor Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 12/19] qapi: allow QObjectInputVisitor to be created with QemuOpts Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 13/19] qom: support non-scalar properties with -object Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 14/19] hmp: support non-scalar properties with object_add Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 15/19] numa: convert to use QObjectInputVisitor for -numa Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 16/19] block: convert crypto driver to use QObjectInputVisitor Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 17/19] acpi: convert to QObjectInputVisitor for -acpi parsing Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 18/19] net: convert to QObjectInputVisitor for -net/-netdev parsing Daniel P. Berrange
2016-09-27 13:13 ` [Qemu-devel] [PATCH v14 19/19] qapi: delete unused OptsVisitor code Daniel P. Berrange
2016-10-20 15:06 ` [Qemu-devel] [PATCH v14 00/19] QAPI/QOM work for non-scalar object properties Markus Armbruster
2016-10-20 15:14 ` Daniel P. Berrange
2016-10-21 9:35 ` Markus Armbruster
2016-10-21 9:38 ` Daniel P. Berrange
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1474982001-20878-4-git-send-email-berrange@redhat.com \
--to=berrange@redhat.com \
--cc=afaerber@suse.de \
--cc=armbru@redhat.com \
--cc=mreitz@redhat.com \
--cc=pbonzini@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.