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
---
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)),
.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