summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--block.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/block.c b/block.c
index f377158c42..c5b887cec1 100644
--- a/block.c
+++ b/block.c
@@ -670,14 +670,48 @@ out:
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
{
+ QemuOpts *protocol_opts;
BlockDriver *drv;
+ QDict *qdict;
+ int ret;
drv = bdrv_find_protocol(filename, true, errp);
if (drv == NULL) {
return -ENOENT;
}
- return bdrv_create(drv, filename, opts, errp);
+ if (!drv->create_opts) {
+ error_setg(errp, "Driver '%s' does not support image creation",
+ drv->format_name);
+ return -ENOTSUP;
+ }
+
+ /*
+ * 'opts' contains a QemuOptsList with a combination of format and protocol
+ * default values.
+ *
+ * The format properly removes its options, but the default values remain
+ * in 'opts->list'. So if the protocol has options with the same name
+ * (e.g. rbd has 'cluster_size' as qcow2), it will see the default values
+ * of the format, since for overlapping options, the format wins.
+ *
+ * To avoid this issue, lets convert QemuOpts to QDict, in this way we take
+ * only the set options, and then convert it back to QemuOpts, using the
+ * create_opts of the protocol. So the new QemuOpts, will contain only the
+ * protocol defaults.
+ */
+ qdict = qemu_opts_to_qdict(opts, NULL);
+ protocol_opts = qemu_opts_from_qdict(drv->create_opts, qdict, errp);
+ if (protocol_opts == NULL) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = bdrv_create(drv, filename, protocol_opts, errp);
+out:
+ qemu_opts_del(protocol_opts);
+ qobject_unref(qdict);
+ return ret;
}
int coroutine_fn bdrv_co_delete_file(BlockDriverState *bs, Error **errp)