+static int coroutine_fn vdi_co_create(BlockdevCreateOptions *create_options,
+ Error **errp)
+{
+ return vdi_co_do_create(create_options, DEFAULT_CLUSTER_SIZE, errp);
+}
+
+static int coroutine_fn vdi_co_create_opts(const char *filename, QemuOpts *opts,
+ Error **errp)
+{
+ QDict *qdict = NULL;
+ BlockdevCreateOptions *create_options = NULL;
+ BlockDriverState *bs_file = NULL;
+ uint64_t block_size = DEFAULT_CLUSTER_SIZE;
+ bool is_static = false;
+ Visitor *v;
+ Error *local_err = NULL;
+ int ret;
+
+ /* Parse options and convert legacy syntax.
+ *
+ * Since CONFIG_VDI_BLOCK_SIZE is disabled by default,
+ * cluster-size is not part of the QAPI schema; therefore we have
+ * to parse it before creating the QAPI object. */
+#if defined(CONFIG_VDI_BLOCK_SIZE)
+ block_size = qemu_opt_get_size_del(opts,
+ BLOCK_OPT_CLUSTER_SIZE,
+ DEFAULT_CLUSTER_SIZE);
+ if (block_size < BDRV_SECTOR_SIZE || block_size > UINT32_MAX ||
+ !is_power_of_2(block_size))
+ {
+ error_setg(errp, "Invalid cluster size");
+ ret = -EINVAL;
+ goto done;
+ }
+#endif
+ if (qemu_opt_get_bool_del(opts, BLOCK_OPT_STATIC, false)) {
+ is_static = true;
+ }
+
+ qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vdi_create_opts, true);
+
+ /* Create and open the file (protocol layer) */
+ ret = bdrv_create_file(filename, opts, errp);
+ if (ret < 0) {
+ goto done;
+ }
+
+ bs_file = bdrv_open(filename, NULL, NULL,
+ BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
+ if (!bs_file) {
+ ret = -EIO;
+ goto done;
+ }
+
+ qdict_put_str(qdict, "driver", "vdi");
+ qdict_put_str(qdict, "file", bs_file->node_name);
+ if (is_static) {
+ qdict_put_str(qdict, "preallocation", "metadata");
+ }
+
+ /* Get the QAPI object */
+ v = qobject_input_visitor_new_flat_confused(qdict, errp);
+ if (!v) {
+ ret = -EINVAL;
+ goto done;
+ }
+ visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
+ visit_free(v);
+
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /* Silently round up size */
+ assert(create_options->driver == BLOCKDEV_DRIVER_VDI);
+ create_options->u.vdi.size = ROUND_UP(create_options->u.vdi.size,
+ BDRV_SECTOR_SIZE);
+
+ /* Create the vdi image (format layer) */
+ ret = vdi_co_do_create(create_options, block_size, errp);
+done:
+ qobject_unref(qdict);
+ qapi_free_BlockdevCreateOptions(create_options);
+ bdrv_unref(bs_file);
+ return ret;
+}
+