[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH V12 3/4] Use QemuOpts support in block layer
From: |
Markus Armbruster |
Subject: |
Re: [Qemu-devel] [PATCH V12 3/4] Use QemuOpts support in block layer |
Date: |
Thu, 21 Mar 2013 16:31:45 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux) |
Dong Xu Wang <address@hidden> writes:
> This patch will use QemuOpts related functions in block layer, add
> a member bdrv_create_opts to BlockDriver struct, it will return
> a QemuOptsList pointer, which includes the image format's create
> options.
>
> And create options's primary consumer is block creating related
> functions, so modify them together.
>
> Signed-off-by: Dong Xu Wang <address@hidden>
> ---
>
> v11->v12:
> 1) create functions, such as qemu_opt_get_del and qemu_opt_replace_set.
> These functions works like origin code.
> 2) use QEMU_OPT_SIZE, not QEMU_OPT_NUMBER.
> 3) in bdrv_create, if opts is NULL, will create an empty one, so can
> discard if(opts) code safely.
>
> v10->v11:
> 1) qed.h move QED_DEFAULT_CLUSTER_SIZE from enum to macro, or
> qemu_opts_print produce un-expanded cluster_size.
> 2) In qcow2.c and qcow.c, bdrv_create_file(filename, NULL), NULL ->
> opts,
> or while using protocol, there will be an error.
>
> v8->v9:
> 1) add qemu_ prefix to gluster_create_opts.
> 2) fix bug: bdrv_gluster_unix and bdrv_gluster_rdma should also be
> converted.
>
> v7->v8:
> 1) rebase to upstream source tree.
> 2) add gluster.c, raw-win32.c, and rbd.c.
>
> v6->v7:
> 1) use osdep.h:stringify(), not redefining new macro.
> 2) preserve TODO comment.
> 3) fix typo. BLOCK_OPT_ENCRYPT->BLOCK_OPT_STATIC.
> 4) initialize disk_type even when opts is NULL.
>
> v5->v6:
> 1) judge if opts == NULL in block layer create functions.
> 2) use bdrv_create_file(filename, NULL) in qcow_create and cow_create
> funtion.
> 3) made more readable while using qemu_opt_get_number.
>
>
> block.c | 91 ++++++++++++------------
> block/cow.c | 46 ++++++------
> block/gluster.c | 37 +++++-----
> block/iscsi.c | 8 +--
> block/qcow.c | 61 ++++++++--------
> block/qcow2.c | 173
> +++++++++++++++++++++++-----------------------
> block/qed.c | 86 +++++++++++------------
> block/qed.h | 2 +-
> block/raw-posix.c | 59 +++++++---------
> block/raw-win32.c | 31 +++++----
> block/raw.c | 30 ++++----
> block/rbd.c | 62 ++++++++---------
> block/sheepdog.c | 75 ++++++++++----------
> block/vdi.c | 70 +++++++++----------
> block/vmdk.c | 90 ++++++++++++------------
> block/vpc.c | 57 +++++++--------
> block/vvfat.c | 11 +--
> include/block/block.h | 4 +-
> include/block/block_int.h | 6 +-
> include/qemu/option.h | 13 +++-
> qemu-img.c | 61 ++++++++--------
> util/qemu-option.c | 93 +++++++++++++++++++++++--
> 22 files changed, 613 insertions(+), 553 deletions(-)
*Ouch*
Any chance to split this patch up some? Its size makes it really hard
to review...
> diff --git a/block.c b/block.c
> index 4582961..975c3d8 100644
> --- a/block.c
> +++ b/block.c
> @@ -357,7 +357,7 @@ BlockDriver *bdrv_find_whitelisted_format(const char
> *format_name)
> typedef struct CreateCo {
> BlockDriver *drv;
> char *filename;
> - QEMUOptionParameter *options;
> + QemuOpts *opts;
> int ret;
> } CreateCo;
>
> @@ -366,11 +366,11 @@ static void coroutine_fn bdrv_create_co_entry(void
> *opaque)
> CreateCo *cco = opaque;
> assert(cco->drv);
>
> - cco->ret = cco->drv->bdrv_create(cco->filename, cco->options);
> + cco->ret = cco->drv->bdrv_create(cco->filename, cco->opts);
> }
>
> int bdrv_create(BlockDriver *drv, const char* filename,
> - QEMUOptionParameter *options)
> + QemuOpts *opts)
Since you touch this anyway, consider unbreaking the line:
int bdrv_create(BlockDriver *drv, const char* filename, QemuOpts *opts)
> {
> int ret;
>
> @@ -378,7 +378,7 @@ int bdrv_create(BlockDriver *drv, const char* filename,
> CreateCo cco = {
> .drv = drv,
> .filename = g_strdup(filename),
> - .options = options,
> + .opts = opts ?: qemu_opts_create_nofail(drv->bdrv_create_opts),
> .ret = NOT_DONE,
> };
>
As discussed during review of v11, this avoids passing null opts to the
bdrv_create() method. Good.
> @@ -405,7 +405,7 @@ out:
out:
g_free(cco.filename);
> return ret;
> }
I suspect you need
if (!opts) {
qemu_opts_del(cco->opts);
}
to avoid leaking the empty cco->opts you create in the previous hunk.
>
> -int bdrv_create_file(const char* filename, QEMUOptionParameter *options)
> +int bdrv_create_file(const char *filename, QemuOpts *opts)
> {
> BlockDriver *drv;
>
> @@ -414,7 +414,7 @@ int bdrv_create_file(const char* filename,
> QEMUOptionParameter *options)
> return -ENOENT;
> }
>
> - return bdrv_create(drv, filename, options);
> + return bdrv_create(drv, filename, opts);
> }
>
> /*
> @@ -814,7 +814,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename,
> int flags,
> int64_t total_size;
> int is_protocol = 0;
> BlockDriver *bdrv_qcow2;
> - QEMUOptionParameter *options;
> + QemuOpts *opts;
> char backing_filename[PATH_MAX];
>
> /* if snapshot, we create a temporary backing file and open it
> @@ -847,17 +847,16 @@ int bdrv_open(BlockDriverState *bs, const char
> *filename, int flags,
> return -errno;
>
> bdrv_qcow2 = bdrv_find_format("qcow2");
> - options = parse_option_parameters("", bdrv_qcow2->create_options,
> NULL);
> + opts = qemu_opts_create_nofail(bdrv_qcow2->bdrv_create_opts);
>
> - set_option_parameter_int(options, BLOCK_OPT_SIZE, total_size);
> - set_option_parameter(options, BLOCK_OPT_BACKING_FILE,
> backing_filename);
> + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_size);
> + qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, backing_filename);
> if (drv) {
> - set_option_parameter(options, BLOCK_OPT_BACKING_FMT,
> - drv->format_name);
> + qemu_opt_set(opts, BLOCK_OPT_BACKING_FMT, drv->format_name);
> }
>
> - ret = bdrv_create(bdrv_qcow2, tmp_filename, options);
> - free_option_parameters(options);
> + ret = bdrv_create(bdrv_qcow2, tmp_filename, opts);
> + qemu_opts_del(opts);
> if (ret < 0) {
> return ret;
> }
> @@ -4502,8 +4501,10 @@ void bdrv_img_create(const char *filename, const char
> *fmt,
> char *options, uint64_t img_size, int flags,
> Error **errp, bool quiet)
> {
> - QEMUOptionParameter *param = NULL, *create_options = NULL;
> - QEMUOptionParameter *backing_fmt, *backing_file, *size;
> + QemuOpts *opts = NULL;
> + QemuOptsList *create_opts = NULL;
> + const char *backing_fmt, *backing_file;
> + int64_t size;
> BlockDriverState *bs = NULL;
> BlockDriver *drv, *proto_drv;
> BlockDriver *backing_drv = NULL;
> @@ -4521,28 +4522,23 @@ void bdrv_img_create(const char *filename, const char
> *fmt,
> error_setg(errp, "Unknown protocol '%s'", filename);
> return;
> }
> -
> - create_options = append_option_parameters(create_options,
> - drv->create_options);
> - create_options = append_option_parameters(create_options,
> - proto_drv->create_options);
> -
> + create_opts = qemu_opts_append(drv->bdrv_create_opts,
> + proto_drv->bdrv_create_opts);
qemu_opts_append() dereferences its arguments to compute
dest->merge_lists = first->merge_lists || second->merge_lists;
However, either of drv->create_opts and proto_drv->create_opts may be
null, as far as I can see. If I'm correct, you need a few more test
cases :)
Before: format's options get appended first, then protocol's options.
Because get_option_parameter() searches in order, format options shadow
protocol options.
After: append_opts_list() gives first argument's options precedence.
Thus, no change. Good.
Should bdrv_create_options option name clashes be avoided? Beyond the
scope of this patch.
> /* Create parameter list with default values */
> - param = parse_option_parameters("", create_options, param);
> + opts = qemu_opts_create_nofail(create_opts);
Before: param empty.
After: opts empty.
Good.
>
> - set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
> + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size);
Before: param contains exactly BLOCK_OPT_SIZE = img_size.
After: opts contains exactly BLOCK_OPT_SIZE = img_size.
Both old and new code seem to assume BLOCK_OPT_SIZE is always a valid
option. Beyond the scope of this patch.
Good.
>
> /* Parse -o options */
> if (options) {
> - param = parse_option_parameters(options, create_options, param);
> - if (param == NULL) {
> + if (qemu_opts_do_parse_replace(opts, options, NULL) != 0) {
> error_setg(errp, "Invalid options for file format '%s'.", fmt);
> goto out;
> }
> }
Before: values from -o replace whatever is in param already.
After: values from -o replace whatever is in opts already.
In particular, size from -o replaces img_size before and after.
Did you test it does?
$ qemu-img create -f raw -o size=1024 t.img 512
Formatting 't.img', fmt=raw size=1024
$ ls -l t.img
-rw-r--r--. 1 armbru armbru 1024 Mar 21 15:12 t.img
>
> if (base_filename) {
> - if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
> + if (qemu_opt_replace_set(opts, BLOCK_OPT_BACKING_FILE,
> base_filename)) {
> error_setg(errp, "Backing file not supported for file format
> '%s'",
> fmt);
Before: base_filename replaces any backing_file from -o in param.
After: base_filename replaces any backing_file from -o in opts.
Did you test it does?
$ qemu-img create -f qcow2 -b t.img -o backing_file=/dev/null t.qcow2
Formatting 't.qcow2', fmt=qcow2 size=1024 backing_file='t.img'
encryption=off cluster_size=65536 lazy_refcounts=off
$ qemu-img info t.qcow2image: t.qcow2
file format: qcow2
virtual size: 1.0K (1024 bytes)
disk size: 196K
cluster_size: 65536
backing file: t.img
> @@ -4551,39 +4547,37 @@ void bdrv_img_create(const char *filename, const char
> *fmt,
> }
>
> if (base_fmt) {
> - if (set_option_parameter(param, BLOCK_OPT_BACKING_FMT, base_fmt)) {
> + if (qemu_opt_replace_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) {
> error_setg(errp, "Backing file format not supported for file "
> "format '%s'", fmt);
> goto out;
> }
> }
Likewise.
Did you test?
$ qemu-img create -f qcow2 -b t.img -F file -o
backing_file=/dev/null,backing_fmt=host_device t.qcow2
Formatting 't.qcow2', fmt=qcow2 size=1024 backing_file='t.img'
backing_fmt='file' encryption=off cluster_size=65536 lazy_refcounts=off
$ qemu-img info t.qcow2image: t.qcow2
file format: qcow2
virtual size: 1.0K (1024 bytes)
disk size: 196K
cluster_size: 65536
backing file: t.img
backing file format: file
>
> - backing_file = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
> - if (backing_file && backing_file->value.s) {
> - if (!strcmp(filename, backing_file->value.s)) {
> + backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
> + if (backing_file) {
> + if (!strcmp(filename, backing_file)) {
> error_setg(errp, "Error: Trying to create an image with the "
> "same filename as the backing file");
> goto out;
> }
> }
>
> - backing_fmt = get_option_parameter(param, BLOCK_OPT_BACKING_FMT);
> - if (backing_fmt && backing_fmt->value.s) {
> - backing_drv = bdrv_find_format(backing_fmt->value.s);
> + backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
> + if (backing_fmt) {
> + backing_drv = bdrv_find_format(backing_fmt);
> if (!backing_drv) {
> - error_setg(errp, "Unknown backing file format '%s'",
> - backing_fmt->value.s);
> + error_setg(errp, "Unknown backing file format '%s'",
> backing_fmt);
> goto out;
> }
> }
>
> // The size for the image must always be specified, with one exception:
> // If we are using a backing file, we can obtain the size from there
> - size = get_option_parameter(param, BLOCK_OPT_SIZE);
> - if (size && size->value.n == -1) {
> - if (backing_file && backing_file->value.s) {
> + size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0);
> + if (size == -1) {
> + if (backing_file) {
> uint64_t size;
> - char buf[32];
> int back_flags;
>
> /* backing files always opened read-only */
> @@ -4592,17 +4586,16 @@ void bdrv_img_create(const char *filename, const char
> *fmt,
>
> bs = bdrv_new("");
>
> - ret = bdrv_open(bs, backing_file->value.s, back_flags,
> backing_drv);
> + ret = bdrv_open(bs, backing_file, back_flags, backing_drv);
> if (ret < 0) {
> error_setg_errno(errp, -ret, "Could not open '%s'",
> - backing_file->value.s);
> + backing_file);
> goto out;
> }
> bdrv_get_geometry(bs, &size);
> size *= 512;
>
> - snprintf(buf, sizeof(buf), "%" PRId64, size);
> - set_option_parameter(param, BLOCK_OPT_SIZE, buf);
> + qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size);
We get here only when opts doesn't have BLOCK_OPT_SIZE.
Good.
> } else {
> error_setg(errp, "Image creation needs a size parameter");
> goto out;
> @@ -4611,10 +4604,10 @@ 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, NULL);
> puts("");
> }
Before:
param[] contains all valid options. If the option in param[i] hasn't
been set, param[i].value still has the default value defined in the
.create_options[] where we got this option.
print_option_parameters() iterates over all valid options, and prints
NAME=VALUE. Except it prints nothing for an option of type OPT_STRING
when the value is null. That's the case when the default is null and
the option hasn't been set.
After:
opts contains only the options that have been set. opts->list->desc[]
contains all valid options (or is empty, which means "accept all", but
that shouldn't happen here).
qemu_opts_print() in master prints only the options that have been set.
Differs from print_option_parameters() for unset options. That's why
you rewrite qemu_opts_print() in PATCH 1/4.
The rewritten qemu_opts_print() prints all all valid options, except
unset ones that have a null def_value_str.
Therefore:
* OPT_STRING parameters need to become QEMU_OPT_STRING options, and
their default value needs to go both into def_value_str *and* into
every caller's handling of qemu_opt_get() returning null.
* OPT_FLAG, OPT_NUMBER, OPT_STRING parameters need to become
QEMU_OPT_BOOL, QEMU_OPT_NUMBER, QEMU_OPT_SIZE options, and their
default value needs to go both into def_value_str *and* into the last
argument of every qemu_opt_bool() getting it.
I hate how the default value needs to go in multiple places now. More
on that in my forthcoming review of PATCH 1/4.
> - ret = bdrv_create(drv, filename, param);
> + ret = bdrv_create(drv, filename, opts);
> if (ret < 0) {
> if (ret == -ENOTSUP) {
> error_setg(errp,"Formatting or formatting option not supported
> for "
> @@ -4629,8 +4622,10 @@ void bdrv_img_create(const char *filename, const char
> *fmt,
> }
>
> out:
> - free_option_parameters(create_options);
> - free_option_parameters(param);
> + qemu_opts_free(create_opts);
> + if (opts) {
> + qemu_opts_del(opts);
> + }
>
> if (bs) {
> bdrv_delete(bs);
> diff --git a/block/cow.c b/block/cow.c
> index 4baf904..135fa33 100644
> --- a/block/cow.c
> +++ b/block/cow.c
> @@ -255,7 +255,7 @@ static void cow_close(BlockDriverState *bs)
> {
> }
>
> -static int cow_create(const char *filename, QEMUOptionParameter *options)
> +static int cow_create(const char *filename, QemuOpts *opts)
> {
> struct cow_header_v2 cow_header;
> struct stat st;
> @@ -264,17 +264,11 @@ static int cow_create(const char *filename,
> QEMUOptionParameter *options)
> int ret;
> BlockDriverState *cow_bs;
>
> - /* Read out options */
> - while (options && options->name) {
> - if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> - image_sectors = options->value.n / 512;
> - } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
> - image_filename = options->value.s;
> - }
> - options++;
> - }
> + /* Read out opts */
> + image_sectors = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0) / 512;
> + image_filename = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE);
Why _del?
>
> - ret = bdrv_create_file(filename, options);
> + ret = bdrv_create_file(filename, opts);
> if (ret < 0) {
> return ret;
> }
> @@ -318,18 +312,22 @@ exit:
> return ret;
> }
>
> -static QEMUOptionParameter cow_create_options[] = {
> - {
> - .name = BLOCK_OPT_SIZE,
> - .type = OPT_SIZE,
> - .help = "Virtual disk size"
> - },
> - {
> - .name = BLOCK_OPT_BACKING_FILE,
> - .type = OPT_STRING,
> - .help = "File name of a base image"
> - },
> - { NULL }
> +static QemuOptsList cow_create_opts = {
> + .name = "cow-create-opts",
> + .head = QTAILQ_HEAD_INITIALIZER(cow_create_opts.head),
> + .desc = {
> + {
> + .name = BLOCK_OPT_SIZE,
> + .type = QEMU_OPT_SIZE,
> + .help = "Virtual disk size"
> + },
> + {
> + .name = BLOCK_OPT_BACKING_FILE,
> + .type = QEMU_OPT_STRING,
> + .help = "File name of a base image"
> + },
> + { /* end of list */ }
> + }
> };
>
> static BlockDriver bdrv_cow = {
> @@ -345,7 +343,7 @@ static BlockDriver bdrv_cow = {
> .bdrv_write = cow_co_write,
> .bdrv_co_is_allocated = cow_co_is_allocated,
>
> - .create_options = cow_create_options,
> + .bdrv_create_opts = &cow_create_opts,
> };
>
> static void bdrv_cow_init(void)
[Boatload of drivers snipped; not reviewed in this round]
> diff --git a/include/block/block.h b/include/block/block.h
> index 0f750d7..a477b7a 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -126,8 +126,8 @@ BlockDriver *bdrv_find_protocol(const char *filename);
> BlockDriver *bdrv_find_format(const char *format_name);
> BlockDriver *bdrv_find_whitelisted_format(const char *format_name);
> int bdrv_create(BlockDriver *drv, const char* filename,
> - QEMUOptionParameter *options);
> -int bdrv_create_file(const char* filename, QEMUOptionParameter *options);
> + QemuOpts *options);
> +int bdrv_create_file(const char *filename, QemuOpts *options);
QemuOpts *opts
> BlockDriverState *bdrv_new(const char *device_name);
> void bdrv_make_anon(BlockDriverState *bs);
> void bdrv_swap(BlockDriverState *bs_new, BlockDriverState *bs_old);
> diff --git a/include/block/block_int.h b/include/block/block_int.h
> index eaad53e..4f942ef 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -90,7 +90,7 @@ struct BlockDriver {
> const uint8_t *buf, int nb_sectors);
> void (*bdrv_close)(BlockDriverState *bs);
> void (*bdrv_rebind)(BlockDriverState *bs);
> - int (*bdrv_create)(const char *filename, QEMUOptionParameter *options);
> + int (*bdrv_create)(const char *filename, QemuOpts *options);
QemuOpts *opts
> int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
> int (*bdrv_make_empty)(BlockDriverState *bs);
> /* aio */
> @@ -179,9 +179,7 @@ struct BlockDriver {
> unsigned long int req, void *buf,
> BlockDriverCompletionFunc *cb, void *opaque);
>
> - /* List of options for creating images, terminated by name == NULL */
> - QEMUOptionParameter *create_options;
> -
> + QemuOptsList *bdrv_create_opts;
>
> /*
> * Returns 0 for completed check, -errno for internal errors.
> diff --git a/include/qemu/option.h b/include/qemu/option.h
> index c58db43..0d5fb66 100644
> --- a/include/qemu/option.h
> +++ b/include/qemu/option.h
> @@ -108,6 +108,7 @@ struct QemuOptsList {
> };
>
> const char *qemu_opt_get(QemuOpts *opts, const char *name);
> +const char *qemu_opt_get_del(QemuOpts *opts, const char *name);
> /**
> * qemu_opt_has_help_opt:
> * @opts: options to search for a help request
> @@ -121,9 +122,13 @@ const char *qemu_opt_get(QemuOpts *opts, const char
> *name);
> */
> bool qemu_opt_has_help_opt(QemuOpts *opts);
> bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval);
> +bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval);
> uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t
> defval);
> uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t
> defval);
> +uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name,
> + uint64_t defval);
> int qemu_opt_set(QemuOpts *opts, const char *name, const char *value);
> +int qemu_opt_replace_set(QemuOpts *opts, const char *name, const char
> *value);
> void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value,
> Error **errp);
> int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val);
> @@ -144,7 +149,10 @@ const char *qemu_opts_id(QemuOpts *opts);
> void qemu_opts_del(QemuOpts *opts);
> void qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc, Error
> **errp);
> int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char
> *firstname);
> -QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, int
> permit_abbrev);
> +int qemu_opts_do_parse_replace(QemuOpts *opts, const char *params,
> + const char *firstname);
> +QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
> + int permit_abbrev);
> void qemu_opts_set_defaults(QemuOptsList *list, const char *params,
> int permit_abbrev);
> QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict,
Putting these new qemu_opt_*() functions in their own patch would reduce
this patch's size a little.
> @@ -156,8 +164,7 @@ 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 *qemu_opts_append(QemuOptsList *first,
> - QemuOptsList *second);
> +QemuOptsList *qemu_opts_append(QemuOptsList *first, QemuOptsList *second);
> void qemu_opts_free(QemuOptsList *list);
> void qemu_opts_print_help(QemuOptsList *list);
> #endif
> diff --git a/qemu-img.c b/qemu-img.c
> index 471de7d..9339957 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -229,7 +229,7 @@ static int read_password(char *buf, int buf_size)
> static int print_block_option_help(const char *filename, const char *fmt)
> {
> BlockDriver *drv, *proto_drv;
> - QEMUOptionParameter *create_options = NULL;
> + QemuOptsList *create_opts = NULL;
>
> /* Find driver and parse its options */
> drv = bdrv_find_format(fmt);
> @@ -244,12 +244,10 @@ static int print_block_option_help(const char
> *filename, const char *fmt)
> return 1;
> }
>
> - create_options = append_option_parameters(create_options,
> - drv->create_options);
> - create_options = append_option_parameters(create_options,
> - proto_drv->create_options);
> - print_option_help(create_options);
> - free_option_parameters(create_options);
> + create_opts = qemu_opts_append(drv->bdrv_create_opts,
> + proto_drv->bdrv_create_opts);
> + qemu_opts_print_help(create_opts);
> + qemu_opts_free(create_opts);
> return 0;
> }
>
Must merge options exactly like bdrv_img_create(). It does. Good.
I suspect the merge code should be factored out. Beyond the scope of
this patch.
Running out of steam, review is becoming more superficial and less
reliable.
> @@ -301,19 +299,19 @@ fail:
> return NULL;
> }
>
> -static int add_old_style_options(const char *fmt, QEMUOptionParameter *list,
> +static int add_old_style_options(const char *fmt, QemuOpts *list,
> const char *base_filename,
> const char *base_fmt)
> {
> if (base_filename) {
> - if (set_option_parameter(list, BLOCK_OPT_BACKING_FILE,
> base_filename)) {
> + if (qemu_opt_set(list, BLOCK_OPT_BACKING_FILE, base_filename)) {
> error_report("Backing file not supported for file format '%s'",
> fmt);
> return -1;
> }
> }
> if (base_fmt) {
> - if (set_option_parameter(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
> + if (qemu_opt_set(list, BLOCK_OPT_BACKING_FMT, base_fmt)) {
> error_report("Backing file format not supported for file "
> "format '%s'", fmt);
> return -1;
Looks like this duplicates code in bdrv_img_create(). Cleanup beyond
the scope of this patch.
> @@ -1120,8 +1118,9 @@ static int img_convert(int argc, char **argv)
> uint8_t * buf = NULL;
> const uint8_t *buf1;
> BlockDriverInfo bdi;
> - QEMUOptionParameter *param = NULL, *create_options = NULL;
> - QEMUOptionParameter *out_baseimg_param;
> + QemuOpts *param = NULL;
> + QemuOptsList *create_opts = NULL;
> + const char *out_baseimg_param;
> char *options = NULL;
> const char *snapshot_name = NULL;
> float local_progress = 0;
> @@ -1265,40 +1264,36 @@ static int img_convert(int argc, char **argv)
> goto out;
> }
>
> - create_options = append_option_parameters(create_options,
> - drv->create_options);
> - create_options = append_option_parameters(create_options,
> - proto_drv->create_options);
> + create_opts = qemu_opts_append(drv->bdrv_create_opts,
> + proto_drv->bdrv_create_opts);
>
More duplicated option merge code. Cleanup beyond the scope of this
patch.
> if (options) {
> - param = parse_option_parameters(options, create_options, param);
> - if (param == NULL) {
> + if (qemu_opts_do_parse_replace(param, options, NULL) != 0) {
> error_report("Invalid options for file format '%s'.", out_fmt);
> ret = -1;
> goto out;
> }
> } else {
> - param = parse_option_parameters("", create_options, param);
> + param = qemu_opts_create_nofail(create_opts);
> }
> -
> - set_option_parameter_int(param, BLOCK_OPT_SIZE, total_sectors * 512);
> + qemu_opt_set_number(param, BLOCK_OPT_SIZE, total_sectors * 512);
> ret = add_old_style_options(out_fmt, param, out_baseimg, NULL);
> if (ret < 0) {
> goto out;
> }
>
> /* Get backing file name if -o backing_file was used */
> - out_baseimg_param = get_option_parameter(param, BLOCK_OPT_BACKING_FILE);
> + out_baseimg_param = qemu_opt_get(param, BLOCK_OPT_BACKING_FILE);
> if (out_baseimg_param) {
> - out_baseimg = out_baseimg_param->value.s;
> + out_baseimg = out_baseimg_param;
> }
More copy/paste coding. Cleanup beyond the scope of this patch.
>
> /* Check if compression is supported */
> if (compress) {
> - QEMUOptionParameter *encryption =
> - get_option_parameter(param, BLOCK_OPT_ENCRYPT);
> - QEMUOptionParameter *preallocation =
> - get_option_parameter(param, BLOCK_OPT_PREALLOC);
> + bool encryption =
> + qemu_opt_get_bool(param, BLOCK_OPT_ENCRYPT, false);
> + const char *preallocation =
> + qemu_opt_get(param, BLOCK_OPT_PREALLOC);
>
> if (!drv->bdrv_write_compressed) {
> error_report("Compression not supported for this file format");
> @@ -1306,15 +1301,15 @@ static int img_convert(int argc, char **argv)
> goto out;
> }
>
> - if (encryption && encryption->value.n) {
> + if (encryption) {
> error_report("Compression and encryption not supported at "
> "the same time");
> ret = -1;
> goto out;
> }
>
> - if (preallocation && preallocation->value.s
> - && strcmp(preallocation->value.s, "off"))
> + if (preallocation
> + && strcmp(preallocation, "off"))
> {
> error_report("Compression and preallocation not supported at "
> "the same time");
> @@ -1532,8 +1527,10 @@ static int img_convert(int argc, char **argv)
> }
> out:
> qemu_progress_end();
> - free_option_parameters(create_options);
> - free_option_parameters(param);
> + qemu_opts_free(create_opts);
> + if (param) {
> + qemu_opts_del(param);
> + }
> qemu_vfree(buf);
> if (out_bs) {
> bdrv_delete(out_bs);
> diff --git a/util/qemu-option.c b/util/qemu-option.c
> index 0e42452..dba82b4 100644
> --- a/util/qemu-option.c
> +++ b/util/qemu-option.c
Changes to this file not reviewed in this round.
> @@ -33,6 +33,8 @@
> #include "qapi/qmp/qerror.h"
> #include "qemu/option_int.h"
>
> +static void qemu_opt_del(QemuOpt *opt);
> +
> /*
> * Extracts the name of an option from the parameter string (p points at the
> * first byte of the option name)
> @@ -531,6 +533,16 @@ const char *qemu_opt_get(QemuOpts *opts, const char
> *name)
> return opt ? opt->str : NULL;
> }
>
> +const char *qemu_opt_get_del(QemuOpts *opts, const char *name)
> +{
> + QemuOpt *opt = qemu_opt_find(opts, name);
> + const char *str = opt ? opt->str : NULL;
> + if (opt) {
> + qemu_opt_del(opt);
> + }
> + return str;
> +}
> +
> bool qemu_opt_has_help_opt(QemuOpts *opts)
> {
> QemuOpt *opt;
> @@ -553,6 +565,22 @@ bool qemu_opt_get_bool(QemuOpts *opts, const char *name,
> bool defval)
> return opt->value.boolean;
> }
>
> +bool qemu_opt_get_bool_del(QemuOpts *opts, const char *name, bool defval)
> +{
> + QemuOpt *opt = qemu_opt_find(opts, name);
> + bool ret;
> +
> + if (opt == NULL) {
> + return defval;
> + }
> + ret = opt->value.boolean;
> + assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
> + if (opt) {
> + qemu_opt_del(opt);
> + }
> + return ret;
> +}
> +
> uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t
> defval)
> {
> QemuOpt *opt = qemu_opt_find(opts, name);
> @@ -573,6 +601,23 @@ uint64_t qemu_opt_get_size(QemuOpts *opts, const char
> *name, uint64_t defval)
> return opt->value.uint;
> }
>
> +uint64_t qemu_opt_get_size_del(QemuOpts *opts, const char *name,
> + uint64_t defval)
> +{
> + QemuOpt *opt = qemu_opt_find(opts, name);
> + uint64_t ret;
> +
> + if (opt == NULL) {
> + return defval;
> + }
> + ret = opt->value.uint;
> + assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
> + if (opt) {
> + qemu_opt_del(opt);
> + }
> + return ret;
> +}
> +
> static void qemu_opt_parse(QemuOpt *opt, Error **errp)
> {
> if (opt->desc == NULL)
> @@ -624,7 +669,7 @@ static const QemuOptDesc *find_desc_by_name(const
> QemuOptDesc *desc,
> }
>
> static void opt_set(QemuOpts *opts, const char *name, const char *value,
> - bool prepend, Error **errp)
> + bool prepend, bool replace, Error **errp)
> {
> QemuOpt *opt;
> const QemuOptDesc *desc;
> @@ -636,6 +681,11 @@ static void opt_set(QemuOpts *opts, const char *name,
> const char *value,
> return;
> }
>
> + opt = qemu_opt_find(opts, name);
> + if (replace && opt) {
> + qemu_opt_del(opt);
> + }
> +
> opt = g_malloc0(sizeof(*opt));
> opt->name = g_strdup(name);
> opt->opts = opts;
> @@ -658,7 +708,29 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const
> char *value)
> {
> Error *local_err = NULL;
>
> - opt_set(opts, name, value, false, &local_err);
> + opt_set(opts, name, value, false, false, &local_err);
> + if (error_is_set(&local_err)) {
> + qerror_report_err(local_err);
> + error_free(local_err);
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +/*
> + * If name exists, the function will delete the opt first and then add a new
> + * one.
> + */
> +int qemu_opt_replace_set(QemuOpts *opts, const char *name, const char *value)
> +{
> + Error *local_err = NULL;
> + QemuOpt *opt = qemu_opt_find(opts, name);
> +
> + if (opt) {
> + qemu_opt_del(opt);
> + }
> + opt_set(opts, name, value, false, true, &local_err);
> if (error_is_set(&local_err)) {
> qerror_report_err(local_err);
> error_free(local_err);
> @@ -671,7 +743,7 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const
> char *value)
> void qemu_opt_set_err(QemuOpts *opts, const char *name, const char *value,
> Error **errp)
> {
> - opt_set(opts, name, value, false, errp);
> + opt_set(opts, name, value, false, false, errp);
> }
>
> int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
> @@ -895,7 +967,7 @@ int qemu_opts_print(QemuOpts *opts, void *dummy)
> }
>
> static int opts_do_parse(QemuOpts *opts, const char *params,
> - const char *firstname, bool prepend)
> + const char *firstname, bool prepend, bool replace)
> {
> char option[128], value[1024];
> const char *p,*pe,*pc;
> @@ -931,7 +1003,7 @@ static int opts_do_parse(QemuOpts *opts, const char
> *params,
> }
> if (strcmp(option, "id") != 0) {
> /* store and parse */
> - opt_set(opts, option, value, prepend, &local_err);
> + opt_set(opts, option, value, prepend, replace, &local_err);
> if (error_is_set(&local_err)) {
> qerror_report_err(local_err);
> error_free(local_err);
> @@ -947,9 +1019,16 @@ static int opts_do_parse(QemuOpts *opts, const char
> *params,
>
> int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char
> *firstname)
> {
> - return opts_do_parse(opts, params, firstname, false);
> + return opts_do_parse(opts, params, firstname, false, false);
> +}
> +
> +int qemu_opts_do_parse_replace(QemuOpts *opts, const char *params,
> + const char *firstname)
> +{
> + return opts_do_parse(opts, params, firstname, false, true);
> }
>
> +
> static QemuOpts *opts_parse(QemuOptsList *list, const char *params,
> int permit_abbrev, bool defaults)
> {
> @@ -986,7 +1065,7 @@ static QemuOpts *opts_parse(QemuOptsList *list, const
> char *params,
> return NULL;
> }
>
> - if (opts_do_parse(opts, params, firstname, defaults) != 0) {
> + if (opts_do_parse(opts, params, firstname, defaults, false) != 0) {
> qemu_opts_del(opts);
> return NULL;
> }