2014-03-12 0:54 GMT+08:00 Eric Blake <ebl...@redhat.com>:

> On 03/10/2014 01:31 AM, Chunyan Liu wrote:
> > Change block layer to support both QemuOpts and QEMUOptionParameter.
> > After this patch, it will change backend drivers one by one. At the end,
> > QEMUOptionParameter will be removed and only QemuOpts is kept.
> >
> > Signed-off-by: Dong Xu Wang <wdon...@linux.vnet.ibm.com>
> > Signed-off-by: Chunyan Liu <cy...@suse.com>
> > ---
>
> >  int bdrv_create(BlockDriver *drv, const char* filename,
> > -    QEMUOptionParameter *options, Error **errp)
> > +    QEMUOptionParameter *options, QemuOpts *opts, Error **errp)
> >  {
> >      int ret;
>
> In addition to my remarks last night:
>
> I wonder if you should add:
>
> assert(!(options && opts))
>
> to prove that all callers are passing at most one of the two supported
> option lists, while doing the conversion.
>
> > @@ -5248,28 +5266,31 @@ void bdrv_img_create(const char *filename, const
> char *fmt,
> >          return;
> >      }
> >
> > -    create_options = append_option_parameters(create_options,
> > -                                              drv->create_options);
> > -    create_options = append_option_parameters(create_options,
> > -
>  proto_drv->create_options);
> > +    if (drv->bdrv_create2) {
> > +        create_opts = qemu_opts_append(create_opts, drv->create_opts);
> > +        create_opts = qemu_opts_append(create_opts,
> proto_drv->create_opts);
>
> In addition to the memory leak I pointed out earlier,


Should use g_realloc in qemu_opts_append, realloc create_opts
to the desired space and append 2nd list to it. Saving the effort to free
memory while append many times.

I see another
> potential problem: What if drv has been converted to QemuOpts, but
> proto_drv is still on QEMUOptionParameter?
>

> > +    } else {
> > +        create_options = append_option_parameters(create_options,
> > +                                                  drv->create_options);
> > +        create_options = append_option_parameters(create_options,
> > +
>  proto_drv->create_options);
>
> Or the converse, if drv is still on QEMUOptionParameter, but proto_drv
> has been converted to QEMUOpts?
>
> Either way, you will be appending NULL for the proto_drv case, when what
> you really wanted to be doing was merging both the QemuOpts and
> QEMUOptionParameters into a single list.
>
> > +        create_opts = params_to_opts(create_options);
> > +    }
>
> I think a better path to conversion would be doing everything possible
> in QemuOpts, and only switching to QEMUOptionParameters at the last
> possible moment, rather than having two separate append code paths.
>
> My suggestion: until the conversion is complete, add a new function,
> something like:
>
> void qemu_opts_append_pair(QemuOpts *dst, QemuOpts *opts,
>                            QEMUOptionParameter *options) {
>     assert(!(opts && options));
>     ... modify dst in-place to have it cover the entries from opts or
> options
> }
>
> then in this code, you do:
>     create_options = /* generate empty QemuOpts */;
>     qemu_opts_append_pair(options, drv->create_opts,
>                           drv->create_options);
>     qemu_opts_append_pair(options, proto_drv->create_options,
>                           proto_drv->create_options);
>
>
Good. Together with always using QemuOpts and only converting to
QEMUOptionParameter until it calls .bdrv_create in specific driver,
the drv/proto_drv inconsistent problem could be solved.
Will update.

Thanks very much for all your suggestions!

Chunyan

>
> >      /* Create parameter list with default values */
> > -    param = parse_option_parameters("", create_options, param);
> > -
> > -    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
> > +    opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
> > +    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size);
>
> This part worked nicely - once you convert both incoming styles to
> QemuOpts, it really is easier to have this part of the code just use
> QemuOpts functions for setting the size....
>
> > ...
> > @@ -5343,16 +5364,23 @@ void bdrv_img_create(const char *filename, const
> char *fmt,
> >
> >      if (!quiet) {
> >          printf("Formatting '%s', fmt=%s ", filename, fmt);
> > -        print_option_parameters(param);
> > +        qemu_opts_print(opts);
> >          puts("");
> >      }
> > -    ret = bdrv_create(drv, filename, param, &local_err);
> > +
> > +    if (drv->bdrv_create2) {
> > +        ret = bdrv_create(drv, filename, NULL, opts, &local_err);
> > +    } else {
> > +        param = opts_to_params(opts);
> > +        ret = bdrv_create(drv, filename, param, NULL, &local_err);
> > +    }
>
> ...and finally convert back to QEMUOptionParameters at the last moment.
>  But wait a minute - why are you checking for drv->bdrv_create2 here?
> Isn't the last possible moment really inside bdrv_create() (that is, the
> actual function that decides whether to call drv->bdrv_create vs.
> drv->bdrv_create2)?  For the code to be as clean as possible, you want
> to use QemuOpts everywhere until the actual point where you are calling
> the unconverted callback.
>
>
> > -int bdrv_amend_options(BlockDriverState *bs, QEMUOptionParameter
> *options)
> > +int bdrv_amend_options(BlockDriverState *bs, QEMUOptionParameter
> *options,
> > +                       QemuOpts *opts)
> >  {
> > -    if (bs->drv->bdrv_amend_options == NULL) {
> > +    if (!bs->drv->bdrv_amend_options && !bs->drv->bdrv_amend_options2) {
> >          return -ENOTSUP;
> >      }
> > -    return bs->drv->bdrv_amend_options(bs, options);
> > +    if (bs->drv->bdrv_amend_options2) {
> > +        return bs->drv->bdrv_amend_options2(bs, opts);
> > +    } else {
> > +        return bs->drv->bdrv_amend_options(bs, options);
>
> Similar to the create/create2 situation, _this_ function is the last
> possible place to make the conversions.  You have a problem in that if
> the user passes you options but the callback expects opts, you are
> passing NULL to the callback.  I think this should look more like:
>
> int bdrv_amend_options(BlockDriverState *bs, QEMUOptionParameter *options,
>                        QemuOpts *opts)
> {
>     int ret;
>     assert(!(opts && options));
>     if (!bs->drv->bdrv_amend_options && !bs->drv->bdrv_amend_options2) {
>         return -ENOTSUP;
>     }
>     if (bs->drv->bdrv_amend_options2) {
>         if (options) {
>             opts = params_to_opts(options);
>         }
>         ret = bs->drv->bdrv_amend_options2(bs, opts);
>         if (options) {
>             g_free(opts); // or whatever correct spelling to avoid leak
>         }
>     } else {
>         if (opts) {
>             options = opts_to_params(opts);
>         }
>         ret = bs->drv->bdrv_amend_options(bs, options);
>         if (opts) {
>             g_free(options); // again, with correct spelling
>         }
>     }
>     return ret;
>
> > +++ b/include/block/block_int.h
> > @@ -118,6 +118,8 @@ struct BlockDriver {
> >      void (*bdrv_rebind)(BlockDriverState *bs);
> >      int (*bdrv_create)(const char *filename, QEMUOptionParameter
> *options,
> >                         Error **errp);
> > +    /* FIXME: will remove the duplicate and rename back to bdrv_create
> later */
> > +    int (*bdrv_create2)(const char *filename, QemuOpts *opts, Error
> **errp);
>
> I like the FIXME here; maybe also mention that bdrv_create and
> bdrv_create2 are mutually exclusive (at most one can be non-NULL).
>
> >      int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
> >      int (*bdrv_make_empty)(BlockDriverState *bs);
> >      /* aio */
> > @@ -217,7 +219,7 @@ struct BlockDriver {
> >
> >      /* List of options for creating images, terminated by name == NULL
> */
> >      QEMUOptionParameter *create_options;
> > -
> > +    QemuOptsList *create_opts;
>
> A similar FIXME comment here might be nice, likewise mentioning that at
> most one of these two fields should be non-NULL.
>
> > @@ -244,21 +245,34 @@ static int print_block_option_help(const char
> *filename, const char *fmt)
> >          return 1;
> >      }
> >
> > -    create_options = append_option_parameters(create_options,
> > -                                              drv->create_options);
> > -
> > +    if (drv->create_opts) {
> > +        create_opts = qemu_opts_append(create_opts, drv->create_opts);
> > +    } else {
> > +        create_options = append_option_parameters(create_options,
> > +                                                  drv->create_options);
> > +    }
> >      if (filename) {
> >          proto_drv = bdrv_find_protocol(filename, true);
> >          if (!proto_drv) {
> >              error_report("Unknown protocol '%s'", filename);
> >              return 1;
> >          }
> > -        create_options = append_option_parameters(create_options,
> > -
>  proto_drv->create_options);
> > +        if (drv->create_opts) {
> > +            create_opts = qemu_opts_append(create_opts,
> proto_drv->create_opts);
>
> Memory leak.
>
> > +        } else {
> > +            create_options =
> > +                append_option_parameters(create_options,
> > +                                         proto_drv->create_options);
> > +        }
> >      }
> >
> > -    print_option_help(create_options);
> > +    if (drv->create_opts) {
> > +        qemu_opts_print_help(create_opts);
> > +    } else {
> > +        print_option_help(create_options);
> > +    }
>
> Another case where if you add a new helper function that absorbs either
> style of options into a QemuOpts, then all you have to do here is print
> the QemuOpts, instead of trying to switch between print methods here.
>
>
> > @@ -1340,40 +1356,42 @@ static int img_convert(int argc, char **argv)
> >          goto out;
> >      }
>
> > -        }
> > +    if (drv->bdrv_create2) {
> > +        create_opts = qemu_opts_append(create_opts, drv->create_opts);
> > +        create_opts = qemu_opts_append(create_opts,
> proto_drv->create_opts);
>
> More memory leaks.
>
>
> > @@ -1400,7 +1418,12 @@ static int img_convert(int argc, char **argv)
> >
> >      if (!skip_create) {
> >          /* Create the new image */
> > -        ret = bdrv_create(drv, out_filename, param, &local_err);
> > +        if (drv->bdrv_create2) {
> > +            ret = bdrv_create(drv, out_filename, NULL, opts,
> &local_err);
> > +        } else {
> > +            param = opts_to_params(opts);
> > +            ret = bdrv_create(drv, out_filename, param, NULL,
> &local_err);
> > +        }
>
> Another case where you should just always pass opts to bdrv_create(),
> and let bdrv_create() do the last minute conversion to
> QEMUOptionParameters based on what callbacks drv supports, rather than
> trying to make decisions here based on contents of drv.
>
>
> > @@ -2721,17 +2748,26 @@ static int img_amend(int argc, char **argv)
> >          goto out;
> >      }
> >
> > -    create_options = append_option_parameters(create_options,
> > -            bs->drv->create_options);
> > -    options_param = parse_option_parameters(options, create_options,
> > -            options_param);
> > -    if (options_param == NULL) {
> > +    if (bs->drv->bdrv_amend_options2) {
>
> And again, you should not be making decisions on the contents of
> bs->drv, but just blindly setting up QemuOpts here...
>
> > +        create_opts = qemu_opts_append(create_opts,
> bs->drv->create_opts);
> > +    } else {
> > +        create_options = append_option_parameters(create_options,
> > +
>  bs->drv->create_options);
> > +        create_opts = params_to_opts(create_options);
> > +    }
> > +    opts = qemu_opts_create(create_opts, NULL, 0, &error_abort);
> > +    if (options && qemu_opts_do_parse(opts, options, NULL)) {
> >          error_report("Invalid options for file format '%s'", fmt);
> >          ret = -1;
> >          goto out;
> >      }
> >
> > -    ret = bdrv_amend_options(bs, options_param);
> > +    if (bs->drv->bdrv_amend_options2) {
> > +        ret = bdrv_amend_options(bs, NULL, opts);
> > +    } else {
> > +        options_param = opts_to_params(opts);
> > +        ret = bdrv_amend_options(bs, options_param, NULL);
>
> ...and blindly letting bdrv_amend_options() be the place that converts
> to QEMUOptionParameters as needed.
>
> Here's hoping v23 is nicer; I'm looking forward to ditching
> QEMUOptionParameters.
>

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

Reply via email to