From: Markus Armbruster <armbru@redhat.com>
To: "Daniel P. Berrange" <berrange@redhat.com>
Cc: qemu-devel@nongnu.org, qemu-block@nongnu.org,
"Max Reitz" <mreitz@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Andreas Färber" <afaerber@suse.de>
Subject: Re: [Qemu-devel] [PATCH v14 12/21] option: allow qemu_opts_to_qdict to merge repeated options
Date: Thu, 13 Oct 2016 10:31:37 +0200 [thread overview]
Message-ID: <87wphcd506.fsf@dusky.pond.sub.org> (raw)
In-Reply-To: <1475246744-29302-13-git-send-email-berrange@redhat.com> (Daniel P. Berrange's message of "Fri, 30 Sep 2016 15:45:35 +0100")
"Daniel P. Berrange" <berrange@redhat.com> writes:
> 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=QString("1024")
> nodes=QString("1-2")
> policy=QString("bind")
>
> With this change the caller can optionally ask for all
> the repeated values to be stored in a QList. In the
> above example that would result in 'nodes' being a
> QList, so the returned dict would contain
>
> size=QString("1024")
> nodes=QList([QString("10"),
> QString("4-5"),
> QString("1-2")])
> policy=QString("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 a QString or a QList for the
> key 'foo'.
Actually three cases, not two:
0. qdict does not contain the key means empty list.
1. qdict contains the key with a QString value means list of one
element.
2. qdict contains the key with a QList value means list of more than one
element.
I consider this weird. However, it's usefully weird with at least your
QObject input visitor.
> In a third mode, it is possible to ask for repeated
> options to be reported as an error, rather than silently
> dropping all but the last one.
Got users for this policy in the pipeline?
> All existing callers are all converted to explicitly
> request the historical behaviour of only reporting the
> last key. Later patches will make use of the new modes.
>
> Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
> ---
> blockdev.c | 7 ++-
> include/qemu/option.h | 13 ++++-
> monitor.c | 3 +-
> qapi/qobject-input-visitor.c | 4 +-
> 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 | 132 +++++++++++++++++++++++++++++++++++++++++++
> tests/test-replication.c | 9 ++-
> util/qemu-option.c | 64 ++++++++++++++++++---
> 12 files changed, 229 insertions(+), 22 deletions(-)
>
> diff --git a/blockdev.c b/blockdev.c
> index 814d49f..a999d46 100644
> --- a/blockdev.c
> +++ b/blockdev.c
> @@ -914,7 +914,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,
> + &error_abort);
>
> legacy_opts = qemu_opts_create(&qemu_legacy_drive_opts, NULL, 0,
> &error_abort);
> @@ -3804,8 +3805,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,
> + &error_abort);
> 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 29f3f18..ffd841d 100644
> --- a/include/qemu/option.h
> +++ b/include/qemu/option.h
> @@ -125,7 +125,18 @@ 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(const QemuOpts *opts, QDict *qdict);
Blank line here, please.
> +typedef enum {
> + /* Last occurrence of a duplicate option silently replaces earlier */
> + QEMU_OPTS_REPEAT_POLICY_LAST,
> + /* Each occurrence of a duplicate option converts value to a QList */
> + QEMU_OPTS_REPEAT_POLICY_ALL,
> + /* First occurrence of a duplicate option causes an error */
> + QEMU_OPTS_REPEAT_POLICY_ERROR,
> +} QemuOptsRepeatPolicy;
> +
> +QDict *qemu_opts_to_qdict(const QemuOpts *opts, QDict *qdict,
> + QemuOptsRepeatPolicy repeatPolicy,
> + Error **errp);
> 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 14089cc..84e79d4 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,
> + &error_abort);
> qemu_opts_del(opts);
> }
> break;
> diff --git a/qapi/qobject-input-visitor.c b/qapi/qobject-input-visitor.c
> index 6b3d0f2..2287d11 100644
> --- a/qapi/qobject-input-visitor.c
> +++ b/qapi/qobject-input-visitor.c
> @@ -759,7 +759,9 @@ Visitor *qobject_input_visitor_new_opts(const QemuOpts *opts,
> QObject *pobj = NULL;
> Visitor *v = NULL;
>
> - pdict = qemu_opts_to_qdict(opts, NULL);
> + pdict = qemu_opts_to_qdict(opts, NULL,
> + QEMU_OPTS_REPEAT_POLICY_LAST,
Join the previous two lines, please.
> + errp);
Unlike the other callers, this one doesn't pass &error_abort. The error
handling is actually dead code. Let's pass &error_abort and be done
with it.
> if (!pdict) {
> goto cleanup;
> }
> diff --git a/qemu-img.c b/qemu-img.c
> index 851422a..f47ea75 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,
> + &error_abort);
> +
> 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..ce654f4 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,
> + &error_abort) : NULL;
Short ternaries are more legible than if statements, but this one is
pushing the limit now.
> 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..bb374a6 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,
> + &error_abort) : NULL;
Likewise.
> 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,
> + &error_abort);
Even this line's getting ugly. Can we find a prefix that's less
loquacious than QEMU_OPTS_REPEAT_POLICY_, but still self-explaining?
> openfile(NULL, flags, writethrough, opts);
> } else {
> if (format) {
> diff --git a/qemu-nbd.c b/qemu-nbd.c
> index 99297a5..73b40b1 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,
> + &error_abort);
> 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 ded4d84..fdc406b 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,
> + &error_abort);
>
> 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..3b59978 100644
> --- a/tests/test-qemu-opts.c
> +++ b/tests/test-qemu-opts.c
> @@ -421,6 +421,130 @@ static void test_qemu_opts_set(void)
> g_assert(opts == NULL);
> }
>
> +
> +static void test_qemu_opts_to_qdict_repeat_last(void)
> +{
> + QemuOpts *opts;
> + QDict *dict;
> +
> + /* dynamically initialized (parsed) opts */
What are you trying to say with this comment? Hmm, you merely copied it
from the existing tests. I'd drop the existing instances of this
comment instead.
> + opts = qemu_opts_parse(&opts_list_03,
> + "size=1024,nodes=10,nodes=4-5,nodes=1-2,policy=bind",
> + false, NULL);
> + g_assert(opts);
You could pass &error_abort.
> +
> + dict = qemu_opts_to_qdict(opts, NULL, QEMU_OPTS_REPEAT_POLICY_LAST,
> + &error_abort);
> + g_assert(dict);
> +
> +
One blank line, not two, please.
> + 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");
Checking for absence of "nodes.0"... feels odd. A better idea is to
check we got exactly the keys we expect, and no more. Here's a simple
way to do that:
g_assert(qdict_size(dict) == 3);
> + QDECREF(dict);
> +
> + qemu_opts_del(opts);
> + qemu_opts_reset(&opts_list_03);
> +}
> +
> +
> +static void test_qemu_opts_to_qdict_repeat_all(void)
> +{
> + QemuOpts *opts;
> + QDict *dict;
> + QList *list;
> + const QListEntry *ent;
> + QString *str;
> +
> + /* 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_ALL,
> + &error_abort);
> + g_assert(dict);
> +
> + g_assert_cmpstr(qdict_get_str(dict, "size"), ==, "1024");
> + g_assert(qdict_haskey(dict, "nodes"));
> + list = qobject_to_qlist(qdict_get(dict, "nodes"));
> + g_assert(list);
Works, but I'd do
obj = qdict_get(dict, "nodes");
g_assert(obj);
list = qobject_to_qlist(obj);
g_assert(list);
> +
> + ent = qlist_first(list);
> + g_assert(ent);
> + str = qobject_to_qstring(ent->value);
> + g_assert(str);
> + g_assert_cmpstr(qstring_get_str(str), ==, "10");
Since g_assert_cmpstr() does the right thing when @str is null,
g_assert(str) is redundant. More of the same below.
> +
> + ent = qlist_next(ent);
> + g_assert(ent);
> + str = qobject_to_qstring(ent->value);
> + g_assert(str);
> + g_assert_cmpstr(qstring_get_str(str), ==, "4-5");
> +
> + ent = qlist_next(ent);
> + g_assert(ent);
> + str = qobject_to_qstring(ent->value);
> + g_assert(str);
> + g_assert_cmpstr(qstring_get_str(str), ==, "1-2");
> +
> + ent = qlist_next(ent);
> + g_assert(!ent);
> +
> + g_assert_cmpstr(qdict_get_str(dict, "policy"), ==, "bind");
g_assert(qdict_size(dict) == 3);
> + QDECREF(dict);
> +
> + qemu_opts_del(opts);
> + qemu_opts_reset(&opts_list_03);
> +}
> +
> +static void test_qemu_opts_to_qdict_repeat_err_fail(void)
> +{
> + QemuOpts *opts;
> + QDict *dict;
> + Error *err = NULL;
> +
> + /* 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_ERROR,
> + &err);
> + error_free_or_abort(&err);
> + g_assert(!dict);
> +
> + qemu_opts_del(opts);
> + qemu_opts_reset(&opts_list_03);
> +}
> +
> +static void test_qemu_opts_to_qdict_repeat_err_ok(void)
> +{
> + QemuOpts *opts;
> + QDict *dict;
> +
> + /* dynamically initialized (parsed) opts */
> + opts = qemu_opts_parse(&opts_list_03,
> + "size=1024,nodes=10,policy=bind",
> + false, NULL);
> + g_assert(opts);
> +
> + dict = qemu_opts_to_qdict(opts, NULL, QEMU_OPTS_REPEAT_POLICY_ERROR,
> + &error_abort);
> + g_assert_cmpstr(qdict_get_str(dict, "size"), ==, "1024");
> + g_assert_cmpstr(qdict_get_str(dict, "nodes"), ==, "10");
> + g_assert_cmpstr(qdict_get_str(dict, "policy"), ==, "bind");
g_assert(qdict_size(dict) == 3);
> +
> + QDECREF(dict);
> + qemu_opts_del(opts);
> + qemu_opts_reset(&opts_list_03);
> +}
> +
> int main(int argc, char *argv[])
> {
> register_opts();
> @@ -435,6 +559,14 @@ 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/repeat-last",
> + test_qemu_opts_to_qdict_repeat_last);
> + g_test_add_func("/qemu-opts/to_qdict/repeat-all",
> + test_qemu_opts_to_qdict_repeat_all);
> + g_test_add_func("/qemu-opts/to_qdict/repeat-err-fail",
> + test_qemu_opts_to_qdict_repeat_err_fail);
> + g_test_add_func("/qemu-opts/to_qdict/repeat-err-ok",
> + test_qemu_opts_to_qdict_repeat_err_ok);
> g_test_run();
> return 0;
> }
> diff --git a/tests/test-replication.c b/tests/test-replication.c
> index 0997bd8..e267f9a 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,
> + &error_abort);
> 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,
> + &error_abort);
> 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,
> + &error_abort);
> 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 418cbb6..0129ede 100644
> --- a/util/qemu-option.c
> +++ b/util/qemu-option.c
> @@ -1057,23 +1057,73 @@ void qemu_opts_absorb_qdict(QemuOpts *opts, QDict *qdict, Error **errp)
> * The QDict values are of type QString.
> * TODO We'll want to use types appropriate for opt->desc->type, but
> * this is enough for now.
While there, we could document @obj and @dict properly. But see below
on @dict.
> + *
> + * If the @opts contains multiple occurrences of the same key,
> + * then the @repeatPolicy parameter determines how they are to
> + * be handled. Traditional behaviour was to only store the
> + * last occurrence, but if @repeatPolicy is set to
> + * QEMU_OPTS_REPEAT_POLICY_ALL, then a QList will be returned
> + * containing all values, for any key with multiple occurrences.
> + * The QEMU_OPTS_REPEAT_POLICY_ERROR value can be used to fail
> + * conversion with an error if multiple occurrences of a key
> + * are seen.
What the traditional behavior was is quite interesting in a commit
message. Less so in a comment. Suggest:
* be handled. With @repeatPolicy QEMU_OPTS_REPEAT_POLICY_LAST,
* all values but the last are silently ignored. With
* QEMU_OPTS_REPEAT_POLICY_ALL, a QList will be returned
* containing all values, for any key with multiple occurrences.
* With QEMU_OPTS_REPEAT_POLICY_ERROR, the conversion fails.
Let's spell out that the function can only fail with
QEMU_OPTS_REPEAT_POLICY_ERROR:
* This is the only way this function can fail.
> */
> -QDict *qemu_opts_to_qdict(const QemuOpts *opts, QDict *qdict)
> +QDict *qemu_opts_to_qdict(const QemuOpts *opts, QDict *qdict,
> + QemuOptsRepeatPolicy repeatPolicy,
> + Error **errp)
> {
> QemuOpt *opt;
> - QObject *val;
> + QObject *val, *prevval;
I'd prefer prev_val.
> + QList *list;
> + QDict *ret;
>
> - if (!qdict) {
> - qdict = qdict_new();
> + if (qdict) {
> + ret = qdict;
> + } else {
> + ret = qdict_new();
> }
You need this change to get the reference counting on failure right.
This makes me question the qdict parameter. I can see two non-null
arguments for it outside tests. The one in drive_new() is basically
stupid:
bs_opts = qdict_new();
qemu_opts_to_qdict(all_opts, bs_opts, QEMU_OPTS_REPEAT_POLICY_LAST,
&error_abort);
Easily replaced by
bs_opts = qemu_opts_to_qdict(all_opts, NULL, QEMU_OPTS_REPEAT_POLICY_LAST,
&error_abort);
The one in monitor_parse_arguments()
qemu_opts_to_qdict(opts, qdict, QEMU_OPTS_REPEAT_POLICY_LAST,
&error_abort);
could be replaced by
QDECREF(qdict);
qdict = qemu_opts_to_qdict(opts, NULL, QEMU_OPTS_REPEAT_POLICY_LAST,
&error_abort);
at a negligible loss of efficiency. We could then drop the parameter,
simplifying the function's contract.
Let's insert a blank line here...
> if (opts->id) {
> - qdict_put(qdict, "id", qstring_from_str(opts->id));
> + qdict_put(ret, "id", qstring_from_str(opts->id));
> }
... and here.
> QTAILQ_FOREACH(opt, &opts->head, next) {
> val = QOBJECT(qstring_from_str(opt->str));
> - qdict_put_obj(qdict, opt->name, val);
> +
> + if (qdict_haskey(ret, opt->name)) {
> + switch (repeatPolicy) {
> + case QEMU_OPTS_REPEAT_POLICY_ERROR:
> + error_setg(errp, "Option '%s' appears more than once",
> + opt->name);
> + qobject_decref(val);
> + if (!qdict) {
> + QDECREF(ret);
> + }
> + return NULL;
> +
> + case QEMU_OPTS_REPEAT_POLICY_ALL:
> + prevval = qdict_get(ret, opt->name);
> + if (qobject_type(prevval) == QTYPE_QLIST) {
> + /* Already identified this key as a list */
> + list = qobject_to_qlist(prevval);
> + } else {
> + /* Replace current scalar with a list */
> + list = qlist_new();
> + qobject_incref(prevval);
Where is this reference decremented?
> + qlist_append_obj(list, prevval);
> + qdict_put_obj(ret, opt->name, QOBJECT(list));
> + }
> + qlist_append_obj(list, val);
> + break;
> +
> + case QEMU_OPTS_REPEAT_POLICY_LAST:
> + /* Just discard previously set value */
> + qdict_put_obj(ret, opt->name, val);
> + break;
> + }
> + } else {
> + qdict_put_obj(ret, opt->name, val);
> + }
A possible alternative:
val = QOBJECT(qstring_from_str(opt->str));
if (qdict_haskey(ret, opt->name)) {
switch (repeatPolicy) {
case QEMU_OPTS_REPEAT_POLICY_ERROR:
error_setg(errp, "Option '%s' appears more than once",
opt->name);
qobject_decref(val);
if (!qdict) {
QDECREF(ret);
}
return NULL;
case QEMU_OPTS_REPEAT_POLICY_ALL:
prevval = qdict_get(ret, opt->name);
if (qobject_type(prevval) == QTYPE_QLIST) {
/* Already identified this key as a list */
list = qobject_to_qlist(prevval);
} else {
/* Replace current scalar with a list */
list = qlist_new();
qobject_incref(prevval);
qlist_append_obj(list, prevval);
}
qlist_append_obj(list, val);
val = QOBJECT(list);
break;
case QEMU_OPTS_REPEAT_POLICY_LAST:
break;
}
}
qdict_put_obj(ret, opt->name, val);
This shows the common part of the behavior more clearly. Matter of
taste, you get to use your artistic license.
> }
> - return qdict;
> + return ret;
> }
>
> /* Validate parsed opts against descriptions where no
next prev parent reply other threads:[~2016-10-13 8:31 UTC|newest]
Thread overview: 109+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-09-30 14:45 [Qemu-devel] [PATCH v14 00/21] QAPI/QOM work for non-scalar object properties Daniel P. Berrange
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 01/21] option: make parse_option_bool/number non-static Daniel P. Berrange
2016-10-21 16:55 ` Markus Armbruster
2016-10-21 17:12 ` Eric Blake
2016-10-21 17:51 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 02/21] qdict: implement a qdict_crumple method for un-flattening a dict Daniel P. Berrange
2016-10-18 14:32 ` Markus Armbruster
2016-10-20 14:11 ` Daniel P. Berrange
2016-10-21 9:58 ` Markus Armbruster
2016-10-21 18:31 ` Max Reitz
2016-10-24 9:18 ` Markus Armbruster
2016-10-24 10:28 ` Daniel P. Berrange
2016-10-24 12:38 ` Markus Armbruster
2016-10-25 10:03 ` Markus Armbruster
2016-10-25 10:20 ` Daniel P. Berrange
2016-10-25 12:29 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 03/21] qapi: add trace events for visitor Daniel P. Berrange
2016-09-30 15:49 ` Eric Blake
2016-10-06 14:39 ` [Qemu-devel] [Qemu-block] " Kevin Wolf
2016-10-07 13:59 ` [Qemu-devel] " Markus Armbruster
2016-10-07 14:16 ` Daniel P. Berrange
2016-10-21 10:52 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 04/21] qapi: rename QmpInputVisitor to QObjectInputVisitor Daniel P. Berrange
2016-10-25 13:41 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 05/21] qapi: rename QmpOutputVisitor to QObjectOutputVisitor Daniel P. Berrange
2016-10-25 13:36 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 06/21] qapi: don't pass two copies of TestInputVisitorData to tests Daniel P. Berrange
2016-09-30 17:43 ` Eric Blake
2016-10-06 14:39 ` [Qemu-devel] [Qemu-block] " Kevin Wolf
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 07/21] qapi: permit scalar type conversions in QObjectInputVisitor Daniel P. Berrange
2016-09-30 17:48 ` Eric Blake
2016-10-11 16:20 ` Markus Armbruster
2016-10-12 14:51 ` Markus Armbruster
2016-10-12 15:05 ` Markus Armbruster
2016-10-12 15:26 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 08/21] qapi: allow QObjectInputVisitor to be created with QemuOpts Daniel P. Berrange
2016-09-30 17:55 ` Eric Blake
2016-10-06 14:56 ` [Qemu-devel] [Qemu-block] " Kevin Wolf
2016-10-12 8:08 ` [Qemu-devel] " Markus Armbruster
2016-10-13 7:23 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 09/21] qapi: permit auto-creating single element lists Daniel P. Berrange
2016-09-30 17:59 ` Eric Blake
2016-10-12 9:18 ` Markus Armbruster
2016-10-20 14:23 ` Daniel P. Berrange
2016-10-21 11:58 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 10/21] qapi: permit auto-creating nested structs Daniel P. Berrange
2016-09-30 18:23 ` Eric Blake
2016-10-06 15:10 ` [Qemu-devel] [Qemu-block] " Kevin Wolf
2016-10-06 15:18 ` Daniel P. Berrange
2016-10-06 15:30 ` Kevin Wolf
2016-10-06 15:39 ` Daniel P. Berrange
2016-10-06 15:51 ` Kevin Wolf
2016-10-06 15:57 ` Daniel P. Berrange
2016-10-12 14:00 ` Markus Armbruster
2016-10-06 17:54 ` Eric Blake
2016-10-12 14:12 ` [Qemu-devel] " Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 11/21] qapi: add integer range support for QObjectInputVisitor Daniel P. Berrange
2016-09-30 19:45 ` Eric Blake
2016-10-12 15:50 ` Markus Armbruster
2016-10-12 16:03 ` [Qemu-devel] [Qemu-block] " Kevin Wolf
2016-10-12 18:14 ` Markus Armbruster
2016-10-20 14:28 ` [Qemu-devel] " Daniel P. Berrange
2016-10-21 10:58 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 12/21] option: allow qemu_opts_to_qdict to merge repeated options Daniel P. Berrange
2016-09-30 20:08 ` Eric Blake
2016-10-12 17:46 ` Markus Armbruster
2016-10-13 9:21 ` Markus Armbruster
2016-10-20 14:29 ` Daniel P. Berrange
2016-10-21 11:09 ` Markus Armbruster
2016-10-21 11:14 ` Daniel P. Berrange
2016-10-13 8:31 ` Markus Armbruster [this message]
2016-10-20 14:37 ` Daniel P. Berrange
2016-10-21 11:28 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 13/21] qdict: allow qdict_crumple to accept compound types as values Daniel P. Berrange
2016-10-13 12:35 ` Markus Armbruster
2016-10-13 14:46 ` Kevin Wolf
2016-10-17 14:50 ` Markus Armbruster
2016-10-17 15:43 ` Paolo Bonzini
2016-10-17 17:48 ` Markus Armbruster
2016-10-17 17:38 ` Eric Blake
2016-10-18 10:59 ` Markus Armbruster
2016-10-18 9:34 ` Kevin Wolf
2016-10-18 15:35 ` Markus Armbruster
2016-10-19 9:25 ` Kevin Wolf
2016-10-19 9:42 ` Daniel P. Berrange
2016-10-19 13:31 ` [Qemu-devel] [Qemu-block] " Eric Blake
2016-10-20 14:46 ` [Qemu-devel] " Daniel P. Berrange
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 14/21] qapi: allow repeated opts with qobject_input_visitor_new_opts Daniel P. Berrange
2016-10-18 17:13 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 15/21] qom: support non-scalar properties with -object Daniel P. Berrange
2016-10-19 16:54 ` Markus Armbruster
2017-07-10 19:30 ` Manos Pitsidianakis
2017-07-11 8:10 ` Markus Armbruster
2017-07-11 14:44 ` Markus Armbruster
2017-07-11 14:49 ` Daniel P. Berrange
2017-07-12 17:56 ` Manos Pitsidianakis
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 16/21] hmp: support non-scalar properties with object_add Daniel P. Berrange
2016-10-20 6:43 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 17/21] numa: convert to use QObjectInputVisitor for -numa Daniel P. Berrange
2016-10-20 6:57 ` Markus Armbruster
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 18/21] block: convert crypto driver to use QObjectInputVisitor Daniel P. Berrange
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 19/21] acpi: convert to QObjectInputVisitor for -acpi parsing Daniel P. Berrange
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 20/21] net: convert to QObjectInputVisitor for -net/-netdev parsing Daniel P. Berrange
2016-10-20 7:38 ` Markus Armbruster
2016-10-20 13:43 ` [Qemu-devel] [Qemu-block] " Eric Blake
2016-09-30 14:45 ` [Qemu-devel] [PATCH v14 21/21] qapi: delete unused OptsVisitor code Daniel P. Berrange
2016-09-30 15:45 ` [Qemu-devel] [PATCH v14 00/21] QAPI/QOM work for non-scalar object properties no-reply
2016-09-30 18:50 ` Eric Blake
2016-10-21 18:30 ` Markus Armbruster
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=87wphcd506.fsf@dusky.pond.sub.org \
--to=armbru@redhat.com \
--cc=afaerber@suse.de \
--cc=berrange@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.