diff mbox

[V11,3/4] Use QemuOpts support in block layer

Message ID 1359022987-6274-4-git-send-email-wdongxu@vnet.linux.ibm.com
State New
Headers show

Commit Message

Dong Xu Wang Jan. 24, 2013, 10:23 a.m. UTC
This patch will use QemuOpts related functions in block layer, add
a member bdrv_create_options 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 <wdongxu@linux.vnet.ibm.com>
---
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/qcow.c              |  60 ++++++++--------
 block/qcow2.c             | 171 +++++++++++++++++++++++-----------------------
 block/qed.c               |  86 +++++++++++------------
 block/qed.h               |   2 +-
 block/raw-posix.c         |  59 ++++++++--------
 block/raw-win32.c         |  30 ++++----
 block/raw.c               |  30 ++++----
 block/rbd.c               |  62 ++++++++---------
 block/sheepdog.c          |  75 ++++++++++----------
 block/vdi.c               |  69 +++++++++----------
 block/vmdk.c              |  74 ++++++++++----------
 block/vpc.c               |  67 +++++++++---------
 block/vvfat.c             |  11 +--
 include/block/block.h     |   4 +-
 include/block/block_int.h |   6 +-
 qemu-img.c                |  61 ++++++++---------
 19 files changed, 519 insertions(+), 522 deletions(-)

Comments

Markus Armbruster Jan. 24, 2013, 8:08 p.m. UTC | #1
Dong Xu Wang <wdongxu@vnet.linux.ibm.com> writes:

> This patch will use QemuOpts related functions in block layer, add
> a member bdrv_create_options 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 <wdongxu@linux.vnet.ibm.com>
> ---
> 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/qcow.c              |  60 ++++++++--------
>  block/qcow2.c             | 171 +++++++++++++++++++++++-----------------------
>  block/qed.c               |  86 +++++++++++------------
>  block/qed.h               |   2 +-
>  block/raw-posix.c         |  59 ++++++++--------
>  block/raw-win32.c         |  30 ++++----
>  block/raw.c               |  30 ++++----
>  block/rbd.c               |  62 ++++++++---------
>  block/sheepdog.c          |  75 ++++++++++----------
>  block/vdi.c               |  69 +++++++++----------
>  block/vmdk.c              |  74 ++++++++++----------
>  block/vpc.c               |  67 +++++++++---------
>  block/vvfat.c             |  11 +--
>  include/block/block.h     |   4 +-
>  include/block/block_int.h |   6 +-
>  qemu-img.c                |  61 ++++++++---------
>  19 files changed, 519 insertions(+), 522 deletions(-)
>
> diff --git a/block.c b/block.c
> index 6fa7c90..56e4613 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)
>  {
>      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,
>          .ret = NOT_DONE,
>      };
>  
> @@ -405,7 +405,7 @@ out:
>      return ret;
>  }
>  
> -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);
>  }
>  
>  /*
> @@ -794,7 +794,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
> @@ -827,17 +827,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_options);
>  
> -        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;
>          }
> @@ -4493,8 +4492,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>                       const char *base_filename, const char *base_fmt,
>                       char *options, uint64_t img_size, int flags, Error **errp)
>  {
> -    QEMUOptionParameter *param = NULL, *create_options = NULL;
> -    QEMUOptionParameter *backing_fmt, *backing_file, *size;
> +    QemuOpts *opts = NULL;
> +    QemuOptsList *create_options = NULL;
> +    const char *backing_fmt, *backing_file;
> +    int64_t size;
>      BlockDriverState *bs = NULL;
>      BlockDriver *drv, *proto_drv;
>      BlockDriver *backing_drv = NULL;
> @@ -4512,28 +4513,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_options = append_opts_list(drv->bdrv_create_options,
> +                                      proto_drv->bdrv_create_options);

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?  Outside the
scope of this patch.

>      /* Create parameter list with default values */
> -    param = parse_option_parameters("", create_options, param);
> +    opts = qemu_opts_create_nofail(create_options);
>  
> -    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
> +    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size);
>  
>      /* Parse -o options */
>      if (options) {
> -        param = parse_option_parameters(options, create_options, param);
> -        if (param == NULL) {
> +        if (qemu_opts_do_parse(opts, options, NULL) != 0) {
>              error_setg(errp, "Invalid options for file format '%s'.", fmt);
>              goto out;
>          }
>      }

Before: size from -o replaces img_size in param.

After: size from -o gets appended to opts, is therefore shadowed by
img_size.  I think.

User-visible change, if my reading is correct.  Should be avoided.

>  
>      if (base_filename) {
> -        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
> +        if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE,
>                                   base_filename)) {
>              error_setg(errp, "Backing file not supported for file format '%s'",
>                         fmt);

Before: base_filename replaces the backing_file from -o.

After: base_filename gets appended to opts, shadowed by backing_file
from -o.

> @@ -4542,39 +4538,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_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) {
>              error_setg(errp, "Backing file format not supported for file "
>                               "format '%s'", fmt);
>              goto out;
>          }
>      }

Likewise.

>  
> -    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_number(opts, BLOCK_OPT_SIZE, -1);
> +    if (size == -1) {
> +        if (backing_file) {

Code has the same before your patch, so it's not your fault, but here
goes anyway:

QemuOpts support only *unsigned* numbers.  Argument -1 is for an
uint64_t parameter, and gets converted to UINT64_MAX.  If the option
isn't set, it's returned.  The assignment to int64_t size converts it
back to -1.

Using the an honest UINT64_MAX instead of -1 would be clearer.  Should
make size uint64_t then.

However, all other places do

    qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0)

Why is this one different?

>              uint64_t size;
> -            char buf[32];
>              int back_flags;
>  
>              /* backing files always opened read-only */
> @@ -4583,17 +4577,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);
>          } else {
>              error_setg(errp, "Image creation needs a size parameter");
>              goto out;
> @@ -4601,10 +4594,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>      }
>  
>      printf("Formatting '%s', fmt=%s ", filename, fmt);
> -    print_option_parameters(param);
> +    qemu_opts_print(opts, NULL);
>      puts("");
>  
> -    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 "
> @@ -4619,8 +4612,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>      }
>  
>  out:
> -    free_option_parameters(create_options);
> -    free_option_parameters(param);
> +    free_opts_list(create_options);
> +    if (opts) {
> +        qemu_opts_del(opts);
> +    }
>  
>      if (bs) {
>          bdrv_delete(bs);
> diff --git a/block/cow.c b/block/cow.c
> index a33ce95..5442c9c 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,13 @@ 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 */
> +    if (opts) {

I suspect you need the if (opts) here and in many other places only
because you special-cased "both lists empty" in append_opts_list().  I
suspect things become easier if you drop that.

> +        image_sectors = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
> +        image_filename = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
>      }
>  
> -    ret = bdrv_create_file(filename, options);
> +    ret = bdrv_create_file(filename, opts);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -318,18 +314,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_NUMBER,

QEMU_OPT_SIZE, or else we lose support for suffixes, don't we?

> +            .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 +345,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_options    = &cow_create_opts,
>  };
>  
>  static void bdrv_cow_init(void)
> diff --git a/block/gluster.c b/block/gluster.c
> index 0f2c32a..a41c684 100644
> --- a/block/gluster.c
> +++ b/block/gluster.c
> @@ -335,8 +335,7 @@ out:
>      return ret;
>  }
>  
> -static int qemu_gluster_create(const char *filename,
> -        QEMUOptionParameter *options)
> +static int qemu_gluster_create(const char *filename, QemuOpts* opts)

Space before the *, not after: QemuOpts *opts

Running out of steam for today, rest of patch only skimmed.

>  {
>      struct glfs *glfs;
>      struct glfs_fd *fd;
> @@ -350,11 +349,9 @@ static int qemu_gluster_create(const char *filename,
>          goto out;
>      }
>  
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            total_size = options->value.n / BDRV_SECTOR_SIZE;
> -        }
> -        options++;
> +    if (opts) {
> +        total_size =
> +            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
>      }
>  
>      fd = glfs_creat(glfs, gconf->image,
> @@ -544,13 +541,17 @@ static void qemu_gluster_close(BlockDriverState *bs)
>      glfs_fini(s->glfs);
>  }
>  
> -static QEMUOptionParameter qemu_gluster_create_options[] = {
> -    {
> -        .name = BLOCK_OPT_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "Virtual disk size"
> -    },
> -    { NULL }
> +static QemuOptsList qemu_gluster_create_opts = {
> +    .name = "qemu-gluster-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        { /* end of list */ }
> +    }
>  };
>  
>  static BlockDriver bdrv_gluster = {
> @@ -565,7 +566,7 @@ static BlockDriver bdrv_gluster = {
>      .bdrv_aio_readv               = qemu_gluster_aio_readv,
>      .bdrv_aio_writev              = qemu_gluster_aio_writev,
>      .bdrv_aio_flush               = qemu_gluster_aio_flush,
> -    .create_options               = qemu_gluster_create_options,
> +    .bdrv_create_options          = &qemu_gluster_create_opts,
>  };
>  
>  static BlockDriver bdrv_gluster_tcp = {
> @@ -580,7 +581,7 @@ static BlockDriver bdrv_gluster_tcp = {
>      .bdrv_aio_readv               = qemu_gluster_aio_readv,
>      .bdrv_aio_writev              = qemu_gluster_aio_writev,
>      .bdrv_aio_flush               = qemu_gluster_aio_flush,
> -    .create_options               = qemu_gluster_create_options,
> +    .bdrv_create_options          = &qemu_gluster_create_opts,
>  };
>  
>  static BlockDriver bdrv_gluster_unix = {
> @@ -595,7 +596,7 @@ static BlockDriver bdrv_gluster_unix = {
>      .bdrv_aio_readv               = qemu_gluster_aio_readv,
>      .bdrv_aio_writev              = qemu_gluster_aio_writev,
>      .bdrv_aio_flush               = qemu_gluster_aio_flush,
> -    .create_options               = qemu_gluster_create_options,
> +    .bdrv_create_options          = &qemu_gluster_create_opts,
>  };
>  
>  static BlockDriver bdrv_gluster_rdma = {
> @@ -610,7 +611,7 @@ static BlockDriver bdrv_gluster_rdma = {
>      .bdrv_aio_readv               = qemu_gluster_aio_readv,
>      .bdrv_aio_writev              = qemu_gluster_aio_writev,
>      .bdrv_aio_flush               = qemu_gluster_aio_flush,
> -    .create_options               = qemu_gluster_create_options,
> +    .bdrv_create_options          = &qemu_gluster_create_opts,
>  };
>  
>  static void bdrv_gluster_init(void)
> diff --git a/block/qcow.c b/block/qcow.c
> index 4276610..4691a3e 100644
> --- a/block/qcow.c
> +++ b/block/qcow.c
> @@ -651,7 +651,7 @@ static void qcow_close(BlockDriverState *bs)
>      error_free(s->migration_blocker);
>  }
>  
> -static int qcow_create(const char *filename, QEMUOptionParameter *options)
> +static int qcow_create(const char *filename, QemuOpts *opts)
>  {
>      int header_size, backing_filename_len, l1_size, shift, i;
>      QCowHeader header;
> @@ -662,19 +662,16 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
>      int ret;
>      BlockDriverState *qcow_bs;
>  
> -    /* Read out options */
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            total_size = options->value.n / 512;
> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
> -            backing_file = options->value.s;
> -        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
> -            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
> +    /* Read out opts */
> +    if (opts) {
> +        total_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, 0)) {
> +            flags |= BLOCK_FLAG_ENCRYPT;
>          }
> -        options++;
>      }
>  
> -    ret = bdrv_create_file(filename, options);
> +    ret = bdrv_create_file(filename, opts);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -851,24 +848,27 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
>      return 0;
>  }
>  
> -
> -static QEMUOptionParameter qcow_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"
> -    },
> -    {
> -        .name = BLOCK_OPT_ENCRYPT,
> -        .type = OPT_FLAG,
> -        .help = "Encrypt the image"
> -    },
> -    { NULL }
> +static QemuOptsList qcow_create_opts = {
> +    .name = "qcow-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(qcow_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        {
> +            .name = BLOCK_OPT_BACKING_FILE,
> +            .type = QEMU_OPT_STRING,
> +            .help = "File name of a base image"
> +        },
> +        {
> +            .name = BLOCK_OPT_ENCRYPT,
> +            .type = QEMU_OPT_BOOL,
> +            .help = "Encrypt the image"
> +        },
> +        { /* end of list */ }
> +    }
>  };
>  
>  static BlockDriver bdrv_qcow = {
> @@ -889,7 +889,7 @@ static BlockDriver bdrv_qcow = {
>      .bdrv_write_compressed  = qcow_write_compressed,
>      .bdrv_get_info          = qcow_get_info,
>  
> -    .create_options = qcow_create_options,
> +    .bdrv_create_options    = &qcow_create_opts,
>  };
>  
>  static void bdrv_qcow_init(void)
> diff --git a/block/qcow2.c b/block/qcow2.c
> index f6abff6..e3ee4af 100644
> --- a/block/qcow2.c
> +++ b/block/qcow2.c
> @@ -1177,7 +1177,7 @@ static int preallocate(BlockDriverState *bs)
>  static int qcow2_create2(const char *filename, int64_t total_size,
>                           const char *backing_file, const char *backing_format,
>                           int flags, size_t cluster_size, int prealloc,
> -                         QEMUOptionParameter *options, int version)
> +                         QemuOpts *opts, int version)
>  {
>      /* Calculate cluster_bits */
>      int cluster_bits;
> @@ -1208,7 +1208,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
>      uint8_t* refcount_table;
>      int ret;
>  
> -    ret = bdrv_create_file(filename, options);
> +    ret = bdrv_create_file(filename, opts);
>      if (ret < 0) {
>          return ret;
>      }
> @@ -1311,7 +1311,7 @@ out:
>      return ret;
>  }
>  
> -static int qcow2_create(const char *filename, QEMUOptionParameter *options)
> +static int qcow2_create(const char *filename, QemuOpts *opts)
>  {
>      const char *backing_file = NULL;
>      const char *backing_fmt = NULL;
> @@ -1320,45 +1320,43 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
>      size_t cluster_size = DEFAULT_CLUSTER_SIZE;
>      int prealloc = 0;
>      int version = 2;
> +    const char *buf;
>  
>      /* Read out options */
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            sectors = options->value.n / 512;
> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
> -            backing_file = options->value.s;
> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
> -            backing_fmt = options->value.s;
> -        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
> -            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
> -        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
> -            if (options->value.n) {
> -                cluster_size = options->value.n;
> -            }
> -        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
> -            if (!options->value.s || !strcmp(options->value.s, "off")) {
> -                prealloc = 0;
> -            } else if (!strcmp(options->value.s, "metadata")) {
> -                prealloc = 1;
> -            } else {
> -                fprintf(stderr, "Invalid preallocation mode: '%s'\n",
> -                    options->value.s);
> -                return -EINVAL;
> -            }
> -        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) {
> -            if (!options->value.s || !strcmp(options->value.s, "0.10")) {
> -                version = 2;
> -            } else if (!strcmp(options->value.s, "1.1")) {
> -                version = 3;
> -            } else {
> -                fprintf(stderr, "Invalid compatibility level: '%s'\n",
> -                    options->value.s);
> -                return -EINVAL;
> -            }
> -        } else if (!strcmp(options->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
> -            flags |= options->value.n ? BLOCK_FLAG_LAZY_REFCOUNTS : 0;
> +    if (opts) {
> +        sectors = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
> +        backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, 0)) {
> +            flags |= BLOCK_FLAG_ENCRYPT;
> +        }
> +        cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE,
> +                                         DEFAULT_CLUSTER_SIZE);
> +        buf = qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
> +        if (!buf || !strcmp(buf, "off")) {
> +            prealloc = 0;
> +        } else if (!strcmp(buf, "metadata")) {
> +            prealloc = 1;
> +        } else {
> +            fprintf(stderr, "Invalid preallocation mode: '%s'\n",
> +                buf);
> +            return -EINVAL;
> +        }
> +
> +        buf = qemu_opt_get(opts, BLOCK_OPT_COMPAT_LEVEL);
> +        if (!buf || !strcmp(buf, "0.10")) {
> +            version = 2;
> +        } else if (!strcmp(buf, "1.1")) {
> +            version = 3;
> +        } else {
> +            fprintf(stderr, "Invalid compatibility level: '%s'\n",
> +                buf);
> +            return -EINVAL;
> +        }
> +
> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS, 0)) {
> +            flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
>          }
> -        options++;
>      }
>  
>      if (backing_file && prealloc) {
> @@ -1374,7 +1372,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
>      }
>  
>      return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
> -                         cluster_size, prealloc, options, version);
> +                         cluster_size, prealloc, opts, version);
>  }
>  
>  static int qcow2_make_empty(BlockDriverState *bs)
> @@ -1635,49 +1633,53 @@ static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf,
>      return ret;
>  }
>  
> -static QEMUOptionParameter qcow2_create_options[] = {
> -    {
> -        .name = BLOCK_OPT_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "Virtual disk size"
> -    },
> -    {
> -        .name = BLOCK_OPT_COMPAT_LEVEL,
> -        .type = OPT_STRING,
> -        .help = "Compatibility level (0.10 or 1.1)"
> -    },
> -    {
> -        .name = BLOCK_OPT_BACKING_FILE,
> -        .type = OPT_STRING,
> -        .help = "File name of a base image"
> -    },
> -    {
> -        .name = BLOCK_OPT_BACKING_FMT,
> -        .type = OPT_STRING,
> -        .help = "Image format of the base image"
> -    },
> -    {
> -        .name = BLOCK_OPT_ENCRYPT,
> -        .type = OPT_FLAG,
> -        .help = "Encrypt the image"
> -    },
> -    {
> -        .name = BLOCK_OPT_CLUSTER_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "qcow2 cluster size",
> -        .value = { .n = DEFAULT_CLUSTER_SIZE },
> -    },
> -    {
> -        .name = BLOCK_OPT_PREALLOC,
> -        .type = OPT_STRING,
> -        .help = "Preallocation mode (allowed values: off, metadata)"
> -    },
> -    {
> -        .name = BLOCK_OPT_LAZY_REFCOUNTS,
> -        .type = OPT_FLAG,
> -        .help = "Postpone refcount updates",
> -    },
> -    { NULL }
> +static QemuOptsList qcow2_create_opts = {
> +    .name = "qcow2-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        {
> +            .name = BLOCK_OPT_COMPAT_LEVEL,
> +            .type = QEMU_OPT_STRING,
> +            .help = "Compatibility level (0.10 or 1.1)"
> +        },
> +        {
> +            .name = BLOCK_OPT_BACKING_FILE,
> +            .type = QEMU_OPT_STRING,
> +            .help = "File name of a base image"
> +        },
> +        {
> +            .name = BLOCK_OPT_BACKING_FMT,
> +            .type = QEMU_OPT_STRING,
> +            .help = "Image format of the base image"
> +        },
> +        {
> +            .name = BLOCK_OPT_ENCRYPT,
> +            .type = QEMU_OPT_BOOL,
> +            .help = "Encrypt the image"
> +        },
> +        {
> +            .name = BLOCK_OPT_CLUSTER_SIZE,
> +            .type = QEMU_OPT_SIZE,
> +            .help = "qcow2 cluster size",
> +            .def_value_str = stringify(DEFAULT_CLUSTER_SIZE)
> +        },
> +        {
> +            .name = BLOCK_OPT_PREALLOC,
> +            .type = QEMU_OPT_STRING,
> +            .help = "Preallocation mode (allowed values: off, metadata)"
> +        },
> +        {
> +            .name = BLOCK_OPT_LAZY_REFCOUNTS,
> +            .type = QEMU_OPT_BOOL,
> +            .help = "Postpone refcount updates",
> +        },
> +        { /* end of list */ }
> +    }
>  };
>  
>  static BlockDriver bdrv_qcow2 = {
> @@ -1715,8 +1717,9 @@ static BlockDriver bdrv_qcow2 = {
>  
>      .bdrv_invalidate_cache      = qcow2_invalidate_cache,
>  
> -    .create_options = qcow2_create_options,
>      .bdrv_check = qcow2_check,
> +
> +    .bdrv_create_options    = &qcow2_create_opts,
>  };
>  
>  static void bdrv_qcow2_init(void)
> diff --git a/block/qed.c b/block/qed.c
> index cf85d8f..766ba6f 100644
> --- a/block/qed.c
> +++ b/block/qed.c
> @@ -603,7 +603,7 @@ out:
>      return ret;
>  }
>  
> -static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
> +static int bdrv_qed_create(const char *filename, QemuOpts *opts)
>  {
>      uint64_t image_size = 0;
>      uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE;
> @@ -611,23 +611,15 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
>      const char *backing_file = NULL;
>      const char *backing_fmt = NULL;
>  
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            image_size = options->value.n;
> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
> -            backing_file = options->value.s;
> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
> -            backing_fmt = options->value.s;
> -        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
> -            if (options->value.n) {
> -                cluster_size = options->value.n;
> -            }
> -        } else if (!strcmp(options->name, BLOCK_OPT_TABLE_SIZE)) {
> -            if (options->value.n) {
> -                table_size = options->value.n;
> -            }
> -        }
> -        options++;
> +    if (opts) {
> +        image_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
> +        backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
> +        cluster_size = qemu_opt_get_size(opts,
> +                                         BLOCK_OPT_CLUSTER_SIZE,
> +                                         QED_DEFAULT_CLUSTER_SIZE);
> +        table_size = qemu_opt_get_size(opts, BLOCK_OPT_TABLE_SIZE,
> +                                       QED_DEFAULT_TABLE_SIZE);
>      }
>  
>      if (!qed_is_cluster_size_valid(cluster_size)) {
> @@ -1537,36 +1529,44 @@ static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,
>      return qed_check(s, result, !!fix);
>  }
>  
> -static QEMUOptionParameter qed_create_options[] = {
> -    {
> -        .name = BLOCK_OPT_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "Virtual disk size (in bytes)"
> -    }, {
> -        .name = BLOCK_OPT_BACKING_FILE,
> -        .type = OPT_STRING,
> -        .help = "File name of a base image"
> -    }, {
> -        .name = BLOCK_OPT_BACKING_FMT,
> -        .type = OPT_STRING,
> -        .help = "Image format of the base image"
> -    }, {
> -        .name = BLOCK_OPT_CLUSTER_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "Cluster size (in bytes)",
> -        .value = { .n = QED_DEFAULT_CLUSTER_SIZE },
> -    }, {
> -        .name = BLOCK_OPT_TABLE_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "L1/L2 table size (in clusters)"
> -    },
> -    { /* end of list */ }
> +static QemuOptsList qed_create_opts = {
> +    .name = "qed-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(qed_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        {
> +            .name = BLOCK_OPT_BACKING_FILE,
> +            .type = QEMU_OPT_STRING,
> +            .help = "File name of a base image"
> +        },
> +        {
> +            .name = BLOCK_OPT_BACKING_FMT,
> +            .type = QEMU_OPT_STRING,
> +            .help = "Image format of the base image"
> +        },
> +        {
> +            .name = BLOCK_OPT_CLUSTER_SIZE,
> +            .type = QEMU_OPT_SIZE,
> +            .help = "Cluster size (in bytes)",
> +            .def_value_str = stringify(QED_DEFAULT_CLUSTER_SIZE),
> +        },
> +        {
> +            .name = BLOCK_OPT_TABLE_SIZE,
> +            .type = QEMU_OPT_SIZE,
> +            .help = "L1/L2 table size (in clusters)"
> +        },
> +        { /* end of list */ }
> +    }
>  };
>  
>  static BlockDriver bdrv_qed = {
>      .format_name              = "qed",
>      .instance_size            = sizeof(BDRVQEDState),
> -    .create_options           = qed_create_options,
> +    .bdrv_create_options      = &qed_create_opts,
>  
>      .bdrv_probe               = bdrv_qed_probe,
>      .bdrv_rebind              = bdrv_qed_rebind,
> diff --git a/block/qed.h b/block/qed.h
> index 2b4dded..99a7726 100644
> --- a/block/qed.h
> +++ b/block/qed.h
> @@ -43,6 +43,7 @@
>   *
>   * All fields are little-endian on disk.
>   */
> +#define  QED_DEFAULT_CLUSTER_SIZE  65536
>  
>  enum {
>      QED_MAGIC = 'Q' | 'E' << 8 | 'D' << 16 | '\0' << 24,
> @@ -69,7 +70,6 @@ enum {
>       */
>      QED_MIN_CLUSTER_SIZE = 4 * 1024, /* in bytes */
>      QED_MAX_CLUSTER_SIZE = 64 * 1024 * 1024,
> -    QED_DEFAULT_CLUSTER_SIZE = 64 * 1024,
>  
>      /* Allocated clusters are tracked using a 2-level pagetable.  Table size is
>       * a multiple of clusters so large maximum image sizes can be supported
> diff --git a/block/raw-posix.c b/block/raw-posix.c
> index 657af95..890c8a7 100644
> --- a/block/raw-posix.c
> +++ b/block/raw-posix.c
> @@ -123,6 +123,19 @@
>  
>  #define MAX_BLOCKSIZE	4096
>  
> +static QemuOptsList file_proto_create_opts = {
> +    .name = "file-proto-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(file_proto_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_SIZE,
> +            .help = "Virtual disk size"
> +        },
> +        { /* end of list */ }
> +    }
> +};
> +
>  typedef struct BDRVRawState {
>      int fd;
>      int type;
> @@ -997,18 +1010,15 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
>      return (int64_t)st.st_blocks * 512;
>  }
>  
> -static int raw_create(const char *filename, QEMUOptionParameter *options)
> +static int raw_create(const char *filename, QemuOpts *opts)
>  {
>      int fd;
>      int result = 0;
>      int64_t total_size = 0;
>  
> -    /* Read out options */
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            total_size = options->value.n / BDRV_SECTOR_SIZE;
> -        }
> -        options++;
> +    if (opts) {
> +        total_size =
> +            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
>      }
>  
>      fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
> @@ -1136,15 +1146,6 @@ static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs,
>                         cb, opaque, QEMU_AIO_DISCARD);
>  }
>  
> -static QEMUOptionParameter raw_create_options[] = {
> -    {
> -        .name = BLOCK_OPT_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "Virtual disk size"
> -    },
> -    { NULL }
> -};
> -
>  static BlockDriver bdrv_file = {
>      .format_name = "file",
>      .protocol_name = "file",
> @@ -1167,8 +1168,7 @@ static BlockDriver bdrv_file = {
>      .bdrv_getlength = raw_getlength,
>      .bdrv_get_allocated_file_size
>                          = raw_get_allocated_file_size,
> -
> -    .create_options = raw_create_options,
> +    .bdrv_create_options = &file_proto_create_opts,
>  };
>  
>  /***********************************************/
> @@ -1403,19 +1403,16 @@ static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs,
>                         cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
>  }
>  
> -static int hdev_create(const char *filename, QEMUOptionParameter *options)
> +static int hdev_create(const char *filename, QemuOpts *opts)
>  {
>      int fd;
>      int ret = 0;
>      struct stat stat_buf;
>      int64_t total_size = 0;
>  
> -    /* Read out options */
> -    while (options && options->name) {
> -        if (!strcmp(options->name, "size")) {
> -            total_size = options->value.n / BDRV_SECTOR_SIZE;
> -        }
> -        options++;
> +    if (opts) {
> +        total_size =
> +            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
>      }
>  
>      fd = qemu_open(filename, O_WRONLY | O_BINARY);
> @@ -1440,7 +1437,7 @@ static int hdev_has_zero_init(BlockDriverState *bs)
>  
>  static BlockDriver bdrv_host_device = {
>      .format_name        = "host_device",
> -    .protocol_name        = "host_device",
> +    .protocol_name      = "host_device",
>      .instance_size      = sizeof(BDRVRawState),
>      .bdrv_probe_device  = hdev_probe_device,
>      .bdrv_file_open     = hdev_open,
> @@ -1449,7 +1446,6 @@ static BlockDriver bdrv_host_device = {
>      .bdrv_reopen_commit  = raw_reopen_commit,
>      .bdrv_reopen_abort   = raw_reopen_abort,
>      .bdrv_create        = hdev_create,
> -    .create_options     = raw_create_options,
>      .bdrv_has_zero_init = hdev_has_zero_init,
>  
>      .bdrv_aio_readv	= raw_aio_readv,
> @@ -1458,9 +1454,10 @@ static BlockDriver bdrv_host_device = {
>      .bdrv_aio_discard   = hdev_aio_discard,
>  
>      .bdrv_truncate      = raw_truncate,
> -    .bdrv_getlength	= raw_getlength,
> +    .bdrv_getlength     = raw_getlength,
>      .bdrv_get_allocated_file_size
>                          = raw_get_allocated_file_size,
> +    .bdrv_create_options = &file_proto_create_opts,
>  
>      /* generic scsi device */
>  #ifdef __linux__
> @@ -1574,7 +1571,6 @@ static BlockDriver bdrv_host_floppy = {
>      .bdrv_reopen_commit  = raw_reopen_commit,
>      .bdrv_reopen_abort   = raw_reopen_abort,
>      .bdrv_create        = hdev_create,
> -    .create_options     = raw_create_options,
>      .bdrv_has_zero_init = hdev_has_zero_init,
>  
>      .bdrv_aio_readv     = raw_aio_readv,
> @@ -1590,6 +1586,7 @@ static BlockDriver bdrv_host_floppy = {
>      .bdrv_is_inserted   = floppy_is_inserted,
>      .bdrv_media_changed = floppy_media_changed,
>      .bdrv_eject         = floppy_eject,
> +    .bdrv_create_options = &file_proto_create_opts,
>  };
>  
>  static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
> @@ -1676,7 +1673,6 @@ static BlockDriver bdrv_host_cdrom = {
>      .bdrv_reopen_commit  = raw_reopen_commit,
>      .bdrv_reopen_abort   = raw_reopen_abort,
>      .bdrv_create        = hdev_create,
> -    .create_options     = raw_create_options,
>      .bdrv_has_zero_init = hdev_has_zero_init,
>  
>      .bdrv_aio_readv     = raw_aio_readv,
> @@ -1696,6 +1692,8 @@ static BlockDriver bdrv_host_cdrom = {
>      /* generic scsi device */
>      .bdrv_ioctl         = hdev_ioctl,
>      .bdrv_aio_ioctl     = hdev_aio_ioctl,
> +
> +    .bdrv_create_options = &file_proto_create_opts,
>  };
>  #endif /* __linux__ */
>  
> @@ -1798,7 +1796,6 @@ static BlockDriver bdrv_host_cdrom = {
>      .bdrv_reopen_commit  = raw_reopen_commit,
>      .bdrv_reopen_abort   = raw_reopen_abort,
>      .bdrv_create        = hdev_create,
> -    .create_options     = raw_create_options,
>      .bdrv_has_zero_init = hdev_has_zero_init,
>  
>      .bdrv_aio_readv     = raw_aio_readv,
> diff --git a/block/raw-win32.c b/block/raw-win32.c
> index b89ac19..34826e0 100644
> --- a/block/raw-win32.c
> +++ b/block/raw-win32.c
> @@ -382,17 +382,15 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
>      return st.st_size;
>  }
>  
> -static int raw_create(const char *filename, QEMUOptionParameter *options)
> +static int raw_create(const char *filename, QemuOpts *opts)
>  {
>      int fd;
>      int64_t total_size = 0;
>  
>      /* Read out options */
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            total_size = options->value.n / 512;
> -        }
> -        options++;
> +    if (opts) {
> +        total_size =
> +            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
>      }
>  
>      fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
> @@ -405,13 +403,17 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
>      return 0;
>  }
>  
> -static QEMUOptionParameter raw_create_options[] = {
> -    {
> -        .name = BLOCK_OPT_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "Virtual disk size"
> -    },
> -    { NULL }
> +static QemuOptsList raw_create_opts = {
> +    .name = "raw-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        { /* end of list */ }
> +    }
>  };
>  
>  static BlockDriver bdrv_file = {
> @@ -431,7 +433,7 @@ static BlockDriver bdrv_file = {
>      .bdrv_get_allocated_file_size
>                          = raw_get_allocated_file_size,
>  
> -    .create_options = raw_create_options,
> +    .bdrv_create_options = &raw_create_opts,
>  };
>  
>  /***********************************************/
> diff --git a/block/raw.c b/block/raw.c
> index 75812db..033ffa6 100644
> --- a/block/raw.c
> +++ b/block/raw.c
> @@ -95,18 +95,22 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
>     return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
>  }
>  
> -static int raw_create(const char *filename, QEMUOptionParameter *options)
> -{
> -    return bdrv_create_file(filename, options);
> -}
> -
> -static QEMUOptionParameter raw_create_options[] = {
> -    {
> -        .name = BLOCK_OPT_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "Virtual disk size"
> -    },
> -    { NULL }
> +static int raw_create(const char *filename, QemuOpts *opts)
> +{
> +    return bdrv_create_file(filename, opts);
> +}
> +
> +static QemuOptsList raw_create_opts = {
> +    .name = "raw-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        { /* end of list */ }
> +    }
>  };
>  
>  static int raw_has_zero_init(BlockDriverState *bs)
> @@ -143,8 +147,8 @@ static BlockDriver bdrv_raw = {
>      .bdrv_aio_ioctl     = raw_aio_ioctl,
>  
>      .bdrv_create        = raw_create,
> -    .create_options     = raw_create_options,
>      .bdrv_has_zero_init = raw_has_zero_init,
> +    .bdrv_create_options = &raw_create_opts,
>  };
>  
>  static void bdrv_raw_init(void)
> diff --git a/block/rbd.c b/block/rbd.c
> index 8cd10a7..a9f8772 100644
> --- a/block/rbd.c
> +++ b/block/rbd.c
> @@ -287,7 +287,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
>      return ret;
>  }
>  
> -static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
> +static int qemu_rbd_create(const char *filename, QemuOpts *opts)
>  {
>      int64_t bytes = 0;
>      int64_t objsize;
> @@ -310,24 +310,20 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
>      }
>  
>      /* Read out options */
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            bytes = options->value.n;
> -        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
> -            if (options->value.n) {
> -                objsize = options->value.n;
> -                if ((objsize - 1) & objsize) {    /* not a power of 2? */
> -                    error_report("obj size needs to be power of 2");
> -                    return -EINVAL;
> -                }
> -                if (objsize < 4096) {
> -                    error_report("obj size too small");
> -                    return -EINVAL;
> -                }
> -                obj_order = ffs(objsize) - 1;
> +    if (opts) {
> +        bytes = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
> +        objsize = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, 0);
> +        if (objsize) {
> +            if ((objsize - 1) & objsize) {    /* not a power of 2? */
> +                error_report("obj size needs to be power of 2");
> +                return -EINVAL;
>              }
> +            if (objsize < 4096) {
> +                error_report("obj size too small");
> +                return -EINVAL;
> +            }
> +            obj_order = ffs(objsize) - 1;
>          }
> -        options++;
>      }
>  
>      clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
> @@ -920,20 +916,24 @@ static BlockDriverAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs,
>  }
>  #endif
>  
> -static QEMUOptionParameter qemu_rbd_create_options[] = {
> -    {
> -     .name = BLOCK_OPT_SIZE,
> -     .type = OPT_SIZE,
> -     .help = "Virtual disk size"
> -    },
> -    {
> -     .name = BLOCK_OPT_CLUSTER_SIZE,
> -     .type = OPT_SIZE,
> -     .help = "RBD object size"
> -    },
> -    {NULL}
> +static QemuOptsList rbd_create_opts = {
> +    .name = "rbd-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(rbd_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        {
> +            .name = BLOCK_OPT_CLUSTER_SIZE,
> +            .type = QEMU_OPT_SIZE,
> +            .help = "RBD object size",
> +            .def_value_str = stringify(0),
> +        },
> +        { /* end of list */ }
> +    }
>  };
> -
>  static BlockDriver bdrv_rbd = {
>      .format_name        = "rbd",
>      .instance_size      = sizeof(BDRVRBDState),
> @@ -941,7 +941,7 @@ static BlockDriver bdrv_rbd = {
>      .bdrv_close         = qemu_rbd_close,
>      .bdrv_create        = qemu_rbd_create,
>      .bdrv_get_info      = qemu_rbd_getinfo,
> -    .create_options     = qemu_rbd_create_options,
> +    .bdrv_create_options = &rbd_create_opts,
>      .bdrv_getlength     = qemu_rbd_getlength,
>      .bdrv_truncate      = qemu_rbd_truncate,
>      .protocol_name      = "rbd",
> diff --git a/block/sheepdog.c b/block/sheepdog.c
> index 3e49bb8..d515e56 100644
> --- a/block/sheepdog.c
> +++ b/block/sheepdog.c
> @@ -1274,12 +1274,12 @@ out:
>      return ret;
>  }
>  
> -static int sd_create(const char *filename, QEMUOptionParameter *options)
> +static int sd_create(const char *filename, QemuOpts *opts)
>  {
>      int ret = 0;
>      uint32_t vid = 0, base_vid = 0;
>      int64_t vdi_size = 0;
> -    char *backing_file = NULL;
> +    const char *backing_file = NULL, *buf = NULL;
>      BDRVSheepdogState *s;
>      char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
>      uint32_t snapid;
> @@ -1298,26 +1298,20 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
>          goto out;
>      }
>  
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            vdi_size = options->value.n;
> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
> -            backing_file = options->value.s;
> -        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
> -            if (!options->value.s || !strcmp(options->value.s, "off")) {
> -                prealloc = false;
> -            } else if (!strcmp(options->value.s, "full")) {
> -                prealloc = true;
> -            } else {
> -                error_report("Invalid preallocation mode: '%s'",
> -                             options->value.s);
> -                ret = -EINVAL;
> -                goto out;
> -            }
> +    if (opts) {
> +        vdi_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
> +        buf = qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
> +        if (!buf || !strcmp(buf, "off")) {
> +            prealloc = false;
> +        } else if (!strcmp(buf, "full")) {
> +            prealloc = true;
> +        } else {
> +            error_report("Invalid preallocation mode: '%s'", buf);
> +            ret = -EINVAL;
> +            goto out;
>          }
> -        options++;
>      }
> -
>      if (vdi_size > SD_MAX_VDI_SIZE) {
>          error_report("too big image size");
>          ret = -EINVAL;
> @@ -2042,24 +2036,27 @@ static int sd_load_vmstate(BlockDriverState *bs, uint8_t *data,
>      return do_load_save_vmstate(s, data, pos, size, 1);
>  }
>  
> -
> -static QEMUOptionParameter sd_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"
> -    },
> -    {
> -        .name = BLOCK_OPT_PREALLOC,
> -        .type = OPT_STRING,
> -        .help = "Preallocation mode (allowed values: off, full)"
> -    },
> -    { NULL }
> +static QemuOptsList sd_create_opts = {
> +    .name = "sheepdog-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(sd_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        {
> +            .name = BLOCK_OPT_BACKING_FILE,
> +            .type = QEMU_OPT_STRING,
> +            .help = "File name of a base image"
> +        },
> +        {
> +            .name = BLOCK_OPT_PREALLOC,
> +            .type = QEMU_OPT_STRING,
> +            .help = "Preallocation mode (allowed values: off, full)"
> +        },
> +        { /* end of list */ }
> +    }
>  };
>  
>  BlockDriver bdrv_sheepdog = {
> @@ -2084,7 +2081,7 @@ BlockDriver bdrv_sheepdog = {
>      .bdrv_save_vmstate  = sd_save_vmstate,
>      .bdrv_load_vmstate  = sd_load_vmstate,
>  
> -    .create_options = sd_create_options,
> +    .bdrv_create_options = &sd_create_opts,
>  };
>  
>  static void bdrv_sheepdog_init(void)
> diff --git a/block/vdi.c b/block/vdi.c
> index 021abaa..95f738e 100644
> --- a/block/vdi.c
> +++ b/block/vdi.c
> @@ -620,7 +620,7 @@ static int vdi_co_write(BlockDriverState *bs,
>      return ret;
>  }
>  
> -static int vdi_create(const char *filename, QEMUOptionParameter *options)
> +static int vdi_create(const char *filename, QemuOpts *opts)
>  {
>      int fd;
>      int result = 0;
> @@ -635,24 +635,19 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
>      logout("\n");
>  
>      /* Read out options. */
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            bytes = options->value.n;
> +    if (opts) {
> +        bytes = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
>  #if defined(CONFIG_VDI_BLOCK_SIZE)
> -        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
> -            if (options->value.n) {
> -                /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
> -                block_size = options->value.n;
> -            }
> +        /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
> +        block_size = qemu_opt_get_size(opts,
> +                                       BLOCK_OPT_CLUSTER_SIZE,
> +                                       DEFAULT_CLUSTER_SIZE);
>  #endif
>  #if defined(CONFIG_VDI_STATIC_IMAGE)
> -        } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
> -            if (options->value.n) {
> -                image_type = VDI_TYPE_STATIC;
> -            }
> -#endif
> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_STATIC, 0)) {
> +            image_type = VDI_TYPE_STATIC;
>          }
> -        options++;
> +#endif
>      }
>  
>      fd = qemu_open(filename,
> @@ -733,29 +728,33 @@ static void vdi_close(BlockDriverState *bs)
>      error_free(s->migration_blocker);
>  }
>  
> -static QEMUOptionParameter vdi_create_options[] = {
> -    {
> -        .name = BLOCK_OPT_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "Virtual disk size"
> -    },
> +static QemuOptsList vdi_create_opts = {
> +    .name = "vdi-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(vdi_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
>  #if defined(CONFIG_VDI_BLOCK_SIZE)
> -    {
> -        .name = BLOCK_OPT_CLUSTER_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "VDI cluster (block) size",
> -        .value = { .n = DEFAULT_CLUSTER_SIZE },
> -    },
> +        {
> +            .name = BLOCK_OPT_CLUSTER_SIZE,
> +            .type = QEMU_OPT_SIZE,
> +            .help = "VDI cluster (block) size",
> +            .def_value_str = stringify(DEFAULT_CLUSTER_SIZE)
> +        },
>  #endif
>  #if defined(CONFIG_VDI_STATIC_IMAGE)
> -    {
> -        .name = BLOCK_OPT_STATIC,
> -        .type = OPT_FLAG,
> -        .help = "VDI static (pre-allocated) image"
> -    },
> +        {
> +            .name = BLOCK_OPT_STATIC,
> +            .type = QEMU_OPT_BOOL,
> +            .help = "VDI static (pre-allocated) image"
> +        },
>  #endif
> -    /* TODO: An additional option to set UUID values might be useful. */
> -    { NULL }
> +        /* TODO: An additional option to set UUID values might be useful. */
> +        { /* end of list */ }
> +    }
>  };
>  
>  static BlockDriver bdrv_vdi = {
> @@ -776,7 +775,7 @@ static BlockDriver bdrv_vdi = {
>  
>      .bdrv_get_info = vdi_get_info,
>  
> -    .create_options = vdi_create_options,
> +    .bdrv_create_options = &vdi_create_opts,
>      .bdrv_check = vdi_check,
>  };
>  
> diff --git a/block/vmdk.c b/block/vmdk.c
> index 19298c2..4c29927 100644
> --- a/block/vmdk.c
> +++ b/block/vmdk.c
> @@ -1437,7 +1437,7 @@ static int relative_path(char *dest, int dest_size,
>      return 0;
>  }
>  
> -static int vmdk_create(const char *filename, QEMUOptionParameter *options)
> +static int vmdk_create(const char *filename, QemuOpts *opts)
>  {
>      int fd, idx = 0;
>      char desc[BUF_SIZE];
> @@ -1476,18 +1476,14 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
>      if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
>          return -EINVAL;
>      }
> -    /* Read out options */
> -    while (options && options->name) {
> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
> -            total_size = options->value.n;
> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
> -            backing_file = options->value.s;
> -        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
> -            flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
> -        } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
> -            fmt = options->value.s;
> +    /* Read out opts */
> +    if (opts) {
> +        total_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_COMPAT6, 0)) {
> +            flags |= BLOCK_FLAG_COMPAT6;
>          }
> -        options++;
> +        fmt = qemu_opt_get(opts, BLOCK_OPT_SUBFMT);
>      }
>      if (!fmt) {
>          /* Default format to monolithicSparse */
> @@ -1654,30 +1650,34 @@ static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs)
>      return ret;
>  }
>  
> -static QEMUOptionParameter vmdk_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"
> -    },
> -    {
> -        .name = BLOCK_OPT_COMPAT6,
> -        .type = OPT_FLAG,
> -        .help = "VMDK version 6 image"
> -    },
> -    {
> -        .name = BLOCK_OPT_SUBFMT,
> -        .type = OPT_STRING,
> -        .help =
> -            "VMDK flat extent format, can be one of "
> -            "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
> -    },
> -    { NULL }
> +static QemuOptsList vmdk_create_opts = {
> +    .name = "vmdk-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        {
> +            .name = BLOCK_OPT_BACKING_FILE,
> +            .type = QEMU_OPT_STRING,
> +            .help = "File name of a base image"
> +        },
> +        {
> +            .name = BLOCK_OPT_COMPAT6,
> +            .type = QEMU_OPT_BOOL,
> +            .help = "VMDK version 6 image"
> +        },
> +        {
> +            .name = BLOCK_OPT_SUBFMT,
> +            .type = QEMU_OPT_STRING,
> +            .help =
> +                "VMDK flat extent format, can be one of "
> +                "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
> +        },
> +        { /* end of list */ }
> +    }
>  };
>  
>  static BlockDriver bdrv_vmdk = {
> @@ -1694,7 +1694,7 @@ static BlockDriver bdrv_vmdk = {
>      .bdrv_co_is_allocated   = vmdk_co_is_allocated,
>      .bdrv_get_allocated_file_size  = vmdk_get_allocated_file_size,
>  
> -    .create_options = vmdk_create_options,
> +    .bdrv_create_options = &vmdk_create_opts,
>  };
>  
>  static void bdrv_vmdk_init(void)
> diff --git a/block/vpc.c b/block/vpc.c
> index 7948609..fcfdc79 100644
> --- a/block/vpc.c
> +++ b/block/vpc.c
> @@ -665,34 +665,33 @@ static int create_fixed_disk(int fd, uint8_t *buf, int64_t total_size)
>      return ret;
>  }
>  
> -static int vpc_create(const char *filename, QEMUOptionParameter *options)
> +static int vpc_create(const char *filename, QemuOpts *opts)
>  {
>      uint8_t buf[1024];
>      struct vhd_footer *footer = (struct vhd_footer *) buf;
> -    QEMUOptionParameter *disk_type_param;
> +    const char *disk_type_param = NULL;
>      int fd, i;
>      uint16_t cyls = 0;
>      uint8_t heads = 0;
>      uint8_t secs_per_cyl = 0;
>      int64_t total_sectors;
> -    int64_t total_size;
> -    int disk_type;
> +    int64_t total_size = 0;
> +    int disk_type = VHD_DYNAMIC;
>      int ret = -EIO;
>  
> -    /* Read out options */
> -    total_size = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n;
> -
> -    disk_type_param = get_option_parameter(options, BLOCK_OPT_SUBFMT);
> -    if (disk_type_param && disk_type_param->value.s) {
> -        if (!strcmp(disk_type_param->value.s, "dynamic")) {
> -            disk_type = VHD_DYNAMIC;
> -        } else if (!strcmp(disk_type_param->value.s, "fixed")) {
> -            disk_type = VHD_FIXED;
> -        } else {
> -            return -EINVAL;
> +    /* Read out opts */
> +    if (opts) {
> +        total_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
> +        disk_type_param = qemu_opt_get(opts, BLOCK_OPT_SUBFMT);
> +        if (disk_type_param) {
> +            if (!strcmp(disk_type_param, "dynamic")) {
> +                disk_type = VHD_DYNAMIC;
> +            } else if (!strcmp(disk_type_param, "fixed")) {
> +                disk_type = VHD_FIXED;
> +            } else {
> +                return -EINVAL;
> +            }
>          }
> -    } else {
> -        disk_type = VHD_DYNAMIC;
>      }
>  
>      /* Create the file */
> @@ -780,20 +779,24 @@ static void vpc_close(BlockDriverState *bs)
>      error_free(s->migration_blocker);
>  }
>  
> -static QEMUOptionParameter vpc_create_options[] = {
> -    {
> -        .name = BLOCK_OPT_SIZE,
> -        .type = OPT_SIZE,
> -        .help = "Virtual disk size"
> -    },
> -    {
> -        .name = BLOCK_OPT_SUBFMT,
> -        .type = OPT_STRING,
> -        .help =
> -            "Type of virtual hard disk format. Supported formats are "
> -            "{dynamic (default) | fixed} "
> -    },
> -    { NULL }
> +static QemuOptsList vpc_create_opts = {
> +    .name = "vpc-create-opts",
> +    .head = QTAILQ_HEAD_INITIALIZER(vpc_create_opts.head),
> +    .desc = {
> +        {
> +            .name = BLOCK_OPT_SIZE,
> +            .type = QEMU_OPT_NUMBER,

QEMU_OPT_SIZE again.

> +            .help = "Virtual disk size"
> +        },
> +        {
> +            .name = BLOCK_OPT_SUBFMT,
> +            .type = OPT_STRING,
> +            .help =
> +                "Type of virtual hard disk format. Supported formats are "
> +                "{dynamic (default) | fixed} "
> +        },
> +        { /* end of list */ }
> +    }
>  };
>  
>  static BlockDriver bdrv_vpc = {
> @@ -809,7 +812,7 @@ static BlockDriver bdrv_vpc = {
>      .bdrv_read              = vpc_co_read,
>      .bdrv_write             = vpc_co_write,
>  
> -    .create_options = vpc_create_options,
> +    .bdrv_create_options = &vpc_create_opts,
>  };
>  
>  static void bdrv_vpc_init(void)
> diff --git a/block/vvfat.c b/block/vvfat.c
> index 06e6654..2343cd4 100644
> --- a/block/vvfat.c
> +++ b/block/vvfat.c
> @@ -2802,7 +2802,7 @@ static BlockDriver vvfat_write_target = {
>  static int enable_write_target(BDRVVVFATState *s)
>  {
>      BlockDriver *bdrv_qcow;
> -    QEMUOptionParameter *options;
> +    QemuOpts *opts;
>      int ret;
>      int size = sector2cluster(s, s->sector_count);
>      s->used_clusters = calloc(size, 1);
> @@ -2818,12 +2818,13 @@ static int enable_write_target(BDRVVVFATState *s)
>      }
>  
>      bdrv_qcow = bdrv_find_format("qcow");
> -    options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
> -    set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
> -    set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
> +    opts = qemu_opts_create_nofail(bdrv_qcow->bdrv_create_options);
> +    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512);
> +    qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:");
>  
> -    if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
> +    if (bdrv_create(bdrv_qcow, s->qcow_filename, opts) < 0) {
>  	return -1;
> +    }
>  
>      s->qcow = bdrv_new("");
>      if (s->qcow == NULL) {
> diff --git a/include/block/block.h b/include/block/block.h
> index ffd1936..c99e8bf 100644
> --- a/include/block/block.h
> +++ b/include/block/block.h
> @@ -124,8 +124,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);
>  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 f83ffb8..71f7670 100644
> --- a/include/block/block_int.h
> +++ b/include/block/block_int.h
> @@ -88,7 +88,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);
>      int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
>      int (*bdrv_make_empty)(BlockDriverState *bs);
>      /* aio */
> @@ -177,9 +177,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_options;

Since you're renaming this anyway, consider renaming to
bdrv_create_opts, to match the names used elsewhere.

>  
>      /*
>       * Returns 0 for completed check, -errno for internal errors.
> diff --git a/qemu-img.c b/qemu-img.c
> index 85d3740..b4b3ce8 100644
> --- a/qemu-img.c
> +++ b/qemu-img.c
> @@ -200,7 +200,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_options = NULL;
>  
>      /* Find driver and parse its options */
>      drv = bdrv_find_format(fmt);
> @@ -215,12 +215,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_options = append_opts_list(drv->bdrv_create_options,
> +                                      proto_drv->bdrv_create_options);
> +    print_opts_list(create_options);
> +    free_opts_list(create_options);
>      return 0;
>  }
>  
> @@ -271,19 +269,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;
> @@ -675,8 +673,9 @@ static int img_convert(int argc, char **argv)
   static int img_convert(int argc, char **argv)
   {
       int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
       int progress = 0, flags;
       const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
       BlockDriver *drv, *proto_drv;
       BlockDriverState **bs = NULL, *out_bs = NULL;
       int64_t total_sectors, nb_sectors, sector_num, bs_offset;

Some or all of these should probably be uint64_t.  Not your patch's
fault, feel free to ignore.

       uint64_t bs_sectors;
>      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_options = NULL;
> +    const char *out_baseimg_param;
>      char *options = NULL;
>      const char *snapshot_name = NULL;
>      float local_progress = 0;
> @@ -811,40 +810,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_options = append_opts_list(drv->bdrv_create_options,
> +                                      proto_drv->bdrv_create_options);
>  
>      if (options) {
> -        param = parse_option_parameters(options, create_options, param);
> -        if (param == NULL) {
> +        if (qemu_opts_do_parse(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_options);
>      }
> -
> -    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;
>      }
>  
>      /* 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");
> @@ -852,15 +847,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");
> @@ -1078,8 +1073,10 @@ static int img_convert(int argc, char **argv)
>      }
>  out:
>      qemu_progress_end();
> -    free_option_parameters(create_options);
> -    free_option_parameters(param);
> +    free_opts_list(create_options);
> +    if (param) {
> +        qemu_opts_del(param);
> +    }
>      qemu_vfree(buf);
>      if (out_bs) {
>          bdrv_delete(out_bs);
Robert Wang Jan. 28, 2013, 7:57 a.m. UTC | #2
于 2013-1-25 4:08, Markus Armbruster 写道:
> Dong Xu Wang <wdongxu@vnet.linux.ibm.com> writes:
> 
>> This patch will use QemuOpts related functions in block layer, add
>> a member bdrv_create_options 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 <wdongxu@linux.vnet.ibm.com>
>> ---
>> 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/qcow.c              |  60 ++++++++--------
>>   block/qcow2.c             | 171 +++++++++++++++++++++++-----------------------
>>   block/qed.c               |  86 +++++++++++------------
>>   block/qed.h               |   2 +-
>>   block/raw-posix.c         |  59 ++++++++--------
>>   block/raw-win32.c         |  30 ++++----
>>   block/raw.c               |  30 ++++----
>>   block/rbd.c               |  62 ++++++++---------
>>   block/sheepdog.c          |  75 ++++++++++----------
>>   block/vdi.c               |  69 +++++++++----------
>>   block/vmdk.c              |  74 ++++++++++----------
>>   block/vpc.c               |  67 +++++++++---------
>>   block/vvfat.c             |  11 +--
>>   include/block/block.h     |   4 +-
>>   include/block/block_int.h |   6 +-
>>   qemu-img.c                |  61 ++++++++---------
>>   19 files changed, 519 insertions(+), 522 deletions(-)
>>
>> diff --git a/block.c b/block.c
>> index 6fa7c90..56e4613 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)
>>   {
>>       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,
>>           .ret = NOT_DONE,
>>       };
>>   
>> @@ -405,7 +405,7 @@ out:
>>       return ret;
>>   }
>>   
>> -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);
>>   }
>>   
>>   /*
>> @@ -794,7 +794,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
>> @@ -827,17 +827,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_options);
>>   
>> -        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;
>>           }
>> @@ -4493,8 +4492,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>>                        const char *base_filename, const char *base_fmt,
>>                        char *options, uint64_t img_size, int flags, Error **errp)
>>   {
>> -    QEMUOptionParameter *param = NULL, *create_options = NULL;
>> -    QEMUOptionParameter *backing_fmt, *backing_file, *size;
>> +    QemuOpts *opts = NULL;
>> +    QemuOptsList *create_options = NULL;
>> +    const char *backing_fmt, *backing_file;
>> +    int64_t size;
>>       BlockDriverState *bs = NULL;
>>       BlockDriver *drv, *proto_drv;
>>       BlockDriver *backing_drv = NULL;
>> @@ -4512,28 +4513,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_options = append_opts_list(drv->bdrv_create_options,
>> +                                      proto_drv->bdrv_create_options);
> 
> 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?  Outside the
> scope of this patch.
Sorry, I do not understand this line, clash? Can you explain some more?
Do you mean bdrv_create_options should be renamed such as bdrv_create_opts?
> 
>>       /* Create parameter list with default values */
>> -    param = parse_option_parameters("", create_options, param);
>> +    opts = qemu_opts_create_nofail(create_options);
>>   
>> -    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
>> +    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size);
>>   
>>       /* Parse -o options */
>>       if (options) {
>> -        param = parse_option_parameters(options, create_options, param);
>> -        if (param == NULL) {
>> +        if (qemu_opts_do_parse(opts, options, NULL) != 0) {
>>               error_setg(errp, "Invalid options for file format '%s'.", fmt);
>>               goto out;
>>           }
>>       }
> 
> Before: size from -o replaces img_size in param.
> 
> After: size from -o gets appended to opts, is therefore shadowed by
> img_size.  I think.
> 
> User-visible change, if my reading is correct.  Should be avoided.
> 
Okay. will also "replace", not "append".
>>   
>>       if (base_filename) {
>> -        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
>> +        if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE,
>>                                    base_filename)) {
>>               error_setg(errp, "Backing file not supported for file format '%s'",
>>                          fmt);
> 
> Before: base_filename replaces the backing_file from -o.
> 
> After: base_filename gets appended to opts, shadowed by backing_file
> from -o.
> 
>> @@ -4542,39 +4538,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_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) {
>>               error_setg(errp, "Backing file format not supported for file "
>>                                "format '%s'", fmt);
>>               goto out;
>>           }
>>       }
> 
> Likewise.
> 
>>   
>> -    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_number(opts, BLOCK_OPT_SIZE, -1);
>> +    if (size == -1) {
>> +        if (backing_file) {
> 
> Code has the same before your patch, so it's not your fault, but here
> goes anyway:
> 
> QemuOpts support only *unsigned* numbers.  Argument -1 is for an
> uint64_t parameter, and gets converted to UINT64_MAX.  If the option
> isn't set, it's returned.  The assignment to int64_t size converts it
> back to -1.
> 
> Using the an honest UINT64_MAX instead of -1 would be clearer.  Should
> make size uint64_t then.
> 
> However, all other places do
> 
>      qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0)
> 
> Why is this one different?
> 
Because previous use -1, so, I passed default value -1.
>>               uint64_t size;
>> -            char buf[32];
>>               int back_flags;
>>   
>>               /* backing files always opened read-only */
>> @@ -4583,17 +4577,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);
>>           } else {
>>               error_setg(errp, "Image creation needs a size parameter");
>>               goto out;
>> @@ -4601,10 +4594,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>>       }
>>   
>>       printf("Formatting '%s', fmt=%s ", filename, fmt);
>> -    print_option_parameters(param);
>> +    qemu_opts_print(opts, NULL);
>>       puts("");
>>   
>> -    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 "
>> @@ -4619,8 +4612,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>>       }
>>   
>>   out:
>> -    free_option_parameters(create_options);
>> -    free_option_parameters(param);
>> +    free_opts_list(create_options);
>> +    if (opts) {
>> +        qemu_opts_del(opts);
>> +    }
>>   
>>       if (bs) {
>>           bdrv_delete(bs);
>> diff --git a/block/cow.c b/block/cow.c
>> index a33ce95..5442c9c 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,13 @@ 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 */
>> +    if (opts) {
> 
> I suspect you need the if (opts) here and in many other places only
> because you special-cased "both lists empty" in append_opts_list().  I
> suspect things become easier if you drop that.

No, in this version, if(opt) is needed in "protocol", not needed in
"format", I want to have the same code style, so I also judged if opts
is NULL in "format" _create functions. Do you think is it acceptable?
> 
>> +        image_sectors = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
>> +        image_filename = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
>>       }
>>   
>> -    ret = bdrv_create_file(filename, options);
>> +    ret = bdrv_create_file(filename, opts);
>>       if (ret < 0) {
>>           return ret;
>>       }
>> @@ -318,18 +314,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_NUMBER,
> 
> QEMU_OPT_SIZE, or else we lose support for suffixes, don't we?
> 
In qemu-img.c, strtosz_suffix convert suffixes to regular digitals.
Okay. I will change to 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 +345,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_options    = &cow_create_opts,
>>   };
>>   
>>   static void bdrv_cow_init(void)
>> diff --git a/block/gluster.c b/block/gluster.c
>> index 0f2c32a..a41c684 100644
>> --- a/block/gluster.c
>> +++ b/block/gluster.c
>> @@ -335,8 +335,7 @@ out:
>>       return ret;
>>   }
>>   
>> -static int qemu_gluster_create(const char *filename,
>> -        QEMUOptionParameter *options)
>> +static int qemu_gluster_create(const char *filename, QemuOpts* opts)
> 
> Space before the *, not after: QemuOpts *opts
> 
Okay.
> Running out of steam for today, rest of patch only skimmed.
> 
>>   {
>>       struct glfs *glfs;
>>       struct glfs_fd *fd;
>> @@ -350,11 +349,9 @@ static int qemu_gluster_create(const char *filename,
>>           goto out;
>>       }
>>   
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            total_size = options->value.n / BDRV_SECTOR_SIZE;
>> -        }
>> -        options++;
>> +    if (opts) {
>> +        total_size =
>> +            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
>>       }
>>   
>>       fd = glfs_creat(glfs, gconf->image,
>> @@ -544,13 +541,17 @@ static void qemu_gluster_close(BlockDriverState *bs)
>>       glfs_fini(s->glfs);
>>   }
>>   
>> -static QEMUOptionParameter qemu_gluster_create_options[] = {
>> -    {
>> -        .name = BLOCK_OPT_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "Virtual disk size"
>> -    },
>> -    { NULL }
>> +static QemuOptsList qemu_gluster_create_opts = {
>> +    .name = "qemu-gluster-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   static BlockDriver bdrv_gluster = {
>> @@ -565,7 +566,7 @@ static BlockDriver bdrv_gluster = {
>>       .bdrv_aio_readv               = qemu_gluster_aio_readv,
>>       .bdrv_aio_writev              = qemu_gluster_aio_writev,
>>       .bdrv_aio_flush               = qemu_gluster_aio_flush,
>> -    .create_options               = qemu_gluster_create_options,
>> +    .bdrv_create_options          = &qemu_gluster_create_opts,
>>   };
>>   
>>   static BlockDriver bdrv_gluster_tcp = {
>> @@ -580,7 +581,7 @@ static BlockDriver bdrv_gluster_tcp = {
>>       .bdrv_aio_readv               = qemu_gluster_aio_readv,
>>       .bdrv_aio_writev              = qemu_gluster_aio_writev,
>>       .bdrv_aio_flush               = qemu_gluster_aio_flush,
>> -    .create_options               = qemu_gluster_create_options,
>> +    .bdrv_create_options          = &qemu_gluster_create_opts,
>>   };
>>   
>>   static BlockDriver bdrv_gluster_unix = {
>> @@ -595,7 +596,7 @@ static BlockDriver bdrv_gluster_unix = {
>>       .bdrv_aio_readv               = qemu_gluster_aio_readv,
>>       .bdrv_aio_writev              = qemu_gluster_aio_writev,
>>       .bdrv_aio_flush               = qemu_gluster_aio_flush,
>> -    .create_options               = qemu_gluster_create_options,
>> +    .bdrv_create_options          = &qemu_gluster_create_opts,
>>   };
>>   
>>   static BlockDriver bdrv_gluster_rdma = {
>> @@ -610,7 +611,7 @@ static BlockDriver bdrv_gluster_rdma = {
>>       .bdrv_aio_readv               = qemu_gluster_aio_readv,
>>       .bdrv_aio_writev              = qemu_gluster_aio_writev,
>>       .bdrv_aio_flush               = qemu_gluster_aio_flush,
>> -    .create_options               = qemu_gluster_create_options,
>> +    .bdrv_create_options          = &qemu_gluster_create_opts,
>>   };
>>   
>>   static void bdrv_gluster_init(void)
>> diff --git a/block/qcow.c b/block/qcow.c
>> index 4276610..4691a3e 100644
>> --- a/block/qcow.c
>> +++ b/block/qcow.c
>> @@ -651,7 +651,7 @@ static void qcow_close(BlockDriverState *bs)
>>       error_free(s->migration_blocker);
>>   }
>>   
>> -static int qcow_create(const char *filename, QEMUOptionParameter *options)
>> +static int qcow_create(const char *filename, QemuOpts *opts)
>>   {
>>       int header_size, backing_filename_len, l1_size, shift, i;
>>       QCowHeader header;
>> @@ -662,19 +662,16 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options)
>>       int ret;
>>       BlockDriverState *qcow_bs;
>>   
>> -    /* Read out options */
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            total_size = options->value.n / 512;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
>> -            backing_file = options->value.s;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
>> -            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
>> +    /* Read out opts */
>> +    if (opts) {
>> +        total_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
>> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
>> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, 0)) {
>> +            flags |= BLOCK_FLAG_ENCRYPT;
>>           }
>> -        options++;
>>       }
>>   
>> -    ret = bdrv_create_file(filename, options);
>> +    ret = bdrv_create_file(filename, opts);
>>       if (ret < 0) {
>>           return ret;
>>       }
>> @@ -851,24 +848,27 @@ static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
>>       return 0;
>>   }
>>   
>> -
>> -static QEMUOptionParameter qcow_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"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_ENCRYPT,
>> -        .type = OPT_FLAG,
>> -        .help = "Encrypt the image"
>> -    },
>> -    { NULL }
>> +static QemuOptsList qcow_create_opts = {
>> +    .name = "qcow-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(qcow_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_BACKING_FILE,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "File name of a base image"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_ENCRYPT,
>> +            .type = QEMU_OPT_BOOL,
>> +            .help = "Encrypt the image"
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   static BlockDriver bdrv_qcow = {
>> @@ -889,7 +889,7 @@ static BlockDriver bdrv_qcow = {
>>       .bdrv_write_compressed  = qcow_write_compressed,
>>       .bdrv_get_info          = qcow_get_info,
>>   
>> -    .create_options = qcow_create_options,
>> +    .bdrv_create_options    = &qcow_create_opts,
>>   };
>>   
>>   static void bdrv_qcow_init(void)
>> diff --git a/block/qcow2.c b/block/qcow2.c
>> index f6abff6..e3ee4af 100644
>> --- a/block/qcow2.c
>> +++ b/block/qcow2.c
>> @@ -1177,7 +1177,7 @@ static int preallocate(BlockDriverState *bs)
>>   static int qcow2_create2(const char *filename, int64_t total_size,
>>                            const char *backing_file, const char *backing_format,
>>                            int flags, size_t cluster_size, int prealloc,
>> -                         QEMUOptionParameter *options, int version)
>> +                         QemuOpts *opts, int version)
>>   {
>>       /* Calculate cluster_bits */
>>       int cluster_bits;
>> @@ -1208,7 +1208,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
>>       uint8_t* refcount_table;
>>       int ret;
>>   
>> -    ret = bdrv_create_file(filename, options);
>> +    ret = bdrv_create_file(filename, opts);
>>       if (ret < 0) {
>>           return ret;
>>       }
>> @@ -1311,7 +1311,7 @@ out:
>>       return ret;
>>   }
>>   
>> -static int qcow2_create(const char *filename, QEMUOptionParameter *options)
>> +static int qcow2_create(const char *filename, QemuOpts *opts)
>>   {
>>       const char *backing_file = NULL;
>>       const char *backing_fmt = NULL;
>> @@ -1320,45 +1320,43 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
>>       size_t cluster_size = DEFAULT_CLUSTER_SIZE;
>>       int prealloc = 0;
>>       int version = 2;
>> +    const char *buf;
>>   
>>       /* Read out options */
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            sectors = options->value.n / 512;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
>> -            backing_file = options->value.s;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
>> -            backing_fmt = options->value.s;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
>> -            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
>> -            if (options->value.n) {
>> -                cluster_size = options->value.n;
>> -            }
>> -        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
>> -            if (!options->value.s || !strcmp(options->value.s, "off")) {
>> -                prealloc = 0;
>> -            } else if (!strcmp(options->value.s, "metadata")) {
>> -                prealloc = 1;
>> -            } else {
>> -                fprintf(stderr, "Invalid preallocation mode: '%s'\n",
>> -                    options->value.s);
>> -                return -EINVAL;
>> -            }
>> -        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) {
>> -            if (!options->value.s || !strcmp(options->value.s, "0.10")) {
>> -                version = 2;
>> -            } else if (!strcmp(options->value.s, "1.1")) {
>> -                version = 3;
>> -            } else {
>> -                fprintf(stderr, "Invalid compatibility level: '%s'\n",
>> -                    options->value.s);
>> -                return -EINVAL;
>> -            }
>> -        } else if (!strcmp(options->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
>> -            flags |= options->value.n ? BLOCK_FLAG_LAZY_REFCOUNTS : 0;
>> +    if (opts) {
>> +        sectors = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
>> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
>> +        backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
>> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, 0)) {
>> +            flags |= BLOCK_FLAG_ENCRYPT;
>> +        }
>> +        cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE,
>> +                                         DEFAULT_CLUSTER_SIZE);
>> +        buf = qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
>> +        if (!buf || !strcmp(buf, "off")) {
>> +            prealloc = 0;
>> +        } else if (!strcmp(buf, "metadata")) {
>> +            prealloc = 1;
>> +        } else {
>> +            fprintf(stderr, "Invalid preallocation mode: '%s'\n",
>> +                buf);
>> +            return -EINVAL;
>> +        }
>> +
>> +        buf = qemu_opt_get(opts, BLOCK_OPT_COMPAT_LEVEL);
>> +        if (!buf || !strcmp(buf, "0.10")) {
>> +            version = 2;
>> +        } else if (!strcmp(buf, "1.1")) {
>> +            version = 3;
>> +        } else {
>> +            fprintf(stderr, "Invalid compatibility level: '%s'\n",
>> +                buf);
>> +            return -EINVAL;
>> +        }
>> +
>> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS, 0)) {
>> +            flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
>>           }
>> -        options++;
>>       }
>>   
>>       if (backing_file && prealloc) {
>> @@ -1374,7 +1372,7 @@ static int qcow2_create(const char *filename, QEMUOptionParameter *options)
>>       }
>>   
>>       return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
>> -                         cluster_size, prealloc, options, version);
>> +                         cluster_size, prealloc, opts, version);
>>   }
>>   
>>   static int qcow2_make_empty(BlockDriverState *bs)
>> @@ -1635,49 +1633,53 @@ static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf,
>>       return ret;
>>   }
>>   
>> -static QEMUOptionParameter qcow2_create_options[] = {
>> -    {
>> -        .name = BLOCK_OPT_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "Virtual disk size"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_COMPAT_LEVEL,
>> -        .type = OPT_STRING,
>> -        .help = "Compatibility level (0.10 or 1.1)"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_BACKING_FILE,
>> -        .type = OPT_STRING,
>> -        .help = "File name of a base image"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_BACKING_FMT,
>> -        .type = OPT_STRING,
>> -        .help = "Image format of the base image"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_ENCRYPT,
>> -        .type = OPT_FLAG,
>> -        .help = "Encrypt the image"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_CLUSTER_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "qcow2 cluster size",
>> -        .value = { .n = DEFAULT_CLUSTER_SIZE },
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_PREALLOC,
>> -        .type = OPT_STRING,
>> -        .help = "Preallocation mode (allowed values: off, metadata)"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_LAZY_REFCOUNTS,
>> -        .type = OPT_FLAG,
>> -        .help = "Postpone refcount updates",
>> -    },
>> -    { NULL }
>> +static QemuOptsList qcow2_create_opts = {
>> +    .name = "qcow2-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_COMPAT_LEVEL,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "Compatibility level (0.10 or 1.1)"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_BACKING_FILE,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "File name of a base image"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_BACKING_FMT,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "Image format of the base image"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_ENCRYPT,
>> +            .type = QEMU_OPT_BOOL,
>> +            .help = "Encrypt the image"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_CLUSTER_SIZE,
>> +            .type = QEMU_OPT_SIZE,
>> +            .help = "qcow2 cluster size",
>> +            .def_value_str = stringify(DEFAULT_CLUSTER_SIZE)
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_PREALLOC,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "Preallocation mode (allowed values: off, metadata)"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_LAZY_REFCOUNTS,
>> +            .type = QEMU_OPT_BOOL,
>> +            .help = "Postpone refcount updates",
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   static BlockDriver bdrv_qcow2 = {
>> @@ -1715,8 +1717,9 @@ static BlockDriver bdrv_qcow2 = {
>>   
>>       .bdrv_invalidate_cache      = qcow2_invalidate_cache,
>>   
>> -    .create_options = qcow2_create_options,
>>       .bdrv_check = qcow2_check,
>> +
>> +    .bdrv_create_options    = &qcow2_create_opts,
>>   };
>>   
>>   static void bdrv_qcow2_init(void)
>> diff --git a/block/qed.c b/block/qed.c
>> index cf85d8f..766ba6f 100644
>> --- a/block/qed.c
>> +++ b/block/qed.c
>> @@ -603,7 +603,7 @@ out:
>>       return ret;
>>   }
>>   
>> -static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
>> +static int bdrv_qed_create(const char *filename, QemuOpts *opts)
>>   {
>>       uint64_t image_size = 0;
>>       uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE;
>> @@ -611,23 +611,15 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
>>       const char *backing_file = NULL;
>>       const char *backing_fmt = NULL;
>>   
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            image_size = options->value.n;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
>> -            backing_file = options->value.s;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
>> -            backing_fmt = options->value.s;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
>> -            if (options->value.n) {
>> -                cluster_size = options->value.n;
>> -            }
>> -        } else if (!strcmp(options->name, BLOCK_OPT_TABLE_SIZE)) {
>> -            if (options->value.n) {
>> -                table_size = options->value.n;
>> -            }
>> -        }
>> -        options++;
>> +    if (opts) {
>> +        image_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
>> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
>> +        backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
>> +        cluster_size = qemu_opt_get_size(opts,
>> +                                         BLOCK_OPT_CLUSTER_SIZE,
>> +                                         QED_DEFAULT_CLUSTER_SIZE);
>> +        table_size = qemu_opt_get_size(opts, BLOCK_OPT_TABLE_SIZE,
>> +                                       QED_DEFAULT_TABLE_SIZE);
>>       }
>>   
>>       if (!qed_is_cluster_size_valid(cluster_size)) {
>> @@ -1537,36 +1529,44 @@ static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,
>>       return qed_check(s, result, !!fix);
>>   }
>>   
>> -static QEMUOptionParameter qed_create_options[] = {
>> -    {
>> -        .name = BLOCK_OPT_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "Virtual disk size (in bytes)"
>> -    }, {
>> -        .name = BLOCK_OPT_BACKING_FILE,
>> -        .type = OPT_STRING,
>> -        .help = "File name of a base image"
>> -    }, {
>> -        .name = BLOCK_OPT_BACKING_FMT,
>> -        .type = OPT_STRING,
>> -        .help = "Image format of the base image"
>> -    }, {
>> -        .name = BLOCK_OPT_CLUSTER_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "Cluster size (in bytes)",
>> -        .value = { .n = QED_DEFAULT_CLUSTER_SIZE },
>> -    }, {
>> -        .name = BLOCK_OPT_TABLE_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "L1/L2 table size (in clusters)"
>> -    },
>> -    { /* end of list */ }
>> +static QemuOptsList qed_create_opts = {
>> +    .name = "qed-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(qed_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_BACKING_FILE,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "File name of a base image"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_BACKING_FMT,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "Image format of the base image"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_CLUSTER_SIZE,
>> +            .type = QEMU_OPT_SIZE,
>> +            .help = "Cluster size (in bytes)",
>> +            .def_value_str = stringify(QED_DEFAULT_CLUSTER_SIZE),
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_TABLE_SIZE,
>> +            .type = QEMU_OPT_SIZE,
>> +            .help = "L1/L2 table size (in clusters)"
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   static BlockDriver bdrv_qed = {
>>       .format_name              = "qed",
>>       .instance_size            = sizeof(BDRVQEDState),
>> -    .create_options           = qed_create_options,
>> +    .bdrv_create_options      = &qed_create_opts,
>>   
>>       .bdrv_probe               = bdrv_qed_probe,
>>       .bdrv_rebind              = bdrv_qed_rebind,
>> diff --git a/block/qed.h b/block/qed.h
>> index 2b4dded..99a7726 100644
>> --- a/block/qed.h
>> +++ b/block/qed.h
>> @@ -43,6 +43,7 @@
>>    *
>>    * All fields are little-endian on disk.
>>    */
>> +#define  QED_DEFAULT_CLUSTER_SIZE  65536
>>   
>>   enum {
>>       QED_MAGIC = 'Q' | 'E' << 8 | 'D' << 16 | '\0' << 24,
>> @@ -69,7 +70,6 @@ enum {
>>        */
>>       QED_MIN_CLUSTER_SIZE = 4 * 1024, /* in bytes */
>>       QED_MAX_CLUSTER_SIZE = 64 * 1024 * 1024,
>> -    QED_DEFAULT_CLUSTER_SIZE = 64 * 1024,
>>   
>>       /* Allocated clusters are tracked using a 2-level pagetable.  Table size is
>>        * a multiple of clusters so large maximum image sizes can be supported
>> diff --git a/block/raw-posix.c b/block/raw-posix.c
>> index 657af95..890c8a7 100644
>> --- a/block/raw-posix.c
>> +++ b/block/raw-posix.c
>> @@ -123,6 +123,19 @@
>>   
>>   #define MAX_BLOCKSIZE	4096
>>   
>> +static QemuOptsList file_proto_create_opts = {
>> +    .name = "file-proto-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(file_proto_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_SIZE,
>> +            .help = "Virtual disk size"
>> +        },
>> +        { /* end of list */ }
>> +    }
>> +};
>> +
>>   typedef struct BDRVRawState {
>>       int fd;
>>       int type;
>> @@ -997,18 +1010,15 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
>>       return (int64_t)st.st_blocks * 512;
>>   }
>>   
>> -static int raw_create(const char *filename, QEMUOptionParameter *options)
>> +static int raw_create(const char *filename, QemuOpts *opts)
>>   {
>>       int fd;
>>       int result = 0;
>>       int64_t total_size = 0;
>>   
>> -    /* Read out options */
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            total_size = options->value.n / BDRV_SECTOR_SIZE;
>> -        }
>> -        options++;
>> +    if (opts) {
>> +        total_size =
>> +            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
>>       }
>>   
>>       fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
>> @@ -1136,15 +1146,6 @@ static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs,
>>                          cb, opaque, QEMU_AIO_DISCARD);
>>   }
>>   
>> -static QEMUOptionParameter raw_create_options[] = {
>> -    {
>> -        .name = BLOCK_OPT_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "Virtual disk size"
>> -    },
>> -    { NULL }
>> -};
>> -
>>   static BlockDriver bdrv_file = {
>>       .format_name = "file",
>>       .protocol_name = "file",
>> @@ -1167,8 +1168,7 @@ static BlockDriver bdrv_file = {
>>       .bdrv_getlength = raw_getlength,
>>       .bdrv_get_allocated_file_size
>>                           = raw_get_allocated_file_size,
>> -
>> -    .create_options = raw_create_options,
>> +    .bdrv_create_options = &file_proto_create_opts,
>>   };
>>   
>>   /***********************************************/
>> @@ -1403,19 +1403,16 @@ static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs,
>>                          cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
>>   }
>>   
>> -static int hdev_create(const char *filename, QEMUOptionParameter *options)
>> +static int hdev_create(const char *filename, QemuOpts *opts)
>>   {
>>       int fd;
>>       int ret = 0;
>>       struct stat stat_buf;
>>       int64_t total_size = 0;
>>   
>> -    /* Read out options */
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, "size")) {
>> -            total_size = options->value.n / BDRV_SECTOR_SIZE;
>> -        }
>> -        options++;
>> +    if (opts) {
>> +        total_size =
>> +            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
>>       }
>>   
>>       fd = qemu_open(filename, O_WRONLY | O_BINARY);
>> @@ -1440,7 +1437,7 @@ static int hdev_has_zero_init(BlockDriverState *bs)
>>   
>>   static BlockDriver bdrv_host_device = {
>>       .format_name        = "host_device",
>> -    .protocol_name        = "host_device",
>> +    .protocol_name      = "host_device",
>>       .instance_size      = sizeof(BDRVRawState),
>>       .bdrv_probe_device  = hdev_probe_device,
>>       .bdrv_file_open     = hdev_open,
>> @@ -1449,7 +1446,6 @@ static BlockDriver bdrv_host_device = {
>>       .bdrv_reopen_commit  = raw_reopen_commit,
>>       .bdrv_reopen_abort   = raw_reopen_abort,
>>       .bdrv_create        = hdev_create,
>> -    .create_options     = raw_create_options,
>>       .bdrv_has_zero_init = hdev_has_zero_init,
>>   
>>       .bdrv_aio_readv	= raw_aio_readv,
>> @@ -1458,9 +1454,10 @@ static BlockDriver bdrv_host_device = {
>>       .bdrv_aio_discard   = hdev_aio_discard,
>>   
>>       .bdrv_truncate      = raw_truncate,
>> -    .bdrv_getlength	= raw_getlength,
>> +    .bdrv_getlength     = raw_getlength,
>>       .bdrv_get_allocated_file_size
>>                           = raw_get_allocated_file_size,
>> +    .bdrv_create_options = &file_proto_create_opts,
>>   
>>       /* generic scsi device */
>>   #ifdef __linux__
>> @@ -1574,7 +1571,6 @@ static BlockDriver bdrv_host_floppy = {
>>       .bdrv_reopen_commit  = raw_reopen_commit,
>>       .bdrv_reopen_abort   = raw_reopen_abort,
>>       .bdrv_create        = hdev_create,
>> -    .create_options     = raw_create_options,
>>       .bdrv_has_zero_init = hdev_has_zero_init,
>>   
>>       .bdrv_aio_readv     = raw_aio_readv,
>> @@ -1590,6 +1586,7 @@ static BlockDriver bdrv_host_floppy = {
>>       .bdrv_is_inserted   = floppy_is_inserted,
>>       .bdrv_media_changed = floppy_media_changed,
>>       .bdrv_eject         = floppy_eject,
>> +    .bdrv_create_options = &file_proto_create_opts,
>>   };
>>   
>>   static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
>> @@ -1676,7 +1673,6 @@ static BlockDriver bdrv_host_cdrom = {
>>       .bdrv_reopen_commit  = raw_reopen_commit,
>>       .bdrv_reopen_abort   = raw_reopen_abort,
>>       .bdrv_create        = hdev_create,
>> -    .create_options     = raw_create_options,
>>       .bdrv_has_zero_init = hdev_has_zero_init,
>>   
>>       .bdrv_aio_readv     = raw_aio_readv,
>> @@ -1696,6 +1692,8 @@ static BlockDriver bdrv_host_cdrom = {
>>       /* generic scsi device */
>>       .bdrv_ioctl         = hdev_ioctl,
>>       .bdrv_aio_ioctl     = hdev_aio_ioctl,
>> +
>> +    .bdrv_create_options = &file_proto_create_opts,
>>   };
>>   #endif /* __linux__ */
>>   
>> @@ -1798,7 +1796,6 @@ static BlockDriver bdrv_host_cdrom = {
>>       .bdrv_reopen_commit  = raw_reopen_commit,
>>       .bdrv_reopen_abort   = raw_reopen_abort,
>>       .bdrv_create        = hdev_create,
>> -    .create_options     = raw_create_options,
>>       .bdrv_has_zero_init = hdev_has_zero_init,
>>   
>>       .bdrv_aio_readv     = raw_aio_readv,
>> diff --git a/block/raw-win32.c b/block/raw-win32.c
>> index b89ac19..34826e0 100644
>> --- a/block/raw-win32.c
>> +++ b/block/raw-win32.c
>> @@ -382,17 +382,15 @@ static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
>>       return st.st_size;
>>   }
>>   
>> -static int raw_create(const char *filename, QEMUOptionParameter *options)
>> +static int raw_create(const char *filename, QemuOpts *opts)
>>   {
>>       int fd;
>>       int64_t total_size = 0;
>>   
>>       /* Read out options */
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            total_size = options->value.n / 512;
>> -        }
>> -        options++;
>> +    if (opts) {
>> +        total_size =
>> +            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
>>       }
>>   
>>       fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
>> @@ -405,13 +403,17 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
>>       return 0;
>>   }
>>   
>> -static QEMUOptionParameter raw_create_options[] = {
>> -    {
>> -        .name = BLOCK_OPT_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "Virtual disk size"
>> -    },
>> -    { NULL }
>> +static QemuOptsList raw_create_opts = {
>> +    .name = "raw-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   static BlockDriver bdrv_file = {
>> @@ -431,7 +433,7 @@ static BlockDriver bdrv_file = {
>>       .bdrv_get_allocated_file_size
>>                           = raw_get_allocated_file_size,
>>   
>> -    .create_options = raw_create_options,
>> +    .bdrv_create_options = &raw_create_opts,
>>   };
>>   
>>   /***********************************************/
>> diff --git a/block/raw.c b/block/raw.c
>> index 75812db..033ffa6 100644
>> --- a/block/raw.c
>> +++ b/block/raw.c
>> @@ -95,18 +95,22 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
>>      return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
>>   }
>>   
>> -static int raw_create(const char *filename, QEMUOptionParameter *options)
>> -{
>> -    return bdrv_create_file(filename, options);
>> -}
>> -
>> -static QEMUOptionParameter raw_create_options[] = {
>> -    {
>> -        .name = BLOCK_OPT_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "Virtual disk size"
>> -    },
>> -    { NULL }
>> +static int raw_create(const char *filename, QemuOpts *opts)
>> +{
>> +    return bdrv_create_file(filename, opts);
>> +}
>> +
>> +static QemuOptsList raw_create_opts = {
>> +    .name = "raw-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   static int raw_has_zero_init(BlockDriverState *bs)
>> @@ -143,8 +147,8 @@ static BlockDriver bdrv_raw = {
>>       .bdrv_aio_ioctl     = raw_aio_ioctl,
>>   
>>       .bdrv_create        = raw_create,
>> -    .create_options     = raw_create_options,
>>       .bdrv_has_zero_init = raw_has_zero_init,
>> +    .bdrv_create_options = &raw_create_opts,
>>   };
>>   
>>   static void bdrv_raw_init(void)
>> diff --git a/block/rbd.c b/block/rbd.c
>> index 8cd10a7..a9f8772 100644
>> --- a/block/rbd.c
>> +++ b/block/rbd.c
>> @@ -287,7 +287,7 @@ static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
>>       return ret;
>>   }
>>   
>> -static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
>> +static int qemu_rbd_create(const char *filename, QemuOpts *opts)
>>   {
>>       int64_t bytes = 0;
>>       int64_t objsize;
>> @@ -310,24 +310,20 @@ static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
>>       }
>>   
>>       /* Read out options */
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            bytes = options->value.n;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
>> -            if (options->value.n) {
>> -                objsize = options->value.n;
>> -                if ((objsize - 1) & objsize) {    /* not a power of 2? */
>> -                    error_report("obj size needs to be power of 2");
>> -                    return -EINVAL;
>> -                }
>> -                if (objsize < 4096) {
>> -                    error_report("obj size too small");
>> -                    return -EINVAL;
>> -                }
>> -                obj_order = ffs(objsize) - 1;
>> +    if (opts) {
>> +        bytes = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
>> +        objsize = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, 0);
>> +        if (objsize) {
>> +            if ((objsize - 1) & objsize) {    /* not a power of 2? */
>> +                error_report("obj size needs to be power of 2");
>> +                return -EINVAL;
>>               }
>> +            if (objsize < 4096) {
>> +                error_report("obj size too small");
>> +                return -EINVAL;
>> +            }
>> +            obj_order = ffs(objsize) - 1;
>>           }
>> -        options++;
>>       }
>>   
>>       clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
>> @@ -920,20 +916,24 @@ static BlockDriverAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs,
>>   }
>>   #endif
>>   
>> -static QEMUOptionParameter qemu_rbd_create_options[] = {
>> -    {
>> -     .name = BLOCK_OPT_SIZE,
>> -     .type = OPT_SIZE,
>> -     .help = "Virtual disk size"
>> -    },
>> -    {
>> -     .name = BLOCK_OPT_CLUSTER_SIZE,
>> -     .type = OPT_SIZE,
>> -     .help = "RBD object size"
>> -    },
>> -    {NULL}
>> +static QemuOptsList rbd_create_opts = {
>> +    .name = "rbd-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(rbd_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_CLUSTER_SIZE,
>> +            .type = QEMU_OPT_SIZE,
>> +            .help = "RBD object size",
>> +            .def_value_str = stringify(0),
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>> -
>>   static BlockDriver bdrv_rbd = {
>>       .format_name        = "rbd",
>>       .instance_size      = sizeof(BDRVRBDState),
>> @@ -941,7 +941,7 @@ static BlockDriver bdrv_rbd = {
>>       .bdrv_close         = qemu_rbd_close,
>>       .bdrv_create        = qemu_rbd_create,
>>       .bdrv_get_info      = qemu_rbd_getinfo,
>> -    .create_options     = qemu_rbd_create_options,
>> +    .bdrv_create_options = &rbd_create_opts,
>>       .bdrv_getlength     = qemu_rbd_getlength,
>>       .bdrv_truncate      = qemu_rbd_truncate,
>>       .protocol_name      = "rbd",
>> diff --git a/block/sheepdog.c b/block/sheepdog.c
>> index 3e49bb8..d515e56 100644
>> --- a/block/sheepdog.c
>> +++ b/block/sheepdog.c
>> @@ -1274,12 +1274,12 @@ out:
>>       return ret;
>>   }
>>   
>> -static int sd_create(const char *filename, QEMUOptionParameter *options)
>> +static int sd_create(const char *filename, QemuOpts *opts)
>>   {
>>       int ret = 0;
>>       uint32_t vid = 0, base_vid = 0;
>>       int64_t vdi_size = 0;
>> -    char *backing_file = NULL;
>> +    const char *backing_file = NULL, *buf = NULL;
>>       BDRVSheepdogState *s;
>>       char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
>>       uint32_t snapid;
>> @@ -1298,26 +1298,20 @@ static int sd_create(const char *filename, QEMUOptionParameter *options)
>>           goto out;
>>       }
>>   
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            vdi_size = options->value.n;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
>> -            backing_file = options->value.s;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
>> -            if (!options->value.s || !strcmp(options->value.s, "off")) {
>> -                prealloc = false;
>> -            } else if (!strcmp(options->value.s, "full")) {
>> -                prealloc = true;
>> -            } else {
>> -                error_report("Invalid preallocation mode: '%s'",
>> -                             options->value.s);
>> -                ret = -EINVAL;
>> -                goto out;
>> -            }
>> +    if (opts) {
>> +        vdi_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
>> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
>> +        buf = qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
>> +        if (!buf || !strcmp(buf, "off")) {
>> +            prealloc = false;
>> +        } else if (!strcmp(buf, "full")) {
>> +            prealloc = true;
>> +        } else {
>> +            error_report("Invalid preallocation mode: '%s'", buf);
>> +            ret = -EINVAL;
>> +            goto out;
>>           }
>> -        options++;
>>       }
>> -
>>       if (vdi_size > SD_MAX_VDI_SIZE) {
>>           error_report("too big image size");
>>           ret = -EINVAL;
>> @@ -2042,24 +2036,27 @@ static int sd_load_vmstate(BlockDriverState *bs, uint8_t *data,
>>       return do_load_save_vmstate(s, data, pos, size, 1);
>>   }
>>   
>> -
>> -static QEMUOptionParameter sd_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"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_PREALLOC,
>> -        .type = OPT_STRING,
>> -        .help = "Preallocation mode (allowed values: off, full)"
>> -    },
>> -    { NULL }
>> +static QemuOptsList sd_create_opts = {
>> +    .name = "sheepdog-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(sd_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_BACKING_FILE,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "File name of a base image"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_PREALLOC,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "Preallocation mode (allowed values: off, full)"
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   BlockDriver bdrv_sheepdog = {
>> @@ -2084,7 +2081,7 @@ BlockDriver bdrv_sheepdog = {
>>       .bdrv_save_vmstate  = sd_save_vmstate,
>>       .bdrv_load_vmstate  = sd_load_vmstate,
>>   
>> -    .create_options = sd_create_options,
>> +    .bdrv_create_options = &sd_create_opts,
>>   };
>>   
>>   static void bdrv_sheepdog_init(void)
>> diff --git a/block/vdi.c b/block/vdi.c
>> index 021abaa..95f738e 100644
>> --- a/block/vdi.c
>> +++ b/block/vdi.c
>> @@ -620,7 +620,7 @@ static int vdi_co_write(BlockDriverState *bs,
>>       return ret;
>>   }
>>   
>> -static int vdi_create(const char *filename, QEMUOptionParameter *options)
>> +static int vdi_create(const char *filename, QemuOpts *opts)
>>   {
>>       int fd;
>>       int result = 0;
>> @@ -635,24 +635,19 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
>>       logout("\n");
>>   
>>       /* Read out options. */
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            bytes = options->value.n;
>> +    if (opts) {
>> +        bytes = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
>>   #if defined(CONFIG_VDI_BLOCK_SIZE)
>> -        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
>> -            if (options->value.n) {
>> -                /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
>> -                block_size = options->value.n;
>> -            }
>> +        /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
>> +        block_size = qemu_opt_get_size(opts,
>> +                                       BLOCK_OPT_CLUSTER_SIZE,
>> +                                       DEFAULT_CLUSTER_SIZE);
>>   #endif
>>   #if defined(CONFIG_VDI_STATIC_IMAGE)
>> -        } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
>> -            if (options->value.n) {
>> -                image_type = VDI_TYPE_STATIC;
>> -            }
>> -#endif
>> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_STATIC, 0)) {
>> +            image_type = VDI_TYPE_STATIC;
>>           }
>> -        options++;
>> +#endif
>>       }
>>   
>>       fd = qemu_open(filename,
>> @@ -733,29 +728,33 @@ static void vdi_close(BlockDriverState *bs)
>>       error_free(s->migration_blocker);
>>   }
>>   
>> -static QEMUOptionParameter vdi_create_options[] = {
>> -    {
>> -        .name = BLOCK_OPT_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "Virtual disk size"
>> -    },
>> +static QemuOptsList vdi_create_opts = {
>> +    .name = "vdi-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(vdi_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>>   #if defined(CONFIG_VDI_BLOCK_SIZE)
>> -    {
>> -        .name = BLOCK_OPT_CLUSTER_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "VDI cluster (block) size",
>> -        .value = { .n = DEFAULT_CLUSTER_SIZE },
>> -    },
>> +        {
>> +            .name = BLOCK_OPT_CLUSTER_SIZE,
>> +            .type = QEMU_OPT_SIZE,
>> +            .help = "VDI cluster (block) size",
>> +            .def_value_str = stringify(DEFAULT_CLUSTER_SIZE)
>> +        },
>>   #endif
>>   #if defined(CONFIG_VDI_STATIC_IMAGE)
>> -    {
>> -        .name = BLOCK_OPT_STATIC,
>> -        .type = OPT_FLAG,
>> -        .help = "VDI static (pre-allocated) image"
>> -    },
>> +        {
>> +            .name = BLOCK_OPT_STATIC,
>> +            .type = QEMU_OPT_BOOL,
>> +            .help = "VDI static (pre-allocated) image"
>> +        },
>>   #endif
>> -    /* TODO: An additional option to set UUID values might be useful. */
>> -    { NULL }
>> +        /* TODO: An additional option to set UUID values might be useful. */
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   static BlockDriver bdrv_vdi = {
>> @@ -776,7 +775,7 @@ static BlockDriver bdrv_vdi = {
>>   
>>       .bdrv_get_info = vdi_get_info,
>>   
>> -    .create_options = vdi_create_options,
>> +    .bdrv_create_options = &vdi_create_opts,
>>       .bdrv_check = vdi_check,
>>   };
>>   
>> diff --git a/block/vmdk.c b/block/vmdk.c
>> index 19298c2..4c29927 100644
>> --- a/block/vmdk.c
>> +++ b/block/vmdk.c
>> @@ -1437,7 +1437,7 @@ static int relative_path(char *dest, int dest_size,
>>       return 0;
>>   }
>>   
>> -static int vmdk_create(const char *filename, QEMUOptionParameter *options)
>> +static int vmdk_create(const char *filename, QemuOpts *opts)
>>   {
>>       int fd, idx = 0;
>>       char desc[BUF_SIZE];
>> @@ -1476,18 +1476,14 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options)
>>       if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
>>           return -EINVAL;
>>       }
>> -    /* Read out options */
>> -    while (options && options->name) {
>> -        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
>> -            total_size = options->value.n;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
>> -            backing_file = options->value.s;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
>> -            flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
>> -        } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
>> -            fmt = options->value.s;
>> +    /* Read out opts */
>> +    if (opts) {
>> +        total_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
>> +        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
>> +        if (qemu_opt_get_bool(opts, BLOCK_OPT_COMPAT6, 0)) {
>> +            flags |= BLOCK_FLAG_COMPAT6;
>>           }
>> -        options++;
>> +        fmt = qemu_opt_get(opts, BLOCK_OPT_SUBFMT);
>>       }
>>       if (!fmt) {
>>           /* Default format to monolithicSparse */
>> @@ -1654,30 +1650,34 @@ static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs)
>>       return ret;
>>   }
>>   
>> -static QEMUOptionParameter vmdk_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"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_COMPAT6,
>> -        .type = OPT_FLAG,
>> -        .help = "VMDK version 6 image"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_SUBFMT,
>> -        .type = OPT_STRING,
>> -        .help =
>> -            "VMDK flat extent format, can be one of "
>> -            "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
>> -    },
>> -    { NULL }
>> +static QemuOptsList vmdk_create_opts = {
>> +    .name = "vmdk-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_BACKING_FILE,
>> +            .type = QEMU_OPT_STRING,
>> +            .help = "File name of a base image"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_COMPAT6,
>> +            .type = QEMU_OPT_BOOL,
>> +            .help = "VMDK version 6 image"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_SUBFMT,
>> +            .type = QEMU_OPT_STRING,
>> +            .help =
>> +                "VMDK flat extent format, can be one of "
>> +                "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   static BlockDriver bdrv_vmdk = {
>> @@ -1694,7 +1694,7 @@ static BlockDriver bdrv_vmdk = {
>>       .bdrv_co_is_allocated   = vmdk_co_is_allocated,
>>       .bdrv_get_allocated_file_size  = vmdk_get_allocated_file_size,
>>   
>> -    .create_options = vmdk_create_options,
>> +    .bdrv_create_options = &vmdk_create_opts,
>>   };
>>   
>>   static void bdrv_vmdk_init(void)
>> diff --git a/block/vpc.c b/block/vpc.c
>> index 7948609..fcfdc79 100644
>> --- a/block/vpc.c
>> +++ b/block/vpc.c
>> @@ -665,34 +665,33 @@ static int create_fixed_disk(int fd, uint8_t *buf, int64_t total_size)
>>       return ret;
>>   }
>>   
>> -static int vpc_create(const char *filename, QEMUOptionParameter *options)
>> +static int vpc_create(const char *filename, QemuOpts *opts)
>>   {
>>       uint8_t buf[1024];
>>       struct vhd_footer *footer = (struct vhd_footer *) buf;
>> -    QEMUOptionParameter *disk_type_param;
>> +    const char *disk_type_param = NULL;
>>       int fd, i;
>>       uint16_t cyls = 0;
>>       uint8_t heads = 0;
>>       uint8_t secs_per_cyl = 0;
>>       int64_t total_sectors;
>> -    int64_t total_size;
>> -    int disk_type;
>> +    int64_t total_size = 0;
>> +    int disk_type = VHD_DYNAMIC;
>>       int ret = -EIO;
>>   
>> -    /* Read out options */
>> -    total_size = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n;
>> -
>> -    disk_type_param = get_option_parameter(options, BLOCK_OPT_SUBFMT);
>> -    if (disk_type_param && disk_type_param->value.s) {
>> -        if (!strcmp(disk_type_param->value.s, "dynamic")) {
>> -            disk_type = VHD_DYNAMIC;
>> -        } else if (!strcmp(disk_type_param->value.s, "fixed")) {
>> -            disk_type = VHD_FIXED;
>> -        } else {
>> -            return -EINVAL;
>> +    /* Read out opts */
>> +    if (opts) {
>> +        total_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
>> +        disk_type_param = qemu_opt_get(opts, BLOCK_OPT_SUBFMT);
>> +        if (disk_type_param) {
>> +            if (!strcmp(disk_type_param, "dynamic")) {
>> +                disk_type = VHD_DYNAMIC;
>> +            } else if (!strcmp(disk_type_param, "fixed")) {
>> +                disk_type = VHD_FIXED;
>> +            } else {
>> +                return -EINVAL;
>> +            }
>>           }
>> -    } else {
>> -        disk_type = VHD_DYNAMIC;
>>       }
>>   
>>       /* Create the file */
>> @@ -780,20 +779,24 @@ static void vpc_close(BlockDriverState *bs)
>>       error_free(s->migration_blocker);
>>   }
>>   
>> -static QEMUOptionParameter vpc_create_options[] = {
>> -    {
>> -        .name = BLOCK_OPT_SIZE,
>> -        .type = OPT_SIZE,
>> -        .help = "Virtual disk size"
>> -    },
>> -    {
>> -        .name = BLOCK_OPT_SUBFMT,
>> -        .type = OPT_STRING,
>> -        .help =
>> -            "Type of virtual hard disk format. Supported formats are "
>> -            "{dynamic (default) | fixed} "
>> -    },
>> -    { NULL }
>> +static QemuOptsList vpc_create_opts = {
>> +    .name = "vpc-create-opts",
>> +    .head = QTAILQ_HEAD_INITIALIZER(vpc_create_opts.head),
>> +    .desc = {
>> +        {
>> +            .name = BLOCK_OPT_SIZE,
>> +            .type = QEMU_OPT_NUMBER,
> 
> QEMU_OPT_SIZE again.
> 
>> +            .help = "Virtual disk size"
>> +        },
>> +        {
>> +            .name = BLOCK_OPT_SUBFMT,
>> +            .type = OPT_STRING,
>> +            .help =
>> +                "Type of virtual hard disk format. Supported formats are "
>> +                "{dynamic (default) | fixed} "
>> +        },
>> +        { /* end of list */ }
>> +    }
>>   };
>>   
>>   static BlockDriver bdrv_vpc = {
>> @@ -809,7 +812,7 @@ static BlockDriver bdrv_vpc = {
>>       .bdrv_read              = vpc_co_read,
>>       .bdrv_write             = vpc_co_write,
>>   
>> -    .create_options = vpc_create_options,
>> +    .bdrv_create_options = &vpc_create_opts,
>>   };
>>   
>>   static void bdrv_vpc_init(void)
>> diff --git a/block/vvfat.c b/block/vvfat.c
>> index 06e6654..2343cd4 100644
>> --- a/block/vvfat.c
>> +++ b/block/vvfat.c
>> @@ -2802,7 +2802,7 @@ static BlockDriver vvfat_write_target = {
>>   static int enable_write_target(BDRVVVFATState *s)
>>   {
>>       BlockDriver *bdrv_qcow;
>> -    QEMUOptionParameter *options;
>> +    QemuOpts *opts;
>>       int ret;
>>       int size = sector2cluster(s, s->sector_count);
>>       s->used_clusters = calloc(size, 1);
>> @@ -2818,12 +2818,13 @@ static int enable_write_target(BDRVVVFATState *s)
>>       }
>>   
>>       bdrv_qcow = bdrv_find_format("qcow");
>> -    options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
>> -    set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
>> -    set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
>> +    opts = qemu_opts_create_nofail(bdrv_qcow->bdrv_create_options);
>> +    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512);
>> +    qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:");
>>   
>> -    if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
>> +    if (bdrv_create(bdrv_qcow, s->qcow_filename, opts) < 0) {
>>   	return -1;
>> +    }
>>   
>>       s->qcow = bdrv_new("");
>>       if (s->qcow == NULL) {
>> diff --git a/include/block/block.h b/include/block/block.h
>> index ffd1936..c99e8bf 100644
>> --- a/include/block/block.h
>> +++ b/include/block/block.h
>> @@ -124,8 +124,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);
>>   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 f83ffb8..71f7670 100644
>> --- a/include/block/block_int.h
>> +++ b/include/block/block_int.h
>> @@ -88,7 +88,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);
>>       int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
>>       int (*bdrv_make_empty)(BlockDriverState *bs);
>>       /* aio */
>> @@ -177,9 +177,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_options;
> 
> Since you're renaming this anyway, consider renaming to
> bdrv_create_opts, to match the names used elsewhere.
> 
>>   
>>       /*
>>        * Returns 0 for completed check, -errno for internal errors.
>> diff --git a/qemu-img.c b/qemu-img.c
>> index 85d3740..b4b3ce8 100644
>> --- a/qemu-img.c
>> +++ b/qemu-img.c
>> @@ -200,7 +200,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_options = NULL;
>>   
>>       /* Find driver and parse its options */
>>       drv = bdrv_find_format(fmt);
>> @@ -215,12 +215,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_options = append_opts_list(drv->bdrv_create_options,
>> +                                      proto_drv->bdrv_create_options);
>> +    print_opts_list(create_options);
>> +    free_opts_list(create_options);
>>       return 0;
>>   }
>>   
>> @@ -271,19 +269,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;
>> @@ -675,8 +673,9 @@ static int img_convert(int argc, char **argv)
>     static int img_convert(int argc, char **argv)
>     {
>         int c, ret = 0, n, n1, bs_n, bs_i, compress, cluster_size, cluster_sectors;
>         int progress = 0, flags;
>         const char *fmt, *out_fmt, *cache, *out_baseimg, *out_filename;
>         BlockDriver *drv, *proto_drv;
>         BlockDriverState **bs = NULL, *out_bs = NULL;
>         int64_t total_sectors, nb_sectors, sector_num, bs_offset;
> 
> Some or all of these should probably be uint64_t.  Not your patch's
> fault, feel free to ignore.
> 
>         uint64_t bs_sectors;
>>       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_options = NULL;
>> +    const char *out_baseimg_param;
>>       char *options = NULL;
>>       const char *snapshot_name = NULL;
>>       float local_progress = 0;
>> @@ -811,40 +810,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_options = append_opts_list(drv->bdrv_create_options,
>> +                                      proto_drv->bdrv_create_options);
>>   
>>       if (options) {
>> -        param = parse_option_parameters(options, create_options, param);
>> -        if (param == NULL) {
>> +        if (qemu_opts_do_parse(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_options);
>>       }
>> -
>> -    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;
>>       }
>>   
>>       /* 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");
>> @@ -852,15 +847,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");
>> @@ -1078,8 +1073,10 @@ static int img_convert(int argc, char **argv)
>>       }
>>   out:
>>       qemu_progress_end();
>> -    free_option_parameters(create_options);
>> -    free_option_parameters(param);
>> +    free_opts_list(create_options);
>> +    if (param) {
>> +        qemu_opts_del(param);
>> +    }
>>       qemu_vfree(buf);
>>       if (out_bs) {
>>           bdrv_delete(out_bs);
> 
>
Markus Armbruster Jan. 28, 2013, 5:41 p.m. UTC | #3
Dong Xu Wang <wdongxu@linux.vnet.ibm.com> writes:

> Markus Armbruster <armbru@redhat.com> writes:
>> Dong Xu Wang <wdongxu@vnet.linux.ibm.com> writes:
>> 
>>> This patch will use QemuOpts related functions in block layer, add
>>> a member bdrv_create_options 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 <wdongxu@linux.vnet.ibm.com>
>>> ---
>>> 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/qcow.c              |  60 ++++++++--------
>>>   block/qcow2.c             | 171 +++++++++++++++++++++++-----------------------
>>>   block/qed.c               |  86 +++++++++++------------
>>>   block/qed.h               |   2 +-
>>>   block/raw-posix.c         |  59 ++++++++--------
>>>   block/raw-win32.c         |  30 ++++----
>>>   block/raw.c               |  30 ++++----
>>>   block/rbd.c               |  62 ++++++++---------
>>>   block/sheepdog.c          |  75 ++++++++++----------
>>>   block/vdi.c               |  69 +++++++++----------
>>>   block/vmdk.c              |  74 ++++++++++----------
>>>   block/vpc.c               |  67 +++++++++---------
>>>   block/vvfat.c             |  11 +--
>>>   include/block/block.h     |   4 +-
>>>   include/block/block_int.h |   6 +-
>>>   qemu-img.c                |  61 ++++++++---------
>>>   19 files changed, 519 insertions(+), 522 deletions(-)
>>>
>>> diff --git a/block.c b/block.c
>>> index 6fa7c90..56e4613 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)
>>>   {
>>>       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,
>>>           .ret = NOT_DONE,
>>>       };
>>>   
>>> @@ -405,7 +405,7 @@ out:
>>>       return ret;
>>>   }
>>>   
>>> -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);
>>>   }
>>>   
>>>   /*
>>> @@ -794,7 +794,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
>>> @@ -827,17 +827,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_options);
>>>   
>>> -        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;
>>>           }
>>> @@ -4493,8 +4492,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>>>                        const char *base_filename, const char *base_fmt,
>>>                        char *options, uint64_t img_size, int flags, Error **errp)
>>>   {
>>> -    QEMUOptionParameter *param = NULL, *create_options = NULL;
>>> -    QEMUOptionParameter *backing_fmt, *backing_file, *size;
>>> +    QemuOpts *opts = NULL;
>>> +    QemuOptsList *create_options = NULL;
>>> +    const char *backing_fmt, *backing_file;
>>> +    int64_t size;
>>>       BlockDriverState *bs = NULL;
>>>       BlockDriver *drv, *proto_drv;
>>>       BlockDriver *backing_drv = NULL;
>>> @@ -4512,28 +4513,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_options = append_opts_list(drv->bdrv_create_options,
>>> +                                      proto_drv->bdrv_create_options);
>> 
>> 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?  Outside the
>> scope of this patch.
> Sorry, I do not understand this line, clash? Can you explain some more?
> Do you mean bdrv_create_options should be renamed such as bdrv_create_opts?

No.  I was talking about what happens when drv->create_options and
proto->create_options both have an entry with the same name.

First, I reasoned why your patch doesn't change the way such a clash is
handled.

Then I wondered whether we should avoid such clashes, but hastened to
add that I'm not asking you to do that now.

>>>       /* Create parameter list with default values */
>>> -    param = parse_option_parameters("", create_options, param);
>>> +    opts = qemu_opts_create_nofail(create_options);
>>>   
>>> -    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
>>> +    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size);
>>>   
>>>       /* Parse -o options */
>>>       if (options) {
>>> -        param = parse_option_parameters(options, create_options, param);
>>> -        if (param == NULL) {
>>> +        if (qemu_opts_do_parse(opts, options, NULL) != 0) {
>>>               error_setg(errp, "Invalid options for file format '%s'.", fmt);
>>>               goto out;
>>>           }
>>>       }
>> 
>> Before: size from -o replaces img_size in param.
>> 
>> After: size from -o gets appended to opts, is therefore shadowed by
>> img_size.  I think.
>> 
>> User-visible change, if my reading is correct.  Should be avoided.
>> 
> Okay. will also "replace", not "append".

Prepending could also work.

Doing things in a different order could make appending work.

Whatever is easiest.

>>>   
>>>       if (base_filename) {
>>> -        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
>>> +        if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE,
>>>                                    base_filename)) {
>>>               error_setg(errp, "Backing file not supported for file format '%s'",
>>>                          fmt);
>> 
>> Before: base_filename replaces the backing_file from -o.
>> 
>> After: base_filename gets appended to opts, shadowed by backing_file
>> from -o.
>> 
>>> @@ -4542,39 +4538,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_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) {
>>>               error_setg(errp, "Backing file format not supported for file "
>>>                                "format '%s'", fmt);
>>>               goto out;
>>>           }
>>>       }
>> 
>> Likewise.
>> 
>>>   
>>> -    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_number(opts, BLOCK_OPT_SIZE, -1);
>>> +    if (size == -1) {
>>> +        if (backing_file) {
>> 
>> Code has the same before your patch, so it's not your fault, but here
>> goes anyway:
>> 
>> QemuOpts support only *unsigned* numbers.  Argument -1 is for an
>> uint64_t parameter, and gets converted to UINT64_MAX.  If the option
>> isn't set, it's returned.  The assignment to int64_t size converts it
>> back to -1.
>> 
>> Using the an honest UINT64_MAX instead of -1 would be clearer.  Should
>> make size uint64_t then.
>> 
>> However, all other places do
>> 
>>      qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0)
>> 
>> Why is this one different?
>> 
> Because previous use -1, so, I passed default value -1.

I have no idea what you're talking about, and I'm not 100% sure you do
:)

The last argument to qemu_opt_get_number() is *not* used here.  That's
because a few lines above, you do

    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size);

So, opts always has the BLOCK_OPT_SIZE option, and the default value
never applies.

Let's take a step back and figure out how the current code works before
we further review your patch.

bdrv_img_create() merges parameters img_size, base_filename, base_fmt
with options as follows:

1. Get format and protocol driver from parameters @fmt and @filename.

2. Combine the two drivers' option lists.

3. Copy the resulting option list for no discernible reason.

4. If %BLOCK_OPT_SIZE is a valid option, set its value to parameter
   @img_size.

5. For all KEY=VAL in parameter @options:
       KEY must be a valid option (error out if not)
       set its value to VAL

6. If parameter @base_filename isn't null:
       %BLOCK_OPT_BACKING_FILE must be a valid option (error out if not)
       set its value to @base_filename

7. If parameter @base_fmt isn't null:
       %BLOCK_OPT_BACKING_FMT must be a valid option (error out if not)
       set its value to @base_fmt

In short, @base_filename and @base_fmt take precedence over @options
(unless they're null, of course).  @options takes precedence over
@img_size.  What a mess :)  Not your fault.

Now let's look at the code retrieving BLOCK_OPT_SIZE:

    // 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) {
           // compute size, put it into buf
            set_option_parameter(param, BLOCK_OPT_SIZE, buf);
        } else {
           // error out
        }

If %BLOCK_OPT_SIZE is a valid option, and has the special value
(uint64_t)-1, then we must have a backing file (error out if not), and
we use its size instead.  In other words, the special value means "use
the backing file's size".

The value can come either from @img_size or from @options.

Some callers indeed pass (uint64_t)-1 for @img_size.  For instance,
qemu-img create passes it when run without the optional size argument.
Works.

qemu-img is the only caller passing @options.  With -o size=-1, it
actually puts (uint64_t)-1 into @param (parse_option_size() sucks).
Weird.

The whole bloody mess should be cleaned up.  But I'm not asking you to
do that now.

I do think, however, that you should stick to

    qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0)

instead of your voodoo

    qemu_opt_get_number(opts, BLOCK_OPT_SIZE, -1)

>>>               uint64_t size;
>>> -            char buf[32];
>>>               int back_flags;
>>>   
>>>               /* backing files always opened read-only */
>>> @@ -4583,17 +4577,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);
>>>           } else {
>>>               error_setg(errp, "Image creation needs a size parameter");
>>>               goto out;
>>> @@ -4601,10 +4594,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>>>       }
>>>   
>>>       printf("Formatting '%s', fmt=%s ", filename, fmt);
>>> -    print_option_parameters(param);
>>> +    qemu_opts_print(opts, NULL);
>>>       puts("");
>>>   
>>> -    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 "
>>> @@ -4619,8 +4612,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>>>       }
>>>   
>>>   out:
>>> -    free_option_parameters(create_options);
>>> -    free_option_parameters(param);
>>> +    free_opts_list(create_options);
>>> +    if (opts) {
>>> +        qemu_opts_del(opts);
>>> +    }
>>>   
>>>       if (bs) {
>>>           bdrv_delete(bs);
>>> diff --git a/block/cow.c b/block/cow.c
>>> index a33ce95..5442c9c 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,13 @@ 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 */
>>> +    if (opts) {
>> 
>> I suspect you need the if (opts) here and in many other places only
>> because you special-cased "both lists empty" in append_opts_list().  I
>> suspect things become easier if you drop that.
>
> No, in this version, if(opt) is needed in "protocol", not needed in
> "format", I want to have the same code style, so I also judged if opts
> is NULL in "format" _create functions. Do you think is it acceptable?

I still don't get it.  Can you explain how opts can be null here even
when append_opts_list() is changed not to return null?

>> 
>>> +        image_sectors = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
>>> +        image_filename = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
>>>       }
>>>   
>>> -    ret = bdrv_create_file(filename, options);
>>> +    ret = bdrv_create_file(filename, opts);
>>>       if (ret < 0) {
>>>           return ret;
>>>       }
>>> @@ -318,18 +314,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_NUMBER,
>> 
>> QEMU_OPT_SIZE, or else we lose support for suffixes, don't we?
>> 
> In qemu-img.c, strtosz_suffix convert suffixes to regular digitals.

That's correct for the optional size argument, but not for -o size=...

> Okay. I will change to QEMU_OPT_SIZE.

Please do, and test that both the size argument and -o size=... works
just like before, with and without suffixes.

>>> +            .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 +345,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_options    = &cow_create_opts,
>>>   };
>>>   
>>>   static void bdrv_cow_init(void)
>>> diff --git a/block/gluster.c b/block/gluster.c
>>> index 0f2c32a..a41c684 100644
>>> --- a/block/gluster.c
>>> +++ b/block/gluster.c
>>> @@ -335,8 +335,7 @@ out:
>>>       return ret;
>>>   }
>>>   
>>> -static int qemu_gluster_create(const char *filename,
>>> -        QEMUOptionParameter *options)
>>> +static int qemu_gluster_create(const char *filename, QemuOpts* opts)
>> 
>> Space before the *, not after: QemuOpts *opts
>> 
> Okay.

[...]
Robert Wang Jan. 29, 2013, 2:31 a.m. UTC | #4
于 2013-1-29 1:41, Markus Armbruster 写道:
> Dong Xu Wang <wdongxu@linux.vnet.ibm.com> writes:
> 
>> Markus Armbruster <armbru@redhat.com> writes:
>>> Dong Xu Wang <wdongxu@vnet.linux.ibm.com> writes:
>>>
>>>> This patch will use QemuOpts related functions in block layer, add
>>>> a member bdrv_create_options 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 <wdongxu@linux.vnet.ibm.com>
>>>> ---
>>>> 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/qcow.c              |  60 ++++++++--------
>>>>    block/qcow2.c             | 171 +++++++++++++++++++++++-----------------------
>>>>    block/qed.c               |  86 +++++++++++------------
>>>>    block/qed.h               |   2 +-
>>>>    block/raw-posix.c         |  59 ++++++++--------
>>>>    block/raw-win32.c         |  30 ++++----
>>>>    block/raw.c               |  30 ++++----
>>>>    block/rbd.c               |  62 ++++++++---------
>>>>    block/sheepdog.c          |  75 ++++++++++----------
>>>>    block/vdi.c               |  69 +++++++++----------
>>>>    block/vmdk.c              |  74 ++++++++++----------
>>>>    block/vpc.c               |  67 +++++++++---------
>>>>    block/vvfat.c             |  11 +--
>>>>    include/block/block.h     |   4 +-
>>>>    include/block/block_int.h |   6 +-
>>>>    qemu-img.c                |  61 ++++++++---------
>>>>    19 files changed, 519 insertions(+), 522 deletions(-)
>>>>
>>>> diff --git a/block.c b/block.c
>>>> index 6fa7c90..56e4613 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)
>>>>    {
>>>>        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,
>>>>            .ret = NOT_DONE,
>>>>        };
>>>>    
>>>> @@ -405,7 +405,7 @@ out:
>>>>        return ret;
>>>>    }
>>>>    
>>>> -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);
>>>>    }
>>>>    
>>>>    /*
>>>> @@ -794,7 +794,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
>>>> @@ -827,17 +827,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_options);
>>>>    
>>>> -        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;
>>>>            }
>>>> @@ -4493,8 +4492,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>>>>                         const char *base_filename, const char *base_fmt,
>>>>                         char *options, uint64_t img_size, int flags, Error **errp)
>>>>    {
>>>> -    QEMUOptionParameter *param = NULL, *create_options = NULL;
>>>> -    QEMUOptionParameter *backing_fmt, *backing_file, *size;
>>>> +    QemuOpts *opts = NULL;
>>>> +    QemuOptsList *create_options = NULL;
>>>> +    const char *backing_fmt, *backing_file;
>>>> +    int64_t size;
>>>>        BlockDriverState *bs = NULL;
>>>>        BlockDriver *drv, *proto_drv;
>>>>        BlockDriver *backing_drv = NULL;
>>>> @@ -4512,28 +4513,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_options = append_opts_list(drv->bdrv_create_options,
>>>> +                                      proto_drv->bdrv_create_options);
>>>
>>> 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?  Outside the
>>> scope of this patch.
>> Sorry, I do not understand this line, clash? Can you explain some more?
>> Do you mean bdrv_create_options should be renamed such as bdrv_create_opts?
> 
> No.  I was talking about what happens when drv->create_options and
> proto->create_options both have an entry with the same name.
> 
> First, I reasoned why your patch doesn't change the way such a clash is
> handled.
> 
> Then I wondered whether we should avoid such clashes, but hastened to
> add that I'm not asking you to do that now.
> 
>>>>        /* Create parameter list with default values */
>>>> -    param = parse_option_parameters("", create_options, param);
>>>> +    opts = qemu_opts_create_nofail(create_options);
>>>>    
>>>> -    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
>>>> +    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size);
>>>>    
>>>>        /* Parse -o options */
>>>>        if (options) {
>>>> -        param = parse_option_parameters(options, create_options, param);
>>>> -        if (param == NULL) {
>>>> +        if (qemu_opts_do_parse(opts, options, NULL) != 0) {
>>>>                error_setg(errp, "Invalid options for file format '%s'.", fmt);
>>>>                goto out;
>>>>            }
>>>>        }
>>>
>>> Before: size from -o replaces img_size in param.
>>>
>>> After: size from -o gets appended to opts, is therefore shadowed by
>>> img_size.  I think.
>>>
>>> User-visible change, if my reading is correct.  Should be avoided.
>>>
>> Okay. will also "replace", not "append".
> 
> Prepending could also work.
> 
> Doing things in a different order could make appending work.
> 
> Whatever is easiest.
> 
>>>>    
>>>>        if (base_filename) {
>>>> -        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
>>>> +        if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE,
>>>>                                     base_filename)) {
>>>>                error_setg(errp, "Backing file not supported for file format '%s'",
>>>>                           fmt);
>>>
>>> Before: base_filename replaces the backing_file from -o.
>>>
>>> After: base_filename gets appended to opts, shadowed by backing_file
>>> from -o.
>>>
>>>> @@ -4542,39 +4538,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_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) {
>>>>                error_setg(errp, "Backing file format not supported for file "
>>>>                                 "format '%s'", fmt);
>>>>                goto out;
>>>>            }
>>>>        }
>>>
>>> Likewise.
>>>
>>>>    
>>>> -    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_number(opts, BLOCK_OPT_SIZE, -1);
>>>> +    if (size == -1) {
>>>> +        if (backing_file) {
>>>
>>> Code has the same before your patch, so it's not your fault, but here
>>> goes anyway:
>>>
>>> QemuOpts support only *unsigned* numbers.  Argument -1 is for an
>>> uint64_t parameter, and gets converted to UINT64_MAX.  If the option
>>> isn't set, it's returned.  The assignment to int64_t size converts it
>>> back to -1.
>>>
>>> Using the an honest UINT64_MAX instead of -1 would be clearer.  Should
>>> make size uint64_t then.
>>>
>>> However, all other places do
>>>
>>>       qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0)
>>>
>>> Why is this one different?
>>>
>> Because previous use -1, so, I passed default value -1.
> 
> I have no idea what you're talking about, and I'm not 100% sure you do
> :)
> 
> The last argument to qemu_opt_get_number() is *not* used here.  That's
> because a few lines above, you do
> 
>      qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size);
> 
> So, opts always has the BLOCK_OPT_SIZE option, and the default value
> never applies.
> 
> Let's take a step back and figure out how the current code works before
> we further review your patch.
> 
> bdrv_img_create() merges parameters img_size, base_filename, base_fmt
> with options as follows:
> 
> 1. Get format and protocol driver from parameters @fmt and @filename.
> 
> 2. Combine the two drivers' option lists.
> 
> 3. Copy the resulting option list for no discernible reason.
> 
> 4. If %BLOCK_OPT_SIZE is a valid option, set its value to parameter
>     @img_size.
> 
> 5. For all KEY=VAL in parameter @options:
>         KEY must be a valid option (error out if not)
>         set its value to VAL
> 
> 6. If parameter @base_filename isn't null:
>         %BLOCK_OPT_BACKING_FILE must be a valid option (error out if not)
>         set its value to @base_filename
> 
> 7. If parameter @base_fmt isn't null:
>         %BLOCK_OPT_BACKING_FMT must be a valid option (error out if not)
>         set its value to @base_fmt
> 
> In short, @base_filename and @base_fmt take precedence over @options
> (unless they're null, of course).  @options takes precedence over
> @img_size.  What a mess :)  Not your fault.
> 
> Now let's look at the code retrieving BLOCK_OPT_SIZE:
> 
>      // 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) {
>             // compute size, put it into buf
>              set_option_parameter(param, BLOCK_OPT_SIZE, buf);
>          } else {
>             // error out
>          }
> 
> If %BLOCK_OPT_SIZE is a valid option, and has the special value
> (uint64_t)-1, then we must have a backing file (error out if not), and
> we use its size instead.  In other words, the special value means "use
> the backing file's size".
> 
> The value can come either from @img_size or from @options.
> 
> Some callers indeed pass (uint64_t)-1 for @img_size.  For instance,
> qemu-img create passes it when run without the optional size argument.
> Works.
> 
> qemu-img is the only caller passing @options.  With -o size=-1, it
> actually puts (uint64_t)-1 into @param (parse_option_size() sucks).
> Weird.
> 
> The whole bloody mess should be cleaned up.  But I'm not asking you to
> do that now.
> 
> I do think, however, that you should stick to
> 
>      qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0)
> 
> instead of your voodoo
> 
>      qemu_opt_get_number(opts, BLOCK_OPT_SIZE, -1)
> 
>>>>                uint64_t size;
>>>> -            char buf[32];
>>>>                int back_flags;
>>>>    
>>>>                /* backing files always opened read-only */
>>>> @@ -4583,17 +4577,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);
>>>>            } else {
>>>>                error_setg(errp, "Image creation needs a size parameter");
>>>>                goto out;
>>>> @@ -4601,10 +4594,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>>>>        }
>>>>    
>>>>        printf("Formatting '%s', fmt=%s ", filename, fmt);
>>>> -    print_option_parameters(param);
>>>> +    qemu_opts_print(opts, NULL);
>>>>        puts("");
>>>>    
>>>> -    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 "
>>>> @@ -4619,8 +4612,10 @@ void bdrv_img_create(const char *filename, const char *fmt,
>>>>        }
>>>>    
>>>>    out:
>>>> -    free_option_parameters(create_options);
>>>> -    free_option_parameters(param);
>>>> +    free_opts_list(create_options);
>>>> +    if (opts) {
>>>> +        qemu_opts_del(opts);
>>>> +    }
>>>>    
>>>>        if (bs) {
>>>>            bdrv_delete(bs);
>>>> diff --git a/block/cow.c b/block/cow.c
>>>> index a33ce95..5442c9c 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,13 @@ 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 */
>>>> +    if (opts) {
>>>
>>> I suspect you need the if (opts) here and in many other places only
>>> because you special-cased "both lists empty" in append_opts_list().  I
>>> suspect things become easier if you drop that.
>>
>> No, in this version, if(opt) is needed in "protocol", not needed in
>> "format", I want to have the same code style, so I also judged if opts
>> is NULL in "format" _create functions. Do you think is it acceptable?
> 
> I still don't get it.  Can you explain how opts can be null here even
> when append_opts_list() is changed not to return null?
> 
I mean: When I use protocol, such as gluster:
/usr/bin/qemu-img create -f qed -o cluster_size=65536
gluster://kvm11/single-volume/12.qed 10M

Then opts will be null:
qemu_gluster_create (filename=0x555555c11930
"gluster://kvm11/single-volume/12.qed", opts=0x0) at block/gluster.c:339

So it checked if opts is NULL now:
352	    if (opts) {
353	        total_size =
354	            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) /
BDRV_SECTOR_SIZE;
355	    }

I want to make these code in only one kind of style, so I judged if opts
is NULL in block format code.

>>>
>>>> +        image_sectors = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
>>>> +        image_filename = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
>>>>        }
>>>>    
>>>> -    ret = bdrv_create_file(filename, options);
>>>> +    ret = bdrv_create_file(filename, opts);
>>>>        if (ret < 0) {
>>>>            return ret;
>>>>        }
>>>> @@ -318,18 +314,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_NUMBER,
>>>
>>> QEMU_OPT_SIZE, or else we lose support for suffixes, don't we?
>>>
>> In qemu-img.c, strtosz_suffix convert suffixes to regular digitals.
> 
> That's correct for the optional size argument, but not for -o size=...
> 
>> Okay. I will change to QEMU_OPT_SIZE.
> 
> Please do, and test that both the size argument and -o size=... works
> just like before, with and without suffixes.
> 
>>>> +            .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 +345,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_options    = &cow_create_opts,
>>>>    };
>>>>    
>>>>    static void bdrv_cow_init(void)
>>>> diff --git a/block/gluster.c b/block/gluster.c
>>>> index 0f2c32a..a41c684 100644
>>>> --- a/block/gluster.c
>>>> +++ b/block/gluster.c
>>>> @@ -335,8 +335,7 @@ out:
>>>>        return ret;
>>>>    }
>>>>    
>>>> -static int qemu_gluster_create(const char *filename,
>>>> -        QEMUOptionParameter *options)
>>>> +static int qemu_gluster_create(const char *filename, QemuOpts* opts)
>>>
>>> Space before the *, not after: QemuOpts *opts
>>>
>> Okay.
> 
> [...]
> 
> 
>
Markus Armbruster Jan. 29, 2013, 9:45 a.m. UTC | #5
Dong Xu Wang <wdongxu@linux.vnet.ibm.com> writes:

> Markus Armbruster <armbru@redhat.com> writes:
>> Dong Xu Wang <wdongxu@linux.vnet.ibm.com> writes:
>> 
>>> Markus Armbruster <armbru@redhat.com> writes:
>>>> Dong Xu Wang <wdongxu@vnet.linux.ibm.com> writes:
[...]
>>>>> @@ -264,17 +264,13 @@ 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 */
>>>>> +    if (opts) {
>>>>
>>>> I suspect you need the if (opts) here and in many other places only
>>>> because you special-cased "both lists empty" in append_opts_list().  I
>>>> suspect things become easier if you drop that.
>>>
>>> No, in this version, if(opt) is needed in "protocol", not needed in
>>> "format", I want to have the same code style, so I also judged if opts
>>> is NULL in "format" _create functions. Do you think is it acceptable?
>> 
>> I still don't get it.  Can you explain how opts can be null here even
>> when append_opts_list() is changed not to return null?
>> 
> I mean: When I use protocol, such as gluster:
> /usr/bin/qemu-img create -f qed -o cluster_size=65536
> gluster://kvm11/single-volume/12.qed 10M
>
> Then opts will be null:
> qemu_gluster_create (filename=0x555555c11930
> "gluster://kvm11/single-volume/12.qed", opts=0x0) at block/gluster.c:339
>
> So it checked if opts is NULL now:
> 352	    if (opts) {
> 353	        total_size =
> 354	            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) /
> BDRV_SECTOR_SIZE;
> 355	    }

I see.

> I want to make these code in only one kind of style, so I judged if opts
> is NULL in block format code.

As far as I can tell, there are just two sources of NULL
QEMUOptionParameter *:

1. parse_option_parameters() returns NULL on error (documented), but
   some callers use it like this without checking for errors:

       param = parse_option_parameters("", create_options, param);

   The only error that can happen then is null create_options.
   Depending on that is slightly unclean.

   Your patch replaces these uses by

       opts = qemu_opts_create_nofail(create_options);

   which cannot return NULL.  I'd call that an improvement.

2. qed_create() calls bdrv_create_file(filename, NULL), which passes on
   the null options to bdrv_create().  To get rid of this source, one of
   the two functions needs to create empty options.

Your patch adds a third source:

3. bdrv_img_create() merges drv->create_options and
   proto_drv->create_options (both possibly null) into create_options.
   Unlike the current code, your patch merges two empty lists into null.
   I don't think that's a wise change, and asked you to drop this
   special case in my review of PATCH 2/4.

[...]
Robert Wang Jan. 30, 2013, 5:50 a.m. UTC | #6
于 2013-1-29 17:45, Markus Armbruster 写道:
> Dong Xu Wang <wdongxu@linux.vnet.ibm.com> writes:
> 
>> Markus Armbruster <armbru@redhat.com> writes:
>>> Dong Xu Wang <wdongxu@linux.vnet.ibm.com> writes:
>>>
>>>> Markus Armbruster <armbru@redhat.com> writes:
>>>>> Dong Xu Wang <wdongxu@vnet.linux.ibm.com> writes:
> [...]
>>>>>> @@ -264,17 +264,13 @@ 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 */
>>>>>> +    if (opts) {
>>>>>
>>>>> I suspect you need the if (opts) here and in many other places only
>>>>> because you special-cased "both lists empty" in append_opts_list().  I
>>>>> suspect things become easier if you drop that.
>>>>
>>>> No, in this version, if(opt) is needed in "protocol", not needed in
>>>> "format", I want to have the same code style, so I also judged if opts
>>>> is NULL in "format" _create functions. Do you think is it acceptable?
>>>
>>> I still don't get it.  Can you explain how opts can be null here even
>>> when append_opts_list() is changed not to return null?
>>>
>> I mean: When I use protocol, such as gluster:
>> /usr/bin/qemu-img create -f qed -o cluster_size=65536
>> gluster://kvm11/single-volume/12.qed 10M
>>
>> Then opts will be null:
>> qemu_gluster_create (filename=0x555555c11930
>> "gluster://kvm11/single-volume/12.qed", opts=0x0) at block/gluster.c:339
>>
>> So it checked if opts is NULL now:
>> 352	    if (opts) {
>> 353	        total_size =
>> 354	            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) /
>> BDRV_SECTOR_SIZE;
>> 355	    }
> 
> I see.
> 
>> I want to make these code in only one kind of style, so I judged if opts
>> is NULL in block format code.
> 
> As far as I can tell, there are just two sources of NULL
> QEMUOptionParameter *:
> 
> 1. parse_option_parameters() returns NULL on error (documented), but
>     some callers use it like this without checking for errors:
> 
>         param = parse_option_parameters("", create_options, param);
> 
>     The only error that can happen then is null create_options.
>     Depending on that is slightly unclean.
> 
>     Your patch replaces these uses by
> 
>         opts = qemu_opts_create_nofail(create_options);
> 
>     which cannot return NULL.  I'd call that an improvement.
> 
> 2. qed_create() calls bdrv_create_file(filename, NULL), which passes on
>     the null options to bdrv_create().  To get rid of this source, one of
>     the two functions needs to create empty options.
> 
> Your patch adds a third source:
> 
> 3. bdrv_img_create() merges drv->create_options and
>     proto_drv->create_options (both possibly null) into create_options.
>     Unlike the current code, your patch merges two empty lists into null.
>     I don't think that's a wise change, and asked you to drop this
>     special case in my review of PATCH 2/4.
> 
> [...]

Got it, thank you Markus, I will consider your comments in next version.
> 
> 
>
diff mbox

Patch

diff --git a/block.c b/block.c
index 6fa7c90..56e4613 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)
 {
     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,
         .ret = NOT_DONE,
     };
 
@@ -405,7 +405,7 @@  out:
     return ret;
 }
 
-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);
 }
 
 /*
@@ -794,7 +794,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
@@ -827,17 +827,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_options);
 
-        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;
         }
@@ -4493,8 +4492,10 @@  void bdrv_img_create(const char *filename, const char *fmt,
                      const char *base_filename, const char *base_fmt,
                      char *options, uint64_t img_size, int flags, Error **errp)
 {
-    QEMUOptionParameter *param = NULL, *create_options = NULL;
-    QEMUOptionParameter *backing_fmt, *backing_file, *size;
+    QemuOpts *opts = NULL;
+    QemuOptsList *create_options = NULL;
+    const char *backing_fmt, *backing_file;
+    int64_t size;
     BlockDriverState *bs = NULL;
     BlockDriver *drv, *proto_drv;
     BlockDriver *backing_drv = NULL;
@@ -4512,28 +4513,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_options = append_opts_list(drv->bdrv_create_options,
+                                      proto_drv->bdrv_create_options);
     /* Create parameter list with default values */
-    param = parse_option_parameters("", create_options, param);
+    opts = qemu_opts_create_nofail(create_options);
 
-    set_option_parameter_int(param, BLOCK_OPT_SIZE, img_size);
+    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, img_size);
 
     /* Parse -o options */
     if (options) {
-        param = parse_option_parameters(options, create_options, param);
-        if (param == NULL) {
+        if (qemu_opts_do_parse(opts, options, NULL) != 0) {
             error_setg(errp, "Invalid options for file format '%s'.", fmt);
             goto out;
         }
     }
 
     if (base_filename) {
-        if (set_option_parameter(param, BLOCK_OPT_BACKING_FILE,
+        if (qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE,
                                  base_filename)) {
             error_setg(errp, "Backing file not supported for file format '%s'",
                        fmt);
@@ -4542,39 +4538,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_set(opts, BLOCK_OPT_BACKING_FMT, base_fmt)) {
             error_setg(errp, "Backing file format not supported for file "
                              "format '%s'", fmt);
             goto out;
         }
     }
 
-    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_number(opts, BLOCK_OPT_SIZE, -1);
+    if (size == -1) {
+        if (backing_file) {
             uint64_t size;
-            char buf[32];
             int back_flags;
 
             /* backing files always opened read-only */
@@ -4583,17 +4577,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);
         } else {
             error_setg(errp, "Image creation needs a size parameter");
             goto out;
@@ -4601,10 +4594,10 @@  void bdrv_img_create(const char *filename, const char *fmt,
     }
 
     printf("Formatting '%s', fmt=%s ", filename, fmt);
-    print_option_parameters(param);
+    qemu_opts_print(opts, NULL);
     puts("");
 
-    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 "
@@ -4619,8 +4612,10 @@  void bdrv_img_create(const char *filename, const char *fmt,
     }
 
 out:
-    free_option_parameters(create_options);
-    free_option_parameters(param);
+    free_opts_list(create_options);
+    if (opts) {
+        qemu_opts_del(opts);
+    }
 
     if (bs) {
         bdrv_delete(bs);
diff --git a/block/cow.c b/block/cow.c
index a33ce95..5442c9c 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,13 @@  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 */
+    if (opts) {
+        image_sectors = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
+        image_filename = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
     }
 
-    ret = bdrv_create_file(filename, options);
+    ret = bdrv_create_file(filename, opts);
     if (ret < 0) {
         return ret;
     }
@@ -318,18 +314,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_NUMBER,
+            .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 +345,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_options    = &cow_create_opts,
 };
 
 static void bdrv_cow_init(void)
diff --git a/block/gluster.c b/block/gluster.c
index 0f2c32a..a41c684 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -335,8 +335,7 @@  out:
     return ret;
 }
 
-static int qemu_gluster_create(const char *filename,
-        QEMUOptionParameter *options)
+static int qemu_gluster_create(const char *filename, QemuOpts* opts)
 {
     struct glfs *glfs;
     struct glfs_fd *fd;
@@ -350,11 +349,9 @@  static int qemu_gluster_create(const char *filename,
         goto out;
     }
 
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            total_size = options->value.n / BDRV_SECTOR_SIZE;
-        }
-        options++;
+    if (opts) {
+        total_size =
+            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
     }
 
     fd = glfs_creat(glfs, gconf->image,
@@ -544,13 +541,17 @@  static void qemu_gluster_close(BlockDriverState *bs)
     glfs_fini(s->glfs);
 }
 
-static QEMUOptionParameter qemu_gluster_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
-    { NULL }
+static QemuOptsList qemu_gluster_create_opts = {
+    .name = "qemu-gluster-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(qemu_gluster_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        { /* end of list */ }
+    }
 };
 
 static BlockDriver bdrv_gluster = {
@@ -565,7 +566,7 @@  static BlockDriver bdrv_gluster = {
     .bdrv_aio_readv               = qemu_gluster_aio_readv,
     .bdrv_aio_writev              = qemu_gluster_aio_writev,
     .bdrv_aio_flush               = qemu_gluster_aio_flush,
-    .create_options               = qemu_gluster_create_options,
+    .bdrv_create_options          = &qemu_gluster_create_opts,
 };
 
 static BlockDriver bdrv_gluster_tcp = {
@@ -580,7 +581,7 @@  static BlockDriver bdrv_gluster_tcp = {
     .bdrv_aio_readv               = qemu_gluster_aio_readv,
     .bdrv_aio_writev              = qemu_gluster_aio_writev,
     .bdrv_aio_flush               = qemu_gluster_aio_flush,
-    .create_options               = qemu_gluster_create_options,
+    .bdrv_create_options          = &qemu_gluster_create_opts,
 };
 
 static BlockDriver bdrv_gluster_unix = {
@@ -595,7 +596,7 @@  static BlockDriver bdrv_gluster_unix = {
     .bdrv_aio_readv               = qemu_gluster_aio_readv,
     .bdrv_aio_writev              = qemu_gluster_aio_writev,
     .bdrv_aio_flush               = qemu_gluster_aio_flush,
-    .create_options               = qemu_gluster_create_options,
+    .bdrv_create_options          = &qemu_gluster_create_opts,
 };
 
 static BlockDriver bdrv_gluster_rdma = {
@@ -610,7 +611,7 @@  static BlockDriver bdrv_gluster_rdma = {
     .bdrv_aio_readv               = qemu_gluster_aio_readv,
     .bdrv_aio_writev              = qemu_gluster_aio_writev,
     .bdrv_aio_flush               = qemu_gluster_aio_flush,
-    .create_options               = qemu_gluster_create_options,
+    .bdrv_create_options          = &qemu_gluster_create_opts,
 };
 
 static void bdrv_gluster_init(void)
diff --git a/block/qcow.c b/block/qcow.c
index 4276610..4691a3e 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -651,7 +651,7 @@  static void qcow_close(BlockDriverState *bs)
     error_free(s->migration_blocker);
 }
 
-static int qcow_create(const char *filename, QEMUOptionParameter *options)
+static int qcow_create(const char *filename, QemuOpts *opts)
 {
     int header_size, backing_filename_len, l1_size, shift, i;
     QCowHeader header;
@@ -662,19 +662,16 @@  static int qcow_create(const char *filename, QEMUOptionParameter *options)
     int ret;
     BlockDriverState *qcow_bs;
 
-    /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            total_size = options->value.n / 512;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
-            backing_file = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
-            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
+    /* Read out opts */
+    if (opts) {
+        total_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
+        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
+        if (qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, 0)) {
+            flags |= BLOCK_FLAG_ENCRYPT;
         }
-        options++;
     }
 
-    ret = bdrv_create_file(filename, options);
+    ret = bdrv_create_file(filename, opts);
     if (ret < 0) {
         return ret;
     }
@@ -851,24 +848,27 @@  static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
     return 0;
 }
 
-
-static QEMUOptionParameter qcow_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"
-    },
-    {
-        .name = BLOCK_OPT_ENCRYPT,
-        .type = OPT_FLAG,
-        .help = "Encrypt the image"
-    },
-    { NULL }
+static QemuOptsList qcow_create_opts = {
+    .name = "qcow-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(qcow_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        {
+            .name = BLOCK_OPT_BACKING_FILE,
+            .type = QEMU_OPT_STRING,
+            .help = "File name of a base image"
+        },
+        {
+            .name = BLOCK_OPT_ENCRYPT,
+            .type = QEMU_OPT_BOOL,
+            .help = "Encrypt the image"
+        },
+        { /* end of list */ }
+    }
 };
 
 static BlockDriver bdrv_qcow = {
@@ -889,7 +889,7 @@  static BlockDriver bdrv_qcow = {
     .bdrv_write_compressed  = qcow_write_compressed,
     .bdrv_get_info          = qcow_get_info,
 
-    .create_options = qcow_create_options,
+    .bdrv_create_options    = &qcow_create_opts,
 };
 
 static void bdrv_qcow_init(void)
diff --git a/block/qcow2.c b/block/qcow2.c
index f6abff6..e3ee4af 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -1177,7 +1177,7 @@  static int preallocate(BlockDriverState *bs)
 static int qcow2_create2(const char *filename, int64_t total_size,
                          const char *backing_file, const char *backing_format,
                          int flags, size_t cluster_size, int prealloc,
-                         QEMUOptionParameter *options, int version)
+                         QemuOpts *opts, int version)
 {
     /* Calculate cluster_bits */
     int cluster_bits;
@@ -1208,7 +1208,7 @@  static int qcow2_create2(const char *filename, int64_t total_size,
     uint8_t* refcount_table;
     int ret;
 
-    ret = bdrv_create_file(filename, options);
+    ret = bdrv_create_file(filename, opts);
     if (ret < 0) {
         return ret;
     }
@@ -1311,7 +1311,7 @@  out:
     return ret;
 }
 
-static int qcow2_create(const char *filename, QEMUOptionParameter *options)
+static int qcow2_create(const char *filename, QemuOpts *opts)
 {
     const char *backing_file = NULL;
     const char *backing_fmt = NULL;
@@ -1320,45 +1320,43 @@  static int qcow2_create(const char *filename, QEMUOptionParameter *options)
     size_t cluster_size = DEFAULT_CLUSTER_SIZE;
     int prealloc = 0;
     int version = 2;
+    const char *buf;
 
     /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            sectors = options->value.n / 512;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
-            backing_file = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
-            backing_fmt = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_ENCRYPT)) {
-            flags |= options->value.n ? BLOCK_FLAG_ENCRYPT : 0;
-        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
-            if (options->value.n) {
-                cluster_size = options->value.n;
-            }
-        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
-            if (!options->value.s || !strcmp(options->value.s, "off")) {
-                prealloc = 0;
-            } else if (!strcmp(options->value.s, "metadata")) {
-                prealloc = 1;
-            } else {
-                fprintf(stderr, "Invalid preallocation mode: '%s'\n",
-                    options->value.s);
-                return -EINVAL;
-            }
-        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT_LEVEL)) {
-            if (!options->value.s || !strcmp(options->value.s, "0.10")) {
-                version = 2;
-            } else if (!strcmp(options->value.s, "1.1")) {
-                version = 3;
-            } else {
-                fprintf(stderr, "Invalid compatibility level: '%s'\n",
-                    options->value.s);
-                return -EINVAL;
-            }
-        } else if (!strcmp(options->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
-            flags |= options->value.n ? BLOCK_FLAG_LAZY_REFCOUNTS : 0;
+    if (opts) {
+        sectors = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
+        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
+        backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
+        if (qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, 0)) {
+            flags |= BLOCK_FLAG_ENCRYPT;
+        }
+        cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE,
+                                         DEFAULT_CLUSTER_SIZE);
+        buf = qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
+        if (!buf || !strcmp(buf, "off")) {
+            prealloc = 0;
+        } else if (!strcmp(buf, "metadata")) {
+            prealloc = 1;
+        } else {
+            fprintf(stderr, "Invalid preallocation mode: '%s'\n",
+                buf);
+            return -EINVAL;
+        }
+
+        buf = qemu_opt_get(opts, BLOCK_OPT_COMPAT_LEVEL);
+        if (!buf || !strcmp(buf, "0.10")) {
+            version = 2;
+        } else if (!strcmp(buf, "1.1")) {
+            version = 3;
+        } else {
+            fprintf(stderr, "Invalid compatibility level: '%s'\n",
+                buf);
+            return -EINVAL;
+        }
+
+        if (qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS, 0)) {
+            flags |= BLOCK_FLAG_LAZY_REFCOUNTS;
         }
-        options++;
     }
 
     if (backing_file && prealloc) {
@@ -1374,7 +1372,7 @@  static int qcow2_create(const char *filename, QEMUOptionParameter *options)
     }
 
     return qcow2_create2(filename, sectors, backing_file, backing_fmt, flags,
-                         cluster_size, prealloc, options, version);
+                         cluster_size, prealloc, opts, version);
 }
 
 static int qcow2_make_empty(BlockDriverState *bs)
@@ -1635,49 +1633,53 @@  static int qcow2_load_vmstate(BlockDriverState *bs, uint8_t *buf,
     return ret;
 }
 
-static QEMUOptionParameter qcow2_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
-    {
-        .name = BLOCK_OPT_COMPAT_LEVEL,
-        .type = OPT_STRING,
-        .help = "Compatibility level (0.10 or 1.1)"
-    },
-    {
-        .name = BLOCK_OPT_BACKING_FILE,
-        .type = OPT_STRING,
-        .help = "File name of a base image"
-    },
-    {
-        .name = BLOCK_OPT_BACKING_FMT,
-        .type = OPT_STRING,
-        .help = "Image format of the base image"
-    },
-    {
-        .name = BLOCK_OPT_ENCRYPT,
-        .type = OPT_FLAG,
-        .help = "Encrypt the image"
-    },
-    {
-        .name = BLOCK_OPT_CLUSTER_SIZE,
-        .type = OPT_SIZE,
-        .help = "qcow2 cluster size",
-        .value = { .n = DEFAULT_CLUSTER_SIZE },
-    },
-    {
-        .name = BLOCK_OPT_PREALLOC,
-        .type = OPT_STRING,
-        .help = "Preallocation mode (allowed values: off, metadata)"
-    },
-    {
-        .name = BLOCK_OPT_LAZY_REFCOUNTS,
-        .type = OPT_FLAG,
-        .help = "Postpone refcount updates",
-    },
-    { NULL }
+static QemuOptsList qcow2_create_opts = {
+    .name = "qcow2-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(qcow2_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        {
+            .name = BLOCK_OPT_COMPAT_LEVEL,
+            .type = QEMU_OPT_STRING,
+            .help = "Compatibility level (0.10 or 1.1)"
+        },
+        {
+            .name = BLOCK_OPT_BACKING_FILE,
+            .type = QEMU_OPT_STRING,
+            .help = "File name of a base image"
+        },
+        {
+            .name = BLOCK_OPT_BACKING_FMT,
+            .type = QEMU_OPT_STRING,
+            .help = "Image format of the base image"
+        },
+        {
+            .name = BLOCK_OPT_ENCRYPT,
+            .type = QEMU_OPT_BOOL,
+            .help = "Encrypt the image"
+        },
+        {
+            .name = BLOCK_OPT_CLUSTER_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "qcow2 cluster size",
+            .def_value_str = stringify(DEFAULT_CLUSTER_SIZE)
+        },
+        {
+            .name = BLOCK_OPT_PREALLOC,
+            .type = QEMU_OPT_STRING,
+            .help = "Preallocation mode (allowed values: off, metadata)"
+        },
+        {
+            .name = BLOCK_OPT_LAZY_REFCOUNTS,
+            .type = QEMU_OPT_BOOL,
+            .help = "Postpone refcount updates",
+        },
+        { /* end of list */ }
+    }
 };
 
 static BlockDriver bdrv_qcow2 = {
@@ -1715,8 +1717,9 @@  static BlockDriver bdrv_qcow2 = {
 
     .bdrv_invalidate_cache      = qcow2_invalidate_cache,
 
-    .create_options = qcow2_create_options,
     .bdrv_check = qcow2_check,
+
+    .bdrv_create_options    = &qcow2_create_opts,
 };
 
 static void bdrv_qcow2_init(void)
diff --git a/block/qed.c b/block/qed.c
index cf85d8f..766ba6f 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -603,7 +603,7 @@  out:
     return ret;
 }
 
-static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
+static int bdrv_qed_create(const char *filename, QemuOpts *opts)
 {
     uint64_t image_size = 0;
     uint32_t cluster_size = QED_DEFAULT_CLUSTER_SIZE;
@@ -611,23 +611,15 @@  static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options)
     const char *backing_file = NULL;
     const char *backing_fmt = NULL;
 
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            image_size = options->value.n;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
-            backing_file = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FMT)) {
-            backing_fmt = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
-            if (options->value.n) {
-                cluster_size = options->value.n;
-            }
-        } else if (!strcmp(options->name, BLOCK_OPT_TABLE_SIZE)) {
-            if (options->value.n) {
-                table_size = options->value.n;
-            }
-        }
-        options++;
+    if (opts) {
+        image_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
+        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
+        backing_fmt = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
+        cluster_size = qemu_opt_get_size(opts,
+                                         BLOCK_OPT_CLUSTER_SIZE,
+                                         QED_DEFAULT_CLUSTER_SIZE);
+        table_size = qemu_opt_get_size(opts, BLOCK_OPT_TABLE_SIZE,
+                                       QED_DEFAULT_TABLE_SIZE);
     }
 
     if (!qed_is_cluster_size_valid(cluster_size)) {
@@ -1537,36 +1529,44 @@  static int bdrv_qed_check(BlockDriverState *bs, BdrvCheckResult *result,
     return qed_check(s, result, !!fix);
 }
 
-static QEMUOptionParameter qed_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size (in bytes)"
-    }, {
-        .name = BLOCK_OPT_BACKING_FILE,
-        .type = OPT_STRING,
-        .help = "File name of a base image"
-    }, {
-        .name = BLOCK_OPT_BACKING_FMT,
-        .type = OPT_STRING,
-        .help = "Image format of the base image"
-    }, {
-        .name = BLOCK_OPT_CLUSTER_SIZE,
-        .type = OPT_SIZE,
-        .help = "Cluster size (in bytes)",
-        .value = { .n = QED_DEFAULT_CLUSTER_SIZE },
-    }, {
-        .name = BLOCK_OPT_TABLE_SIZE,
-        .type = OPT_SIZE,
-        .help = "L1/L2 table size (in clusters)"
-    },
-    { /* end of list */ }
+static QemuOptsList qed_create_opts = {
+    .name = "qed-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(qed_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        {
+            .name = BLOCK_OPT_BACKING_FILE,
+            .type = QEMU_OPT_STRING,
+            .help = "File name of a base image"
+        },
+        {
+            .name = BLOCK_OPT_BACKING_FMT,
+            .type = QEMU_OPT_STRING,
+            .help = "Image format of the base image"
+        },
+        {
+            .name = BLOCK_OPT_CLUSTER_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Cluster size (in bytes)",
+            .def_value_str = stringify(QED_DEFAULT_CLUSTER_SIZE),
+        },
+        {
+            .name = BLOCK_OPT_TABLE_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "L1/L2 table size (in clusters)"
+        },
+        { /* end of list */ }
+    }
 };
 
 static BlockDriver bdrv_qed = {
     .format_name              = "qed",
     .instance_size            = sizeof(BDRVQEDState),
-    .create_options           = qed_create_options,
+    .bdrv_create_options      = &qed_create_opts,
 
     .bdrv_probe               = bdrv_qed_probe,
     .bdrv_rebind              = bdrv_qed_rebind,
diff --git a/block/qed.h b/block/qed.h
index 2b4dded..99a7726 100644
--- a/block/qed.h
+++ b/block/qed.h
@@ -43,6 +43,7 @@ 
  *
  * All fields are little-endian on disk.
  */
+#define  QED_DEFAULT_CLUSTER_SIZE  65536
 
 enum {
     QED_MAGIC = 'Q' | 'E' << 8 | 'D' << 16 | '\0' << 24,
@@ -69,7 +70,6 @@  enum {
      */
     QED_MIN_CLUSTER_SIZE = 4 * 1024, /* in bytes */
     QED_MAX_CLUSTER_SIZE = 64 * 1024 * 1024,
-    QED_DEFAULT_CLUSTER_SIZE = 64 * 1024,
 
     /* Allocated clusters are tracked using a 2-level pagetable.  Table size is
      * a multiple of clusters so large maximum image sizes can be supported
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 657af95..890c8a7 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -123,6 +123,19 @@ 
 
 #define MAX_BLOCKSIZE	4096
 
+static QemuOptsList file_proto_create_opts = {
+    .name = "file-proto-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(file_proto_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Virtual disk size"
+        },
+        { /* end of list */ }
+    }
+};
+
 typedef struct BDRVRawState {
     int fd;
     int type;
@@ -997,18 +1010,15 @@  static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
     return (int64_t)st.st_blocks * 512;
 }
 
-static int raw_create(const char *filename, QEMUOptionParameter *options)
+static int raw_create(const char *filename, QemuOpts *opts)
 {
     int fd;
     int result = 0;
     int64_t total_size = 0;
 
-    /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            total_size = options->value.n / BDRV_SECTOR_SIZE;
-        }
-        options++;
+    if (opts) {
+        total_size =
+            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
     }
 
     fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
@@ -1136,15 +1146,6 @@  static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs,
                        cb, opaque, QEMU_AIO_DISCARD);
 }
 
-static QEMUOptionParameter raw_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
-    { NULL }
-};
-
 static BlockDriver bdrv_file = {
     .format_name = "file",
     .protocol_name = "file",
@@ -1167,8 +1168,7 @@  static BlockDriver bdrv_file = {
     .bdrv_getlength = raw_getlength,
     .bdrv_get_allocated_file_size
                         = raw_get_allocated_file_size,
-
-    .create_options = raw_create_options,
+    .bdrv_create_options = &file_proto_create_opts,
 };
 
 /***********************************************/
@@ -1403,19 +1403,16 @@  static coroutine_fn BlockDriverAIOCB *hdev_aio_discard(BlockDriverState *bs,
                        cb, opaque, QEMU_AIO_DISCARD|QEMU_AIO_BLKDEV);
 }
 
-static int hdev_create(const char *filename, QEMUOptionParameter *options)
+static int hdev_create(const char *filename, QemuOpts *opts)
 {
     int fd;
     int ret = 0;
     struct stat stat_buf;
     int64_t total_size = 0;
 
-    /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, "size")) {
-            total_size = options->value.n / BDRV_SECTOR_SIZE;
-        }
-        options++;
+    if (opts) {
+        total_size =
+            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / BDRV_SECTOR_SIZE;
     }
 
     fd = qemu_open(filename, O_WRONLY | O_BINARY);
@@ -1440,7 +1437,7 @@  static int hdev_has_zero_init(BlockDriverState *bs)
 
 static BlockDriver bdrv_host_device = {
     .format_name        = "host_device",
-    .protocol_name        = "host_device",
+    .protocol_name      = "host_device",
     .instance_size      = sizeof(BDRVRawState),
     .bdrv_probe_device  = hdev_probe_device,
     .bdrv_file_open     = hdev_open,
@@ -1449,7 +1446,6 @@  static BlockDriver bdrv_host_device = {
     .bdrv_reopen_commit  = raw_reopen_commit,
     .bdrv_reopen_abort   = raw_reopen_abort,
     .bdrv_create        = hdev_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
     .bdrv_aio_readv	= raw_aio_readv,
@@ -1458,9 +1454,10 @@  static BlockDriver bdrv_host_device = {
     .bdrv_aio_discard   = hdev_aio_discard,
 
     .bdrv_truncate      = raw_truncate,
-    .bdrv_getlength	= raw_getlength,
+    .bdrv_getlength     = raw_getlength,
     .bdrv_get_allocated_file_size
                         = raw_get_allocated_file_size,
+    .bdrv_create_options = &file_proto_create_opts,
 
     /* generic scsi device */
 #ifdef __linux__
@@ -1574,7 +1571,6 @@  static BlockDriver bdrv_host_floppy = {
     .bdrv_reopen_commit  = raw_reopen_commit,
     .bdrv_reopen_abort   = raw_reopen_abort,
     .bdrv_create        = hdev_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
     .bdrv_aio_readv     = raw_aio_readv,
@@ -1590,6 +1586,7 @@  static BlockDriver bdrv_host_floppy = {
     .bdrv_is_inserted   = floppy_is_inserted,
     .bdrv_media_changed = floppy_media_changed,
     .bdrv_eject         = floppy_eject,
+    .bdrv_create_options = &file_proto_create_opts,
 };
 
 static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
@@ -1676,7 +1673,6 @@  static BlockDriver bdrv_host_cdrom = {
     .bdrv_reopen_commit  = raw_reopen_commit,
     .bdrv_reopen_abort   = raw_reopen_abort,
     .bdrv_create        = hdev_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
     .bdrv_aio_readv     = raw_aio_readv,
@@ -1696,6 +1692,8 @@  static BlockDriver bdrv_host_cdrom = {
     /* generic scsi device */
     .bdrv_ioctl         = hdev_ioctl,
     .bdrv_aio_ioctl     = hdev_aio_ioctl,
+
+    .bdrv_create_options = &file_proto_create_opts,
 };
 #endif /* __linux__ */
 
@@ -1798,7 +1796,6 @@  static BlockDriver bdrv_host_cdrom = {
     .bdrv_reopen_commit  = raw_reopen_commit,
     .bdrv_reopen_abort   = raw_reopen_abort,
     .bdrv_create        = hdev_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = hdev_has_zero_init,
 
     .bdrv_aio_readv     = raw_aio_readv,
diff --git a/block/raw-win32.c b/block/raw-win32.c
index b89ac19..34826e0 100644
--- a/block/raw-win32.c
+++ b/block/raw-win32.c
@@ -382,17 +382,15 @@  static int64_t raw_get_allocated_file_size(BlockDriverState *bs)
     return st.st_size;
 }
 
-static int raw_create(const char *filename, QEMUOptionParameter *options)
+static int raw_create(const char *filename, QemuOpts *opts)
 {
     int fd;
     int64_t total_size = 0;
 
     /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            total_size = options->value.n / 512;
-        }
-        options++;
+    if (opts) {
+        total_size =
+            qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0) / 512;
     }
 
     fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
@@ -405,13 +403,17 @@  static int raw_create(const char *filename, QEMUOptionParameter *options)
     return 0;
 }
 
-static QEMUOptionParameter raw_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
-    { NULL }
+static QemuOptsList raw_create_opts = {
+    .name = "raw-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        { /* end of list */ }
+    }
 };
 
 static BlockDriver bdrv_file = {
@@ -431,7 +433,7 @@  static BlockDriver bdrv_file = {
     .bdrv_get_allocated_file_size
                         = raw_get_allocated_file_size,
 
-    .create_options = raw_create_options,
+    .bdrv_create_options = &raw_create_opts,
 };
 
 /***********************************************/
diff --git a/block/raw.c b/block/raw.c
index 75812db..033ffa6 100644
--- a/block/raw.c
+++ b/block/raw.c
@@ -95,18 +95,22 @@  static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
    return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque);
 }
 
-static int raw_create(const char *filename, QEMUOptionParameter *options)
-{
-    return bdrv_create_file(filename, options);
-}
-
-static QEMUOptionParameter raw_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
-    { NULL }
+static int raw_create(const char *filename, QemuOpts *opts)
+{
+    return bdrv_create_file(filename, opts);
+}
+
+static QemuOptsList raw_create_opts = {
+    .name = "raw-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(raw_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        { /* end of list */ }
+    }
 };
 
 static int raw_has_zero_init(BlockDriverState *bs)
@@ -143,8 +147,8 @@  static BlockDriver bdrv_raw = {
     .bdrv_aio_ioctl     = raw_aio_ioctl,
 
     .bdrv_create        = raw_create,
-    .create_options     = raw_create_options,
     .bdrv_has_zero_init = raw_has_zero_init,
+    .bdrv_create_options = &raw_create_opts,
 };
 
 static void bdrv_raw_init(void)
diff --git a/block/rbd.c b/block/rbd.c
index 8cd10a7..a9f8772 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -287,7 +287,7 @@  static int qemu_rbd_set_conf(rados_t cluster, const char *conf)
     return ret;
 }
 
-static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
+static int qemu_rbd_create(const char *filename, QemuOpts *opts)
 {
     int64_t bytes = 0;
     int64_t objsize;
@@ -310,24 +310,20 @@  static int qemu_rbd_create(const char *filename, QEMUOptionParameter *options)
     }
 
     /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            bytes = options->value.n;
-        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
-            if (options->value.n) {
-                objsize = options->value.n;
-                if ((objsize - 1) & objsize) {    /* not a power of 2? */
-                    error_report("obj size needs to be power of 2");
-                    return -EINVAL;
-                }
-                if (objsize < 4096) {
-                    error_report("obj size too small");
-                    return -EINVAL;
-                }
-                obj_order = ffs(objsize) - 1;
+    if (opts) {
+        bytes = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
+        objsize = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE, 0);
+        if (objsize) {
+            if ((objsize - 1) & objsize) {    /* not a power of 2? */
+                error_report("obj size needs to be power of 2");
+                return -EINVAL;
             }
+            if (objsize < 4096) {
+                error_report("obj size too small");
+                return -EINVAL;
+            }
+            obj_order = ffs(objsize) - 1;
         }
-        options++;
     }
 
     clientname = qemu_rbd_parse_clientname(conf, clientname_buf);
@@ -920,20 +916,24 @@  static BlockDriverAIOCB* qemu_rbd_aio_discard(BlockDriverState *bs,
 }
 #endif
 
-static QEMUOptionParameter qemu_rbd_create_options[] = {
-    {
-     .name = BLOCK_OPT_SIZE,
-     .type = OPT_SIZE,
-     .help = "Virtual disk size"
-    },
-    {
-     .name = BLOCK_OPT_CLUSTER_SIZE,
-     .type = OPT_SIZE,
-     .help = "RBD object size"
-    },
-    {NULL}
+static QemuOptsList rbd_create_opts = {
+    .name = "rbd-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(rbd_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        {
+            .name = BLOCK_OPT_CLUSTER_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "RBD object size",
+            .def_value_str = stringify(0),
+        },
+        { /* end of list */ }
+    }
 };
-
 static BlockDriver bdrv_rbd = {
     .format_name        = "rbd",
     .instance_size      = sizeof(BDRVRBDState),
@@ -941,7 +941,7 @@  static BlockDriver bdrv_rbd = {
     .bdrv_close         = qemu_rbd_close,
     .bdrv_create        = qemu_rbd_create,
     .bdrv_get_info      = qemu_rbd_getinfo,
-    .create_options     = qemu_rbd_create_options,
+    .bdrv_create_options = &rbd_create_opts,
     .bdrv_getlength     = qemu_rbd_getlength,
     .bdrv_truncate      = qemu_rbd_truncate,
     .protocol_name      = "rbd",
diff --git a/block/sheepdog.c b/block/sheepdog.c
index 3e49bb8..d515e56 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -1274,12 +1274,12 @@  out:
     return ret;
 }
 
-static int sd_create(const char *filename, QEMUOptionParameter *options)
+static int sd_create(const char *filename, QemuOpts *opts)
 {
     int ret = 0;
     uint32_t vid = 0, base_vid = 0;
     int64_t vdi_size = 0;
-    char *backing_file = NULL;
+    const char *backing_file = NULL, *buf = NULL;
     BDRVSheepdogState *s;
     char vdi[SD_MAX_VDI_LEN], tag[SD_MAX_VDI_TAG_LEN];
     uint32_t snapid;
@@ -1298,26 +1298,20 @@  static int sd_create(const char *filename, QEMUOptionParameter *options)
         goto out;
     }
 
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            vdi_size = options->value.n;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
-            backing_file = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_PREALLOC)) {
-            if (!options->value.s || !strcmp(options->value.s, "off")) {
-                prealloc = false;
-            } else if (!strcmp(options->value.s, "full")) {
-                prealloc = true;
-            } else {
-                error_report("Invalid preallocation mode: '%s'",
-                             options->value.s);
-                ret = -EINVAL;
-                goto out;
-            }
+    if (opts) {
+        vdi_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
+        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
+        buf = qemu_opt_get(opts, BLOCK_OPT_PREALLOC);
+        if (!buf || !strcmp(buf, "off")) {
+            prealloc = false;
+        } else if (!strcmp(buf, "full")) {
+            prealloc = true;
+        } else {
+            error_report("Invalid preallocation mode: '%s'", buf);
+            ret = -EINVAL;
+            goto out;
         }
-        options++;
     }
-
     if (vdi_size > SD_MAX_VDI_SIZE) {
         error_report("too big image size");
         ret = -EINVAL;
@@ -2042,24 +2036,27 @@  static int sd_load_vmstate(BlockDriverState *bs, uint8_t *data,
     return do_load_save_vmstate(s, data, pos, size, 1);
 }
 
-
-static QEMUOptionParameter sd_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"
-    },
-    {
-        .name = BLOCK_OPT_PREALLOC,
-        .type = OPT_STRING,
-        .help = "Preallocation mode (allowed values: off, full)"
-    },
-    { NULL }
+static QemuOptsList sd_create_opts = {
+    .name = "sheepdog-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(sd_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        {
+            .name = BLOCK_OPT_BACKING_FILE,
+            .type = QEMU_OPT_STRING,
+            .help = "File name of a base image"
+        },
+        {
+            .name = BLOCK_OPT_PREALLOC,
+            .type = QEMU_OPT_STRING,
+            .help = "Preallocation mode (allowed values: off, full)"
+        },
+        { /* end of list */ }
+    }
 };
 
 BlockDriver bdrv_sheepdog = {
@@ -2084,7 +2081,7 @@  BlockDriver bdrv_sheepdog = {
     .bdrv_save_vmstate  = sd_save_vmstate,
     .bdrv_load_vmstate  = sd_load_vmstate,
 
-    .create_options = sd_create_options,
+    .bdrv_create_options = &sd_create_opts,
 };
 
 static void bdrv_sheepdog_init(void)
diff --git a/block/vdi.c b/block/vdi.c
index 021abaa..95f738e 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -620,7 +620,7 @@  static int vdi_co_write(BlockDriverState *bs,
     return ret;
 }
 
-static int vdi_create(const char *filename, QEMUOptionParameter *options)
+static int vdi_create(const char *filename, QemuOpts *opts)
 {
     int fd;
     int result = 0;
@@ -635,24 +635,19 @@  static int vdi_create(const char *filename, QEMUOptionParameter *options)
     logout("\n");
 
     /* Read out options. */
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            bytes = options->value.n;
+    if (opts) {
+        bytes = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
 #if defined(CONFIG_VDI_BLOCK_SIZE)
-        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
-            if (options->value.n) {
-                /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
-                block_size = options->value.n;
-            }
+        /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
+        block_size = qemu_opt_get_size(opts,
+                                       BLOCK_OPT_CLUSTER_SIZE,
+                                       DEFAULT_CLUSTER_SIZE);
 #endif
 #if defined(CONFIG_VDI_STATIC_IMAGE)
-        } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
-            if (options->value.n) {
-                image_type = VDI_TYPE_STATIC;
-            }
-#endif
+        if (qemu_opt_get_bool(opts, BLOCK_OPT_STATIC, 0)) {
+            image_type = VDI_TYPE_STATIC;
         }
-        options++;
+#endif
     }
 
     fd = qemu_open(filename,
@@ -733,29 +728,33 @@  static void vdi_close(BlockDriverState *bs)
     error_free(s->migration_blocker);
 }
 
-static QEMUOptionParameter vdi_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
+static QemuOptsList vdi_create_opts = {
+    .name = "vdi-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(vdi_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
 #if defined(CONFIG_VDI_BLOCK_SIZE)
-    {
-        .name = BLOCK_OPT_CLUSTER_SIZE,
-        .type = OPT_SIZE,
-        .help = "VDI cluster (block) size",
-        .value = { .n = DEFAULT_CLUSTER_SIZE },
-    },
+        {
+            .name = BLOCK_OPT_CLUSTER_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "VDI cluster (block) size",
+            .def_value_str = stringify(DEFAULT_CLUSTER_SIZE)
+        },
 #endif
 #if defined(CONFIG_VDI_STATIC_IMAGE)
-    {
-        .name = BLOCK_OPT_STATIC,
-        .type = OPT_FLAG,
-        .help = "VDI static (pre-allocated) image"
-    },
+        {
+            .name = BLOCK_OPT_STATIC,
+            .type = QEMU_OPT_BOOL,
+            .help = "VDI static (pre-allocated) image"
+        },
 #endif
-    /* TODO: An additional option to set UUID values might be useful. */
-    { NULL }
+        /* TODO: An additional option to set UUID values might be useful. */
+        { /* end of list */ }
+    }
 };
 
 static BlockDriver bdrv_vdi = {
@@ -776,7 +775,7 @@  static BlockDriver bdrv_vdi = {
 
     .bdrv_get_info = vdi_get_info,
 
-    .create_options = vdi_create_options,
+    .bdrv_create_options = &vdi_create_opts,
     .bdrv_check = vdi_check,
 };
 
diff --git a/block/vmdk.c b/block/vmdk.c
index 19298c2..4c29927 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1437,7 +1437,7 @@  static int relative_path(char *dest, int dest_size,
     return 0;
 }
 
-static int vmdk_create(const char *filename, QEMUOptionParameter *options)
+static int vmdk_create(const char *filename, QemuOpts *opts)
 {
     int fd, idx = 0;
     char desc[BUF_SIZE];
@@ -1476,18 +1476,14 @@  static int vmdk_create(const char *filename, QEMUOptionParameter *options)
     if (filename_decompose(filename, path, prefix, postfix, PATH_MAX)) {
         return -EINVAL;
     }
-    /* Read out options */
-    while (options && options->name) {
-        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
-            total_size = options->value.n;
-        } else if (!strcmp(options->name, BLOCK_OPT_BACKING_FILE)) {
-            backing_file = options->value.s;
-        } else if (!strcmp(options->name, BLOCK_OPT_COMPAT6)) {
-            flags |= options->value.n ? BLOCK_FLAG_COMPAT6 : 0;
-        } else if (!strcmp(options->name, BLOCK_OPT_SUBFMT)) {
-            fmt = options->value.s;
+    /* Read out opts */
+    if (opts) {
+        total_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
+        backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
+        if (qemu_opt_get_bool(opts, BLOCK_OPT_COMPAT6, 0)) {
+            flags |= BLOCK_FLAG_COMPAT6;
         }
-        options++;
+        fmt = qemu_opt_get(opts, BLOCK_OPT_SUBFMT);
     }
     if (!fmt) {
         /* Default format to monolithicSparse */
@@ -1654,30 +1650,34 @@  static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs)
     return ret;
 }
 
-static QEMUOptionParameter vmdk_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"
-    },
-    {
-        .name = BLOCK_OPT_COMPAT6,
-        .type = OPT_FLAG,
-        .help = "VMDK version 6 image"
-    },
-    {
-        .name = BLOCK_OPT_SUBFMT,
-        .type = OPT_STRING,
-        .help =
-            "VMDK flat extent format, can be one of "
-            "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
-    },
-    { NULL }
+static QemuOptsList vmdk_create_opts = {
+    .name = "vmdk-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        {
+            .name = BLOCK_OPT_BACKING_FILE,
+            .type = QEMU_OPT_STRING,
+            .help = "File name of a base image"
+        },
+        {
+            .name = BLOCK_OPT_COMPAT6,
+            .type = QEMU_OPT_BOOL,
+            .help = "VMDK version 6 image"
+        },
+        {
+            .name = BLOCK_OPT_SUBFMT,
+            .type = QEMU_OPT_STRING,
+            .help =
+                "VMDK flat extent format, can be one of "
+                "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} "
+        },
+        { /* end of list */ }
+    }
 };
 
 static BlockDriver bdrv_vmdk = {
@@ -1694,7 +1694,7 @@  static BlockDriver bdrv_vmdk = {
     .bdrv_co_is_allocated   = vmdk_co_is_allocated,
     .bdrv_get_allocated_file_size  = vmdk_get_allocated_file_size,
 
-    .create_options = vmdk_create_options,
+    .bdrv_create_options = &vmdk_create_opts,
 };
 
 static void bdrv_vmdk_init(void)
diff --git a/block/vpc.c b/block/vpc.c
index 7948609..fcfdc79 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -665,34 +665,33 @@  static int create_fixed_disk(int fd, uint8_t *buf, int64_t total_size)
     return ret;
 }
 
-static int vpc_create(const char *filename, QEMUOptionParameter *options)
+static int vpc_create(const char *filename, QemuOpts *opts)
 {
     uint8_t buf[1024];
     struct vhd_footer *footer = (struct vhd_footer *) buf;
-    QEMUOptionParameter *disk_type_param;
+    const char *disk_type_param = NULL;
     int fd, i;
     uint16_t cyls = 0;
     uint8_t heads = 0;
     uint8_t secs_per_cyl = 0;
     int64_t total_sectors;
-    int64_t total_size;
-    int disk_type;
+    int64_t total_size = 0;
+    int disk_type = VHD_DYNAMIC;
     int ret = -EIO;
 
-    /* Read out options */
-    total_size = get_option_parameter(options, BLOCK_OPT_SIZE)->value.n;
-
-    disk_type_param = get_option_parameter(options, BLOCK_OPT_SUBFMT);
-    if (disk_type_param && disk_type_param->value.s) {
-        if (!strcmp(disk_type_param->value.s, "dynamic")) {
-            disk_type = VHD_DYNAMIC;
-        } else if (!strcmp(disk_type_param->value.s, "fixed")) {
-            disk_type = VHD_FIXED;
-        } else {
-            return -EINVAL;
+    /* Read out opts */
+    if (opts) {
+        total_size = qemu_opt_get_number(opts, BLOCK_OPT_SIZE, 0);
+        disk_type_param = qemu_opt_get(opts, BLOCK_OPT_SUBFMT);
+        if (disk_type_param) {
+            if (!strcmp(disk_type_param, "dynamic")) {
+                disk_type = VHD_DYNAMIC;
+            } else if (!strcmp(disk_type_param, "fixed")) {
+                disk_type = VHD_FIXED;
+            } else {
+                return -EINVAL;
+            }
         }
-    } else {
-        disk_type = VHD_DYNAMIC;
     }
 
     /* Create the file */
@@ -780,20 +779,24 @@  static void vpc_close(BlockDriverState *bs)
     error_free(s->migration_blocker);
 }
 
-static QEMUOptionParameter vpc_create_options[] = {
-    {
-        .name = BLOCK_OPT_SIZE,
-        .type = OPT_SIZE,
-        .help = "Virtual disk size"
-    },
-    {
-        .name = BLOCK_OPT_SUBFMT,
-        .type = OPT_STRING,
-        .help =
-            "Type of virtual hard disk format. Supported formats are "
-            "{dynamic (default) | fixed} "
-    },
-    { NULL }
+static QemuOptsList vpc_create_opts = {
+    .name = "vpc-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(vpc_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_NUMBER,
+            .help = "Virtual disk size"
+        },
+        {
+            .name = BLOCK_OPT_SUBFMT,
+            .type = OPT_STRING,
+            .help =
+                "Type of virtual hard disk format. Supported formats are "
+                "{dynamic (default) | fixed} "
+        },
+        { /* end of list */ }
+    }
 };
 
 static BlockDriver bdrv_vpc = {
@@ -809,7 +812,7 @@  static BlockDriver bdrv_vpc = {
     .bdrv_read              = vpc_co_read,
     .bdrv_write             = vpc_co_write,
 
-    .create_options = vpc_create_options,
+    .bdrv_create_options = &vpc_create_opts,
 };
 
 static void bdrv_vpc_init(void)
diff --git a/block/vvfat.c b/block/vvfat.c
index 06e6654..2343cd4 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -2802,7 +2802,7 @@  static BlockDriver vvfat_write_target = {
 static int enable_write_target(BDRVVVFATState *s)
 {
     BlockDriver *bdrv_qcow;
-    QEMUOptionParameter *options;
+    QemuOpts *opts;
     int ret;
     int size = sector2cluster(s, s->sector_count);
     s->used_clusters = calloc(size, 1);
@@ -2818,12 +2818,13 @@  static int enable_write_target(BDRVVVFATState *s)
     }
 
     bdrv_qcow = bdrv_find_format("qcow");
-    options = parse_option_parameters("", bdrv_qcow->create_options, NULL);
-    set_option_parameter_int(options, BLOCK_OPT_SIZE, s->sector_count * 512);
-    set_option_parameter(options, BLOCK_OPT_BACKING_FILE, "fat:");
+    opts = qemu_opts_create_nofail(bdrv_qcow->bdrv_create_options);
+    qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s->sector_count * 512);
+    qemu_opt_set(opts, BLOCK_OPT_BACKING_FILE, "fat:");
 
-    if (bdrv_create(bdrv_qcow, s->qcow_filename, options) < 0)
+    if (bdrv_create(bdrv_qcow, s->qcow_filename, opts) < 0) {
 	return -1;
+    }
 
     s->qcow = bdrv_new("");
     if (s->qcow == NULL) {
diff --git a/include/block/block.h b/include/block/block.h
index ffd1936..c99e8bf 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -124,8 +124,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);
 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 f83ffb8..71f7670 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -88,7 +88,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);
     int (*bdrv_set_key)(BlockDriverState *bs, const char *key);
     int (*bdrv_make_empty)(BlockDriverState *bs);
     /* aio */
@@ -177,9 +177,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_options;
 
     /*
      * Returns 0 for completed check, -errno for internal errors.
diff --git a/qemu-img.c b/qemu-img.c
index 85d3740..b4b3ce8 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -200,7 +200,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_options = NULL;
 
     /* Find driver and parse its options */
     drv = bdrv_find_format(fmt);
@@ -215,12 +215,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_options = append_opts_list(drv->bdrv_create_options,
+                                      proto_drv->bdrv_create_options);
+    print_opts_list(create_options);
+    free_opts_list(create_options);
     return 0;
 }
 
@@ -271,19 +269,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;
@@ -675,8 +673,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_options = NULL;
+    const char *out_baseimg_param;
     char *options = NULL;
     const char *snapshot_name = NULL;
     float local_progress = 0;
@@ -811,40 +810,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_options = append_opts_list(drv->bdrv_create_options,
+                                      proto_drv->bdrv_create_options);
 
     if (options) {
-        param = parse_option_parameters(options, create_options, param);
-        if (param == NULL) {
+        if (qemu_opts_do_parse(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_options);
     }
-
-    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;
     }
 
     /* 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");
@@ -852,15 +847,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");
@@ -1078,8 +1073,10 @@  static int img_convert(int argc, char **argv)
     }
 out:
     qemu_progress_end();
-    free_option_parameters(create_options);
-    free_option_parameters(param);
+    free_opts_list(create_options);
+    if (param) {
+        qemu_opts_del(param);
+    }
     qemu_vfree(buf);
     if (out_bs) {
         bdrv_delete(out_bs);