On Wed, Mar 15, 2017 at 11:30 AM Stefan Hajnoczi <stefa...@redhat.com> wrote:
> The image creation options parsed by qcow2_create() are also needed to > implement .bdrv_measure(). Extract the parsing code, including input > validation. > > Signed-off-by: Stefan Hajnoczi <stefa...@redhat.com> > --- > block/qcow2.c | 109 > +++++++++++++++++++++++++++++++++++++++------------------- > 1 file changed, 73 insertions(+), 36 deletions(-) > > diff --git a/block/qcow2.c b/block/qcow2.c > index 7c702f4..19be468 100644 > --- a/block/qcow2.c > +++ b/block/qcow2.c > @@ -2168,24 +2168,73 @@ static int64_t qcow2_calc_prealloc_size(int64_t > total_size, > return meta_size + aligned_total_size; > } > > -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, PreallocMode > prealloc, > - QemuOpts *opts, int version, int refcount_order, > - Error **errp) > +static size_t qcow2_opt_get_cluster_size_del(QemuOpts *opts, Error **errp) > { > + size_t cluster_size; > int cluster_bits; > - QDict *options; > > - /* Calculate cluster_bits */ > + cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, > + DEFAULT_CLUSTER_SIZE); > cluster_bits = ctz32(cluster_size); > if (cluster_bits < MIN_CLUSTER_BITS || cluster_bits > > MAX_CLUSTER_BITS || > (1 << cluster_bits) != cluster_size) > { > error_setg(errp, "Cluster size must be a power of two between %d > and " > "%dk", 1 << MIN_CLUSTER_BITS, 1 << (MAX_CLUSTER_BITS - > 10)); > - return -EINVAL; > + return 0; > } > + return cluster_size; > +} > + > +static int qcow2_opt_get_version_del(QemuOpts *opts, Error **errp) > +{ > + char *buf; > + int ret; > + > + buf = qemu_opt_get_del(opts, BLOCK_OPT_COMPAT_LEVEL); > + if (!buf) { > + ret = 3; /* default */ > + } else if (!strcmp(buf, "0.10")) { > + ret = 2; > + } else if (!strcmp(buf, "1.1")) { > + ret = 3; > + } else { > + error_setg(errp, "Invalid compatibility level: '%s'", buf); > + ret = -EINVAL; > + } > + g_free(buf); > + return ret; > +} > + > +static uint64_t qcow2_opt_get_refcount_bits_del(QemuOpts *opts, int > version, > + Error **errp) > +{ > + uint64_t refcount_bits; > + > + refcount_bits = qemu_opt_get_number_del(opts, > BLOCK_OPT_REFCOUNT_BITS, 16); > + if (refcount_bits > 64 || !is_power_of_2(refcount_bits)) { > + error_setg(errp, "Refcount width must be a power of two and may > not " > + "exceed 64 bits"); > + return 0; > + } > + > + if (version < 3 && refcount_bits != 16) { > + error_setg(errp, "Different refcount widths than 16 bits require " > + "compatibility level 1.1 or above (use compat=1.1 or " > + "greater)"); > + return 0; > + } > + > + return refcount_bits; > +} > + > +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, PreallocMode > prealloc, > + QemuOpts *opts, int version, int refcount_order, > + Error **errp) > +{ > + QDict *options; > > /* > * Open the image file and write a minimal qcow2 header. > @@ -2235,7 +2284,7 @@ static int qcow2_create2(const char *filename, > int64_t total_size, > *header = (QCowHeader) { > .magic = cpu_to_be32(QCOW_MAGIC), > .version = cpu_to_be32(version), > - .cluster_bits = cpu_to_be32(cluster_bits), > + .cluster_bits = cpu_to_be32(ctz32(cluster_size)), > Is this related? > .size = cpu_to_be64(0), > .l1_table_offset = cpu_to_be64(0), > .l1_size = cpu_to_be32(0), > @@ -2371,8 +2420,8 @@ static int qcow2_create(const char *filename, > QemuOpts *opts, Error **errp) > int flags = 0; > size_t cluster_size = DEFAULT_CLUSTER_SIZE; > PreallocMode prealloc; > - int version = 3; > - uint64_t refcount_bits = 16; > + int version; > + uint64_t refcount_bits; > int refcount_order; > Error *local_err = NULL; > int ret; > @@ -2385,8 +2434,12 @@ static int qcow2_create(const char *filename, > QemuOpts *opts, Error **errp) > if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ENCRYPT, false)) { > flags |= BLOCK_FLAG_ENCRYPT; > } > - cluster_size = qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, > - DEFAULT_CLUSTER_SIZE); > + cluster_size = qcow2_opt_get_cluster_size_del(opts, &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > + ret = -EINVAL; > + goto finish; > + } > buf = qemu_opt_get_del(opts, BLOCK_OPT_PREALLOC); > prealloc = qapi_enum_parse(PreallocMode_lookup, buf, > PREALLOC_MODE__MAX, PREALLOC_MODE_OFF, > @@ -2396,16 +2449,10 @@ static int qcow2_create(const char *filename, > QemuOpts *opts, Error **errp) > ret = -EINVAL; > goto finish; > } > - g_free(buf); > - buf = qemu_opt_get_del(opts, BLOCK_OPT_COMPAT_LEVEL); > - if (!buf) { > - /* keep the default */ > - } else if (!strcmp(buf, "0.10")) { > - version = 2; > - } else if (!strcmp(buf, "1.1")) { > - version = 3; > - } else { > - error_setg(errp, "Invalid compatibility level: '%s'", buf); > + > + version = qcow2_opt_get_version_del(opts, &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > ret = -EINVAL; > goto finish; > } > @@ -2428,19 +2475,9 @@ static int qcow2_create(const char *filename, > QemuOpts *opts, Error **errp) > goto finish; > } > > - refcount_bits = qemu_opt_get_number_del(opts, BLOCK_OPT_REFCOUNT_BITS, > - refcount_bits); > - if (refcount_bits > 64 || !is_power_of_2(refcount_bits)) { > - error_setg(errp, "Refcount width must be a power of two and may > not " > - "exceed 64 bits"); > - ret = -EINVAL; > - goto finish; > - } > - > - if (version < 3 && refcount_bits != 16) { > - error_setg(errp, "Different refcount widths than 16 bits require " > - "compatibility level 1.1 or above (use compat=1.1 or " > - "greater)"); > + refcount_bits = qcow2_opt_get_refcount_bits_del(opts, version, > &local_err); > + if (local_err) { > + error_propagate(errp, local_err); > ret = -EINVAL; > goto finish; > } > -- > 2.9.3 > Looks good