1019d6b8fSAnthony Liguori /* 2019d6b8fSAnthony Liguori * Block driver for the VMDK format 3019d6b8fSAnthony Liguori * 4019d6b8fSAnthony Liguori * Copyright (c) 2004 Fabrice Bellard 5019d6b8fSAnthony Liguori * Copyright (c) 2005 Filip Navara 6019d6b8fSAnthony Liguori * 7019d6b8fSAnthony Liguori * Permission is hereby granted, free of charge, to any person obtaining a copy 8019d6b8fSAnthony Liguori * of this software and associated documentation files (the "Software"), to deal 9019d6b8fSAnthony Liguori * in the Software without restriction, including without limitation the rights 10019d6b8fSAnthony Liguori * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11019d6b8fSAnthony Liguori * copies of the Software, and to permit persons to whom the Software is 12019d6b8fSAnthony Liguori * furnished to do so, subject to the following conditions: 13019d6b8fSAnthony Liguori * 14019d6b8fSAnthony Liguori * The above copyright notice and this permission notice shall be included in 15019d6b8fSAnthony Liguori * all copies or substantial portions of the Software. 16019d6b8fSAnthony Liguori * 17019d6b8fSAnthony Liguori * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18019d6b8fSAnthony Liguori * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19019d6b8fSAnthony Liguori * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20019d6b8fSAnthony Liguori * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21019d6b8fSAnthony Liguori * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22019d6b8fSAnthony Liguori * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23019d6b8fSAnthony Liguori * THE SOFTWARE. 24019d6b8fSAnthony Liguori */ 25019d6b8fSAnthony Liguori 2680c71a24SPeter Maydell #include "qemu/osdep.h" 27da34e65cSMarkus Armbruster #include "qapi/error.h" 28737e150eSPaolo Bonzini #include "block/block_int.h" 29c4bea169SKevin Wolf #include "sysemu/block-backend.h" 30cc7a8ea7SMarkus Armbruster #include "qapi/qmp/qerror.h" 31d49b6836SMarkus Armbruster #include "qemu/error-report.h" 321de7afc9SPaolo Bonzini #include "qemu/module.h" 33922a01a0SMarkus Armbruster #include "qemu/option.h" 3458369e22SPaolo Bonzini #include "qemu/bswap.h" 35795c40b8SJuan Quintela #include "migration/blocker.h" 36f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 372923d34fSStefan Weil #include <zlib.h> 38019d6b8fSAnthony Liguori 39019d6b8fSAnthony Liguori #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') 40019d6b8fSAnthony Liguori #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') 41432bb170SFam Zheng #define VMDK4_COMPRESSION_DEFLATE 1 4295b0aa42SFam Zheng #define VMDK4_FLAG_NL_DETECT (1 << 0) 43bb45ded9SFam Zheng #define VMDK4_FLAG_RGD (1 << 1) 4414ead646SFam Zheng /* Zeroed-grain enable bit */ 4514ead646SFam Zheng #define VMDK4_FLAG_ZERO_GRAIN (1 << 2) 46432bb170SFam Zheng #define VMDK4_FLAG_COMPRESS (1 << 16) 47432bb170SFam Zheng #define VMDK4_FLAG_MARKER (1 << 17) 4865bd155cSKevin Wolf #define VMDK4_GD_AT_END 0xffffffffffffffffULL 49019d6b8fSAnthony Liguori 50a77672eaSyuchenlin #define VMDK_EXTENT_MAX_SECTORS (1ULL << 32) 51a77672eaSyuchenlin 5214ead646SFam Zheng #define VMDK_GTE_ZEROED 0x1 5365f74725SFam Zheng 5465f74725SFam Zheng /* VMDK internal error codes */ 5565f74725SFam Zheng #define VMDK_OK 0 5665f74725SFam Zheng #define VMDK_ERROR (-1) 5765f74725SFam Zheng /* Cluster not allocated */ 5865f74725SFam Zheng #define VMDK_UNALLOC (-2) 5965f74725SFam Zheng #define VMDK_ZEROED (-3) 6065f74725SFam Zheng 6169e0b6dfSFam Zheng #define BLOCK_OPT_ZEROED_GRAIN "zeroed_grain" 6269e0b6dfSFam Zheng 63019d6b8fSAnthony Liguori typedef struct { 64019d6b8fSAnthony Liguori uint32_t version; 65019d6b8fSAnthony Liguori uint32_t flags; 66019d6b8fSAnthony Liguori uint32_t disk_sectors; 67019d6b8fSAnthony Liguori uint32_t granularity; 68019d6b8fSAnthony Liguori uint32_t l1dir_offset; 69019d6b8fSAnthony Liguori uint32_t l1dir_size; 70019d6b8fSAnthony Liguori uint32_t file_sectors; 71019d6b8fSAnthony Liguori uint32_t cylinders; 72019d6b8fSAnthony Liguori uint32_t heads; 73019d6b8fSAnthony Liguori uint32_t sectors_per_track; 745d8caa54SFam Zheng } QEMU_PACKED VMDK3Header; 75019d6b8fSAnthony Liguori 76019d6b8fSAnthony Liguori typedef struct { 77019d6b8fSAnthony Liguori uint32_t version; 78019d6b8fSAnthony Liguori uint32_t flags; 79e98768d4SFam Zheng uint64_t capacity; 80e98768d4SFam Zheng uint64_t granularity; 81e98768d4SFam Zheng uint64_t desc_offset; 82e98768d4SFam Zheng uint64_t desc_size; 83ca8804ceSFam Zheng /* Number of GrainTableEntries per GrainTable */ 84ca8804ceSFam Zheng uint32_t num_gtes_per_gt; 85e98768d4SFam Zheng uint64_t rgd_offset; 86e98768d4SFam Zheng uint64_t gd_offset; 87e98768d4SFam Zheng uint64_t grain_offset; 88019d6b8fSAnthony Liguori char filler[1]; 89019d6b8fSAnthony Liguori char check_bytes[4]; 90432bb170SFam Zheng uint16_t compressAlgorithm; 91541dc0d4SStefan Weil } QEMU_PACKED VMDK4Header; 92019d6b8fSAnthony Liguori 93019d6b8fSAnthony Liguori #define L2_CACHE_SIZE 16 94019d6b8fSAnthony Liguori 95b3976d3cSFam Zheng typedef struct VmdkExtent { 9624bc15d1SKevin Wolf BdrvChild *file; 97b3976d3cSFam Zheng bool flat; 98432bb170SFam Zheng bool compressed; 99432bb170SFam Zheng bool has_marker; 10014ead646SFam Zheng bool has_zero_grain; 10114ead646SFam Zheng int version; 102b3976d3cSFam Zheng int64_t sectors; 103b3976d3cSFam Zheng int64_t end_sector; 1047fa60fa3SFam Zheng int64_t flat_start_offset; 105019d6b8fSAnthony Liguori int64_t l1_table_offset; 106019d6b8fSAnthony Liguori int64_t l1_backup_table_offset; 107019d6b8fSAnthony Liguori uint32_t *l1_table; 108019d6b8fSAnthony Liguori uint32_t *l1_backup_table; 109019d6b8fSAnthony Liguori unsigned int l1_size; 110019d6b8fSAnthony Liguori uint32_t l1_entry_sectors; 111019d6b8fSAnthony Liguori 112019d6b8fSAnthony Liguori unsigned int l2_size; 113019d6b8fSAnthony Liguori uint32_t *l2_cache; 114019d6b8fSAnthony Liguori uint32_t l2_cache_offsets[L2_CACHE_SIZE]; 115019d6b8fSAnthony Liguori uint32_t l2_cache_counts[L2_CACHE_SIZE]; 116019d6b8fSAnthony Liguori 117301c7d38SFam Zheng int64_t cluster_sectors; 118c6ac36e1SFam Zheng int64_t next_cluster_sector; 119f4c129a3SFam Zheng char *type; 120b3976d3cSFam Zheng } VmdkExtent; 121b3976d3cSFam Zheng 122b3976d3cSFam Zheng typedef struct BDRVVmdkState { 123848c66e8SPaolo Bonzini CoMutex lock; 124e98768d4SFam Zheng uint64_t desc_offset; 12569b4d86dSFam Zheng bool cid_updated; 126c338b6adSFam Zheng bool cid_checked; 127f4c129a3SFam Zheng uint32_t cid; 128019d6b8fSAnthony Liguori uint32_t parent_cid; 129b3976d3cSFam Zheng int num_extents; 130b3976d3cSFam Zheng /* Extent array with num_extents entries, ascend ordered by address */ 131b3976d3cSFam Zheng VmdkExtent *extents; 1322bc3166cSKevin Wolf Error *migration_blocker; 133f4c129a3SFam Zheng char *create_type; 134019d6b8fSAnthony Liguori } BDRVVmdkState; 135019d6b8fSAnthony Liguori 136019d6b8fSAnthony Liguori typedef struct VmdkMetaData { 137019d6b8fSAnthony Liguori unsigned int l1_index; 138019d6b8fSAnthony Liguori unsigned int l2_index; 139019d6b8fSAnthony Liguori unsigned int l2_offset; 140019d6b8fSAnthony Liguori int valid; 141cdeaf1f1SFam Zheng uint32_t *l2_cache_entry; 142019d6b8fSAnthony Liguori } VmdkMetaData; 143019d6b8fSAnthony Liguori 144432bb170SFam Zheng typedef struct VmdkGrainMarker { 145432bb170SFam Zheng uint64_t lba; 146432bb170SFam Zheng uint32_t size; 147432bb170SFam Zheng uint8_t data[0]; 1485d8caa54SFam Zheng } QEMU_PACKED VmdkGrainMarker; 149432bb170SFam Zheng 15065bd155cSKevin Wolf enum { 15165bd155cSKevin Wolf MARKER_END_OF_STREAM = 0, 15265bd155cSKevin Wolf MARKER_GRAIN_TABLE = 1, 15365bd155cSKevin Wolf MARKER_GRAIN_DIRECTORY = 2, 15465bd155cSKevin Wolf MARKER_FOOTER = 3, 15565bd155cSKevin Wolf }; 15665bd155cSKevin Wolf 157019d6b8fSAnthony Liguori static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) 158019d6b8fSAnthony Liguori { 159019d6b8fSAnthony Liguori uint32_t magic; 160019d6b8fSAnthony Liguori 161ae261c86SFam Zheng if (buf_size < 4) { 162019d6b8fSAnthony Liguori return 0; 163ae261c86SFam Zheng } 164019d6b8fSAnthony Liguori magic = be32_to_cpu(*(uint32_t *)buf); 165019d6b8fSAnthony Liguori if (magic == VMDK3_MAGIC || 16601fc99d6SFam Zheng magic == VMDK4_MAGIC) { 167019d6b8fSAnthony Liguori return 100; 16801fc99d6SFam Zheng } else { 16901fc99d6SFam Zheng const char *p = (const char *)buf; 17001fc99d6SFam Zheng const char *end = p + buf_size; 17101fc99d6SFam Zheng while (p < end) { 17201fc99d6SFam Zheng if (*p == '#') { 17301fc99d6SFam Zheng /* skip comment line */ 17401fc99d6SFam Zheng while (p < end && *p != '\n') { 17501fc99d6SFam Zheng p++; 17601fc99d6SFam Zheng } 17701fc99d6SFam Zheng p++; 17801fc99d6SFam Zheng continue; 17901fc99d6SFam Zheng } 18001fc99d6SFam Zheng if (*p == ' ') { 18101fc99d6SFam Zheng while (p < end && *p == ' ') { 18201fc99d6SFam Zheng p++; 18301fc99d6SFam Zheng } 18401fc99d6SFam Zheng /* skip '\r' if windows line endings used. */ 18501fc99d6SFam Zheng if (p < end && *p == '\r') { 18601fc99d6SFam Zheng p++; 18701fc99d6SFam Zheng } 18801fc99d6SFam Zheng /* only accept blank lines before 'version=' line */ 18901fc99d6SFam Zheng if (p == end || *p != '\n') { 190019d6b8fSAnthony Liguori return 0; 191019d6b8fSAnthony Liguori } 19201fc99d6SFam Zheng p++; 19301fc99d6SFam Zheng continue; 19401fc99d6SFam Zheng } 19501fc99d6SFam Zheng if (end - p >= strlen("version=X\n")) { 19601fc99d6SFam Zheng if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 || 19701fc99d6SFam Zheng strncmp("version=2\n", p, strlen("version=2\n")) == 0) { 19801fc99d6SFam Zheng return 100; 19901fc99d6SFam Zheng } 20001fc99d6SFam Zheng } 20101fc99d6SFam Zheng if (end - p >= strlen("version=X\r\n")) { 20201fc99d6SFam Zheng if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 || 20301fc99d6SFam Zheng strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) { 20401fc99d6SFam Zheng return 100; 20501fc99d6SFam Zheng } 20601fc99d6SFam Zheng } 20701fc99d6SFam Zheng return 0; 20801fc99d6SFam Zheng } 20901fc99d6SFam Zheng return 0; 21001fc99d6SFam Zheng } 21101fc99d6SFam Zheng } 212019d6b8fSAnthony Liguori 213019d6b8fSAnthony Liguori #define SECTOR_SIZE 512 214f66fd6c3SFam Zheng #define DESC_SIZE (20 * SECTOR_SIZE) /* 20 sectors of 512 bytes each */ 215f66fd6c3SFam Zheng #define BUF_SIZE 4096 216f66fd6c3SFam Zheng #define HEADER_SIZE 512 /* first sector of 512 bytes */ 217019d6b8fSAnthony Liguori 218b3976d3cSFam Zheng static void vmdk_free_extents(BlockDriverState *bs) 219b3976d3cSFam Zheng { 220b3976d3cSFam Zheng int i; 221b3976d3cSFam Zheng BDRVVmdkState *s = bs->opaque; 222b3c0bfb6SFam Zheng VmdkExtent *e; 223b3976d3cSFam Zheng 224b3976d3cSFam Zheng for (i = 0; i < s->num_extents; i++) { 225b3c0bfb6SFam Zheng e = &s->extents[i]; 226b3c0bfb6SFam Zheng g_free(e->l1_table); 227b3c0bfb6SFam Zheng g_free(e->l2_cache); 228b3c0bfb6SFam Zheng g_free(e->l1_backup_table); 229f4c129a3SFam Zheng g_free(e->type); 2309a4f4c31SKevin Wolf if (e->file != bs->file) { 23124bc15d1SKevin Wolf bdrv_unref_child(bs, e->file); 232b3c0bfb6SFam Zheng } 233b3976d3cSFam Zheng } 2347267c094SAnthony Liguori g_free(s->extents); 235b3976d3cSFam Zheng } 236b3976d3cSFam Zheng 23786c6b429SFam Zheng static void vmdk_free_last_extent(BlockDriverState *bs) 23886c6b429SFam Zheng { 23986c6b429SFam Zheng BDRVVmdkState *s = bs->opaque; 24086c6b429SFam Zheng 24186c6b429SFam Zheng if (s->num_extents == 0) { 24286c6b429SFam Zheng return; 24386c6b429SFam Zheng } 24486c6b429SFam Zheng s->num_extents--; 2455839e53bSMarkus Armbruster s->extents = g_renew(VmdkExtent, s->extents, s->num_extents); 24686c6b429SFam Zheng } 24786c6b429SFam Zheng 2489877860eSPeter Maydell /* Return -ve errno, or 0 on success and write CID into *pcid. */ 2499877860eSPeter Maydell static int vmdk_read_cid(BlockDriverState *bs, int parent, uint32_t *pcid) 250019d6b8fSAnthony Liguori { 2515997c210SFam Zheng char *desc; 2529877860eSPeter Maydell uint32_t cid; 253019d6b8fSAnthony Liguori const char *p_name, *cid_str; 254019d6b8fSAnthony Liguori size_t cid_str_size; 255e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 25699f1835dSKevin Wolf int ret; 257019d6b8fSAnthony Liguori 2585997c210SFam Zheng desc = g_malloc0(DESC_SIZE); 259cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); 26099f1835dSKevin Wolf if (ret < 0) { 2619877860eSPeter Maydell goto out; 262e1da9b24SFam Zheng } 263019d6b8fSAnthony Liguori 264019d6b8fSAnthony Liguori if (parent) { 265019d6b8fSAnthony Liguori cid_str = "parentCID"; 266019d6b8fSAnthony Liguori cid_str_size = sizeof("parentCID"); 267019d6b8fSAnthony Liguori } else { 268019d6b8fSAnthony Liguori cid_str = "CID"; 269019d6b8fSAnthony Liguori cid_str_size = sizeof("CID"); 270019d6b8fSAnthony Liguori } 271019d6b8fSAnthony Liguori 27293897b9fSKevin Wolf desc[DESC_SIZE - 1] = '\0'; 273ae261c86SFam Zheng p_name = strstr(desc, cid_str); 2749877860eSPeter Maydell if (p_name == NULL) { 2759877860eSPeter Maydell ret = -EINVAL; 2769877860eSPeter Maydell goto out; 277019d6b8fSAnthony Liguori } 2789877860eSPeter Maydell p_name += cid_str_size; 2799877860eSPeter Maydell if (sscanf(p_name, "%" SCNx32, &cid) != 1) { 2809877860eSPeter Maydell ret = -EINVAL; 2819877860eSPeter Maydell goto out; 2829877860eSPeter Maydell } 2839877860eSPeter Maydell *pcid = cid; 2849877860eSPeter Maydell ret = 0; 285019d6b8fSAnthony Liguori 2869877860eSPeter Maydell out: 2875997c210SFam Zheng g_free(desc); 2889877860eSPeter Maydell return ret; 289019d6b8fSAnthony Liguori } 290019d6b8fSAnthony Liguori 291019d6b8fSAnthony Liguori static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) 292019d6b8fSAnthony Liguori { 293965415ebSFam Zheng char *desc, *tmp_desc; 294019d6b8fSAnthony Liguori char *p_name, *tmp_str; 295e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 296965415ebSFam Zheng int ret = 0; 297019d6b8fSAnthony Liguori 298965415ebSFam Zheng desc = g_malloc0(DESC_SIZE); 299965415ebSFam Zheng tmp_desc = g_malloc0(DESC_SIZE); 300cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); 30199f1835dSKevin Wolf if (ret < 0) { 302965415ebSFam Zheng goto out; 303e1da9b24SFam Zheng } 304019d6b8fSAnthony Liguori 30593897b9fSKevin Wolf desc[DESC_SIZE - 1] = '\0'; 306019d6b8fSAnthony Liguori tmp_str = strstr(desc, "parentCID"); 30793897b9fSKevin Wolf if (tmp_str == NULL) { 308965415ebSFam Zheng ret = -EINVAL; 309965415ebSFam Zheng goto out; 31093897b9fSKevin Wolf } 31193897b9fSKevin Wolf 312965415ebSFam Zheng pstrcpy(tmp_desc, DESC_SIZE, tmp_str); 313ae261c86SFam Zheng p_name = strstr(desc, "CID"); 314ae261c86SFam Zheng if (p_name != NULL) { 315019d6b8fSAnthony Liguori p_name += sizeof("CID"); 316965415ebSFam Zheng snprintf(p_name, DESC_SIZE - (p_name - desc), "%" PRIx32 "\n", cid); 317965415ebSFam Zheng pstrcat(desc, DESC_SIZE, tmp_desc); 318019d6b8fSAnthony Liguori } 319019d6b8fSAnthony Liguori 320d9ca2ea2SKevin Wolf ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE); 32199f1835dSKevin Wolf 322965415ebSFam Zheng out: 323965415ebSFam Zheng g_free(desc); 324965415ebSFam Zheng g_free(tmp_desc); 325965415ebSFam Zheng return ret; 326019d6b8fSAnthony Liguori } 327019d6b8fSAnthony Liguori 328019d6b8fSAnthony Liguori static int vmdk_is_cid_valid(BlockDriverState *bs) 329019d6b8fSAnthony Liguori { 330019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 331019d6b8fSAnthony Liguori uint32_t cur_pcid; 332019d6b8fSAnthony Liguori 333760e0063SKevin Wolf if (!s->cid_checked && bs->backing) { 334760e0063SKevin Wolf BlockDriverState *p_bs = bs->backing->bs; 335760e0063SKevin Wolf 336439e89fcSMax Reitz if (strcmp(p_bs->drv->format_name, "vmdk")) { 337439e89fcSMax Reitz /* Backing file is not in vmdk format, so it does not have 338439e89fcSMax Reitz * a CID, which makes the overlay's parent CID invalid */ 339439e89fcSMax Reitz return 0; 340439e89fcSMax Reitz } 341439e89fcSMax Reitz 3429877860eSPeter Maydell if (vmdk_read_cid(p_bs, 0, &cur_pcid) != 0) { 3439877860eSPeter Maydell /* read failure: report as not valid */ 3449877860eSPeter Maydell return 0; 3459877860eSPeter Maydell } 346ae261c86SFam Zheng if (s->parent_cid != cur_pcid) { 347ae261c86SFam Zheng /* CID not valid */ 348019d6b8fSAnthony Liguori return 0; 349019d6b8fSAnthony Liguori } 350ae261c86SFam Zheng } 351c338b6adSFam Zheng s->cid_checked = true; 352ae261c86SFam Zheng /* CID valid */ 353019d6b8fSAnthony Liguori return 1; 354019d6b8fSAnthony Liguori } 355019d6b8fSAnthony Liguori 35667251a31SKevin Wolf /* We have nothing to do for VMDK reopen, stubs just return success */ 3573897575fSJeff Cody static int vmdk_reopen_prepare(BDRVReopenState *state, 3583897575fSJeff Cody BlockReopenQueue *queue, Error **errp) 3593897575fSJeff Cody { 3603897575fSJeff Cody assert(state != NULL); 3613897575fSJeff Cody assert(state->bs != NULL); 36267251a31SKevin Wolf return 0; 3633897575fSJeff Cody } 3643897575fSJeff Cody 3659949f97eSKevin Wolf static int vmdk_parent_open(BlockDriverState *bs) 366019d6b8fSAnthony Liguori { 367019d6b8fSAnthony Liguori char *p_name; 36871968dbfSFam Zheng char *desc; 369e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 370588b65a3SPaolo Bonzini int ret; 371019d6b8fSAnthony Liguori 37271968dbfSFam Zheng desc = g_malloc0(DESC_SIZE + 1); 373cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); 374588b65a3SPaolo Bonzini if (ret < 0) { 37571968dbfSFam Zheng goto out; 376e1da9b24SFam Zheng } 37771968dbfSFam Zheng ret = 0; 378019d6b8fSAnthony Liguori 379ae261c86SFam Zheng p_name = strstr(desc, "parentFileNameHint"); 380ae261c86SFam Zheng if (p_name != NULL) { 381019d6b8fSAnthony Liguori char *end_name; 382019d6b8fSAnthony Liguori 383019d6b8fSAnthony Liguori p_name += sizeof("parentFileNameHint") + 1; 384ae261c86SFam Zheng end_name = strchr(p_name, '\"'); 385ae261c86SFam Zheng if (end_name == NULL) { 38671968dbfSFam Zheng ret = -EINVAL; 38771968dbfSFam Zheng goto out; 388ae261c86SFam Zheng } 389ae261c86SFam Zheng if ((end_name - p_name) > sizeof(bs->backing_file) - 1) { 39071968dbfSFam Zheng ret = -EINVAL; 39171968dbfSFam Zheng goto out; 392ae261c86SFam Zheng } 393019d6b8fSAnthony Liguori 394b171271aSKevin Wolf pstrcpy(bs->backing_file, end_name - p_name + 1, p_name); 395019d6b8fSAnthony Liguori } 396019d6b8fSAnthony Liguori 39771968dbfSFam Zheng out: 39871968dbfSFam Zheng g_free(desc); 39971968dbfSFam Zheng return ret; 400019d6b8fSAnthony Liguori } 401019d6b8fSAnthony Liguori 402b3976d3cSFam Zheng /* Create and append extent to the extent array. Return the added VmdkExtent 403b3976d3cSFam Zheng * address. return NULL if allocation failed. */ 4048aa1331cSFam Zheng static int vmdk_add_extent(BlockDriverState *bs, 40524bc15d1SKevin Wolf BdrvChild *file, bool flat, int64_t sectors, 406b3976d3cSFam Zheng int64_t l1_offset, int64_t l1_backup_offset, 407b3976d3cSFam Zheng uint32_t l1_size, 4088aa1331cSFam Zheng int l2_size, uint64_t cluster_sectors, 4094823970bSFam Zheng VmdkExtent **new_extent, 4104823970bSFam Zheng Error **errp) 411b3976d3cSFam Zheng { 412b3976d3cSFam Zheng VmdkExtent *extent; 413b3976d3cSFam Zheng BDRVVmdkState *s = bs->opaque; 4140a156f7cSMarkus Armbruster int64_t nb_sectors; 415b3976d3cSFam Zheng 4168aa1331cSFam Zheng if (cluster_sectors > 0x200000) { 4178aa1331cSFam Zheng /* 0x200000 * 512Bytes = 1GB for one cluster is unrealistic */ 4184823970bSFam Zheng error_setg(errp, "Invalid granularity, image may be corrupt"); 4194823970bSFam Zheng return -EFBIG; 4208aa1331cSFam Zheng } 421b0651b8cSFam Zheng if (l1_size > 512 * 1024 * 1024) { 422b0651b8cSFam Zheng /* Although with big capacity and small l1_entry_sectors, we can get a 423b0651b8cSFam Zheng * big l1_size, we don't want unbounded value to allocate the table. 424b0651b8cSFam Zheng * Limit it to 512M, which is 16PB for default cluster and L2 table 425b0651b8cSFam Zheng * size */ 4264823970bSFam Zheng error_setg(errp, "L1 size too big"); 427b0651b8cSFam Zheng return -EFBIG; 428b0651b8cSFam Zheng } 4298aa1331cSFam Zheng 43024bc15d1SKevin Wolf nb_sectors = bdrv_nb_sectors(file->bs); 4310a156f7cSMarkus Armbruster if (nb_sectors < 0) { 4320a156f7cSMarkus Armbruster return nb_sectors; 433c6ac36e1SFam Zheng } 434c6ac36e1SFam Zheng 4355839e53bSMarkus Armbruster s->extents = g_renew(VmdkExtent, s->extents, s->num_extents + 1); 436b3976d3cSFam Zheng extent = &s->extents[s->num_extents]; 437b3976d3cSFam Zheng s->num_extents++; 438b3976d3cSFam Zheng 439b3976d3cSFam Zheng memset(extent, 0, sizeof(VmdkExtent)); 440b3976d3cSFam Zheng extent->file = file; 441b3976d3cSFam Zheng extent->flat = flat; 442b3976d3cSFam Zheng extent->sectors = sectors; 443b3976d3cSFam Zheng extent->l1_table_offset = l1_offset; 444b3976d3cSFam Zheng extent->l1_backup_table_offset = l1_backup_offset; 445b3976d3cSFam Zheng extent->l1_size = l1_size; 446b3976d3cSFam Zheng extent->l1_entry_sectors = l2_size * cluster_sectors; 447b3976d3cSFam Zheng extent->l2_size = l2_size; 448301c7d38SFam Zheng extent->cluster_sectors = flat ? sectors : cluster_sectors; 4490a156f7cSMarkus Armbruster extent->next_cluster_sector = ROUND_UP(nb_sectors, cluster_sectors); 450b3976d3cSFam Zheng 451b3976d3cSFam Zheng if (s->num_extents > 1) { 452b3976d3cSFam Zheng extent->end_sector = (*(extent - 1)).end_sector + extent->sectors; 453b3976d3cSFam Zheng } else { 454b3976d3cSFam Zheng extent->end_sector = extent->sectors; 455b3976d3cSFam Zheng } 456b3976d3cSFam Zheng bs->total_sectors = extent->end_sector; 4578aa1331cSFam Zheng if (new_extent) { 4588aa1331cSFam Zheng *new_extent = extent; 4598aa1331cSFam Zheng } 4608aa1331cSFam Zheng return 0; 461b3976d3cSFam Zheng } 462b3976d3cSFam Zheng 4634823970bSFam Zheng static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, 4644823970bSFam Zheng Error **errp) 465019d6b8fSAnthony Liguori { 466b4b3ab14SFam Zheng int ret; 46713c4941cSFam Zheng size_t l1_size; 46813c4941cSFam Zheng int i; 469b4b3ab14SFam Zheng 470b4b3ab14SFam Zheng /* read the L1 table */ 471b4b3ab14SFam Zheng l1_size = extent->l1_size * sizeof(uint32_t); 472d6e59931SKevin Wolf extent->l1_table = g_try_malloc(l1_size); 473d6e59931SKevin Wolf if (l1_size && extent->l1_table == NULL) { 474d6e59931SKevin Wolf return -ENOMEM; 475d6e59931SKevin Wolf } 476d6e59931SKevin Wolf 477cf2ab8fcSKevin Wolf ret = bdrv_pread(extent->file, 478b4b3ab14SFam Zheng extent->l1_table_offset, 479b4b3ab14SFam Zheng extent->l1_table, 480b4b3ab14SFam Zheng l1_size); 481b4b3ab14SFam Zheng if (ret < 0) { 4824823970bSFam Zheng error_setg_errno(errp, -ret, 4834823970bSFam Zheng "Could not read l1 table from extent '%s'", 48424bc15d1SKevin Wolf extent->file->bs->filename); 485b4b3ab14SFam Zheng goto fail_l1; 486b4b3ab14SFam Zheng } 487b4b3ab14SFam Zheng for (i = 0; i < extent->l1_size; i++) { 488b4b3ab14SFam Zheng le32_to_cpus(&extent->l1_table[i]); 489b4b3ab14SFam Zheng } 490b4b3ab14SFam Zheng 491b4b3ab14SFam Zheng if (extent->l1_backup_table_offset) { 492d6e59931SKevin Wolf extent->l1_backup_table = g_try_malloc(l1_size); 493d6e59931SKevin Wolf if (l1_size && extent->l1_backup_table == NULL) { 494d6e59931SKevin Wolf ret = -ENOMEM; 495d6e59931SKevin Wolf goto fail_l1; 496d6e59931SKevin Wolf } 497cf2ab8fcSKevin Wolf ret = bdrv_pread(extent->file, 498b4b3ab14SFam Zheng extent->l1_backup_table_offset, 499b4b3ab14SFam Zheng extent->l1_backup_table, 500b4b3ab14SFam Zheng l1_size); 501b4b3ab14SFam Zheng if (ret < 0) { 5024823970bSFam Zheng error_setg_errno(errp, -ret, 5034823970bSFam Zheng "Could not read l1 backup table from extent '%s'", 50424bc15d1SKevin Wolf extent->file->bs->filename); 505b4b3ab14SFam Zheng goto fail_l1b; 506b4b3ab14SFam Zheng } 507b4b3ab14SFam Zheng for (i = 0; i < extent->l1_size; i++) { 508b4b3ab14SFam Zheng le32_to_cpus(&extent->l1_backup_table[i]); 509b4b3ab14SFam Zheng } 510b4b3ab14SFam Zheng } 511b4b3ab14SFam Zheng 512b4b3ab14SFam Zheng extent->l2_cache = 5135839e53bSMarkus Armbruster g_new(uint32_t, extent->l2_size * L2_CACHE_SIZE); 514b4b3ab14SFam Zheng return 0; 515b4b3ab14SFam Zheng fail_l1b: 5167267c094SAnthony Liguori g_free(extent->l1_backup_table); 517b4b3ab14SFam Zheng fail_l1: 5187267c094SAnthony Liguori g_free(extent->l1_table); 519b4b3ab14SFam Zheng return ret; 520b4b3ab14SFam Zheng } 521b4b3ab14SFam Zheng 522daac8fdcSFam Zheng static int vmdk_open_vmfs_sparse(BlockDriverState *bs, 52324bc15d1SKevin Wolf BdrvChild *file, 5244823970bSFam Zheng int flags, Error **errp) 525b4b3ab14SFam Zheng { 526b4b3ab14SFam Zheng int ret; 527019d6b8fSAnthony Liguori uint32_t magic; 528019d6b8fSAnthony Liguori VMDK3Header header; 529b4b3ab14SFam Zheng VmdkExtent *extent; 530b4b3ab14SFam Zheng 531cf2ab8fcSKevin Wolf ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); 532b4b3ab14SFam Zheng if (ret < 0) { 5334823970bSFam Zheng error_setg_errno(errp, -ret, 5344823970bSFam Zheng "Could not read header from file '%s'", 53524bc15d1SKevin Wolf file->bs->filename); 53686c6b429SFam Zheng return ret; 537b3976d3cSFam Zheng } 538f6b61e54SFam Zheng ret = vmdk_add_extent(bs, file, false, 539b3976d3cSFam Zheng le32_to_cpu(header.disk_sectors), 5407237aecdSFam Zheng (int64_t)le32_to_cpu(header.l1dir_offset) << 9, 541f6b61e54SFam Zheng 0, 542f6b61e54SFam Zheng le32_to_cpu(header.l1dir_size), 543f6b61e54SFam Zheng 4096, 5448aa1331cSFam Zheng le32_to_cpu(header.granularity), 5454823970bSFam Zheng &extent, 5464823970bSFam Zheng errp); 5478aa1331cSFam Zheng if (ret < 0) { 5488aa1331cSFam Zheng return ret; 5498aa1331cSFam Zheng } 5504823970bSFam Zheng ret = vmdk_init_tables(bs, extent, errp); 551b4b3ab14SFam Zheng if (ret) { 55286c6b429SFam Zheng /* free extent allocated by vmdk_add_extent */ 55386c6b429SFam Zheng vmdk_free_last_extent(bs); 554b4b3ab14SFam Zheng } 555b4b3ab14SFam Zheng return ret; 556b4b3ab14SFam Zheng } 557b4b3ab14SFam Zheng 558d1833ef5SPaolo Bonzini static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, 559a6468367SKevin Wolf QDict *options, Error **errp); 560f16f509dSFam Zheng 561cf2ab8fcSKevin Wolf static char *vmdk_read_desc(BdrvChild *file, uint64_t desc_offset, Error **errp) 562a8842e6dSPaolo Bonzini { 563a8842e6dSPaolo Bonzini int64_t size; 564a8842e6dSPaolo Bonzini char *buf; 565a8842e6dSPaolo Bonzini int ret; 566a8842e6dSPaolo Bonzini 567cf2ab8fcSKevin Wolf size = bdrv_getlength(file->bs); 568a8842e6dSPaolo Bonzini if (size < 0) { 569a8842e6dSPaolo Bonzini error_setg_errno(errp, -size, "Could not access file"); 570a8842e6dSPaolo Bonzini return NULL; 571a8842e6dSPaolo Bonzini } 572a8842e6dSPaolo Bonzini 57303c3359dSFam Zheng if (size < 4) { 57403c3359dSFam Zheng /* Both descriptor file and sparse image must be much larger than 4 57503c3359dSFam Zheng * bytes, also callers of vmdk_read_desc want to compare the first 4 57603c3359dSFam Zheng * bytes with VMDK4_MAGIC, let's error out if less is read. */ 57703c3359dSFam Zheng error_setg(errp, "File is too small, not a valid image"); 57803c3359dSFam Zheng return NULL; 57903c3359dSFam Zheng } 58003c3359dSFam Zheng 58173b7bcadSFam Zheng size = MIN(size, (1 << 20) - 1); /* avoid unbounded allocation */ 58273b7bcadSFam Zheng buf = g_malloc(size + 1); 583a8842e6dSPaolo Bonzini 584a8842e6dSPaolo Bonzini ret = bdrv_pread(file, desc_offset, buf, size); 585a8842e6dSPaolo Bonzini if (ret < 0) { 586a8842e6dSPaolo Bonzini error_setg_errno(errp, -ret, "Could not read from file"); 587a8842e6dSPaolo Bonzini g_free(buf); 588a8842e6dSPaolo Bonzini return NULL; 589a8842e6dSPaolo Bonzini } 59073b7bcadSFam Zheng buf[ret] = 0; 591a8842e6dSPaolo Bonzini 592a8842e6dSPaolo Bonzini return buf; 593a8842e6dSPaolo Bonzini } 594a8842e6dSPaolo Bonzini 59586c6b429SFam Zheng static int vmdk_open_vmdk4(BlockDriverState *bs, 59624bc15d1SKevin Wolf BdrvChild *file, 597a6468367SKevin Wolf int flags, QDict *options, Error **errp) 598b4b3ab14SFam Zheng { 599b4b3ab14SFam Zheng int ret; 600b4b3ab14SFam Zheng uint32_t magic; 601b4b3ab14SFam Zheng uint32_t l1_size, l1_entry_sectors; 602019d6b8fSAnthony Liguori VMDK4Header header; 603b4b3ab14SFam Zheng VmdkExtent *extent; 604f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 605bb45ded9SFam Zheng int64_t l1_backup_offset = 0; 6063db1d98aSFam Zheng bool compressed; 607b4b3ab14SFam Zheng 608cf2ab8fcSKevin Wolf ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); 609b4b3ab14SFam Zheng if (ret < 0) { 6104823970bSFam Zheng error_setg_errno(errp, -ret, 6114823970bSFam Zheng "Could not read header from file '%s'", 61224bc15d1SKevin Wolf file->bs->filename); 61389ac8480SPaolo Bonzini return -EINVAL; 614b3976d3cSFam Zheng } 6155a394b9eSStefan Hajnoczi if (header.capacity == 0) { 616e98768d4SFam Zheng uint64_t desc_offset = le64_to_cpu(header.desc_offset); 6175a394b9eSStefan Hajnoczi if (desc_offset) { 618cf2ab8fcSKevin Wolf char *buf = vmdk_read_desc(file, desc_offset << 9, errp); 619d1833ef5SPaolo Bonzini if (!buf) { 620d1833ef5SPaolo Bonzini return -EINVAL; 621d1833ef5SPaolo Bonzini } 622a6468367SKevin Wolf ret = vmdk_open_desc_file(bs, flags, buf, options, errp); 623d1833ef5SPaolo Bonzini g_free(buf); 624d1833ef5SPaolo Bonzini return ret; 6255a394b9eSStefan Hajnoczi } 626f16f509dSFam Zheng } 62765bd155cSKevin Wolf 628f4c129a3SFam Zheng if (!s->create_type) { 629f4c129a3SFam Zheng s->create_type = g_strdup("monolithicSparse"); 630f4c129a3SFam Zheng } 631f4c129a3SFam Zheng 63265bd155cSKevin Wolf if (le64_to_cpu(header.gd_offset) == VMDK4_GD_AT_END) { 63365bd155cSKevin Wolf /* 63465bd155cSKevin Wolf * The footer takes precedence over the header, so read it in. The 63565bd155cSKevin Wolf * footer starts at offset -1024 from the end: One sector for the 63665bd155cSKevin Wolf * footer, and another one for the end-of-stream marker. 63765bd155cSKevin Wolf */ 63865bd155cSKevin Wolf struct { 63965bd155cSKevin Wolf struct { 64065bd155cSKevin Wolf uint64_t val; 64165bd155cSKevin Wolf uint32_t size; 64265bd155cSKevin Wolf uint32_t type; 64365bd155cSKevin Wolf uint8_t pad[512 - 16]; 64465bd155cSKevin Wolf } QEMU_PACKED footer_marker; 64565bd155cSKevin Wolf 64665bd155cSKevin Wolf uint32_t magic; 64765bd155cSKevin Wolf VMDK4Header header; 64865bd155cSKevin Wolf uint8_t pad[512 - 4 - sizeof(VMDK4Header)]; 64965bd155cSKevin Wolf 65065bd155cSKevin Wolf struct { 65165bd155cSKevin Wolf uint64_t val; 65265bd155cSKevin Wolf uint32_t size; 65365bd155cSKevin Wolf uint32_t type; 65465bd155cSKevin Wolf uint8_t pad[512 - 16]; 65565bd155cSKevin Wolf } QEMU_PACKED eos_marker; 65665bd155cSKevin Wolf } QEMU_PACKED footer; 65765bd155cSKevin Wolf 658cf2ab8fcSKevin Wolf ret = bdrv_pread(file, 6599a4f4c31SKevin Wolf bs->file->bs->total_sectors * 512 - 1536, 66065bd155cSKevin Wolf &footer, sizeof(footer)); 66165bd155cSKevin Wolf if (ret < 0) { 662d899d2e2SFam Zheng error_setg_errno(errp, -ret, "Failed to read footer"); 66365bd155cSKevin Wolf return ret; 66465bd155cSKevin Wolf } 66565bd155cSKevin Wolf 66665bd155cSKevin Wolf /* Some sanity checks for the footer */ 66765bd155cSKevin Wolf if (be32_to_cpu(footer.magic) != VMDK4_MAGIC || 66865bd155cSKevin Wolf le32_to_cpu(footer.footer_marker.size) != 0 || 66965bd155cSKevin Wolf le32_to_cpu(footer.footer_marker.type) != MARKER_FOOTER || 67065bd155cSKevin Wolf le64_to_cpu(footer.eos_marker.val) != 0 || 67165bd155cSKevin Wolf le32_to_cpu(footer.eos_marker.size) != 0 || 67265bd155cSKevin Wolf le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM) 67365bd155cSKevin Wolf { 674d899d2e2SFam Zheng error_setg(errp, "Invalid footer"); 67565bd155cSKevin Wolf return -EINVAL; 67665bd155cSKevin Wolf } 67765bd155cSKevin Wolf 67865bd155cSKevin Wolf header = footer.header; 67965bd155cSKevin Wolf } 68065bd155cSKevin Wolf 6813db1d98aSFam Zheng compressed = 6823db1d98aSFam Zheng le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; 683509d39aaSFam Zheng if (le32_to_cpu(header.version) > 3) { 684a55448b3SMax Reitz error_setg(errp, "Unsupported VMDK version %" PRIu32, 68596c51eb5SFam Zheng le32_to_cpu(header.version)); 68696c51eb5SFam Zheng return -ENOTSUP; 6873db1d98aSFam Zheng } else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR) && 6883db1d98aSFam Zheng !compressed) { 689509d39aaSFam Zheng /* VMware KB 2064959 explains that version 3 added support for 690509d39aaSFam Zheng * persistent changed block tracking (CBT), and backup software can 691509d39aaSFam Zheng * read it as version=1 if it doesn't care about the changed area 692509d39aaSFam Zheng * information. So we are safe to enable read only. */ 693509d39aaSFam Zheng error_setg(errp, "VMDK version 3 must be read only"); 694509d39aaSFam Zheng return -EINVAL; 69596c51eb5SFam Zheng } 69696c51eb5SFam Zheng 697ca8804ceSFam Zheng if (le32_to_cpu(header.num_gtes_per_gt) > 512) { 69889ac8480SPaolo Bonzini error_setg(errp, "L2 table size too big"); 699f8ce0403SFam Zheng return -EINVAL; 700f8ce0403SFam Zheng } 701f8ce0403SFam Zheng 702ca8804ceSFam Zheng l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt) 703b3976d3cSFam Zheng * le64_to_cpu(header.granularity); 70475d12341SStefan Weil if (l1_entry_sectors == 0) { 705d899d2e2SFam Zheng error_setg(errp, "L1 entry size is invalid"); 70686c6b429SFam Zheng return -EINVAL; 70786c6b429SFam Zheng } 708b3976d3cSFam Zheng l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1) 709b3976d3cSFam Zheng / l1_entry_sectors; 710bb45ded9SFam Zheng if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) { 711bb45ded9SFam Zheng l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9; 712bb45ded9SFam Zheng } 71324bc15d1SKevin Wolf if (bdrv_nb_sectors(file->bs) < le64_to_cpu(header.grain_offset)) { 7144ab9dab5SFam Zheng error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes", 7154ab9dab5SFam Zheng (int64_t)(le64_to_cpu(header.grain_offset) 7164ab9dab5SFam Zheng * BDRV_SECTOR_SIZE)); 71734ceed81SFam Zheng return -EINVAL; 71834ceed81SFam Zheng } 71934ceed81SFam Zheng 7208aa1331cSFam Zheng ret = vmdk_add_extent(bs, file, false, 721b3976d3cSFam Zheng le64_to_cpu(header.capacity), 722b3976d3cSFam Zheng le64_to_cpu(header.gd_offset) << 9, 723bb45ded9SFam Zheng l1_backup_offset, 724b3976d3cSFam Zheng l1_size, 725ca8804ceSFam Zheng le32_to_cpu(header.num_gtes_per_gt), 7268aa1331cSFam Zheng le64_to_cpu(header.granularity), 7274823970bSFam Zheng &extent, 7284823970bSFam Zheng errp); 7298aa1331cSFam Zheng if (ret < 0) { 7308aa1331cSFam Zheng return ret; 7318aa1331cSFam Zheng } 732432bb170SFam Zheng extent->compressed = 733432bb170SFam Zheng le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; 734d8a7b061SFam Zheng if (extent->compressed) { 735d8a7b061SFam Zheng g_free(s->create_type); 736d8a7b061SFam Zheng s->create_type = g_strdup("streamOptimized"); 737d8a7b061SFam Zheng } 738432bb170SFam Zheng extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER; 73914ead646SFam Zheng extent->version = le32_to_cpu(header.version); 74014ead646SFam Zheng extent->has_zero_grain = le32_to_cpu(header.flags) & VMDK4_FLAG_ZERO_GRAIN; 7414823970bSFam Zheng ret = vmdk_init_tables(bs, extent, errp); 742b4b3ab14SFam Zheng if (ret) { 74386c6b429SFam Zheng /* free extent allocated by vmdk_add_extent */ 74486c6b429SFam Zheng vmdk_free_last_extent(bs); 745019d6b8fSAnthony Liguori } 746b4b3ab14SFam Zheng return ret; 747b4b3ab14SFam Zheng } 748b4b3ab14SFam Zheng 7497fa60fa3SFam Zheng /* find an option value out of descriptor file */ 7507fa60fa3SFam Zheng static int vmdk_parse_description(const char *desc, const char *opt_name, 7517fa60fa3SFam Zheng char *buf, int buf_size) 7527fa60fa3SFam Zheng { 7537fa60fa3SFam Zheng char *opt_pos, *opt_end; 7547fa60fa3SFam Zheng const char *end = desc + strlen(desc); 7557fa60fa3SFam Zheng 7567fa60fa3SFam Zheng opt_pos = strstr(desc, opt_name); 7577fa60fa3SFam Zheng if (!opt_pos) { 75865f74725SFam Zheng return VMDK_ERROR; 7597fa60fa3SFam Zheng } 7607fa60fa3SFam Zheng /* Skip "=\"" following opt_name */ 7617fa60fa3SFam Zheng opt_pos += strlen(opt_name) + 2; 7627fa60fa3SFam Zheng if (opt_pos >= end) { 76365f74725SFam Zheng return VMDK_ERROR; 7647fa60fa3SFam Zheng } 7657fa60fa3SFam Zheng opt_end = opt_pos; 7667fa60fa3SFam Zheng while (opt_end < end && *opt_end != '"') { 7677fa60fa3SFam Zheng opt_end++; 7687fa60fa3SFam Zheng } 7697fa60fa3SFam Zheng if (opt_end == end || buf_size < opt_end - opt_pos + 1) { 77065f74725SFam Zheng return VMDK_ERROR; 7717fa60fa3SFam Zheng } 7727fa60fa3SFam Zheng pstrcpy(buf, opt_end - opt_pos + 1, opt_pos); 77365f74725SFam Zheng return VMDK_OK; 7747fa60fa3SFam Zheng } 7757fa60fa3SFam Zheng 77686c6b429SFam Zheng /* Open an extent file and append to bs array */ 77724bc15d1SKevin Wolf static int vmdk_open_sparse(BlockDriverState *bs, BdrvChild *file, int flags, 778a6468367SKevin Wolf char *buf, QDict *options, Error **errp) 77986c6b429SFam Zheng { 78086c6b429SFam Zheng uint32_t magic; 78186c6b429SFam Zheng 782d1833ef5SPaolo Bonzini magic = ldl_be_p(buf); 78386c6b429SFam Zheng switch (magic) { 78486c6b429SFam Zheng case VMDK3_MAGIC: 7854823970bSFam Zheng return vmdk_open_vmfs_sparse(bs, file, flags, errp); 78686c6b429SFam Zheng break; 78786c6b429SFam Zheng case VMDK4_MAGIC: 788a6468367SKevin Wolf return vmdk_open_vmdk4(bs, file, flags, options, errp); 78986c6b429SFam Zheng break; 79086c6b429SFam Zheng default: 79176abe407SPaolo Bonzini error_setg(errp, "Image not in VMDK format"); 79276abe407SPaolo Bonzini return -EINVAL; 79386c6b429SFam Zheng break; 79486c6b429SFam Zheng } 79586c6b429SFam Zheng } 79686c6b429SFam Zheng 797e4937694SMarkus Armbruster static const char *next_line(const char *s) 798e4937694SMarkus Armbruster { 799e4937694SMarkus Armbruster while (*s) { 800e4937694SMarkus Armbruster if (*s == '\n') { 801e4937694SMarkus Armbruster return s + 1; 802e4937694SMarkus Armbruster } 803e4937694SMarkus Armbruster s++; 804e4937694SMarkus Armbruster } 805e4937694SMarkus Armbruster return s; 806e4937694SMarkus Armbruster } 807e4937694SMarkus Armbruster 8087fa60fa3SFam Zheng static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, 809a6468367SKevin Wolf const char *desc_file_path, QDict *options, 810a6468367SKevin Wolf Error **errp) 8117fa60fa3SFam Zheng { 8127fa60fa3SFam Zheng int ret; 813395a22faSJeff Cody int matches; 8147fa60fa3SFam Zheng char access[11]; 8157fa60fa3SFam Zheng char type[11]; 8167fa60fa3SFam Zheng char fname[512]; 817d28d737fSMarkus Armbruster const char *p, *np; 8187fa60fa3SFam Zheng int64_t sectors = 0; 8197fa60fa3SFam Zheng int64_t flat_offset; 820fe206562SJeff Cody char *extent_path; 82124bc15d1SKevin Wolf BdrvChild *extent_file; 822f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 823f4c129a3SFam Zheng VmdkExtent *extent; 824a6468367SKevin Wolf char extent_opt_prefix[32]; 82524bc15d1SKevin Wolf Error *local_err = NULL; 8267fa60fa3SFam Zheng 827e4937694SMarkus Armbruster for (p = desc; *p; p = next_line(p)) { 8288a3e0bc3SFam Zheng /* parse extent line in one of below formats: 8298a3e0bc3SFam Zheng * 8307fa60fa3SFam Zheng * RW [size in sectors] FLAT "file-name.vmdk" OFFSET 8317fa60fa3SFam Zheng * RW [size in sectors] SPARSE "file-name.vmdk" 8328a3e0bc3SFam Zheng * RW [size in sectors] VMFS "file-name.vmdk" 8338a3e0bc3SFam Zheng * RW [size in sectors] VMFSSPARSE "file-name.vmdk" 8347fa60fa3SFam Zheng */ 8357fa60fa3SFam Zheng flat_offset = -1; 836395a22faSJeff Cody matches = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, 8377fa60fa3SFam Zheng access, §ors, type, fname, &flat_offset); 838395a22faSJeff Cody if (matches < 4 || strcmp(access, "RW")) { 839e4937694SMarkus Armbruster continue; 8407fa60fa3SFam Zheng } else if (!strcmp(type, "FLAT")) { 841395a22faSJeff Cody if (matches != 5 || flat_offset < 0) { 842d28d737fSMarkus Armbruster goto invalid; 8437fa60fa3SFam Zheng } 844dbbcaa8dSFam Zheng } else if (!strcmp(type, "VMFS")) { 845395a22faSJeff Cody if (matches == 4) { 846dbbcaa8dSFam Zheng flat_offset = 0; 847b47053bdSFam Zheng } else { 848d28d737fSMarkus Armbruster goto invalid; 849b47053bdSFam Zheng } 850395a22faSJeff Cody } else if (matches != 4) { 851d28d737fSMarkus Armbruster goto invalid; 8527fa60fa3SFam Zheng } 8537fa60fa3SFam Zheng 8547fa60fa3SFam Zheng if (sectors <= 0 || 855daac8fdcSFam Zheng (strcmp(type, "FLAT") && strcmp(type, "SPARSE") && 85604d542c8SPaolo Bonzini strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) || 8577fa60fa3SFam Zheng (strcmp(access, "RW"))) { 858e4937694SMarkus Armbruster continue; 8597fa60fa3SFam Zheng } 8607fa60fa3SFam Zheng 8615c98415bSMax Reitz if (!path_is_absolute(fname) && !path_has_protocol(fname) && 8625c98415bSMax Reitz !desc_file_path[0]) 8635c98415bSMax Reitz { 8645c98415bSMax Reitz error_setg(errp, "Cannot use relative extent paths with VMDK " 8659a4f4c31SKevin Wolf "descriptor file '%s'", bs->file->bs->filename); 8665c98415bSMax Reitz return -EINVAL; 8675c98415bSMax Reitz } 8685c98415bSMax Reitz 869fe206562SJeff Cody extent_path = g_malloc0(PATH_MAX); 870a7be17beSJeff Cody path_combine(extent_path, PATH_MAX, desc_file_path, fname); 871a6468367SKevin Wolf 872a6468367SKevin Wolf ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents); 873a6468367SKevin Wolf assert(ret < 32); 874a6468367SKevin Wolf 87524bc15d1SKevin Wolf extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix, 87624bc15d1SKevin Wolf bs, &child_file, false, &local_err); 877fe206562SJeff Cody g_free(extent_path); 87824bc15d1SKevin Wolf if (local_err) { 87924bc15d1SKevin Wolf error_propagate(errp, local_err); 88024bc15d1SKevin Wolf return -EINVAL; 8817fa60fa3SFam Zheng } 88286c6b429SFam Zheng 88386c6b429SFam Zheng /* save to extents array */ 88404d542c8SPaolo Bonzini if (!strcmp(type, "FLAT") || !strcmp(type, "VMFS")) { 88586c6b429SFam Zheng /* FLAT extent */ 88686c6b429SFam Zheng 8878aa1331cSFam Zheng ret = vmdk_add_extent(bs, extent_file, true, sectors, 8884823970bSFam Zheng 0, 0, 0, 0, 0, &extent, errp); 8898aa1331cSFam Zheng if (ret < 0) { 89024bc15d1SKevin Wolf bdrv_unref_child(bs, extent_file); 8918aa1331cSFam Zheng return ret; 8928aa1331cSFam Zheng } 893f16f509dSFam Zheng extent->flat_start_offset = flat_offset << 9; 894daac8fdcSFam Zheng } else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) { 895daac8fdcSFam Zheng /* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/ 896cf2ab8fcSKevin Wolf char *buf = vmdk_read_desc(extent_file, 0, errp); 897d1833ef5SPaolo Bonzini if (!buf) { 898d1833ef5SPaolo Bonzini ret = -EINVAL; 899d1833ef5SPaolo Bonzini } else { 900a6468367SKevin Wolf ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, buf, 901a6468367SKevin Wolf options, errp); 902d1833ef5SPaolo Bonzini } 903d1833ef5SPaolo Bonzini g_free(buf); 904b6b1d31fSStefan Hajnoczi if (ret) { 90524bc15d1SKevin Wolf bdrv_unref_child(bs, extent_file); 90686c6b429SFam Zheng return ret; 90786c6b429SFam Zheng } 908f4c129a3SFam Zheng extent = &s->extents[s->num_extents - 1]; 9097fa60fa3SFam Zheng } else { 9104823970bSFam Zheng error_setg(errp, "Unsupported extent type '%s'", type); 91124bc15d1SKevin Wolf bdrv_unref_child(bs, extent_file); 9127fa60fa3SFam Zheng return -ENOTSUP; 9137fa60fa3SFam Zheng } 914f4c129a3SFam Zheng extent->type = g_strdup(type); 915899f1ae2SFam Zheng } 9167fa60fa3SFam Zheng return 0; 917d28d737fSMarkus Armbruster 918d28d737fSMarkus Armbruster invalid: 919d28d737fSMarkus Armbruster np = next_line(p); 920d28d737fSMarkus Armbruster assert(np != p); 921d28d737fSMarkus Armbruster if (np[-1] == '\n') { 922d28d737fSMarkus Armbruster np--; 923d28d737fSMarkus Armbruster } 924d28d737fSMarkus Armbruster error_setg(errp, "Invalid extent line: %.*s", (int)(np - p), p); 925d28d737fSMarkus Armbruster return -EINVAL; 9267fa60fa3SFam Zheng } 9277fa60fa3SFam Zheng 928d1833ef5SPaolo Bonzini static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, 929a6468367SKevin Wolf QDict *options, Error **errp) 9307fa60fa3SFam Zheng { 9317fa60fa3SFam Zheng int ret; 9327fa60fa3SFam Zheng char ct[128]; 9337fa60fa3SFam Zheng BDRVVmdkState *s = bs->opaque; 9347fa60fa3SFam Zheng 9357fa60fa3SFam Zheng if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) { 93676abe407SPaolo Bonzini error_setg(errp, "invalid VMDK image descriptor"); 93776abe407SPaolo Bonzini ret = -EINVAL; 9380bed087dSEvgeny Budilovsky goto exit; 9397fa60fa3SFam Zheng } 9406398de51SFam Zheng if (strcmp(ct, "monolithicFlat") && 94104d542c8SPaolo Bonzini strcmp(ct, "vmfs") && 942daac8fdcSFam Zheng strcmp(ct, "vmfsSparse") && 94386c6b429SFam Zheng strcmp(ct, "twoGbMaxExtentSparse") && 9446398de51SFam Zheng strcmp(ct, "twoGbMaxExtentFlat")) { 9454823970bSFam Zheng error_setg(errp, "Unsupported image type '%s'", ct); 9460bed087dSEvgeny Budilovsky ret = -ENOTSUP; 9470bed087dSEvgeny Budilovsky goto exit; 9487fa60fa3SFam Zheng } 949f4c129a3SFam Zheng s->create_type = g_strdup(ct); 9507fa60fa3SFam Zheng s->desc_offset = 0; 9519a4f4c31SKevin Wolf ret = vmdk_parse_extents(buf, bs, bs->file->bs->exact_filename, options, 9529a4f4c31SKevin Wolf errp); 9530bed087dSEvgeny Budilovsky exit: 9540bed087dSEvgeny Budilovsky return ret; 9557fa60fa3SFam Zheng } 9567fa60fa3SFam Zheng 957015a1036SMax Reitz static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, 958015a1036SMax Reitz Error **errp) 959b4b3ab14SFam Zheng { 9609aeecbbcSFam Zheng char *buf; 96186c6b429SFam Zheng int ret; 96286c6b429SFam Zheng BDRVVmdkState *s = bs->opaque; 96337f09e5eSPaolo Bonzini uint32_t magic; 964fe44dc91SAshijeet Acharya Error *local_err = NULL; 965b4b3ab14SFam Zheng 9664e4bf5c4SKevin Wolf bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file, 9674e4bf5c4SKevin Wolf false, errp); 9684e4bf5c4SKevin Wolf if (!bs->file) { 9694e4bf5c4SKevin Wolf return -EINVAL; 9704e4bf5c4SKevin Wolf } 9714e4bf5c4SKevin Wolf 972cf2ab8fcSKevin Wolf buf = vmdk_read_desc(bs->file, 0, errp); 973d1833ef5SPaolo Bonzini if (!buf) { 974d1833ef5SPaolo Bonzini return -EINVAL; 975d1833ef5SPaolo Bonzini } 976d1833ef5SPaolo Bonzini 97737f09e5eSPaolo Bonzini magic = ldl_be_p(buf); 97837f09e5eSPaolo Bonzini switch (magic) { 97937f09e5eSPaolo Bonzini case VMDK3_MAGIC: 98037f09e5eSPaolo Bonzini case VMDK4_MAGIC: 9819a4f4c31SKevin Wolf ret = vmdk_open_sparse(bs, bs->file, flags, buf, options, 98224bc15d1SKevin Wolf errp); 98386c6b429SFam Zheng s->desc_offset = 0x200; 98437f09e5eSPaolo Bonzini break; 98537f09e5eSPaolo Bonzini default: 986a6468367SKevin Wolf ret = vmdk_open_desc_file(bs, flags, buf, options, errp); 98737f09e5eSPaolo Bonzini break; 98837f09e5eSPaolo Bonzini } 989bae0a0ccSPaolo Bonzini if (ret) { 990bae0a0ccSPaolo Bonzini goto fail; 991bae0a0ccSPaolo Bonzini } 99237f09e5eSPaolo Bonzini 99386c6b429SFam Zheng /* try to open parent images, if exist */ 99486c6b429SFam Zheng ret = vmdk_parent_open(bs); 99586c6b429SFam Zheng if (ret) { 996bae0a0ccSPaolo Bonzini goto fail; 997b4b3ab14SFam Zheng } 9989877860eSPeter Maydell ret = vmdk_read_cid(bs, 0, &s->cid); 9999877860eSPeter Maydell if (ret) { 10009877860eSPeter Maydell goto fail; 10019877860eSPeter Maydell } 10029877860eSPeter Maydell ret = vmdk_read_cid(bs, 1, &s->parent_cid); 10039877860eSPeter Maydell if (ret) { 10049877860eSPeter Maydell goto fail; 10059877860eSPeter Maydell } 1006848c66e8SPaolo Bonzini qemu_co_mutex_init(&s->lock); 10072bc3166cSKevin Wolf 10082bc3166cSKevin Wolf /* Disable migration when VMDK images are used */ 100981e5f78aSAlberto Garcia error_setg(&s->migration_blocker, "The vmdk format used by node '%s' " 101081e5f78aSAlberto Garcia "does not support live migration", 101181e5f78aSAlberto Garcia bdrv_get_device_or_node_name(bs)); 1012fe44dc91SAshijeet Acharya ret = migrate_add_blocker(s->migration_blocker, &local_err); 1013fe44dc91SAshijeet Acharya if (local_err) { 1014fe44dc91SAshijeet Acharya error_propagate(errp, local_err); 1015fe44dc91SAshijeet Acharya error_free(s->migration_blocker); 1016fe44dc91SAshijeet Acharya goto fail; 1017fe44dc91SAshijeet Acharya } 1018fe44dc91SAshijeet Acharya 1019d1833ef5SPaolo Bonzini g_free(buf); 10202bc3166cSKevin Wolf return 0; 1021bae0a0ccSPaolo Bonzini 1022bae0a0ccSPaolo Bonzini fail: 1023d1833ef5SPaolo Bonzini g_free(buf); 1024f4c129a3SFam Zheng g_free(s->create_type); 1025f4c129a3SFam Zheng s->create_type = NULL; 1026bae0a0ccSPaolo Bonzini vmdk_free_extents(bs); 1027bae0a0ccSPaolo Bonzini return ret; 1028019d6b8fSAnthony Liguori } 1029019d6b8fSAnthony Liguori 1030d34682cdSKevin Wolf 10313baca891SKevin Wolf static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp) 1032d34682cdSKevin Wolf { 1033d34682cdSKevin Wolf BDRVVmdkState *s = bs->opaque; 1034d34682cdSKevin Wolf int i; 1035d34682cdSKevin Wolf 1036d34682cdSKevin Wolf for (i = 0; i < s->num_extents; i++) { 1037d34682cdSKevin Wolf if (!s->extents[i].flat) { 1038cf081fcaSEric Blake bs->bl.pwrite_zeroes_alignment = 1039cf081fcaSEric Blake MAX(bs->bl.pwrite_zeroes_alignment, 1040cf081fcaSEric Blake s->extents[i].cluster_sectors << BDRV_SECTOR_BITS); 1041d34682cdSKevin Wolf } 1042d34682cdSKevin Wolf } 1043d34682cdSKevin Wolf } 1044d34682cdSKevin Wolf 1045c6ac36e1SFam Zheng /** 1046c6ac36e1SFam Zheng * get_whole_cluster 1047c6ac36e1SFam Zheng * 1048c6ac36e1SFam Zheng * Copy backing file's cluster that covers @sector_num, otherwise write zero, 1049c6ac36e1SFam Zheng * to the cluster at @cluster_sector_num. 1050c6ac36e1SFam Zheng * 1051c6ac36e1SFam Zheng * If @skip_start_sector < @skip_end_sector, the relative range 1052c6ac36e1SFam Zheng * [@skip_start_sector, @skip_end_sector) is not copied or written, and leave 1053c6ac36e1SFam Zheng * it for call to write user data in the request. 1054c6ac36e1SFam Zheng */ 1055b3976d3cSFam Zheng static int get_whole_cluster(BlockDriverState *bs, 1056b3976d3cSFam Zheng VmdkExtent *extent, 105737b1d7d8SKevin Wolf uint64_t cluster_offset, 105837b1d7d8SKevin Wolf uint64_t offset, 105937b1d7d8SKevin Wolf uint64_t skip_start_bytes, 106037b1d7d8SKevin Wolf uint64_t skip_end_bytes) 1061019d6b8fSAnthony Liguori { 1062bf81507dSFam Zheng int ret = VMDK_OK; 1063c6ac36e1SFam Zheng int64_t cluster_bytes; 1064c6ac36e1SFam Zheng uint8_t *whole_grain; 1065019d6b8fSAnthony Liguori 1066c6ac36e1SFam Zheng /* For COW, align request sector_num to cluster start */ 1067c6ac36e1SFam Zheng cluster_bytes = extent->cluster_sectors << BDRV_SECTOR_BITS; 106837b1d7d8SKevin Wolf offset = QEMU_ALIGN_DOWN(offset, cluster_bytes); 1069c6ac36e1SFam Zheng whole_grain = qemu_blockalign(bs, cluster_bytes); 1070c6ac36e1SFam Zheng 1071760e0063SKevin Wolf if (!bs->backing) { 107237b1d7d8SKevin Wolf memset(whole_grain, 0, skip_start_bytes); 107337b1d7d8SKevin Wolf memset(whole_grain + skip_end_bytes, 0, cluster_bytes - skip_end_bytes); 1074c6ac36e1SFam Zheng } 1075c6ac36e1SFam Zheng 107637b1d7d8SKevin Wolf assert(skip_end_bytes <= cluster_bytes); 10770e69c543SFam Zheng /* we will be here if it's first write on non-exist grain(cluster). 10780e69c543SFam Zheng * try to read from parent image, if exist */ 1079760e0063SKevin Wolf if (bs->backing && !vmdk_is_cid_valid(bs)) { 1080c6ac36e1SFam Zheng ret = VMDK_ERROR; 1081c6ac36e1SFam Zheng goto exit; 1082c6ac36e1SFam Zheng } 1083c6ac36e1SFam Zheng 1084c6ac36e1SFam Zheng /* Read backing data before skip range */ 108537b1d7d8SKevin Wolf if (skip_start_bytes > 0) { 1086760e0063SKevin Wolf if (bs->backing) { 108723c4b2a8SMax Reitz /* qcow2 emits this on bs->file instead of bs->backing */ 108823c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_COW_READ); 1089cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->backing, offset, whole_grain, 109037b1d7d8SKevin Wolf skip_start_bytes); 1091c336500dSKevin Wolf if (ret < 0) { 1092bf81507dSFam Zheng ret = VMDK_ERROR; 1093bf81507dSFam Zheng goto exit; 1094019d6b8fSAnthony Liguori } 1095019d6b8fSAnthony Liguori } 109623c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE); 1097d9ca2ea2SKevin Wolf ret = bdrv_pwrite(extent->file, cluster_offset, whole_grain, 109837b1d7d8SKevin Wolf skip_start_bytes); 1099c6ac36e1SFam Zheng if (ret < 0) { 1100c6ac36e1SFam Zheng ret = VMDK_ERROR; 1101c6ac36e1SFam Zheng goto exit; 1102c6ac36e1SFam Zheng } 1103c6ac36e1SFam Zheng } 1104c6ac36e1SFam Zheng /* Read backing data after skip range */ 110537b1d7d8SKevin Wolf if (skip_end_bytes < cluster_bytes) { 1106760e0063SKevin Wolf if (bs->backing) { 110723c4b2a8SMax Reitz /* qcow2 emits this on bs->file instead of bs->backing */ 110823c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_COW_READ); 1109cf2ab8fcSKevin Wolf ret = bdrv_pread(bs->backing, offset + skip_end_bytes, 111037b1d7d8SKevin Wolf whole_grain + skip_end_bytes, 111137b1d7d8SKevin Wolf cluster_bytes - skip_end_bytes); 1112c6ac36e1SFam Zheng if (ret < 0) { 1113c6ac36e1SFam Zheng ret = VMDK_ERROR; 1114c6ac36e1SFam Zheng goto exit; 1115c6ac36e1SFam Zheng } 1116c6ac36e1SFam Zheng } 111723c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_COW_WRITE); 1118d9ca2ea2SKevin Wolf ret = bdrv_pwrite(extent->file, cluster_offset + skip_end_bytes, 111937b1d7d8SKevin Wolf whole_grain + skip_end_bytes, 112037b1d7d8SKevin Wolf cluster_bytes - skip_end_bytes); 1121c6ac36e1SFam Zheng if (ret < 0) { 1122c6ac36e1SFam Zheng ret = VMDK_ERROR; 1123c6ac36e1SFam Zheng goto exit; 1124c6ac36e1SFam Zheng } 1125c6ac36e1SFam Zheng } 1126c6ac36e1SFam Zheng 112737b1d7d8SKevin Wolf ret = VMDK_OK; 1128bf81507dSFam Zheng exit: 1129bf81507dSFam Zheng qemu_vfree(whole_grain); 1130bf81507dSFam Zheng return ret; 1131019d6b8fSAnthony Liguori } 1132019d6b8fSAnthony Liguori 1133c6ac36e1SFam Zheng static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, 1134c6ac36e1SFam Zheng uint32_t offset) 1135019d6b8fSAnthony Liguori { 1136c6ac36e1SFam Zheng offset = cpu_to_le32(offset); 1137019d6b8fSAnthony Liguori /* update L2 table */ 113823c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_L2_UPDATE); 1139d9ca2ea2SKevin Wolf if (bdrv_pwrite_sync(extent->file, 1140b3976d3cSFam Zheng ((int64_t)m_data->l2_offset * 512) 1141c6ac36e1SFam Zheng + (m_data->l2_index * sizeof(offset)), 1142e304e8e5SFam Zheng &offset, sizeof(offset)) < 0) { 114365f74725SFam Zheng return VMDK_ERROR; 1144b3976d3cSFam Zheng } 1145019d6b8fSAnthony Liguori /* update backup L2 table */ 1146b3976d3cSFam Zheng if (extent->l1_backup_table_offset != 0) { 1147b3976d3cSFam Zheng m_data->l2_offset = extent->l1_backup_table[m_data->l1_index]; 1148d9ca2ea2SKevin Wolf if (bdrv_pwrite_sync(extent->file, 1149b3976d3cSFam Zheng ((int64_t)m_data->l2_offset * 512) 1150c6ac36e1SFam Zheng + (m_data->l2_index * sizeof(offset)), 1151e304e8e5SFam Zheng &offset, sizeof(offset)) < 0) { 115265f74725SFam Zheng return VMDK_ERROR; 1153019d6b8fSAnthony Liguori } 1154b3976d3cSFam Zheng } 1155cdeaf1f1SFam Zheng if (m_data->l2_cache_entry) { 1156cdeaf1f1SFam Zheng *m_data->l2_cache_entry = offset; 1157cdeaf1f1SFam Zheng } 1158019d6b8fSAnthony Liguori 115965f74725SFam Zheng return VMDK_OK; 1160019d6b8fSAnthony Liguori } 1161019d6b8fSAnthony Liguori 1162c6ac36e1SFam Zheng /** 1163c6ac36e1SFam Zheng * get_cluster_offset 1164c6ac36e1SFam Zheng * 1165c6ac36e1SFam Zheng * Look up cluster offset in extent file by sector number, and store in 1166c6ac36e1SFam Zheng * @cluster_offset. 1167c6ac36e1SFam Zheng * 1168c6ac36e1SFam Zheng * For flat extents, the start offset as parsed from the description file is 1169c6ac36e1SFam Zheng * returned. 1170c6ac36e1SFam Zheng * 1171c6ac36e1SFam Zheng * For sparse extents, look up in L1, L2 table. If allocate is true, return an 1172c6ac36e1SFam Zheng * offset for a new cluster and update L2 cache. If there is a backing file, 1173c6ac36e1SFam Zheng * COW is done before returning; otherwise, zeroes are written to the allocated 1174c6ac36e1SFam Zheng * cluster. Both COW and zero writing skips the sector range 1175c6ac36e1SFam Zheng * [@skip_start_sector, @skip_end_sector) passed in by caller, because caller 1176c6ac36e1SFam Zheng * has new data to write there. 1177c6ac36e1SFam Zheng * 1178c6ac36e1SFam Zheng * Returns: VMDK_OK if cluster exists and mapped in the image. 1179c6ac36e1SFam Zheng * VMDK_UNALLOC if cluster is not mapped and @allocate is false. 1180c6ac36e1SFam Zheng * VMDK_ERROR if failed. 1181c6ac36e1SFam Zheng */ 118291b85bd3SFam Zheng static int get_cluster_offset(BlockDriverState *bs, 1183b3976d3cSFam Zheng VmdkExtent *extent, 1184b3976d3cSFam Zheng VmdkMetaData *m_data, 118591b85bd3SFam Zheng uint64_t offset, 1186c6ac36e1SFam Zheng bool allocate, 1187c6ac36e1SFam Zheng uint64_t *cluster_offset, 118837b1d7d8SKevin Wolf uint64_t skip_start_bytes, 118937b1d7d8SKevin Wolf uint64_t skip_end_bytes) 1190019d6b8fSAnthony Liguori { 1191019d6b8fSAnthony Liguori unsigned int l1_index, l2_offset, l2_index; 1192019d6b8fSAnthony Liguori int min_index, i, j; 1193e304e8e5SFam Zheng uint32_t min_count, *l2_table; 119414ead646SFam Zheng bool zeroed = false; 1195c6ac36e1SFam Zheng int64_t ret; 1196d1319b07SFam Zheng int64_t cluster_sector; 1197019d6b8fSAnthony Liguori 1198ae261c86SFam Zheng if (m_data) { 1199019d6b8fSAnthony Liguori m_data->valid = 0; 1200ae261c86SFam Zheng } 120191b85bd3SFam Zheng if (extent->flat) { 12027fa60fa3SFam Zheng *cluster_offset = extent->flat_start_offset; 120365f74725SFam Zheng return VMDK_OK; 120491b85bd3SFam Zheng } 1205019d6b8fSAnthony Liguori 12066398de51SFam Zheng offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE; 1207b3976d3cSFam Zheng l1_index = (offset >> 9) / extent->l1_entry_sectors; 1208b3976d3cSFam Zheng if (l1_index >= extent->l1_size) { 120965f74725SFam Zheng return VMDK_ERROR; 1210b3976d3cSFam Zheng } 1211b3976d3cSFam Zheng l2_offset = extent->l1_table[l1_index]; 1212b3976d3cSFam Zheng if (!l2_offset) { 121365f74725SFam Zheng return VMDK_UNALLOC; 1214b3976d3cSFam Zheng } 1215019d6b8fSAnthony Liguori for (i = 0; i < L2_CACHE_SIZE; i++) { 1216b3976d3cSFam Zheng if (l2_offset == extent->l2_cache_offsets[i]) { 1217019d6b8fSAnthony Liguori /* increment the hit count */ 1218b3976d3cSFam Zheng if (++extent->l2_cache_counts[i] == 0xffffffff) { 1219019d6b8fSAnthony Liguori for (j = 0; j < L2_CACHE_SIZE; j++) { 1220b3976d3cSFam Zheng extent->l2_cache_counts[j] >>= 1; 1221019d6b8fSAnthony Liguori } 1222019d6b8fSAnthony Liguori } 1223b3976d3cSFam Zheng l2_table = extent->l2_cache + (i * extent->l2_size); 1224019d6b8fSAnthony Liguori goto found; 1225019d6b8fSAnthony Liguori } 1226019d6b8fSAnthony Liguori } 1227019d6b8fSAnthony Liguori /* not found: load a new entry in the least used one */ 1228019d6b8fSAnthony Liguori min_index = 0; 1229019d6b8fSAnthony Liguori min_count = 0xffffffff; 1230019d6b8fSAnthony Liguori for (i = 0; i < L2_CACHE_SIZE; i++) { 1231b3976d3cSFam Zheng if (extent->l2_cache_counts[i] < min_count) { 1232b3976d3cSFam Zheng min_count = extent->l2_cache_counts[i]; 1233019d6b8fSAnthony Liguori min_index = i; 1234019d6b8fSAnthony Liguori } 1235019d6b8fSAnthony Liguori } 1236b3976d3cSFam Zheng l2_table = extent->l2_cache + (min_index * extent->l2_size); 123723c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_L2_LOAD); 1238cf2ab8fcSKevin Wolf if (bdrv_pread(extent->file, 1239b3976d3cSFam Zheng (int64_t)l2_offset * 512, 1240b3976d3cSFam Zheng l2_table, 1241b3976d3cSFam Zheng extent->l2_size * sizeof(uint32_t) 1242b3976d3cSFam Zheng ) != extent->l2_size * sizeof(uint32_t)) { 124365f74725SFam Zheng return VMDK_ERROR; 1244b3976d3cSFam Zheng } 1245019d6b8fSAnthony Liguori 1246b3976d3cSFam Zheng extent->l2_cache_offsets[min_index] = l2_offset; 1247b3976d3cSFam Zheng extent->l2_cache_counts[min_index] = 1; 1248019d6b8fSAnthony Liguori found: 1249b3976d3cSFam Zheng l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size; 1250c6ac36e1SFam Zheng cluster_sector = le32_to_cpu(l2_table[l2_index]); 1251019d6b8fSAnthony Liguori 1252c6ac36e1SFam Zheng if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) { 125314ead646SFam Zheng zeroed = true; 125414ead646SFam Zheng } 125514ead646SFam Zheng 1256c6ac36e1SFam Zheng if (!cluster_sector || zeroed) { 125791b85bd3SFam Zheng if (!allocate) { 125814ead646SFam Zheng return zeroed ? VMDK_ZEROED : VMDK_UNALLOC; 125991b85bd3SFam Zheng } 12609949f97eSKevin Wolf 1261a77672eaSyuchenlin if (extent->next_cluster_sector >= VMDK_EXTENT_MAX_SECTORS) { 1262a77672eaSyuchenlin return VMDK_ERROR; 1263a77672eaSyuchenlin } 1264a77672eaSyuchenlin 1265c6ac36e1SFam Zheng cluster_sector = extent->next_cluster_sector; 1266c6ac36e1SFam Zheng extent->next_cluster_sector += extent->cluster_sectors; 12679949f97eSKevin Wolf 1268019d6b8fSAnthony Liguori /* First of all we write grain itself, to avoid race condition 1269019d6b8fSAnthony Liguori * that may to corrupt the image. 1270019d6b8fSAnthony Liguori * This problem may occur because of insufficient space on host disk 1271019d6b8fSAnthony Liguori * or inappropriate VM shutdown. 1272019d6b8fSAnthony Liguori */ 127337b1d7d8SKevin Wolf ret = get_whole_cluster(bs, extent, cluster_sector * BDRV_SECTOR_SIZE, 127437b1d7d8SKevin Wolf offset, skip_start_bytes, skip_end_bytes); 1275c6ac36e1SFam Zheng if (ret) { 1276c6ac36e1SFam Zheng return ret; 1277019d6b8fSAnthony Liguori } 1278524089bcSReda Sallahi if (m_data) { 1279524089bcSReda Sallahi m_data->valid = 1; 1280524089bcSReda Sallahi m_data->l1_index = l1_index; 1281524089bcSReda Sallahi m_data->l2_index = l2_index; 1282524089bcSReda Sallahi m_data->l2_offset = l2_offset; 1283524089bcSReda Sallahi m_data->l2_cache_entry = &l2_table[l2_index]; 1284524089bcSReda Sallahi } 1285019d6b8fSAnthony Liguori } 1286c6ac36e1SFam Zheng *cluster_offset = cluster_sector << BDRV_SECTOR_BITS; 128765f74725SFam Zheng return VMDK_OK; 1288019d6b8fSAnthony Liguori } 1289019d6b8fSAnthony Liguori 1290b3976d3cSFam Zheng static VmdkExtent *find_extent(BDRVVmdkState *s, 1291b3976d3cSFam Zheng int64_t sector_num, VmdkExtent *start_hint) 1292b3976d3cSFam Zheng { 1293b3976d3cSFam Zheng VmdkExtent *extent = start_hint; 1294b3976d3cSFam Zheng 1295b3976d3cSFam Zheng if (!extent) { 1296b3976d3cSFam Zheng extent = &s->extents[0]; 1297b3976d3cSFam Zheng } 1298b3976d3cSFam Zheng while (extent < &s->extents[s->num_extents]) { 1299b3976d3cSFam Zheng if (sector_num < extent->end_sector) { 1300b3976d3cSFam Zheng return extent; 1301b3976d3cSFam Zheng } 1302b3976d3cSFam Zheng extent++; 1303b3976d3cSFam Zheng } 1304b3976d3cSFam Zheng return NULL; 1305b3976d3cSFam Zheng } 1306b3976d3cSFam Zheng 1307a844a2b0SKevin Wolf static inline uint64_t vmdk_find_offset_in_cluster(VmdkExtent *extent, 1308a844a2b0SKevin Wolf int64_t offset) 1309a844a2b0SKevin Wolf { 13109be38598SEduardo Habkost uint64_t extent_begin_offset, extent_relative_offset; 1311a844a2b0SKevin Wolf uint64_t cluster_size = extent->cluster_sectors * BDRV_SECTOR_SIZE; 1312a844a2b0SKevin Wolf 1313a844a2b0SKevin Wolf extent_begin_offset = 1314a844a2b0SKevin Wolf (extent->end_sector - extent->sectors) * BDRV_SECTOR_SIZE; 1315a844a2b0SKevin Wolf extent_relative_offset = offset - extent_begin_offset; 13169be38598SEduardo Habkost return extent_relative_offset % cluster_size; 1317a844a2b0SKevin Wolf } 1318a844a2b0SKevin Wolf 1319c72080b9SEric Blake static int coroutine_fn vmdk_co_block_status(BlockDriverState *bs, 1320c72080b9SEric Blake bool want_zero, 1321c72080b9SEric Blake int64_t offset, int64_t bytes, 1322c72080b9SEric Blake int64_t *pnum, int64_t *map, 1323c72080b9SEric Blake BlockDriverState **file) 1324019d6b8fSAnthony Liguori { 1325019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1326b3976d3cSFam Zheng int64_t index_in_cluster, n, ret; 1327c72080b9SEric Blake uint64_t cluster_offset; 1328b3976d3cSFam Zheng VmdkExtent *extent; 1329b3976d3cSFam Zheng 1330c72080b9SEric Blake extent = find_extent(s, offset >> BDRV_SECTOR_BITS, NULL); 1331b3976d3cSFam Zheng if (!extent) { 1332c72080b9SEric Blake return -EIO; 1333b3976d3cSFam Zheng } 1334f8a2e5e3SStefan Hajnoczi qemu_co_mutex_lock(&s->lock); 1335c72080b9SEric Blake ret = get_cluster_offset(bs, extent, NULL, offset, false, &cluster_offset, 1336c6ac36e1SFam Zheng 0, 0); 1337f8a2e5e3SStefan Hajnoczi qemu_co_mutex_unlock(&s->lock); 133814ead646SFam Zheng 1339c72080b9SEric Blake index_in_cluster = vmdk_find_offset_in_cluster(extent, offset); 13404bc74be9SPaolo Bonzini switch (ret) { 13414bc74be9SPaolo Bonzini case VMDK_ERROR: 13424bc74be9SPaolo Bonzini ret = -EIO; 13434bc74be9SPaolo Bonzini break; 13444bc74be9SPaolo Bonzini case VMDK_UNALLOC: 13454bc74be9SPaolo Bonzini ret = 0; 13464bc74be9SPaolo Bonzini break; 13474bc74be9SPaolo Bonzini case VMDK_ZEROED: 13484bc74be9SPaolo Bonzini ret = BDRV_BLOCK_ZERO; 13494bc74be9SPaolo Bonzini break; 13504bc74be9SPaolo Bonzini case VMDK_OK: 13514bc74be9SPaolo Bonzini ret = BDRV_BLOCK_DATA; 1352e0f100f5SFam Zheng if (!extent->compressed) { 1353d0a18f10SFam Zheng ret |= BDRV_BLOCK_OFFSET_VALID; 1354c72080b9SEric Blake *map = cluster_offset + index_in_cluster; 13554bc74be9SPaolo Bonzini } 1356e0f100f5SFam Zheng *file = extent->file->bs; 13574bc74be9SPaolo Bonzini break; 13584bc74be9SPaolo Bonzini } 135991b85bd3SFam Zheng 1360c72080b9SEric Blake n = extent->cluster_sectors * BDRV_SECTOR_SIZE - index_in_cluster; 1361c72080b9SEric Blake *pnum = MIN(n, bytes); 1362b3976d3cSFam Zheng return ret; 1363019d6b8fSAnthony Liguori } 1364019d6b8fSAnthony Liguori 1365dd3f6ee2SFam Zheng static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, 136637b1d7d8SKevin Wolf int64_t offset_in_cluster, QEMUIOVector *qiov, 136737b1d7d8SKevin Wolf uint64_t qiov_offset, uint64_t n_bytes, 136837b1d7d8SKevin Wolf uint64_t offset) 1369dd3f6ee2SFam Zheng { 1370dd3f6ee2SFam Zheng int ret; 13712b2c8c5dSFam Zheng VmdkGrainMarker *data = NULL; 13722b2c8c5dSFam Zheng uLongf buf_len; 137337b1d7d8SKevin Wolf QEMUIOVector local_qiov; 137437b1d7d8SKevin Wolf struct iovec iov; 13755e82a31eSFam Zheng int64_t write_offset; 13765e82a31eSFam Zheng int64_t write_end_sector; 1377dd3f6ee2SFam Zheng 13782b2c8c5dSFam Zheng if (extent->compressed) { 137937b1d7d8SKevin Wolf void *compressed_data; 138037b1d7d8SKevin Wolf 13812b2c8c5dSFam Zheng if (!extent->has_marker) { 13822b2c8c5dSFam Zheng ret = -EINVAL; 13832b2c8c5dSFam Zheng goto out; 13842b2c8c5dSFam Zheng } 13852b2c8c5dSFam Zheng buf_len = (extent->cluster_sectors << 9) * 2; 13862b2c8c5dSFam Zheng data = g_malloc(buf_len + sizeof(VmdkGrainMarker)); 138737b1d7d8SKevin Wolf 138837b1d7d8SKevin Wolf compressed_data = g_malloc(n_bytes); 138937b1d7d8SKevin Wolf qemu_iovec_to_buf(qiov, qiov_offset, compressed_data, n_bytes); 139037b1d7d8SKevin Wolf ret = compress(data->data, &buf_len, compressed_data, n_bytes); 139137b1d7d8SKevin Wolf g_free(compressed_data); 139237b1d7d8SKevin Wolf 139337b1d7d8SKevin Wolf if (ret != Z_OK || buf_len == 0) { 13942b2c8c5dSFam Zheng ret = -EINVAL; 13952b2c8c5dSFam Zheng goto out; 13962b2c8c5dSFam Zheng } 13975e82a31eSFam Zheng 13984545d4f4SQingFeng Hao data->lba = cpu_to_le64(offset >> BDRV_SECTOR_BITS); 13994545d4f4SQingFeng Hao data->size = cpu_to_le32(buf_len); 140037b1d7d8SKevin Wolf 140137b1d7d8SKevin Wolf n_bytes = buf_len + sizeof(VmdkGrainMarker); 140237b1d7d8SKevin Wolf iov = (struct iovec) { 140337b1d7d8SKevin Wolf .iov_base = data, 140437b1d7d8SKevin Wolf .iov_len = n_bytes, 140537b1d7d8SKevin Wolf }; 140637b1d7d8SKevin Wolf qemu_iovec_init_external(&local_qiov, &iov, 1); 140723c4b2a8SMax Reitz 140823c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_WRITE_COMPRESSED); 140937b1d7d8SKevin Wolf } else { 141037b1d7d8SKevin Wolf qemu_iovec_init(&local_qiov, qiov->niov); 141137b1d7d8SKevin Wolf qemu_iovec_concat(&local_qiov, qiov, qiov_offset, n_bytes); 141223c4b2a8SMax Reitz 141323c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_WRITE_AIO); 141437b1d7d8SKevin Wolf } 141537b1d7d8SKevin Wolf 14163c363575SMax Reitz write_offset = cluster_offset + offset_in_cluster; 1417a03ef88fSKevin Wolf ret = bdrv_co_pwritev(extent->file, write_offset, n_bytes, 141837b1d7d8SKevin Wolf &local_qiov, 0); 141937b1d7d8SKevin Wolf 142037b1d7d8SKevin Wolf write_end_sector = DIV_ROUND_UP(write_offset + n_bytes, BDRV_SECTOR_SIZE); 14215e82a31eSFam Zheng 14223efffc32SRadoslav Gerganov if (extent->compressed) { 14233efffc32SRadoslav Gerganov extent->next_cluster_sector = write_end_sector; 14243efffc32SRadoslav Gerganov } else { 14255e82a31eSFam Zheng extent->next_cluster_sector = MAX(extent->next_cluster_sector, 14265e82a31eSFam Zheng write_end_sector); 14273efffc32SRadoslav Gerganov } 14285e82a31eSFam Zheng 142937b1d7d8SKevin Wolf if (ret < 0) { 1430dd3f6ee2SFam Zheng goto out; 1431dd3f6ee2SFam Zheng } 1432dd3f6ee2SFam Zheng ret = 0; 1433dd3f6ee2SFam Zheng out: 14342b2c8c5dSFam Zheng g_free(data); 143537b1d7d8SKevin Wolf if (!extent->compressed) { 143637b1d7d8SKevin Wolf qemu_iovec_destroy(&local_qiov); 143737b1d7d8SKevin Wolf } 1438dd3f6ee2SFam Zheng return ret; 1439dd3f6ee2SFam Zheng } 1440dd3f6ee2SFam Zheng 1441dd3f6ee2SFam Zheng static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, 1442f10cc243SKevin Wolf int64_t offset_in_cluster, QEMUIOVector *qiov, 1443f10cc243SKevin Wolf int bytes) 1444dd3f6ee2SFam Zheng { 1445dd3f6ee2SFam Zheng int ret; 14462b2c8c5dSFam Zheng int cluster_bytes, buf_bytes; 14472b2c8c5dSFam Zheng uint8_t *cluster_buf, *compressed_data; 14482b2c8c5dSFam Zheng uint8_t *uncomp_buf; 14492b2c8c5dSFam Zheng uint32_t data_len; 14502b2c8c5dSFam Zheng VmdkGrainMarker *marker; 14512b2c8c5dSFam Zheng uLongf buf_len; 1452dd3f6ee2SFam Zheng 14532b2c8c5dSFam Zheng 14542b2c8c5dSFam Zheng if (!extent->compressed) { 145523c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_READ_AIO); 1456a03ef88fSKevin Wolf ret = bdrv_co_preadv(extent->file, 1457f10cc243SKevin Wolf cluster_offset + offset_in_cluster, bytes, 1458f10cc243SKevin Wolf qiov, 0); 1459f10cc243SKevin Wolf if (ret < 0) { 1460f10cc243SKevin Wolf return ret; 1461dd3f6ee2SFam Zheng } 1462f10cc243SKevin Wolf return 0; 1463dd3f6ee2SFam Zheng } 14642b2c8c5dSFam Zheng cluster_bytes = extent->cluster_sectors * 512; 14652b2c8c5dSFam Zheng /* Read two clusters in case GrainMarker + compressed data > one cluster */ 14662b2c8c5dSFam Zheng buf_bytes = cluster_bytes * 2; 14672b2c8c5dSFam Zheng cluster_buf = g_malloc(buf_bytes); 14682b2c8c5dSFam Zheng uncomp_buf = g_malloc(cluster_bytes); 146923c4b2a8SMax Reitz BLKDBG_EVENT(extent->file, BLKDBG_READ_COMPRESSED); 1470cf2ab8fcSKevin Wolf ret = bdrv_pread(extent->file, 14712b2c8c5dSFam Zheng cluster_offset, 14722b2c8c5dSFam Zheng cluster_buf, buf_bytes); 14732b2c8c5dSFam Zheng if (ret < 0) { 14742b2c8c5dSFam Zheng goto out; 14752b2c8c5dSFam Zheng } 14762b2c8c5dSFam Zheng compressed_data = cluster_buf; 14772b2c8c5dSFam Zheng buf_len = cluster_bytes; 14782b2c8c5dSFam Zheng data_len = cluster_bytes; 14792b2c8c5dSFam Zheng if (extent->has_marker) { 14802b2c8c5dSFam Zheng marker = (VmdkGrainMarker *)cluster_buf; 14812b2c8c5dSFam Zheng compressed_data = marker->data; 14822b2c8c5dSFam Zheng data_len = le32_to_cpu(marker->size); 14832b2c8c5dSFam Zheng } 14842b2c8c5dSFam Zheng if (!data_len || data_len > buf_bytes) { 14852b2c8c5dSFam Zheng ret = -EINVAL; 14862b2c8c5dSFam Zheng goto out; 14872b2c8c5dSFam Zheng } 14882b2c8c5dSFam Zheng ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len); 14892b2c8c5dSFam Zheng if (ret != Z_OK) { 14902b2c8c5dSFam Zheng ret = -EINVAL; 14912b2c8c5dSFam Zheng goto out; 14922b2c8c5dSFam Zheng 14932b2c8c5dSFam Zheng } 14942b2c8c5dSFam Zheng if (offset_in_cluster < 0 || 1495f10cc243SKevin Wolf offset_in_cluster + bytes > buf_len) { 14962b2c8c5dSFam Zheng ret = -EINVAL; 14972b2c8c5dSFam Zheng goto out; 14982b2c8c5dSFam Zheng } 1499f10cc243SKevin Wolf qemu_iovec_from_buf(qiov, 0, uncomp_buf + offset_in_cluster, bytes); 15002b2c8c5dSFam Zheng ret = 0; 15012b2c8c5dSFam Zheng 15022b2c8c5dSFam Zheng out: 15032b2c8c5dSFam Zheng g_free(uncomp_buf); 15042b2c8c5dSFam Zheng g_free(cluster_buf); 15052b2c8c5dSFam Zheng return ret; 15062b2c8c5dSFam Zheng } 1507dd3f6ee2SFam Zheng 1508f10cc243SKevin Wolf static int coroutine_fn 1509f10cc243SKevin Wolf vmdk_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 1510f10cc243SKevin Wolf QEMUIOVector *qiov, int flags) 1511019d6b8fSAnthony Liguori { 1512019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1513b3976d3cSFam Zheng int ret; 1514f10cc243SKevin Wolf uint64_t n_bytes, offset_in_cluster; 1515b3976d3cSFam Zheng VmdkExtent *extent = NULL; 1516f10cc243SKevin Wolf QEMUIOVector local_qiov; 1517019d6b8fSAnthony Liguori uint64_t cluster_offset; 1518f10cc243SKevin Wolf uint64_t bytes_done = 0; 1519019d6b8fSAnthony Liguori 1520f10cc243SKevin Wolf qemu_iovec_init(&local_qiov, qiov->niov); 1521f10cc243SKevin Wolf qemu_co_mutex_lock(&s->lock); 1522f10cc243SKevin Wolf 1523f10cc243SKevin Wolf while (bytes > 0) { 1524f10cc243SKevin Wolf extent = find_extent(s, offset >> BDRV_SECTOR_BITS, extent); 1525b3976d3cSFam Zheng if (!extent) { 1526f10cc243SKevin Wolf ret = -EIO; 1527f10cc243SKevin Wolf goto fail; 1528b3976d3cSFam Zheng } 1529c6ac36e1SFam Zheng ret = get_cluster_offset(bs, extent, NULL, 1530f10cc243SKevin Wolf offset, false, &cluster_offset, 0, 0); 1531f10cc243SKevin Wolf offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset); 1532f10cc243SKevin Wolf 1533f10cc243SKevin Wolf n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE 1534f10cc243SKevin Wolf - offset_in_cluster); 1535f10cc243SKevin Wolf 153614ead646SFam Zheng if (ret != VMDK_OK) { 153791b85bd3SFam Zheng /* if not allocated, try to read from parent image, if exist */ 1538760e0063SKevin Wolf if (bs->backing && ret != VMDK_ZEROED) { 1539ae261c86SFam Zheng if (!vmdk_is_cid_valid(bs)) { 1540f10cc243SKevin Wolf ret = -EINVAL; 1541f10cc243SKevin Wolf goto fail; 1542019d6b8fSAnthony Liguori } 1543019d6b8fSAnthony Liguori 1544f10cc243SKevin Wolf qemu_iovec_reset(&local_qiov); 1545f10cc243SKevin Wolf qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes); 1546f10cc243SKevin Wolf 154723c4b2a8SMax Reitz /* qcow2 emits this on bs->file instead of bs->backing */ 154823c4b2a8SMax Reitz BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); 1549a03ef88fSKevin Wolf ret = bdrv_co_preadv(bs->backing, offset, n_bytes, 1550f10cc243SKevin Wolf &local_qiov, 0); 1551f10cc243SKevin Wolf if (ret < 0) { 1552f10cc243SKevin Wolf goto fail; 1553f10cc243SKevin Wolf } 1554f10cc243SKevin Wolf } else { 1555f10cc243SKevin Wolf qemu_iovec_memset(qiov, bytes_done, 0, n_bytes); 1556f10cc243SKevin Wolf } 1557f10cc243SKevin Wolf } else { 1558f10cc243SKevin Wolf qemu_iovec_reset(&local_qiov); 1559f10cc243SKevin Wolf qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes); 1560f10cc243SKevin Wolf 1561f10cc243SKevin Wolf ret = vmdk_read_extent(extent, cluster_offset, offset_in_cluster, 1562f10cc243SKevin Wolf &local_qiov, n_bytes); 1563f10cc243SKevin Wolf if (ret) { 1564f10cc243SKevin Wolf goto fail; 1565f10cc243SKevin Wolf } 1566f10cc243SKevin Wolf } 1567f10cc243SKevin Wolf bytes -= n_bytes; 1568f10cc243SKevin Wolf offset += n_bytes; 1569f10cc243SKevin Wolf bytes_done += n_bytes; 1570f10cc243SKevin Wolf } 1571f10cc243SKevin Wolf 1572f10cc243SKevin Wolf ret = 0; 1573f10cc243SKevin Wolf fail: 15742914caa0SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 1575f10cc243SKevin Wolf qemu_iovec_destroy(&local_qiov); 1576f10cc243SKevin Wolf 15772914caa0SPaolo Bonzini return ret; 15782914caa0SPaolo Bonzini } 15792914caa0SPaolo Bonzini 1580cdeaf1f1SFam Zheng /** 1581cdeaf1f1SFam Zheng * vmdk_write: 1582cdeaf1f1SFam Zheng * @zeroed: buf is ignored (data is zero), use zeroed_grain GTE feature 1583cdeaf1f1SFam Zheng * if possible, otherwise return -ENOTSUP. 15848e507243SFam Zheng * @zero_dry_run: used for zeroed == true only, don't update L2 table, just try 15858e507243SFam Zheng * with each cluster. By dry run we can find if the zero write 15868e507243SFam Zheng * is possible without modifying image data. 1587cdeaf1f1SFam Zheng * 1588cdeaf1f1SFam Zheng * Returns: error code with 0 for success. 1589cdeaf1f1SFam Zheng */ 159037b1d7d8SKevin Wolf static int vmdk_pwritev(BlockDriverState *bs, uint64_t offset, 159137b1d7d8SKevin Wolf uint64_t bytes, QEMUIOVector *qiov, 1592cdeaf1f1SFam Zheng bool zeroed, bool zero_dry_run) 1593019d6b8fSAnthony Liguori { 1594019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1595b3976d3cSFam Zheng VmdkExtent *extent = NULL; 1596585ea0c8SFam Zheng int ret; 159737b1d7d8SKevin Wolf int64_t offset_in_cluster, n_bytes; 1598019d6b8fSAnthony Liguori uint64_t cluster_offset; 159937b1d7d8SKevin Wolf uint64_t bytes_done = 0; 1600b3976d3cSFam Zheng VmdkMetaData m_data; 1601019d6b8fSAnthony Liguori 160237b1d7d8SKevin Wolf if (DIV_ROUND_UP(offset, BDRV_SECTOR_SIZE) > bs->total_sectors) { 160337b1d7d8SKevin Wolf error_report("Wrong offset: offset=0x%" PRIx64 16049af9e0feSMarkus Armbruster " total_sectors=0x%" PRIx64, 160537b1d7d8SKevin Wolf offset, bs->total_sectors); 16067fa60fa3SFam Zheng return -EIO; 1607019d6b8fSAnthony Liguori } 1608019d6b8fSAnthony Liguori 160937b1d7d8SKevin Wolf while (bytes > 0) { 161037b1d7d8SKevin Wolf extent = find_extent(s, offset >> BDRV_SECTOR_BITS, extent); 1611b3976d3cSFam Zheng if (!extent) { 1612b3976d3cSFam Zheng return -EIO; 1613b3976d3cSFam Zheng } 161437b1d7d8SKevin Wolf offset_in_cluster = vmdk_find_offset_in_cluster(extent, offset); 161537b1d7d8SKevin Wolf n_bytes = MIN(bytes, extent->cluster_sectors * BDRV_SECTOR_SIZE 161637b1d7d8SKevin Wolf - offset_in_cluster); 161737b1d7d8SKevin Wolf 161837b1d7d8SKevin Wolf ret = get_cluster_offset(bs, extent, &m_data, offset, 1619c6ac36e1SFam Zheng !(extent->compressed || zeroed), 162037b1d7d8SKevin Wolf &cluster_offset, offset_in_cluster, 162137b1d7d8SKevin Wolf offset_in_cluster + n_bytes); 16222b2c8c5dSFam Zheng if (extent->compressed) { 162365f74725SFam Zheng if (ret == VMDK_OK) { 16242b2c8c5dSFam Zheng /* Refuse write to allocated cluster for streamOptimized */ 16254823970bSFam Zheng error_report("Could not write to allocated cluster" 16264823970bSFam Zheng " for streamOptimized"); 16272b2c8c5dSFam Zheng return -EIO; 16282b2c8c5dSFam Zheng } else { 16292b2c8c5dSFam Zheng /* allocate */ 163037b1d7d8SKevin Wolf ret = get_cluster_offset(bs, extent, &m_data, offset, 1631c6ac36e1SFam Zheng true, &cluster_offset, 0, 0); 16322b2c8c5dSFam Zheng } 16332b2c8c5dSFam Zheng } 1634cdeaf1f1SFam Zheng if (ret == VMDK_ERROR) { 163591b85bd3SFam Zheng return -EINVAL; 1636b3976d3cSFam Zheng } 1637cdeaf1f1SFam Zheng if (zeroed) { 1638cdeaf1f1SFam Zheng /* Do zeroed write, buf is ignored */ 1639cdeaf1f1SFam Zheng if (extent->has_zero_grain && 164037b1d7d8SKevin Wolf offset_in_cluster == 0 && 164137b1d7d8SKevin Wolf n_bytes >= extent->cluster_sectors * BDRV_SECTOR_SIZE) { 164237b1d7d8SKevin Wolf n_bytes = extent->cluster_sectors * BDRV_SECTOR_SIZE; 1643cdeaf1f1SFam Zheng if (!zero_dry_run) { 1644cdeaf1f1SFam Zheng /* update L2 tables */ 1645c6ac36e1SFam Zheng if (vmdk_L2update(extent, &m_data, VMDK_GTE_ZEROED) 1646c6ac36e1SFam Zheng != VMDK_OK) { 1647cdeaf1f1SFam Zheng return -EIO; 1648cdeaf1f1SFam Zheng } 1649cdeaf1f1SFam Zheng } 1650cdeaf1f1SFam Zheng } else { 1651cdeaf1f1SFam Zheng return -ENOTSUP; 1652cdeaf1f1SFam Zheng } 1653cdeaf1f1SFam Zheng } else { 165437b1d7d8SKevin Wolf ret = vmdk_write_extent(extent, cluster_offset, offset_in_cluster, 165537b1d7d8SKevin Wolf qiov, bytes_done, n_bytes, offset); 1656dd3f6ee2SFam Zheng if (ret) { 16577fa60fa3SFam Zheng return ret; 1658b3976d3cSFam Zheng } 1659019d6b8fSAnthony Liguori if (m_data.valid) { 1660019d6b8fSAnthony Liguori /* update L2 tables */ 1661c6ac36e1SFam Zheng if (vmdk_L2update(extent, &m_data, 1662c6ac36e1SFam Zheng cluster_offset >> BDRV_SECTOR_BITS) 1663c6ac36e1SFam Zheng != VMDK_OK) { 16647fa60fa3SFam Zheng return -EIO; 1665019d6b8fSAnthony Liguori } 1666b3976d3cSFam Zheng } 1667cdeaf1f1SFam Zheng } 166837b1d7d8SKevin Wolf bytes -= n_bytes; 166937b1d7d8SKevin Wolf offset += n_bytes; 167037b1d7d8SKevin Wolf bytes_done += n_bytes; 1671019d6b8fSAnthony Liguori 1672ae261c86SFam Zheng /* update CID on the first write every time the virtual disk is 1673ae261c86SFam Zheng * opened */ 167469b4d86dSFam Zheng if (!s->cid_updated) { 1675e5dc64b8SFam Zheng ret = vmdk_write_cid(bs, g_random_int()); 167699f1835dSKevin Wolf if (ret < 0) { 167799f1835dSKevin Wolf return ret; 167899f1835dSKevin Wolf } 167969b4d86dSFam Zheng s->cid_updated = true; 1680019d6b8fSAnthony Liguori } 1681019d6b8fSAnthony Liguori } 1682019d6b8fSAnthony Liguori return 0; 1683019d6b8fSAnthony Liguori } 1684019d6b8fSAnthony Liguori 168537b1d7d8SKevin Wolf static int coroutine_fn 168637b1d7d8SKevin Wolf vmdk_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes, 168737b1d7d8SKevin Wolf QEMUIOVector *qiov, int flags) 1688e183ef75SPaolo Bonzini { 1689e183ef75SPaolo Bonzini int ret; 1690e183ef75SPaolo Bonzini BDRVVmdkState *s = bs->opaque; 1691e183ef75SPaolo Bonzini qemu_co_mutex_lock(&s->lock); 169237b1d7d8SKevin Wolf ret = vmdk_pwritev(bs, offset, bytes, qiov, false, false); 1693cdeaf1f1SFam Zheng qemu_co_mutex_unlock(&s->lock); 1694cdeaf1f1SFam Zheng return ret; 1695cdeaf1f1SFam Zheng } 1696cdeaf1f1SFam Zheng 1697b2c622d3SPavel Butsykin static int coroutine_fn 1698b2c622d3SPavel Butsykin vmdk_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset, 1699b2c622d3SPavel Butsykin uint64_t bytes, QEMUIOVector *qiov) 170037b1d7d8SKevin Wolf { 170151b3c6b7Syuchenlin if (bytes == 0) { 170251b3c6b7Syuchenlin /* The caller will write bytes 0 to signal EOF. 170351b3c6b7Syuchenlin * When receive it, we align EOF to a sector boundary. */ 170451b3c6b7Syuchenlin BDRVVmdkState *s = bs->opaque; 170551b3c6b7Syuchenlin int i, ret; 170651b3c6b7Syuchenlin int64_t length; 170751b3c6b7Syuchenlin 170851b3c6b7Syuchenlin for (i = 0; i < s->num_extents; i++) { 170951b3c6b7Syuchenlin length = bdrv_getlength(s->extents[i].file->bs); 171051b3c6b7Syuchenlin if (length < 0) { 171151b3c6b7Syuchenlin return length; 171251b3c6b7Syuchenlin } 171351b3c6b7Syuchenlin length = QEMU_ALIGN_UP(length, BDRV_SECTOR_SIZE); 171451b3c6b7Syuchenlin ret = bdrv_truncate(s->extents[i].file, length, 171551b3c6b7Syuchenlin PREALLOC_MODE_OFF, NULL); 171651b3c6b7Syuchenlin if (ret < 0) { 171751b3c6b7Syuchenlin return ret; 171851b3c6b7Syuchenlin } 171951b3c6b7Syuchenlin } 172051b3c6b7Syuchenlin return 0; 172151b3c6b7Syuchenlin } 1722b2c622d3SPavel Butsykin return vmdk_co_pwritev(bs, offset, bytes, qiov, 0); 1723ba0ad89eSFam Zheng } 1724ba0ad89eSFam Zheng 1725a620f2aeSEric Blake static int coroutine_fn vmdk_co_pwrite_zeroes(BlockDriverState *bs, 1726a620f2aeSEric Blake int64_t offset, 1727a620f2aeSEric Blake int bytes, 1728aa7bfbffSPeter Lieven BdrvRequestFlags flags) 1729cdeaf1f1SFam Zheng { 1730cdeaf1f1SFam Zheng int ret; 1731cdeaf1f1SFam Zheng BDRVVmdkState *s = bs->opaque; 173237b1d7d8SKevin Wolf 1733cdeaf1f1SFam Zheng qemu_co_mutex_lock(&s->lock); 17348e507243SFam Zheng /* write zeroes could fail if sectors not aligned to cluster, test it with 17358e507243SFam Zheng * dry_run == true before really updating image */ 173637b1d7d8SKevin Wolf ret = vmdk_pwritev(bs, offset, bytes, NULL, true, true); 1737cdeaf1f1SFam Zheng if (!ret) { 173837b1d7d8SKevin Wolf ret = vmdk_pwritev(bs, offset, bytes, NULL, true, false); 1739cdeaf1f1SFam Zheng } 1740e183ef75SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 1741e183ef75SPaolo Bonzini return ret; 1742e183ef75SPaolo Bonzini } 1743e183ef75SPaolo Bonzini 17445be28490SFam Zheng static int vmdk_init_extent(BlockBackend *blk, 17455be28490SFam Zheng int64_t filesize, bool flat, 17465be28490SFam Zheng bool compress, bool zeroed_grain, 17475be28490SFam Zheng Error **errp) 1748019d6b8fSAnthony Liguori { 1749f66fd6c3SFam Zheng int ret, i; 1750019d6b8fSAnthony Liguori VMDK4Header header; 1751917703c1SFam Zheng uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count; 1752917703c1SFam Zheng uint32_t *gd_buf = NULL; 1753917703c1SFam Zheng int gd_buf_size; 17540e7e1989SKevin Wolf 1755917703c1SFam Zheng if (flat) { 17563a691c50SMax Reitz ret = blk_truncate(blk, filesize, PREALLOC_MODE_OFF, errp); 1757f66fd6c3SFam Zheng goto exit; 1758f66fd6c3SFam Zheng } 1759019d6b8fSAnthony Liguori magic = cpu_to_be32(VMDK4_MAGIC); 1760019d6b8fSAnthony Liguori memset(&header, 0, sizeof(header)); 1761d62d9dc4SFam Zheng if (compress) { 1762d62d9dc4SFam Zheng header.version = 3; 1763d62d9dc4SFam Zheng } else if (zeroed_grain) { 1764d62d9dc4SFam Zheng header.version = 2; 1765d62d9dc4SFam Zheng } else { 1766d62d9dc4SFam Zheng header.version = 1; 1767d62d9dc4SFam Zheng } 176895b0aa42SFam Zheng header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT 176969e0b6dfSFam Zheng | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0) 177069e0b6dfSFam Zheng | (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0); 17716c031aacSFam Zheng header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0; 1772917703c1SFam Zheng header.capacity = filesize / BDRV_SECTOR_SIZE; 177316372ff0SAlexander Graf header.granularity = 128; 1774917703c1SFam Zheng header.num_gtes_per_gt = BDRV_SECTOR_SIZE; 1775019d6b8fSAnthony Liguori 1776917703c1SFam Zheng grains = DIV_ROUND_UP(filesize / BDRV_SECTOR_SIZE, header.granularity); 1777917703c1SFam Zheng gt_size = DIV_ROUND_UP(header.num_gtes_per_gt * sizeof(uint32_t), 1778917703c1SFam Zheng BDRV_SECTOR_SIZE); 1779917703c1SFam Zheng gt_count = DIV_ROUND_UP(grains, header.num_gtes_per_gt); 1780917703c1SFam Zheng gd_sectors = DIV_ROUND_UP(gt_count * sizeof(uint32_t), BDRV_SECTOR_SIZE); 1781019d6b8fSAnthony Liguori 1782019d6b8fSAnthony Liguori header.desc_offset = 1; 1783019d6b8fSAnthony Liguori header.desc_size = 20; 1784019d6b8fSAnthony Liguori header.rgd_offset = header.desc_offset + header.desc_size; 1785917703c1SFam Zheng header.gd_offset = header.rgd_offset + gd_sectors + (gt_size * gt_count); 1786019d6b8fSAnthony Liguori header.grain_offset = 1787917703c1SFam Zheng ROUND_UP(header.gd_offset + gd_sectors + (gt_size * gt_count), 1788917703c1SFam Zheng header.granularity); 178916372ff0SAlexander Graf /* swap endianness for all header fields */ 179016372ff0SAlexander Graf header.version = cpu_to_le32(header.version); 179116372ff0SAlexander Graf header.flags = cpu_to_le32(header.flags); 179216372ff0SAlexander Graf header.capacity = cpu_to_le64(header.capacity); 179316372ff0SAlexander Graf header.granularity = cpu_to_le64(header.granularity); 1794ca8804ceSFam Zheng header.num_gtes_per_gt = cpu_to_le32(header.num_gtes_per_gt); 1795019d6b8fSAnthony Liguori header.desc_offset = cpu_to_le64(header.desc_offset); 1796019d6b8fSAnthony Liguori header.desc_size = cpu_to_le64(header.desc_size); 1797019d6b8fSAnthony Liguori header.rgd_offset = cpu_to_le64(header.rgd_offset); 1798019d6b8fSAnthony Liguori header.gd_offset = cpu_to_le64(header.gd_offset); 1799019d6b8fSAnthony Liguori header.grain_offset = cpu_to_le64(header.grain_offset); 18006c031aacSFam Zheng header.compressAlgorithm = cpu_to_le16(header.compressAlgorithm); 1801019d6b8fSAnthony Liguori 1802019d6b8fSAnthony Liguori header.check_bytes[0] = 0xa; 1803019d6b8fSAnthony Liguori header.check_bytes[1] = 0x20; 1804019d6b8fSAnthony Liguori header.check_bytes[2] = 0xd; 1805019d6b8fSAnthony Liguori header.check_bytes[3] = 0xa; 1806019d6b8fSAnthony Liguori 1807019d6b8fSAnthony Liguori /* write all the data */ 18088341f00dSEric Blake ret = blk_pwrite(blk, 0, &magic, sizeof(magic), 0); 1809917703c1SFam Zheng if (ret < 0) { 1810c6bd8c70SMarkus Armbruster error_setg(errp, QERR_IO_ERROR); 18111640366cSKirill A. Shutemov goto exit; 18121640366cSKirill A. Shutemov } 18138341f00dSEric Blake ret = blk_pwrite(blk, sizeof(magic), &header, sizeof(header), 0); 1814917703c1SFam Zheng if (ret < 0) { 1815c6bd8c70SMarkus Armbruster error_setg(errp, QERR_IO_ERROR); 18161640366cSKirill A. Shutemov goto exit; 18171640366cSKirill A. Shutemov } 1818019d6b8fSAnthony Liguori 18193a691c50SMax Reitz ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, 18203a691c50SMax Reitz PREALLOC_MODE_OFF, errp); 18211640366cSKirill A. Shutemov if (ret < 0) { 18221640366cSKirill A. Shutemov goto exit; 18231640366cSKirill A. Shutemov } 1824019d6b8fSAnthony Liguori 1825019d6b8fSAnthony Liguori /* write grain directory */ 1826917703c1SFam Zheng gd_buf_size = gd_sectors * BDRV_SECTOR_SIZE; 1827917703c1SFam Zheng gd_buf = g_malloc0(gd_buf_size); 1828917703c1SFam Zheng for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_sectors; 18291640366cSKirill A. Shutemov i < gt_count; i++, tmp += gt_size) { 1830917703c1SFam Zheng gd_buf[i] = cpu_to_le32(tmp); 18311640366cSKirill A. Shutemov } 1832c4bea169SKevin Wolf ret = blk_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE, 18338341f00dSEric Blake gd_buf, gd_buf_size, 0); 1834917703c1SFam Zheng if (ret < 0) { 1835c6bd8c70SMarkus Armbruster error_setg(errp, QERR_IO_ERROR); 1836917703c1SFam Zheng goto exit; 18371640366cSKirill A. Shutemov } 1838019d6b8fSAnthony Liguori 1839019d6b8fSAnthony Liguori /* write backup grain directory */ 1840917703c1SFam Zheng for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_sectors; 18411640366cSKirill A. Shutemov i < gt_count; i++, tmp += gt_size) { 1842917703c1SFam Zheng gd_buf[i] = cpu_to_le32(tmp); 18431640366cSKirill A. Shutemov } 1844c4bea169SKevin Wolf ret = blk_pwrite(blk, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE, 18458341f00dSEric Blake gd_buf, gd_buf_size, 0); 1846917703c1SFam Zheng if (ret < 0) { 1847c6bd8c70SMarkus Armbruster error_setg(errp, QERR_IO_ERROR); 18481640366cSKirill A. Shutemov } 1849019d6b8fSAnthony Liguori 1850f66fd6c3SFam Zheng ret = 0; 1851f66fd6c3SFam Zheng exit: 1852917703c1SFam Zheng g_free(gd_buf); 1853f66fd6c3SFam Zheng return ret; 1854f66fd6c3SFam Zheng } 1855019d6b8fSAnthony Liguori 18565be28490SFam Zheng static int vmdk_create_extent(const char *filename, int64_t filesize, 18575be28490SFam Zheng bool flat, bool compress, bool zeroed_grain, 18585be28490SFam Zheng BlockBackend **pbb, 18595be28490SFam Zheng QemuOpts *opts, Error **errp) 18605be28490SFam Zheng { 18615be28490SFam Zheng int ret; 18625be28490SFam Zheng BlockBackend *blk = NULL; 18635be28490SFam Zheng Error *local_err = NULL; 18645be28490SFam Zheng 18655be28490SFam Zheng ret = bdrv_create_file(filename, opts, &local_err); 18665be28490SFam Zheng if (ret < 0) { 18675be28490SFam Zheng error_propagate(errp, local_err); 18685be28490SFam Zheng goto exit; 18695be28490SFam Zheng } 18705be28490SFam Zheng 18715be28490SFam Zheng blk = blk_new_open(filename, NULL, NULL, 18725be28490SFam Zheng BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, 18735be28490SFam Zheng &local_err); 18745be28490SFam Zheng if (blk == NULL) { 18755be28490SFam Zheng error_propagate(errp, local_err); 18765be28490SFam Zheng ret = -EIO; 18775be28490SFam Zheng goto exit; 18785be28490SFam Zheng } 18795be28490SFam Zheng 18805be28490SFam Zheng blk_set_allow_write_beyond_eof(blk, true); 18815be28490SFam Zheng 18825be28490SFam Zheng ret = vmdk_init_extent(blk, filesize, flat, compress, zeroed_grain, errp); 18835be28490SFam Zheng exit: 18845be28490SFam Zheng if (blk) { 18855be28490SFam Zheng if (pbb) { 18865be28490SFam Zheng *pbb = blk; 18875be28490SFam Zheng } else { 18885be28490SFam Zheng blk_unref(blk); 18895be28490SFam Zheng blk = NULL; 18905be28490SFam Zheng } 18915be28490SFam Zheng } 18925be28490SFam Zheng return ret; 18935be28490SFam Zheng } 18945be28490SFam Zheng 1895f66fd6c3SFam Zheng static int filename_decompose(const char *filename, char *path, char *prefix, 18964823970bSFam Zheng char *postfix, size_t buf_len, Error **errp) 1897f66fd6c3SFam Zheng { 1898f66fd6c3SFam Zheng const char *p, *q; 1899f66fd6c3SFam Zheng 1900f66fd6c3SFam Zheng if (filename == NULL || !strlen(filename)) { 19014823970bSFam Zheng error_setg(errp, "No filename provided"); 190265f74725SFam Zheng return VMDK_ERROR; 1903f66fd6c3SFam Zheng } 1904f66fd6c3SFam Zheng p = strrchr(filename, '/'); 1905f66fd6c3SFam Zheng if (p == NULL) { 1906f66fd6c3SFam Zheng p = strrchr(filename, '\\'); 1907f66fd6c3SFam Zheng } 1908f66fd6c3SFam Zheng if (p == NULL) { 1909f66fd6c3SFam Zheng p = strrchr(filename, ':'); 1910f66fd6c3SFam Zheng } 1911f66fd6c3SFam Zheng if (p != NULL) { 1912f66fd6c3SFam Zheng p++; 1913f66fd6c3SFam Zheng if (p - filename >= buf_len) { 191465f74725SFam Zheng return VMDK_ERROR; 1915f66fd6c3SFam Zheng } 1916f66fd6c3SFam Zheng pstrcpy(path, p - filename + 1, filename); 1917f66fd6c3SFam Zheng } else { 1918f66fd6c3SFam Zheng p = filename; 1919f66fd6c3SFam Zheng path[0] = '\0'; 1920f66fd6c3SFam Zheng } 1921f66fd6c3SFam Zheng q = strrchr(p, '.'); 1922f66fd6c3SFam Zheng if (q == NULL) { 1923f66fd6c3SFam Zheng pstrcpy(prefix, buf_len, p); 1924f66fd6c3SFam Zheng postfix[0] = '\0'; 1925f66fd6c3SFam Zheng } else { 1926f66fd6c3SFam Zheng if (q - p >= buf_len) { 192765f74725SFam Zheng return VMDK_ERROR; 1928f66fd6c3SFam Zheng } 1929f66fd6c3SFam Zheng pstrcpy(prefix, q - p + 1, p); 1930f66fd6c3SFam Zheng pstrcpy(postfix, buf_len, q); 1931f66fd6c3SFam Zheng } 193265f74725SFam Zheng return VMDK_OK; 1933f66fd6c3SFam Zheng } 1934f66fd6c3SFam Zheng 19353015372dSFam Zheng /* 19363015372dSFam Zheng * idx == 0: get or create the descriptor file (also the image file if in a 19373015372dSFam Zheng * non-split format. 19383015372dSFam Zheng * idx >= 1: get the n-th extent if in a split subformat 19393015372dSFam Zheng */ 19403015372dSFam Zheng typedef BlockBackend *(*vmdk_create_extent_fn)(int64_t size, 19413015372dSFam Zheng int idx, 19423015372dSFam Zheng bool flat, 19433015372dSFam Zheng bool split, 19443015372dSFam Zheng bool compress, 19453015372dSFam Zheng bool zeroed_grain, 19463015372dSFam Zheng void *opaque, 19473015372dSFam Zheng Error **errp); 19483015372dSFam Zheng 19493015372dSFam Zheng static void vmdk_desc_add_extent(GString *desc, 19503015372dSFam Zheng const char *extent_line_fmt, 19513015372dSFam Zheng int64_t size, const char *filename) 19523015372dSFam Zheng { 19533015372dSFam Zheng char *basename = g_path_get_basename(filename); 19543015372dSFam Zheng 19553015372dSFam Zheng g_string_append_printf(desc, extent_line_fmt, 19563015372dSFam Zheng DIV_ROUND_UP(size, BDRV_SECTOR_SIZE), basename); 19573015372dSFam Zheng g_free(basename); 19583015372dSFam Zheng } 19593015372dSFam Zheng 19603015372dSFam Zheng static int coroutine_fn vmdk_co_do_create(int64_t size, 19613015372dSFam Zheng BlockdevVmdkSubformat subformat, 19623015372dSFam Zheng BlockdevVmdkAdapterType adapter_type, 19633015372dSFam Zheng const char *backing_file, 19643015372dSFam Zheng const char *hw_version, 19653015372dSFam Zheng bool compat6, 19663015372dSFam Zheng bool zeroed_grain, 19673015372dSFam Zheng vmdk_create_extent_fn extent_fn, 19683015372dSFam Zheng void *opaque, 1969efc75e2aSStefan Hajnoczi Error **errp) 1970f66fd6c3SFam Zheng { 19713015372dSFam Zheng int extent_idx; 19723015372dSFam Zheng BlockBackend *blk = NULL; 19734a960eceSKevin Wolf BlockBackend *extent_blk; 1974c13959c7SFam Zheng Error *local_err = NULL; 1975af057fe7SFam Zheng char *desc = NULL; 1976f66fd6c3SFam Zheng int ret = 0; 19776c031aacSFam Zheng bool flat, split, compress; 1978af057fe7SFam Zheng GString *ext_desc_lines; 1979f66fd6c3SFam Zheng const int64_t split_size = 0x80000000; /* VMDK has constant split size */ 19803015372dSFam Zheng int64_t extent_size; 19813015372dSFam Zheng int64_t created_size = 0; 19823015372dSFam Zheng const char *extent_line_fmt; 1983fe206562SJeff Cody char *parent_desc_line = g_malloc0(BUF_SIZE); 1984f66fd6c3SFam Zheng uint32_t parent_cid = 0xffffffff; 19857f2039f6SOthmar Pasteka uint32_t number_heads = 16; 1986917703c1SFam Zheng uint32_t desc_offset = 0, desc_len; 1987f66fd6c3SFam Zheng const char desc_template[] = 1988f66fd6c3SFam Zheng "# Disk DescriptorFile\n" 1989f66fd6c3SFam Zheng "version=1\n" 19909b17031aSFam Zheng "CID=%" PRIx32 "\n" 19919b17031aSFam Zheng "parentCID=%" PRIx32 "\n" 1992f66fd6c3SFam Zheng "createType=\"%s\"\n" 1993f66fd6c3SFam Zheng "%s" 1994f66fd6c3SFam Zheng "\n" 1995f66fd6c3SFam Zheng "# Extent description\n" 1996f66fd6c3SFam Zheng "%s" 1997f66fd6c3SFam Zheng "\n" 1998f66fd6c3SFam Zheng "# The Disk Data Base\n" 1999f66fd6c3SFam Zheng "#DDB\n" 2000f66fd6c3SFam Zheng "\n" 2001f249924eSJanne Karhunen "ddb.virtualHWVersion = \"%s\"\n" 2002f66fd6c3SFam Zheng "ddb.geometry.cylinders = \"%" PRId64 "\"\n" 20034ab9dab5SFam Zheng "ddb.geometry.heads = \"%" PRIu32 "\"\n" 2004f66fd6c3SFam Zheng "ddb.geometry.sectors = \"63\"\n" 20057f2039f6SOthmar Pasteka "ddb.adapterType = \"%s\"\n"; 2006f66fd6c3SFam Zheng 2007af057fe7SFam Zheng ext_desc_lines = g_string_new(NULL); 2008af057fe7SFam Zheng 2009f66fd6c3SFam Zheng /* Read out options */ 20103015372dSFam Zheng if (compat6) { 20113015372dSFam Zheng if (hw_version) { 2012f249924eSJanne Karhunen error_setg(errp, 2013f249924eSJanne Karhunen "compat6 cannot be enabled with hwversion set"); 2014f249924eSJanne Karhunen ret = -EINVAL; 2015f249924eSJanne Karhunen goto exit; 2016f249924eSJanne Karhunen } 20173015372dSFam Zheng hw_version = "6"; 2018f249924eSJanne Karhunen } 20193015372dSFam Zheng if (!hw_version) { 20203015372dSFam Zheng hw_version = "4"; 2021f66fd6c3SFam Zheng } 20225820f1daSChunyan Liu 20233015372dSFam Zheng if (adapter_type != BLOCKDEV_VMDK_ADAPTER_TYPE_IDE) { 20247f2039f6SOthmar Pasteka /* that's the number of heads with which vmware operates when 20257f2039f6SOthmar Pasteka creating, exporting, etc. vmdk files with a non-ide adapter type */ 20267f2039f6SOthmar Pasteka number_heads = 255; 20277f2039f6SOthmar Pasteka } 20283015372dSFam Zheng split = (subformat == BLOCKDEV_VMDK_SUBFORMAT_TWOGBMAXEXTENTFLAT) || 20293015372dSFam Zheng (subformat == BLOCKDEV_VMDK_SUBFORMAT_TWOGBMAXEXTENTSPARSE); 20303015372dSFam Zheng flat = (subformat == BLOCKDEV_VMDK_SUBFORMAT_MONOLITHICFLAT) || 20313015372dSFam Zheng (subformat == BLOCKDEV_VMDK_SUBFORMAT_TWOGBMAXEXTENTFLAT); 20323015372dSFam Zheng compress = subformat == BLOCKDEV_VMDK_SUBFORMAT_STREAMOPTIMIZED; 20333015372dSFam Zheng 2034f66fd6c3SFam Zheng if (flat) { 20353015372dSFam Zheng extent_line_fmt = "RW %" PRId64 " FLAT \"%s\" 0\n"; 2036f66fd6c3SFam Zheng } else { 20373015372dSFam Zheng extent_line_fmt = "RW %" PRId64 " SPARSE \"%s\"\n"; 2038f66fd6c3SFam Zheng } 2039f66fd6c3SFam Zheng if (flat && backing_file) { 20404823970bSFam Zheng error_setg(errp, "Flat image can't have backing file"); 2041af057fe7SFam Zheng ret = -ENOTSUP; 2042af057fe7SFam Zheng goto exit; 2043f66fd6c3SFam Zheng } 204452c8d629SFam Zheng if (flat && zeroed_grain) { 204552c8d629SFam Zheng error_setg(errp, "Flat image can't enable zeroed grain"); 2046af057fe7SFam Zheng ret = -ENOTSUP; 2047af057fe7SFam Zheng goto exit; 204852c8d629SFam Zheng } 20493015372dSFam Zheng 20503015372dSFam Zheng /* Create extents */ 20513015372dSFam Zheng if (split) { 20523015372dSFam Zheng extent_size = split_size; 20533015372dSFam Zheng } else { 20543015372dSFam Zheng extent_size = size; 20553015372dSFam Zheng } 20563015372dSFam Zheng if (!split && !flat) { 20573015372dSFam Zheng created_size = extent_size; 20583015372dSFam Zheng } else { 20593015372dSFam Zheng created_size = 0; 20603015372dSFam Zheng } 20613015372dSFam Zheng /* Get the descriptor file BDS */ 20623015372dSFam Zheng blk = extent_fn(created_size, 0, flat, split, compress, zeroed_grain, 20633015372dSFam Zheng opaque, errp); 20643015372dSFam Zheng if (!blk) { 20653015372dSFam Zheng ret = -EIO; 20663015372dSFam Zheng goto exit; 20673015372dSFam Zheng } 20683015372dSFam Zheng if (!split && !flat) { 20693015372dSFam Zheng vmdk_desc_add_extent(ext_desc_lines, extent_line_fmt, created_size, 20703015372dSFam Zheng blk_bs(blk)->filename); 20713015372dSFam Zheng } 20723015372dSFam Zheng 2073f66fd6c3SFam Zheng if (backing_file) { 20743015372dSFam Zheng BlockBackend *backing; 20751085daf9SMax Reitz char *full_backing = g_new0(char, PATH_MAX); 20763015372dSFam Zheng bdrv_get_full_backing_filename_from_filename(blk_bs(blk)->filename, backing_file, 20771085daf9SMax Reitz full_backing, PATH_MAX, 20781085daf9SMax Reitz &local_err); 20791085daf9SMax Reitz if (local_err) { 20801085daf9SMax Reitz g_free(full_backing); 20811085daf9SMax Reitz error_propagate(errp, local_err); 20821085daf9SMax Reitz ret = -ENOENT; 20831085daf9SMax Reitz goto exit; 20841085daf9SMax Reitz } 2085c4bea169SKevin Wolf 20863015372dSFam Zheng backing = blk_new_open(full_backing, NULL, NULL, 208772e775c7SKevin Wolf BDRV_O_NO_BACKING, errp); 20881085daf9SMax Reitz g_free(full_backing); 20893015372dSFam Zheng if (backing == NULL) { 2090c4bea169SKevin Wolf ret = -EIO; 2091af057fe7SFam Zheng goto exit; 2092f66fd6c3SFam Zheng } 20933015372dSFam Zheng if (strcmp(blk_bs(backing)->drv->format_name, "vmdk")) { 20943015372dSFam Zheng error_setg(errp, "Invalid backing file format: %s. Must be vmdk", 20953015372dSFam Zheng blk_bs(backing)->drv->format_name); 20963015372dSFam Zheng blk_unref(backing); 2097af057fe7SFam Zheng ret = -EINVAL; 2098af057fe7SFam Zheng goto exit; 2099f66fd6c3SFam Zheng } 21003015372dSFam Zheng ret = vmdk_read_cid(blk_bs(backing), 0, &parent_cid); 21013015372dSFam Zheng blk_unref(backing); 21029877860eSPeter Maydell if (ret) { 21033015372dSFam Zheng error_setg(errp, "Failed to read parent CID"); 21049877860eSPeter Maydell goto exit; 21059877860eSPeter Maydell } 2106fe206562SJeff Cody snprintf(parent_desc_line, BUF_SIZE, 21078ed610a1SFam Zheng "parentFileNameHint=\"%s\"", backing_file); 2108f66fd6c3SFam Zheng } 21093015372dSFam Zheng extent_idx = 1; 21103015372dSFam Zheng while (created_size < size) { 21113015372dSFam Zheng int64_t cur_size = MIN(size - created_size, extent_size); 21123015372dSFam Zheng extent_blk = extent_fn(cur_size, extent_idx, flat, split, compress, 21133015372dSFam Zheng zeroed_grain, opaque, errp); 21143015372dSFam Zheng if (!extent_blk) { 2115af057fe7SFam Zheng ret = -EINVAL; 2116af057fe7SFam Zheng goto exit; 2117f66fd6c3SFam Zheng } 21183015372dSFam Zheng vmdk_desc_add_extent(ext_desc_lines, extent_line_fmt, cur_size, 21193015372dSFam Zheng blk_bs(extent_blk)->filename); 21203015372dSFam Zheng created_size += cur_size; 21213015372dSFam Zheng extent_idx++; 21223015372dSFam Zheng blk_unref(extent_blk); 2123f66fd6c3SFam Zheng } 21244a960eceSKevin Wolf 21254a960eceSKevin Wolf /* Check whether we got excess extents */ 21264a960eceSKevin Wolf extent_blk = extent_fn(-1, extent_idx, flat, split, compress, zeroed_grain, 21274a960eceSKevin Wolf opaque, NULL); 21284a960eceSKevin Wolf if (extent_blk) { 21294a960eceSKevin Wolf blk_unref(extent_blk); 21304a960eceSKevin Wolf error_setg(errp, "List of extents contains unused extents"); 21314a960eceSKevin Wolf ret = -EINVAL; 21324a960eceSKevin Wolf goto exit; 21334a960eceSKevin Wolf } 21344a960eceSKevin Wolf 2135f66fd6c3SFam Zheng /* generate descriptor file */ 2136af057fe7SFam Zheng desc = g_strdup_printf(desc_template, 2137e5dc64b8SFam Zheng g_random_int(), 2138f66fd6c3SFam Zheng parent_cid, 21393015372dSFam Zheng BlockdevVmdkSubformat_str(subformat), 2140f66fd6c3SFam Zheng parent_desc_line, 2141af057fe7SFam Zheng ext_desc_lines->str, 2142f249924eSJanne Karhunen hw_version, 21433015372dSFam Zheng size / 2144917703c1SFam Zheng (int64_t)(63 * number_heads * BDRV_SECTOR_SIZE), 2145af057fe7SFam Zheng number_heads, 21463015372dSFam Zheng BlockdevVmdkAdapterType_str(adapter_type)); 2147917703c1SFam Zheng desc_len = strlen(desc); 2148917703c1SFam Zheng /* the descriptor offset = 0x200 */ 2149917703c1SFam Zheng if (!split && !flat) { 2150917703c1SFam Zheng desc_offset = 0x200; 2151f66fd6c3SFam Zheng } 2152c4bea169SKevin Wolf 21533015372dSFam Zheng ret = blk_pwrite(blk, desc_offset, desc, desc_len, 0); 2154917703c1SFam Zheng if (ret < 0) { 2155917703c1SFam Zheng error_setg_errno(errp, -ret, "Could not write description"); 2156917703c1SFam Zheng goto exit; 2157917703c1SFam Zheng } 2158917703c1SFam Zheng /* bdrv_pwrite write padding zeros to align to sector, we don't need that 2159917703c1SFam Zheng * for description file */ 2160917703c1SFam Zheng if (desc_offset == 0) { 21613015372dSFam Zheng ret = blk_truncate(blk, desc_len, PREALLOC_MODE_OFF, errp); 21623015372dSFam Zheng if (ret < 0) { 21633015372dSFam Zheng goto exit; 2164917703c1SFam Zheng } 21653015372dSFam Zheng } 21663015372dSFam Zheng ret = 0; 2167af057fe7SFam Zheng exit: 21683015372dSFam Zheng if (blk) { 21693015372dSFam Zheng blk_unref(blk); 2170917703c1SFam Zheng } 21713015372dSFam Zheng g_free(desc); 21723015372dSFam Zheng g_free(parent_desc_line); 21733015372dSFam Zheng g_string_free(ext_desc_lines, true); 21743015372dSFam Zheng return ret; 21753015372dSFam Zheng } 21763015372dSFam Zheng 21773015372dSFam Zheng typedef struct { 21783015372dSFam Zheng char *path; 21793015372dSFam Zheng char *prefix; 21803015372dSFam Zheng char *postfix; 21813015372dSFam Zheng QemuOpts *opts; 21823015372dSFam Zheng } VMDKCreateOptsData; 21833015372dSFam Zheng 21843015372dSFam Zheng static BlockBackend *vmdk_co_create_opts_cb(int64_t size, int idx, 21853015372dSFam Zheng bool flat, bool split, bool compress, 21863015372dSFam Zheng bool zeroed_grain, void *opaque, 21873015372dSFam Zheng Error **errp) 21883015372dSFam Zheng { 21893015372dSFam Zheng BlockBackend *blk = NULL; 21903015372dSFam Zheng BlockDriverState *bs = NULL; 21913015372dSFam Zheng VMDKCreateOptsData *data = opaque; 21923015372dSFam Zheng char *ext_filename = NULL; 21933015372dSFam Zheng char *rel_filename = NULL; 21943015372dSFam Zheng 21954a960eceSKevin Wolf /* We're done, don't create excess extents. */ 21964a960eceSKevin Wolf if (size == -1) { 21974a960eceSKevin Wolf assert(errp == NULL); 21984a960eceSKevin Wolf return NULL; 21994a960eceSKevin Wolf } 22004a960eceSKevin Wolf 22013015372dSFam Zheng if (idx == 0) { 22023015372dSFam Zheng rel_filename = g_strdup_printf("%s%s", data->prefix, data->postfix); 22033015372dSFam Zheng } else if (split) { 22043015372dSFam Zheng rel_filename = g_strdup_printf("%s-%c%03d%s", 22053015372dSFam Zheng data->prefix, 22063015372dSFam Zheng flat ? 'f' : 's', idx, data->postfix); 22073015372dSFam Zheng } else { 22083015372dSFam Zheng assert(idx == 1); 22093015372dSFam Zheng rel_filename = g_strdup_printf("%s-flat%s", data->prefix, data->postfix); 22103015372dSFam Zheng } 22113015372dSFam Zheng 22123015372dSFam Zheng ext_filename = g_strdup_printf("%s%s", data->path, rel_filename); 22133015372dSFam Zheng g_free(rel_filename); 22143015372dSFam Zheng 22153015372dSFam Zheng if (vmdk_create_extent(ext_filename, size, 22163015372dSFam Zheng flat, compress, zeroed_grain, &blk, data->opts, 22173015372dSFam Zheng errp)) { 22183015372dSFam Zheng goto exit; 22193015372dSFam Zheng } 22203015372dSFam Zheng bdrv_unref(bs); 22213015372dSFam Zheng exit: 22223015372dSFam Zheng g_free(ext_filename); 22233015372dSFam Zheng return blk; 22243015372dSFam Zheng } 22253015372dSFam Zheng 22263015372dSFam Zheng static int coroutine_fn vmdk_co_create_opts(const char *filename, QemuOpts *opts, 22273015372dSFam Zheng Error **errp) 22283015372dSFam Zheng { 22293015372dSFam Zheng Error *local_err = NULL; 22303015372dSFam Zheng char *desc = NULL; 22313015372dSFam Zheng int64_t total_size = 0; 22323015372dSFam Zheng char *adapter_type = NULL; 22333015372dSFam Zheng BlockdevVmdkAdapterType adapter_type_enum; 22343015372dSFam Zheng char *backing_file = NULL; 22353015372dSFam Zheng char *hw_version = NULL; 22363015372dSFam Zheng char *fmt = NULL; 22373015372dSFam Zheng BlockdevVmdkSubformat subformat; 22383015372dSFam Zheng int ret = 0; 22393015372dSFam Zheng char *path = g_malloc0(PATH_MAX); 22403015372dSFam Zheng char *prefix = g_malloc0(PATH_MAX); 22413015372dSFam Zheng char *postfix = g_malloc0(PATH_MAX); 22423015372dSFam Zheng char *desc_line = g_malloc0(BUF_SIZE); 22433015372dSFam Zheng char *ext_filename = g_malloc0(PATH_MAX); 22443015372dSFam Zheng char *desc_filename = g_malloc0(PATH_MAX); 22453015372dSFam Zheng char *parent_desc_line = g_malloc0(BUF_SIZE); 22463015372dSFam Zheng bool zeroed_grain; 22473015372dSFam Zheng bool compat6; 22483015372dSFam Zheng VMDKCreateOptsData data; 22493015372dSFam Zheng 22503015372dSFam Zheng if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) { 22513015372dSFam Zheng ret = -EINVAL; 22523015372dSFam Zheng goto exit; 22533015372dSFam Zheng } 22543015372dSFam Zheng /* Read out options */ 22553015372dSFam Zheng total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), 22563015372dSFam Zheng BDRV_SECTOR_SIZE); 22573015372dSFam Zheng adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE); 22583015372dSFam Zheng backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); 22593015372dSFam Zheng hw_version = qemu_opt_get_del(opts, BLOCK_OPT_HWVERSION); 22603015372dSFam Zheng compat6 = qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false); 22613015372dSFam Zheng if (strcmp(hw_version, "undefined") == 0) { 22623015372dSFam Zheng g_free(hw_version); 22633015372dSFam Zheng hw_version = g_strdup("4"); 22643015372dSFam Zheng } 22653015372dSFam Zheng fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); 22663015372dSFam Zheng zeroed_grain = qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false); 22673015372dSFam Zheng 22683015372dSFam Zheng if (adapter_type) { 22693015372dSFam Zheng adapter_type_enum = qapi_enum_parse(&BlockdevVmdkAdapterType_lookup, 22703015372dSFam Zheng adapter_type, 22713015372dSFam Zheng BLOCKDEV_VMDK_ADAPTER_TYPE_IDE, 22723015372dSFam Zheng &local_err); 22733015372dSFam Zheng if (local_err) { 22743015372dSFam Zheng error_propagate(errp, local_err); 22753015372dSFam Zheng ret = -EINVAL; 22763015372dSFam Zheng goto exit; 22773015372dSFam Zheng } 22783015372dSFam Zheng } else { 22793015372dSFam Zheng adapter_type_enum = BLOCKDEV_VMDK_ADAPTER_TYPE_IDE; 22803015372dSFam Zheng } 22813015372dSFam Zheng 22823015372dSFam Zheng if (!fmt) { 22833015372dSFam Zheng /* Default format to monolithicSparse */ 22843015372dSFam Zheng subformat = BLOCKDEV_VMDK_SUBFORMAT_MONOLITHICSPARSE; 22853015372dSFam Zheng } else { 22863015372dSFam Zheng subformat = qapi_enum_parse(&BlockdevVmdkSubformat_lookup, 22873015372dSFam Zheng fmt, 22883015372dSFam Zheng BLOCKDEV_VMDK_SUBFORMAT_MONOLITHICSPARSE, 22893015372dSFam Zheng &local_err); 22903015372dSFam Zheng if (local_err) { 22913015372dSFam Zheng error_propagate(errp, local_err); 22923015372dSFam Zheng ret = -EINVAL; 22933015372dSFam Zheng goto exit; 22943015372dSFam Zheng } 22953015372dSFam Zheng } 22963015372dSFam Zheng data = (VMDKCreateOptsData){ 22973015372dSFam Zheng .prefix = prefix, 22983015372dSFam Zheng .postfix = postfix, 22993015372dSFam Zheng .path = path, 23003015372dSFam Zheng .opts = opts, 23013015372dSFam Zheng }; 23023015372dSFam Zheng ret = vmdk_co_do_create(total_size, subformat, adapter_type_enum, 23033015372dSFam Zheng backing_file, hw_version, compat6, zeroed_grain, 23043015372dSFam Zheng vmdk_co_create_opts_cb, &data, errp); 23053015372dSFam Zheng 23063015372dSFam Zheng exit: 23075820f1daSChunyan Liu g_free(adapter_type); 23085820f1daSChunyan Liu g_free(backing_file); 2309f249924eSJanne Karhunen g_free(hw_version); 23105820f1daSChunyan Liu g_free(fmt); 2311af057fe7SFam Zheng g_free(desc); 2312fe206562SJeff Cody g_free(path); 2313fe206562SJeff Cody g_free(prefix); 2314fe206562SJeff Cody g_free(postfix); 2315fe206562SJeff Cody g_free(desc_line); 2316fe206562SJeff Cody g_free(ext_filename); 2317fe206562SJeff Cody g_free(desc_filename); 2318fe206562SJeff Cody g_free(parent_desc_line); 23193015372dSFam Zheng return ret; 23203015372dSFam Zheng } 23213015372dSFam Zheng 23223015372dSFam Zheng static BlockBackend *vmdk_co_create_cb(int64_t size, int idx, 23233015372dSFam Zheng bool flat, bool split, bool compress, 23243015372dSFam Zheng bool zeroed_grain, void *opaque, 23253015372dSFam Zheng Error **errp) 23263015372dSFam Zheng { 23273015372dSFam Zheng int ret; 23283015372dSFam Zheng BlockDriverState *bs; 23293015372dSFam Zheng BlockBackend *blk; 23303015372dSFam Zheng BlockdevCreateOptionsVmdk *opts = opaque; 23313015372dSFam Zheng 23323015372dSFam Zheng if (idx == 0) { 23333015372dSFam Zheng bs = bdrv_open_blockdev_ref(opts->file, errp); 23343015372dSFam Zheng } else { 23353015372dSFam Zheng int i; 23363015372dSFam Zheng BlockdevRefList *list = opts->extents; 23373015372dSFam Zheng for (i = 1; i < idx; i++) { 23383015372dSFam Zheng if (!list || !list->next) { 23393015372dSFam Zheng error_setg(errp, "Extent [%d] not specified", i); 23403015372dSFam Zheng return NULL; 23413015372dSFam Zheng } 23423015372dSFam Zheng list = list->next; 23433015372dSFam Zheng } 23443015372dSFam Zheng if (!list) { 23453015372dSFam Zheng error_setg(errp, "Extent [%d] not specified", idx - 1); 23463015372dSFam Zheng return NULL; 23473015372dSFam Zheng } 23483015372dSFam Zheng bs = bdrv_open_blockdev_ref(list->value, errp); 23493015372dSFam Zheng } 23503015372dSFam Zheng if (!bs) { 23513015372dSFam Zheng return NULL; 23523015372dSFam Zheng } 23533015372dSFam Zheng blk = blk_new(BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE | BLK_PERM_RESIZE, 23543015372dSFam Zheng BLK_PERM_ALL); 23553015372dSFam Zheng if (blk_insert_bs(blk, bs, errp)) { 23563015372dSFam Zheng bdrv_unref(bs); 23573015372dSFam Zheng return NULL; 23583015372dSFam Zheng } 23593015372dSFam Zheng blk_set_allow_write_beyond_eof(blk, true); 23603015372dSFam Zheng bdrv_unref(bs); 23613015372dSFam Zheng 23624a960eceSKevin Wolf if (size != -1) { 23633015372dSFam Zheng ret = vmdk_init_extent(blk, size, flat, compress, zeroed_grain, errp); 23643015372dSFam Zheng if (ret) { 23653015372dSFam Zheng blk_unref(blk); 23663015372dSFam Zheng blk = NULL; 23673015372dSFam Zheng } 23684a960eceSKevin Wolf } 23693015372dSFam Zheng return blk; 23703015372dSFam Zheng } 23713015372dSFam Zheng 23723015372dSFam Zheng static int coroutine_fn vmdk_co_create(BlockdevCreateOptions *create_options, 23733015372dSFam Zheng Error **errp) 23743015372dSFam Zheng { 23753015372dSFam Zheng int ret; 23763015372dSFam Zheng BlockdevCreateOptionsVmdk *opts; 23773015372dSFam Zheng 23783015372dSFam Zheng opts = &create_options->u.vmdk; 23793015372dSFam Zheng 23803015372dSFam Zheng /* Validate options */ 23813015372dSFam Zheng if (!QEMU_IS_ALIGNED(opts->size, BDRV_SECTOR_SIZE)) { 23823015372dSFam Zheng error_setg(errp, "Image size must be a multiple of 512 bytes"); 23833015372dSFam Zheng ret = -EINVAL; 23843015372dSFam Zheng goto out; 23853015372dSFam Zheng } 23863015372dSFam Zheng 23873015372dSFam Zheng ret = vmdk_co_do_create(opts->size, 23883015372dSFam Zheng opts->subformat, 23893015372dSFam Zheng opts->adapter_type, 23903015372dSFam Zheng opts->backing_file, 23913015372dSFam Zheng opts->hwversion, 23923015372dSFam Zheng false, 23933015372dSFam Zheng opts->zeroed_grain, 23943015372dSFam Zheng vmdk_co_create_cb, 23953015372dSFam Zheng opts, errp); 23963015372dSFam Zheng return ret; 23973015372dSFam Zheng 23983015372dSFam Zheng out: 23991640366cSKirill A. Shutemov return ret; 2400019d6b8fSAnthony Liguori } 2401019d6b8fSAnthony Liguori 2402019d6b8fSAnthony Liguori static void vmdk_close(BlockDriverState *bs) 2403019d6b8fSAnthony Liguori { 24042bc3166cSKevin Wolf BDRVVmdkState *s = bs->opaque; 24052bc3166cSKevin Wolf 2406b3976d3cSFam Zheng vmdk_free_extents(bs); 2407f4c129a3SFam Zheng g_free(s->create_type); 24082bc3166cSKevin Wolf 24092bc3166cSKevin Wolf migrate_del_blocker(s->migration_blocker); 24102bc3166cSKevin Wolf error_free(s->migration_blocker); 2411019d6b8fSAnthony Liguori } 2412019d6b8fSAnthony Liguori 24138b94ff85SPaolo Bonzini static coroutine_fn int vmdk_co_flush(BlockDriverState *bs) 2414019d6b8fSAnthony Liguori { 2415333c574dSFam Zheng BDRVVmdkState *s = bs->opaque; 241629cdb251SPaolo Bonzini int i, err; 241729cdb251SPaolo Bonzini int ret = 0; 2418333c574dSFam Zheng 2419333c574dSFam Zheng for (i = 0; i < s->num_extents; i++) { 242024bc15d1SKevin Wolf err = bdrv_co_flush(s->extents[i].file->bs); 2421333c574dSFam Zheng if (err < 0) { 2422333c574dSFam Zheng ret = err; 2423333c574dSFam Zheng } 2424333c574dSFam Zheng } 2425333c574dSFam Zheng return ret; 2426019d6b8fSAnthony Liguori } 2427019d6b8fSAnthony Liguori 24284a1d5e1fSFam Zheng static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) 24294a1d5e1fSFam Zheng { 24304a1d5e1fSFam Zheng int i; 24314a1d5e1fSFam Zheng int64_t ret = 0; 24324a1d5e1fSFam Zheng int64_t r; 24334a1d5e1fSFam Zheng BDRVVmdkState *s = bs->opaque; 24344a1d5e1fSFam Zheng 24359a4f4c31SKevin Wolf ret = bdrv_get_allocated_file_size(bs->file->bs); 24364a1d5e1fSFam Zheng if (ret < 0) { 24374a1d5e1fSFam Zheng return ret; 24384a1d5e1fSFam Zheng } 24394a1d5e1fSFam Zheng for (i = 0; i < s->num_extents; i++) { 24409a4f4c31SKevin Wolf if (s->extents[i].file == bs->file) { 24414a1d5e1fSFam Zheng continue; 24424a1d5e1fSFam Zheng } 244324bc15d1SKevin Wolf r = bdrv_get_allocated_file_size(s->extents[i].file->bs); 24444a1d5e1fSFam Zheng if (r < 0) { 24454a1d5e1fSFam Zheng return r; 24464a1d5e1fSFam Zheng } 24474a1d5e1fSFam Zheng ret += r; 24484a1d5e1fSFam Zheng } 24494a1d5e1fSFam Zheng return ret; 24504a1d5e1fSFam Zheng } 24510e7e1989SKevin Wolf 2452da7a50f9SFam Zheng static int vmdk_has_zero_init(BlockDriverState *bs) 2453da7a50f9SFam Zheng { 2454da7a50f9SFam Zheng int i; 2455da7a50f9SFam Zheng BDRVVmdkState *s = bs->opaque; 2456da7a50f9SFam Zheng 2457da7a50f9SFam Zheng /* If has a flat extent and its underlying storage doesn't have zero init, 2458da7a50f9SFam Zheng * return 0. */ 2459da7a50f9SFam Zheng for (i = 0; i < s->num_extents; i++) { 2460da7a50f9SFam Zheng if (s->extents[i].flat) { 246124bc15d1SKevin Wolf if (!bdrv_has_zero_init(s->extents[i].file->bs)) { 2462da7a50f9SFam Zheng return 0; 2463da7a50f9SFam Zheng } 2464da7a50f9SFam Zheng } 2465da7a50f9SFam Zheng } 2466da7a50f9SFam Zheng return 1; 2467da7a50f9SFam Zheng } 2468da7a50f9SFam Zheng 2469f4c129a3SFam Zheng static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) 2470f4c129a3SFam Zheng { 2471f4c129a3SFam Zheng ImageInfo *info = g_new0(ImageInfo, 1); 2472f4c129a3SFam Zheng 2473f4c129a3SFam Zheng *info = (ImageInfo){ 247424bc15d1SKevin Wolf .filename = g_strdup(extent->file->bs->filename), 2475f4c129a3SFam Zheng .format = g_strdup(extent->type), 2476f4c129a3SFam Zheng .virtual_size = extent->sectors * BDRV_SECTOR_SIZE, 2477f4c129a3SFam Zheng .compressed = extent->compressed, 2478f4c129a3SFam Zheng .has_compressed = extent->compressed, 2479f4c129a3SFam Zheng .cluster_size = extent->cluster_sectors * BDRV_SECTOR_SIZE, 2480f4c129a3SFam Zheng .has_cluster_size = !extent->flat, 2481f4c129a3SFam Zheng }; 2482f4c129a3SFam Zheng 2483f4c129a3SFam Zheng return info; 2484f4c129a3SFam Zheng } 2485f4c129a3SFam Zheng 24862fd61638SPaolo Bonzini static int coroutine_fn vmdk_co_check(BlockDriverState *bs, 24872fd61638SPaolo Bonzini BdrvCheckResult *result, 2488f43aa8e1SPeter Lieven BdrvCheckMode fix) 2489f43aa8e1SPeter Lieven { 2490f43aa8e1SPeter Lieven BDRVVmdkState *s = bs->opaque; 2491f43aa8e1SPeter Lieven VmdkExtent *extent = NULL; 2492f43aa8e1SPeter Lieven int64_t sector_num = 0; 249357322b78SMarkus Armbruster int64_t total_sectors = bdrv_nb_sectors(bs); 2494f43aa8e1SPeter Lieven int ret; 2495f43aa8e1SPeter Lieven uint64_t cluster_offset; 2496f43aa8e1SPeter Lieven 2497f43aa8e1SPeter Lieven if (fix) { 2498f43aa8e1SPeter Lieven return -ENOTSUP; 2499f43aa8e1SPeter Lieven } 2500f43aa8e1SPeter Lieven 2501f43aa8e1SPeter Lieven for (;;) { 2502f43aa8e1SPeter Lieven if (sector_num >= total_sectors) { 2503f43aa8e1SPeter Lieven return 0; 2504f43aa8e1SPeter Lieven } 2505f43aa8e1SPeter Lieven extent = find_extent(s, sector_num, extent); 2506f43aa8e1SPeter Lieven if (!extent) { 2507f43aa8e1SPeter Lieven fprintf(stderr, 2508f43aa8e1SPeter Lieven "ERROR: could not find extent for sector %" PRId64 "\n", 2509f43aa8e1SPeter Lieven sector_num); 25100e51b9b7SFam Zheng ret = -EINVAL; 2511f43aa8e1SPeter Lieven break; 2512f43aa8e1SPeter Lieven } 2513f43aa8e1SPeter Lieven ret = get_cluster_offset(bs, extent, NULL, 2514f43aa8e1SPeter Lieven sector_num << BDRV_SECTOR_BITS, 2515c6ac36e1SFam Zheng false, &cluster_offset, 0, 0); 2516f43aa8e1SPeter Lieven if (ret == VMDK_ERROR) { 2517f43aa8e1SPeter Lieven fprintf(stderr, 2518f43aa8e1SPeter Lieven "ERROR: could not get cluster_offset for sector %" 2519f43aa8e1SPeter Lieven PRId64 "\n", sector_num); 2520f43aa8e1SPeter Lieven break; 2521f43aa8e1SPeter Lieven } 25220e51b9b7SFam Zheng if (ret == VMDK_OK) { 25230e51b9b7SFam Zheng int64_t extent_len = bdrv_getlength(extent->file->bs); 25240e51b9b7SFam Zheng if (extent_len < 0) { 25250e51b9b7SFam Zheng fprintf(stderr, 25260e51b9b7SFam Zheng "ERROR: could not get extent file length for sector %" 25270e51b9b7SFam Zheng PRId64 "\n", sector_num); 25280e51b9b7SFam Zheng ret = extent_len; 25290e51b9b7SFam Zheng break; 25300e51b9b7SFam Zheng } 25310e51b9b7SFam Zheng if (cluster_offset >= extent_len) { 2532f43aa8e1SPeter Lieven fprintf(stderr, 2533f43aa8e1SPeter Lieven "ERROR: cluster offset for sector %" 2534f43aa8e1SPeter Lieven PRId64 " points after EOF\n", sector_num); 25350e51b9b7SFam Zheng ret = -EINVAL; 2536f43aa8e1SPeter Lieven break; 2537f43aa8e1SPeter Lieven } 25380e51b9b7SFam Zheng } 2539f43aa8e1SPeter Lieven sector_num += extent->cluster_sectors; 2540f43aa8e1SPeter Lieven } 2541f43aa8e1SPeter Lieven 2542f43aa8e1SPeter Lieven result->corruptions++; 25430e51b9b7SFam Zheng return ret; 2544f43aa8e1SPeter Lieven } 2545f43aa8e1SPeter Lieven 2546*1bf6e9caSAndrey Shinkevich static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs, 2547*1bf6e9caSAndrey Shinkevich Error **errp) 2548f4c129a3SFam Zheng { 2549f4c129a3SFam Zheng int i; 2550f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 2551f4c129a3SFam Zheng ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1); 2552f4c129a3SFam Zheng ImageInfoList **next; 2553f4c129a3SFam Zheng 2554f4c129a3SFam Zheng *spec_info = (ImageInfoSpecific){ 25556a8f9661SEric Blake .type = IMAGE_INFO_SPECIFIC_KIND_VMDK, 255632bafa8fSEric Blake .u = { 255732bafa8fSEric Blake .vmdk.data = g_new0(ImageInfoSpecificVmdk, 1), 2558f4c129a3SFam Zheng }, 2559f4c129a3SFam Zheng }; 2560f4c129a3SFam Zheng 256132bafa8fSEric Blake *spec_info->u.vmdk.data = (ImageInfoSpecificVmdk) { 2562f4c129a3SFam Zheng .create_type = g_strdup(s->create_type), 2563f4c129a3SFam Zheng .cid = s->cid, 2564f4c129a3SFam Zheng .parent_cid = s->parent_cid, 2565f4c129a3SFam Zheng }; 2566f4c129a3SFam Zheng 256732bafa8fSEric Blake next = &spec_info->u.vmdk.data->extents; 2568f4c129a3SFam Zheng for (i = 0; i < s->num_extents; i++) { 2569f4c129a3SFam Zheng *next = g_new0(ImageInfoList, 1); 2570f4c129a3SFam Zheng (*next)->value = vmdk_get_extent_info(&s->extents[i]); 2571f4c129a3SFam Zheng (*next)->next = NULL; 2572f4c129a3SFam Zheng next = &(*next)->next; 2573f4c129a3SFam Zheng } 2574f4c129a3SFam Zheng 2575f4c129a3SFam Zheng return spec_info; 2576f4c129a3SFam Zheng } 2577f4c129a3SFam Zheng 25785f583307SFam Zheng static bool vmdk_extents_type_eq(const VmdkExtent *a, const VmdkExtent *b) 25795f583307SFam Zheng { 25805f583307SFam Zheng return a->flat == b->flat && 25815f583307SFam Zheng a->compressed == b->compressed && 25825f583307SFam Zheng (a->flat || a->cluster_sectors == b->cluster_sectors); 25835f583307SFam Zheng } 25845f583307SFam Zheng 258574fe188cSFam Zheng static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) 258674fe188cSFam Zheng { 258774fe188cSFam Zheng int i; 258874fe188cSFam Zheng BDRVVmdkState *s = bs->opaque; 258974fe188cSFam Zheng assert(s->num_extents); 25905f583307SFam Zheng 25915f583307SFam Zheng /* See if we have multiple extents but they have different cases */ 25925f583307SFam Zheng for (i = 1; i < s->num_extents; i++) { 25935f583307SFam Zheng if (!vmdk_extents_type_eq(&s->extents[0], &s->extents[i])) { 25945f583307SFam Zheng return -ENOTSUP; 25955f583307SFam Zheng } 25965f583307SFam Zheng } 259774fe188cSFam Zheng bdi->needs_compressed_writes = s->extents[0].compressed; 259874fe188cSFam Zheng if (!s->extents[0].flat) { 259974fe188cSFam Zheng bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS; 260074fe188cSFam Zheng } 260174fe188cSFam Zheng return 0; 260274fe188cSFam Zheng } 260374fe188cSFam Zheng 26045820f1daSChunyan Liu static QemuOptsList vmdk_create_opts = { 26055820f1daSChunyan Liu .name = "vmdk-create-opts", 26065820f1daSChunyan Liu .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head), 26075820f1daSChunyan Liu .desc = { 2608db08adf5SKevin Wolf { 2609db08adf5SKevin Wolf .name = BLOCK_OPT_SIZE, 26105820f1daSChunyan Liu .type = QEMU_OPT_SIZE, 2611db08adf5SKevin Wolf .help = "Virtual disk size" 2612db08adf5SKevin Wolf }, 2613db08adf5SKevin Wolf { 26147f2039f6SOthmar Pasteka .name = BLOCK_OPT_ADAPTER_TYPE, 26155820f1daSChunyan Liu .type = QEMU_OPT_STRING, 26167f2039f6SOthmar Pasteka .help = "Virtual adapter type, can be one of " 26177f2039f6SOthmar Pasteka "ide (default), lsilogic, buslogic or legacyESX" 26187f2039f6SOthmar Pasteka }, 26197f2039f6SOthmar Pasteka { 2620db08adf5SKevin Wolf .name = BLOCK_OPT_BACKING_FILE, 26215820f1daSChunyan Liu .type = QEMU_OPT_STRING, 2622db08adf5SKevin Wolf .help = "File name of a base image" 2623db08adf5SKevin Wolf }, 2624db08adf5SKevin Wolf { 2625db08adf5SKevin Wolf .name = BLOCK_OPT_COMPAT6, 26265820f1daSChunyan Liu .type = QEMU_OPT_BOOL, 26275820f1daSChunyan Liu .help = "VMDK version 6 image", 26285820f1daSChunyan Liu .def_value_str = "off" 2629db08adf5SKevin Wolf }, 2630f66fd6c3SFam Zheng { 2631f249924eSJanne Karhunen .name = BLOCK_OPT_HWVERSION, 2632f249924eSJanne Karhunen .type = QEMU_OPT_STRING, 2633f249924eSJanne Karhunen .help = "VMDK hardware version", 2634f249924eSJanne Karhunen .def_value_str = "undefined" 2635f249924eSJanne Karhunen }, 2636f249924eSJanne Karhunen { 2637f66fd6c3SFam Zheng .name = BLOCK_OPT_SUBFMT, 26385820f1daSChunyan Liu .type = QEMU_OPT_STRING, 2639f66fd6c3SFam Zheng .help = 2640f66fd6c3SFam Zheng "VMDK flat extent format, can be one of " 26416c031aacSFam Zheng "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} " 2642f66fd6c3SFam Zheng }, 264369e0b6dfSFam Zheng { 264469e0b6dfSFam Zheng .name = BLOCK_OPT_ZEROED_GRAIN, 26455820f1daSChunyan Liu .type = QEMU_OPT_BOOL, 26465820f1daSChunyan Liu .help = "Enable efficient zero writes " 26475820f1daSChunyan Liu "using the zeroed-grain GTE feature" 264869e0b6dfSFam Zheng }, 26495820f1daSChunyan Liu { /* end of list */ } 26505820f1daSChunyan Liu } 26510e7e1989SKevin Wolf }; 26520e7e1989SKevin Wolf 2653019d6b8fSAnthony Liguori static BlockDriver bdrv_vmdk = { 2654019d6b8fSAnthony Liguori .format_name = "vmdk", 2655019d6b8fSAnthony Liguori .instance_size = sizeof(BDRVVmdkState), 2656019d6b8fSAnthony Liguori .bdrv_probe = vmdk_probe, 26576511ef77SKevin Wolf .bdrv_open = vmdk_open, 26582fd61638SPaolo Bonzini .bdrv_co_check = vmdk_co_check, 26593897575fSJeff Cody .bdrv_reopen_prepare = vmdk_reopen_prepare, 2660862f215fSKevin Wolf .bdrv_child_perm = bdrv_format_default_perms, 2661f10cc243SKevin Wolf .bdrv_co_preadv = vmdk_co_preadv, 266237b1d7d8SKevin Wolf .bdrv_co_pwritev = vmdk_co_pwritev, 2663b2c622d3SPavel Butsykin .bdrv_co_pwritev_compressed = vmdk_co_pwritev_compressed, 2664a620f2aeSEric Blake .bdrv_co_pwrite_zeroes = vmdk_co_pwrite_zeroes, 2665019d6b8fSAnthony Liguori .bdrv_close = vmdk_close, 2666efc75e2aSStefan Hajnoczi .bdrv_co_create_opts = vmdk_co_create_opts, 26673015372dSFam Zheng .bdrv_co_create = vmdk_co_create, 2668c68b89acSKevin Wolf .bdrv_co_flush_to_disk = vmdk_co_flush, 2669c72080b9SEric Blake .bdrv_co_block_status = vmdk_co_block_status, 26704a1d5e1fSFam Zheng .bdrv_get_allocated_file_size = vmdk_get_allocated_file_size, 2671da7a50f9SFam Zheng .bdrv_has_zero_init = vmdk_has_zero_init, 2672f4c129a3SFam Zheng .bdrv_get_specific_info = vmdk_get_specific_info, 2673d34682cdSKevin Wolf .bdrv_refresh_limits = vmdk_refresh_limits, 267474fe188cSFam Zheng .bdrv_get_info = vmdk_get_info, 26750e7e1989SKevin Wolf 26768ee79e70SKevin Wolf .supports_backing = true, 26775820f1daSChunyan Liu .create_opts = &vmdk_create_opts, 2678019d6b8fSAnthony Liguori }; 2679019d6b8fSAnthony Liguori 2680019d6b8fSAnthony Liguori static void bdrv_vmdk_init(void) 2681019d6b8fSAnthony Liguori { 2682019d6b8fSAnthony Liguori bdrv_register(&bdrv_vmdk); 2683019d6b8fSAnthony Liguori } 2684019d6b8fSAnthony Liguori 2685019d6b8fSAnthony Liguori block_init(bdrv_vmdk_init); 2686