From: Dong Xu Wang <wdongxu@vnet.linux.ibm.com>
To: Markus Armbruster <armbru@redhat.com>
Cc: qemu-devel@nongnu.org, Luiz Capitulino <lcapitulino@redhat.com>
Subject: Re: [Qemu-devel] [PATCH RFC] remove QEMUOptionParameter
Date: Fri, 21 Sep 2012 10:47:18 +0800 [thread overview]
Message-ID: <505BD536.2090600@vnet.linux.ibm.com> (raw)
In-Reply-To: <505BD440.9010302@vnet.linux.ibm.com>
Missed cc qemu-devel, added CC, sorry.
-------- 原始消息 --------
主题: Re: [Qemu-devel] [PATCH RFC] remove QEMUOptionParameter
日期: Fri, 21 Sep 2012 10:43:12 +0800
发件人: Dong Xu Wang <wdongxu@vnet.linux.ibm.com>
收件人: Markus Armbruster <armbru@redhat.com>
于 9/20/2012 5:16 PM, Markus Armbruster 写道:
> Dong Xu Wang <wdongxu@linux.vnet.ibm.com> writes:
>
>> Markus, I am working with v2 and have some questions based your comments.
>
> Your replies are very hard to read, because whatever you use to send
> them wraps quoted lines. Please fix that.
>
Sorry for that, will notice next time.
>> On Fri, Sep 7, 2012 at 4:42 PM, Markus Armbruster <armbru@redhat.com> wrote:
>>> Some overlap with what I'm working on, but since you have code to show,
>>> and I don't, I'll review yours as if mine didn't exist.
>>>
>>>
>>> Dong Xu Wang <wdongxu@linux.vnet.ibm.com> writes:
> [...]
>>>> diff --git a/qemu-option.c b/qemu-option.c
>>>> index 27891e7..b83ca52 100644
>>>> --- a/qemu-option.c
>>>> +++ b/qemu-option.c
> [...]
>>>> static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
>>>> @@ -832,14 +547,36 @@ void qemu_opts_del(QemuOpts *opts)
>>>>
>>>> int qemu_opts_print(QemuOpts *opts, void *dummy)
>>>> {
>>>> - QemuOpt *opt;
>>>> + QemuOpt *opt = NULL;
>>>> + QemuOptDesc *desc = opts->list->desc;
>>>>
>>>> - fprintf(stderr, "%s: %s:", opts->list->name,
>>>> - opts->id ? opts->id : "<noid>");
>>>> - QTAILQ_FOREACH(opt, &opts->head, next) {
>>>> - fprintf(stderr, " %s=\"%s\"", opt->name, opt->str);
>>>> + while (desc && desc->name) {
>>>> + opt = qemu_opt_find(opts, desc->name);
>>>> + switch (desc->type) {
>>>> + case QEMU_OPT_STRING:
>>>> + if (opt != NULL) {
>>>> + printf("%s='%s' ", opt->name, opt->str);
>>>> + }
>>>> + break;
>>>> + case QEMU_OPT_BOOL:
>>>> + printf("%s=%s ", desc->name, (opt && opt->str) ? "on" : "off");
>>>> + break;
>>>> + case QEMU_OPT_NUMBER:
>>>> + case QEMU_OPT_SIZE:
>>>> + if (strcmp(desc->name, "cluster_size")) {
>>>> + printf("%s=%" PRId64 " ", desc->name,
>>>> + (opt && opt->value.uint) ? opt->value.uint : 0);
>>>> + } else {
>>>> + printf("%s=%" PRId64 " ", desc->name,
>>>> + (opt && opt->value.uint) ? opt->value.uint : desc->def_value);
>>>> + }
>>>> + break;
>>>> + default:
>>>> + printf("%s=(unknown type) ", desc->name);
>>>> + break;
>>>> + }
>>>> + desc++;
>>>> }
>>>> - fprintf(stderr, "\n");
>>>> return 0;
>>>> }
>>>>
>>>
>>> Why do you need to change this function?
>>
>> I just want to have the same output as before, and I noticed that
>> qemu_opts_print function
>> has no user. Is it Okay to change it?
>
> Can you give examples where unchanged qemu_opts_print() prints something
> else than your code?
>
After changing is:
[wdongxu]$ qemu-img create -f qcow2 t.qcow2 8G
Formatting 't.qcow2', fmt=qcow2 size=8589934592 encryption=off
cluster_size=65536 lazy_refcounts=off
If use qemu_otps_print directly:
[wdongxu]$ qemu-img create -f qcow2 t.qcow2 8G
qcow2-create-opts: <noid>: size="(null)"
Formatting 't.qcow2', fmt=qcow2
Without this patch, block.c uses print_option_parameters, output is as
the same as my code.
>>>> @@ -1110,3 +847,140 @@ int qemu_opts_foreach(QemuOptsList *list,
>> qemu_opts_loopfunc func, void *opaque,
>>>> loc_pop(&loc);
>>>> return rc;
>>>> }
>>>> +
>>>> +static size_t count_opts_list(QemuOptsList *list)
>>>> +{
>>>> + size_t i = 0;
>>>> +
>>>> + while (list && list->desc[i].name) {
>>>> + i++;
>>>> + }
>>>> +
>>>> + return i;
>>>> +}
>>>> +
>>>> +static bool opts_desc_find(QemuOptsList *list, const char *name)
>>>> +{
>>>> + const QemuOptDesc *desc = list->desc;
>>>> + int i;
>>>> +
>>>> + for (i = 0; desc[i].name != NULL; i++) {
>>>> + if (strcmp(desc[i].name, name) == 0) {
>>>> + return true;;
>>>
>>> Extra ;
>>>
>>>> + }
>>>> + }
>>>> + return false;
>>>> +}
>>>
>>> Duplicates the loop searching list->desc[] yet again. What about
>>> factoring out all the copies into a function? Separate cleanup patch
>>> preceding this one.
>>
>> Okay.
>>
>>>
>>>> +
>>>> +/* merge two QemuOptsLists to one and return it. */
>>>> +QemuOptsList *append_opts_list(QemuOptsList *first,
>>>> + QemuOptsList *second)
>>>> +{
>>>> + size_t num_first_options, num_second_options;
>>>> + QemuOptsList *dest = NULL;
>>>> + int i = 0;
>>>> + int index = 0;
>>>> +
>>>> + num_first_options = count_opts_list(first);
>>>> + num_second_options = count_opts_list(second);
>>>> + if (num_first_options + num_second_options == 0) {
>>>> + return NULL;
>>>> + }
>>>> +
>>>> + dest = g_malloc0(sizeof(QemuOptsList)
>>>> + + (num_first_options + num_second_options) * sizeof(QemuOptDesc));
>>>
>>> Allocate space for both first and second.
>>
>> I just make sure we have enough to hold struct QemuOptsList and
>> QemuOptDesc members.
>
> Let me correct myself: allocate space for one new QemuOptsList plus
> enough space for the QemuOptDesc in first and second.
>
>>>> +
>>>> + if (first) {
>>>> + memcpy(dest, first, sizeof(QemuOptsList));
>>>> + } else if (second) {
>>>> + memcpy(dest, second, sizeof(QemuOptsList));
>>>> + }
>>>
>>> Copy either first or second.
>>>
>>> If both are non-null, the space for second remains blank.
>>>
>>> Why copy at all? The loops below copy again, don't they?
>>>
>>
>> struct QemuOptsList has a member "QemuOptDesc desc[]", what I want to do is:
>>
>> 1) Copy QemuOptsList, excluding "QemuOptDesc desc[]", because it is
>> "flexible array member",
>> does not take any space in QemuOptsList. Then dest will have the same
>> name and implied_opt_name
>> as first QemuoptsList's(if first is null, will be the same as second's).
>>
>> 2) Copy desc member, I have to allocate space for the "flexible array member",
>> g_strdup name and help, if it already exists in desc, then skip g_strdup.
>>
>> Am I right?
>
> Your code confused me. Let me try again.
>
> dest->desc is set below. All the other members of dest get copied from
> first if it's non-null, else from second if it's non-null, else remain
> blank.
>
> Issues with copying from first or second:
>
> * Copying dest->head from is evil. It makes dest look like it was a
> member of tail queue dest->head.tqh_first, but that's not true.
>
> I figure you need to QTAILQ_EMPTY(&dest->head).
>
> * Copying dest->name isn't quite kosher, either, but probably harmless.
>
> * Copying dest->implied_opt_name isn't optimal. What if
> first->implied_opt_name is null, but second->implied_opt_name is
> non-null? Then dest->implied_opt_name = second->implied_opt_name
> would be nicer.
>
> I guess your particular use doesn't care, because all your
> implied_opt_name are null.
>
> * dest->merge_lists is fishy, too. It governs how multiple
> qemu_opts_create(dest, ...) with the same ID behave. What should
> happen if first->merge_lists != second->merge_lists?
>
> I guess all your merge_list are false.
>
> * When both first and second are null, *dest remains blank. Why is that
> okay?
>
> Perhaps a less problematic operation than "merge two QemuOptsLists"
> would be "set QemuOptsList C's desc to the merge of A's and B's desc."
> That way, the caller has to set up all the problematic members of the
> new QemuOptsList. Then use it to build a special function to create
> options for a pair of BlockDrivers.
>
Okay, you are right, I did not think about it so carefully. I will
follow your advice, using new name and initializing other struct members
in a new function.
>>>> +
>>>> + while (first && (first->desc[i].name)) {
>>>> + if (!opts_desc_find(dest, first->desc[i].name)) {
>>>> + dest->desc[index].name = strdup(first->desc[i].name);
>>>> + dest->desc[index].help = strdup(first->desc[i].help);
>>>
>>> g_strdup()
>>>
>>> Why do you need to copy name and help?
>
> No answer?
>
I want dest->desc has the same members as first plus second, so I copy
name and help, and desc->name will be used in opts_desc_find
function(see below).
>>>> + dest->desc[index].type = first->desc[i].type;
>>>> + dest->desc[index].def_value = first->desc[i].def_value;
>>>> + dest->desc[++index].name = NULL;
>>>
>>> I'd terminate dest->desc[] after the loop, not in every iteration.
>>
>> Okay.
>>
>>>
>>>> + }
>>>> + i++;
>>>> + }
>>>> + i = 0;
>>>> + while (second && (second->desc[i].name)) {
>>>> + if (!opts_desc_find(dest, second->desc[i].name)) {
>>>> + dest->desc[index].name = strdup(first->desc[i].name);
>>>> + dest->desc[index].help = strdup(first->desc[i].help);
>>>> + dest->desc[index].type = second->desc[i].type;
>>>> + dest->desc[index].def_value = second->desc[i].def_value;
>>>> + dest->desc[++i].name = NULL;
>>>> + }
>>>> + i++;
>>>> + }
>>>
>>> Please avoid duplicating the loop.
>>>
>>> What if first and second both contain the same parameter name?
>>
>> Then the second will be skipped, I used opts_desc_find to determine
>> whether it already exists or not.
>
> Ah, missed that, thanks.
>
> First argument's options take precedence over second's, same as in the
> function this replaces (append_option_parameters()). Okay.
>
> Document it in the function comment?
Okay, will add in v2.
>
>>>> + return dest;
>>>> +}
>>>> +
>>>> +void free_opts_list(QemuOptsList *list)
>>>> +{
>>>> + int i = 0;
>>>> +
>>>> + while (list && list->desc[i].name) {
>>>> + g_free((char *)list->desc[i].name);
>>>> + g_free((char *)list->desc[i].help);
>>>> + i++;
>>>> + }
>>>> +
>>>> + g_free(list);
>>>> +}
>>>> +
>>>> +void print_opts_list(QemuOptsList *list)
>>>> +{
>>>> + int i = 0;
>>>> + printf("Supported options:\n");
>>>> + while (list && list->desc[i].name) {
>>>> + printf("%-16s %s\n", list->desc[i].name,
>>>> + list->desc[i].help ? list->desc[i].help : "No description
>> available");
>>>> + i++;
>>>> + }
>>>> +}
>>>> +
>>>> +QemuOpts *parse_opts_list(const char *param,
>>>> + QemuOptsList *list, QemuOpts *dest)
>>>> +{
>>>> + char name[256];
>>>> + char value[256];
>>>> + char *param_delim, *value_delim;
>>>> + char next_delim;
>>>> +
>>>> + if (list == NULL) {
>>>> + return NULL;
>>>> + }
>>>> + while (*param) {
>>>> + param_delim = strchr(param, ',');
>>>> + value_delim = strchr(param, '=');
>>>> +
>>>> + if (value_delim && (value_delim < param_delim || !param_delim)) {
>>>> + next_delim = '=';
>>>> + } else {
>>>> + next_delim = ',';
>>>> + value_delim = NULL;
>>>> + }
>>>> +
>>>> + param = get_opt_name(name, sizeof(name), param, next_delim);
>>>> + if (value_delim) {
>>>> + param = get_opt_value(value, sizeof(value), param + 1);
>>>> + }
>>>> + if (*param != '\0') {
>>>> + param++;
>>>> + }
>>>> +
>>>> + if (qemu_opt_set(dest, name, value_delim ? value : NULL)) {
>>>> + goto fail;
>>>> + }
>>>> + }
>>>> +
>>>> + return dest;
>>>> +
>>>> +fail:
>>>> + return NULL;
>>>> +}
>>>
>>> Can you explain why the existing QemuOpts parsers won't do?
>>
>> I think exsiting parsers is for QEMUOptionParameter, I have not found
>> them for QemuOpts?
>
> Check out opts_do_parse() and its callers.
>
Okay.
>>>> diff --git a/qemu-option.h b/qemu-option.h
>>>> index ca72986..75718fe 100644
>>>> --- a/qemu-option.h
>>>> +++ b/qemu-option.h
>>>> @@ -31,24 +31,6 @@
>>>> #include "error.h"
>>>> #include "qdict.h"
>>>>
>>>> -enum QEMUOptionParType {
>>>> - OPT_FLAG,
>>>> - OPT_NUMBER,
>>>> - OPT_SIZE,
>>>> - OPT_STRING,
>>>> -};
>>>> -
>>>> -typedef struct QEMUOptionParameter {
>>>> - const char *name;
>>>> - enum QEMUOptionParType type;
>>>> - union {
>>>> - uint64_t n;
>>>> - char* s;
>>>> - } value;
>>>> - const char *help;
>>>> -} QEMUOptionParameter;
>>>> -
>>>> -
>>>> const char *get_opt_name(char *buf, int buf_size, const char *p,
>> char delim);
>>>> const char *get_opt_value(char *buf, int buf_size, const char *p);
>>>> int get_next_param_value(char *buf, int buf_size,
>>>> @@ -58,27 +40,6 @@ int get_param_value(char *buf, int buf_size,
>>>> int check_params(char *buf, int buf_size,
>>>> const char * const *params, const char *str);
>>>>
>>>> -
>>>> -/*
>>>> - * The following functions take a parameter list as input. This is
>> a pointer to
>>>> - * the first element of a QEMUOptionParameter array which is
>> terminated by an
>>>> - * entry with entry->name == NULL.
>>>> - */
>>>> -
>>>> -QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
>>>> - const char *name);
>>>> -int set_option_parameter(QEMUOptionParameter *list, const char *name,
>>>> - const char *value);
>>>> -int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
>>>> - uint64_t value);
>>>> -QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest,
>>>> - QEMUOptionParameter *list);
>>>> -QEMUOptionParameter *parse_option_parameters(const char *param,
>>>> - QEMUOptionParameter *list, QEMUOptionParameter *dest);
>>>> -void free_option_parameters(QEMUOptionParameter *list);
>>>> -void print_option_parameters(QEMUOptionParameter *list);
>>>> -void print_option_help(QEMUOptionParameter *list);
>>>> -
>>>> /* ------------------------------------------------------------------ */
>>>>
>>>> typedef struct QemuOpt QemuOpt;
>>>> @@ -96,6 +57,7 @@ typedef struct QemuOptDesc {
>>>> const char *name;
>>>> enum QemuOptType type;
>>>> const char *help;
>>>> + uint64_t def_value;
>>>
>>> The only user I can see is qemu_opts_print(), which can't be right.
>>
>> I want to pass default value, such as QCOW2_DEFAULT_CLUSTER_SIZE, it
>> will be used
>> while qemu-img create, or qcow2_create can not get correct default
>> cluster size. Is it Okay?
>
> Maybe, but I can't see where def_value gets used, by qemu-img create or
> anything else. Please point me to the code that uses it.
>
Yep, it can be removed, I used such code to pass default value:
cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE,
DEFAULT_CLUSTER_SIZE);
>>>> } QemuOptDesc;
>>>>
>>>> struct QemuOptsList {
>>>> @@ -152,5 +114,10 @@ typedef int (*qemu_opts_loopfunc)(QemuOpts
>> *opts, void *opaque);
>>>> int qemu_opts_print(QemuOpts *opts, void *dummy);
>>>> int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func,
>> void *opaque,
>>>> int abort_on_failure);
>>>> -
>>>> +QemuOptsList *append_opts_list(QemuOptsList *dest,
>>>> + QemuOptsList *list);
>>>> +void free_opts_list(QemuOptsList *list);
>>>> +void print_opts_list(QemuOptsList *list);
>>>> +QemuOpts *parse_opts_list(const char *param,
>>>> + QemuOptsList *list, QemuOpts *dest);
>>>> #endif
>>>
>>
>> Thank you Markus for you so detail comments, :)
>
> You're welcome.
>
>> Luiz, I think I need to use your 1-3 patchs in your series.
>> http://lists.nongnu.org/archive/html/qemu-devel/2012-07/msg02716.html
>
Thank you Markus.
next parent reply other threads:[~2012-09-21 2:46 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <505BD440.9010302@vnet.linux.ibm.com>
2012-09-21 2:47 ` Dong Xu Wang [this message]
2012-09-06 3:13 [Qemu-devel] [PATCH RFC] remove QEMUOptionParameter Dong Xu Wang
2012-09-07 8:42 ` Markus Armbruster
2012-09-07 11:42 ` Kevin Wolf
2012-09-10 2:10 ` Dong Xu Wang
2012-09-10 17:38 ` Luiz Capitulino
2012-09-11 1:57 ` Dong Xu Wang
2012-09-11 12:10 ` Luiz Capitulino
2012-09-20 3:10 ` Dong Xu Wang
2012-09-20 9:16 ` Markus Armbruster
2012-09-20 12:36 ` Luiz Capitulino
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=505BD536.2090600@vnet.linux.ibm.com \
--to=wdongxu@vnet.linux.ibm.com \
--cc=armbru@redhat.com \
--cc=lcapitulino@redhat.com \
--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.