+ return ret;
+}
+
+static BlockBackend *vmdk_co_create_cb(int64_t size, int idx,
+ bool flat, bool split, bool compress,
+ bool zeroed_grain, void *opaque,
+ Error **errp)
+{
+ int ret;
+ BlockDriverState *bs;
+ BlockBackend *blk;
+ BlockdevCreateOptionsVmdk *opts = opaque;
+
+ if (idx == 0) {
+ bs = bdrv_open_blockdev_ref(opts->file, errp);
+ } else {
+ int i;
+ BlockdevRefList *list = opts->extents;
+ for (i = 1; i < idx; i++) {
+ if (!list || !list->next) {
+ error_setg(errp, "Extent [%d] not specified", i);
+ return NULL;
+ }
+ list = list->next;
+ }
+ if (!list) {
+ error_setg(errp, "Extent [%d] not specified", idx - 1);
+ return NULL;
+ }
+ bs = bdrv_open_blockdev_ref(list->value, errp);
+ }
+ if (!bs) {
+ return NULL;
+ }
+ blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE,
+ BLK_PERM_ALL);
+ if (blk_insert_bs(blk, bs, errp)) {
+ bdrv_unref(bs);
+ return NULL;
+ }
+ blk_set_allow_write_beyond_eof(blk, true);
+ bdrv_unref(bs);
+
+ if (size != -1) {
+ ret = vmdk_init_extent(blk, size, flat, compress, zeroed_grain, errp);
+ if (ret) {
+ blk_unref(blk);
+ blk = NULL;
+ }
+ }
+ return blk;
+}
+
+static int coroutine_fn vmdk_co_create(BlockdevCreateOptions *create_options,
+ Error **errp)
+{
+ int ret;
+ BlockdevCreateOptionsVmdk *opts;
+
+ opts = &create_options->u.vmdk;
+
+ /* Validate options */
+ if (!QEMU_IS_ALIGNED(opts->size, BDRV_SECTOR_SIZE)) {
+ error_setg(errp, "Image size must be a multiple of 512 bytes");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = vmdk_co_do_create(opts->size,
+ opts->subformat,
+ opts->adapter_type,
+ opts->backing_file,
+ opts->hwversion,
+ false,
+ opts->zeroed_grain,
+ vmdk_co_create_cb,
+ opts, errp);
+ return ret;
+
+out: