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" 33caf71f86SPaolo Bonzini #include "migration/migration.h" 34f348b6d1SVeronia Bahaa #include "qemu/cutils.h" 352923d34fSStefan Weil #include <zlib.h> 36e5dc64b8SFam Zheng #include <glib.h> 37019d6b8fSAnthony Liguori 38019d6b8fSAnthony Liguori #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') 39019d6b8fSAnthony Liguori #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') 40432bb170SFam Zheng #define VMDK4_COMPRESSION_DEFLATE 1 4195b0aa42SFam Zheng #define VMDK4_FLAG_NL_DETECT (1 << 0) 42bb45ded9SFam Zheng #define VMDK4_FLAG_RGD (1 << 1) 4314ead646SFam Zheng /* Zeroed-grain enable bit */ 4414ead646SFam Zheng #define VMDK4_FLAG_ZERO_GRAIN (1 << 2) 45432bb170SFam Zheng #define VMDK4_FLAG_COMPRESS (1 << 16) 46432bb170SFam Zheng #define VMDK4_FLAG_MARKER (1 << 17) 4765bd155cSKevin Wolf #define VMDK4_GD_AT_END 0xffffffffffffffffULL 48019d6b8fSAnthony Liguori 4914ead646SFam Zheng #define VMDK_GTE_ZEROED 0x1 5065f74725SFam Zheng 5165f74725SFam Zheng /* VMDK internal error codes */ 5265f74725SFam Zheng #define VMDK_OK 0 5365f74725SFam Zheng #define VMDK_ERROR (-1) 5465f74725SFam Zheng /* Cluster not allocated */ 5565f74725SFam Zheng #define VMDK_UNALLOC (-2) 5665f74725SFam Zheng #define VMDK_ZEROED (-3) 5765f74725SFam Zheng 5869e0b6dfSFam Zheng #define BLOCK_OPT_ZEROED_GRAIN "zeroed_grain" 5969e0b6dfSFam Zheng 60019d6b8fSAnthony Liguori typedef struct { 61019d6b8fSAnthony Liguori uint32_t version; 62019d6b8fSAnthony Liguori uint32_t flags; 63019d6b8fSAnthony Liguori uint32_t disk_sectors; 64019d6b8fSAnthony Liguori uint32_t granularity; 65019d6b8fSAnthony Liguori uint32_t l1dir_offset; 66019d6b8fSAnthony Liguori uint32_t l1dir_size; 67019d6b8fSAnthony Liguori uint32_t file_sectors; 68019d6b8fSAnthony Liguori uint32_t cylinders; 69019d6b8fSAnthony Liguori uint32_t heads; 70019d6b8fSAnthony Liguori uint32_t sectors_per_track; 715d8caa54SFam Zheng } QEMU_PACKED VMDK3Header; 72019d6b8fSAnthony Liguori 73019d6b8fSAnthony Liguori typedef struct { 74019d6b8fSAnthony Liguori uint32_t version; 75019d6b8fSAnthony Liguori uint32_t flags; 76e98768d4SFam Zheng uint64_t capacity; 77e98768d4SFam Zheng uint64_t granularity; 78e98768d4SFam Zheng uint64_t desc_offset; 79e98768d4SFam Zheng uint64_t desc_size; 80ca8804ceSFam Zheng /* Number of GrainTableEntries per GrainTable */ 81ca8804ceSFam Zheng uint32_t num_gtes_per_gt; 82e98768d4SFam Zheng uint64_t rgd_offset; 83e98768d4SFam Zheng uint64_t gd_offset; 84e98768d4SFam Zheng uint64_t grain_offset; 85019d6b8fSAnthony Liguori char filler[1]; 86019d6b8fSAnthony Liguori char check_bytes[4]; 87432bb170SFam Zheng uint16_t compressAlgorithm; 88541dc0d4SStefan Weil } QEMU_PACKED VMDK4Header; 89019d6b8fSAnthony Liguori 90019d6b8fSAnthony Liguori #define L2_CACHE_SIZE 16 91019d6b8fSAnthony Liguori 92b3976d3cSFam Zheng typedef struct VmdkExtent { 9324bc15d1SKevin Wolf BdrvChild *file; 94b3976d3cSFam Zheng bool flat; 95432bb170SFam Zheng bool compressed; 96432bb170SFam Zheng bool has_marker; 9714ead646SFam Zheng bool has_zero_grain; 9814ead646SFam Zheng int version; 99b3976d3cSFam Zheng int64_t sectors; 100b3976d3cSFam Zheng int64_t end_sector; 1017fa60fa3SFam Zheng int64_t flat_start_offset; 102019d6b8fSAnthony Liguori int64_t l1_table_offset; 103019d6b8fSAnthony Liguori int64_t l1_backup_table_offset; 104019d6b8fSAnthony Liguori uint32_t *l1_table; 105019d6b8fSAnthony Liguori uint32_t *l1_backup_table; 106019d6b8fSAnthony Liguori unsigned int l1_size; 107019d6b8fSAnthony Liguori uint32_t l1_entry_sectors; 108019d6b8fSAnthony Liguori 109019d6b8fSAnthony Liguori unsigned int l2_size; 110019d6b8fSAnthony Liguori uint32_t *l2_cache; 111019d6b8fSAnthony Liguori uint32_t l2_cache_offsets[L2_CACHE_SIZE]; 112019d6b8fSAnthony Liguori uint32_t l2_cache_counts[L2_CACHE_SIZE]; 113019d6b8fSAnthony Liguori 114301c7d38SFam Zheng int64_t cluster_sectors; 115c6ac36e1SFam Zheng int64_t next_cluster_sector; 116f4c129a3SFam Zheng char *type; 117b3976d3cSFam Zheng } VmdkExtent; 118b3976d3cSFam Zheng 119b3976d3cSFam Zheng typedef struct BDRVVmdkState { 120848c66e8SPaolo Bonzini CoMutex lock; 121e98768d4SFam Zheng uint64_t desc_offset; 12269b4d86dSFam Zheng bool cid_updated; 123c338b6adSFam Zheng bool cid_checked; 124f4c129a3SFam Zheng uint32_t cid; 125019d6b8fSAnthony Liguori uint32_t parent_cid; 126b3976d3cSFam Zheng int num_extents; 127b3976d3cSFam Zheng /* Extent array with num_extents entries, ascend ordered by address */ 128b3976d3cSFam Zheng VmdkExtent *extents; 1292bc3166cSKevin Wolf Error *migration_blocker; 130f4c129a3SFam Zheng char *create_type; 131019d6b8fSAnthony Liguori } BDRVVmdkState; 132019d6b8fSAnthony Liguori 133019d6b8fSAnthony Liguori typedef struct VmdkMetaData { 134019d6b8fSAnthony Liguori unsigned int l1_index; 135019d6b8fSAnthony Liguori unsigned int l2_index; 136019d6b8fSAnthony Liguori unsigned int l2_offset; 137019d6b8fSAnthony Liguori int valid; 138cdeaf1f1SFam Zheng uint32_t *l2_cache_entry; 139019d6b8fSAnthony Liguori } VmdkMetaData; 140019d6b8fSAnthony Liguori 141432bb170SFam Zheng typedef struct VmdkGrainMarker { 142432bb170SFam Zheng uint64_t lba; 143432bb170SFam Zheng uint32_t size; 144432bb170SFam Zheng uint8_t data[0]; 1455d8caa54SFam Zheng } QEMU_PACKED VmdkGrainMarker; 146432bb170SFam Zheng 14765bd155cSKevin Wolf enum { 14865bd155cSKevin Wolf MARKER_END_OF_STREAM = 0, 14965bd155cSKevin Wolf MARKER_GRAIN_TABLE = 1, 15065bd155cSKevin Wolf MARKER_GRAIN_DIRECTORY = 2, 15165bd155cSKevin Wolf MARKER_FOOTER = 3, 15265bd155cSKevin Wolf }; 15365bd155cSKevin Wolf 154019d6b8fSAnthony Liguori static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) 155019d6b8fSAnthony Liguori { 156019d6b8fSAnthony Liguori uint32_t magic; 157019d6b8fSAnthony Liguori 158ae261c86SFam Zheng if (buf_size < 4) { 159019d6b8fSAnthony Liguori return 0; 160ae261c86SFam Zheng } 161019d6b8fSAnthony Liguori magic = be32_to_cpu(*(uint32_t *)buf); 162019d6b8fSAnthony Liguori if (magic == VMDK3_MAGIC || 16301fc99d6SFam Zheng magic == VMDK4_MAGIC) { 164019d6b8fSAnthony Liguori return 100; 16501fc99d6SFam Zheng } else { 16601fc99d6SFam Zheng const char *p = (const char *)buf; 16701fc99d6SFam Zheng const char *end = p + buf_size; 16801fc99d6SFam Zheng while (p < end) { 16901fc99d6SFam Zheng if (*p == '#') { 17001fc99d6SFam Zheng /* skip comment line */ 17101fc99d6SFam Zheng while (p < end && *p != '\n') { 17201fc99d6SFam Zheng p++; 17301fc99d6SFam Zheng } 17401fc99d6SFam Zheng p++; 17501fc99d6SFam Zheng continue; 17601fc99d6SFam Zheng } 17701fc99d6SFam Zheng if (*p == ' ') { 17801fc99d6SFam Zheng while (p < end && *p == ' ') { 17901fc99d6SFam Zheng p++; 18001fc99d6SFam Zheng } 18101fc99d6SFam Zheng /* skip '\r' if windows line endings used. */ 18201fc99d6SFam Zheng if (p < end && *p == '\r') { 18301fc99d6SFam Zheng p++; 18401fc99d6SFam Zheng } 18501fc99d6SFam Zheng /* only accept blank lines before 'version=' line */ 18601fc99d6SFam Zheng if (p == end || *p != '\n') { 187019d6b8fSAnthony Liguori return 0; 188019d6b8fSAnthony Liguori } 18901fc99d6SFam Zheng p++; 19001fc99d6SFam Zheng continue; 19101fc99d6SFam Zheng } 19201fc99d6SFam Zheng if (end - p >= strlen("version=X\n")) { 19301fc99d6SFam Zheng if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 || 19401fc99d6SFam Zheng strncmp("version=2\n", p, strlen("version=2\n")) == 0) { 19501fc99d6SFam Zheng return 100; 19601fc99d6SFam Zheng } 19701fc99d6SFam Zheng } 19801fc99d6SFam Zheng if (end - p >= strlen("version=X\r\n")) { 19901fc99d6SFam Zheng if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 || 20001fc99d6SFam Zheng strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) { 20101fc99d6SFam Zheng return 100; 20201fc99d6SFam Zheng } 20301fc99d6SFam Zheng } 20401fc99d6SFam Zheng return 0; 20501fc99d6SFam Zheng } 20601fc99d6SFam Zheng return 0; 20701fc99d6SFam Zheng } 20801fc99d6SFam Zheng } 209019d6b8fSAnthony Liguori 210019d6b8fSAnthony Liguori #define SECTOR_SIZE 512 211f66fd6c3SFam Zheng #define DESC_SIZE (20 * SECTOR_SIZE) /* 20 sectors of 512 bytes each */ 212f66fd6c3SFam Zheng #define BUF_SIZE 4096 213f66fd6c3SFam Zheng #define HEADER_SIZE 512 /* first sector of 512 bytes */ 214019d6b8fSAnthony Liguori 215b3976d3cSFam Zheng static void vmdk_free_extents(BlockDriverState *bs) 216b3976d3cSFam Zheng { 217b3976d3cSFam Zheng int i; 218b3976d3cSFam Zheng BDRVVmdkState *s = bs->opaque; 219b3c0bfb6SFam Zheng VmdkExtent *e; 220b3976d3cSFam Zheng 221b3976d3cSFam Zheng for (i = 0; i < s->num_extents; i++) { 222b3c0bfb6SFam Zheng e = &s->extents[i]; 223b3c0bfb6SFam Zheng g_free(e->l1_table); 224b3c0bfb6SFam Zheng g_free(e->l2_cache); 225b3c0bfb6SFam Zheng g_free(e->l1_backup_table); 226f4c129a3SFam Zheng g_free(e->type); 2279a4f4c31SKevin Wolf if (e->file != bs->file) { 22824bc15d1SKevin Wolf bdrv_unref_child(bs, e->file); 229b3c0bfb6SFam Zheng } 230b3976d3cSFam Zheng } 2317267c094SAnthony Liguori g_free(s->extents); 232b3976d3cSFam Zheng } 233b3976d3cSFam Zheng 23486c6b429SFam Zheng static void vmdk_free_last_extent(BlockDriverState *bs) 23586c6b429SFam Zheng { 23686c6b429SFam Zheng BDRVVmdkState *s = bs->opaque; 23786c6b429SFam Zheng 23886c6b429SFam Zheng if (s->num_extents == 0) { 23986c6b429SFam Zheng return; 24086c6b429SFam Zheng } 24186c6b429SFam Zheng s->num_extents--; 2425839e53bSMarkus Armbruster s->extents = g_renew(VmdkExtent, s->extents, s->num_extents); 24386c6b429SFam Zheng } 24486c6b429SFam Zheng 245019d6b8fSAnthony Liguori static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) 246019d6b8fSAnthony Liguori { 2475997c210SFam Zheng char *desc; 2488379e46dSPavel Borzenkov uint32_t cid = 0xffffffff; 249019d6b8fSAnthony Liguori const char *p_name, *cid_str; 250019d6b8fSAnthony Liguori size_t cid_str_size; 251e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 25299f1835dSKevin Wolf int ret; 253019d6b8fSAnthony Liguori 2545997c210SFam Zheng desc = g_malloc0(DESC_SIZE); 2559a4f4c31SKevin Wolf ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE); 25699f1835dSKevin Wolf if (ret < 0) { 2575997c210SFam Zheng g_free(desc); 258019d6b8fSAnthony Liguori return 0; 259e1da9b24SFam Zheng } 260019d6b8fSAnthony Liguori 261019d6b8fSAnthony Liguori if (parent) { 262019d6b8fSAnthony Liguori cid_str = "parentCID"; 263019d6b8fSAnthony Liguori cid_str_size = sizeof("parentCID"); 264019d6b8fSAnthony Liguori } else { 265019d6b8fSAnthony Liguori cid_str = "CID"; 266019d6b8fSAnthony Liguori cid_str_size = sizeof("CID"); 267019d6b8fSAnthony Liguori } 268019d6b8fSAnthony Liguori 26993897b9fSKevin Wolf desc[DESC_SIZE - 1] = '\0'; 270ae261c86SFam Zheng p_name = strstr(desc, cid_str); 271ae261c86SFam Zheng if (p_name != NULL) { 272019d6b8fSAnthony Liguori p_name += cid_str_size; 2739b17031aSFam Zheng sscanf(p_name, "%" SCNx32, &cid); 274019d6b8fSAnthony Liguori } 275019d6b8fSAnthony Liguori 2765997c210SFam Zheng g_free(desc); 277019d6b8fSAnthony Liguori return cid; 278019d6b8fSAnthony Liguori } 279019d6b8fSAnthony Liguori 280019d6b8fSAnthony Liguori static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) 281019d6b8fSAnthony Liguori { 282965415ebSFam Zheng char *desc, *tmp_desc; 283019d6b8fSAnthony Liguori char *p_name, *tmp_str; 284e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 285965415ebSFam Zheng int ret = 0; 286019d6b8fSAnthony Liguori 287965415ebSFam Zheng desc = g_malloc0(DESC_SIZE); 288965415ebSFam Zheng tmp_desc = g_malloc0(DESC_SIZE); 2899a4f4c31SKevin Wolf ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE); 29099f1835dSKevin Wolf if (ret < 0) { 291965415ebSFam Zheng goto out; 292e1da9b24SFam Zheng } 293019d6b8fSAnthony Liguori 29493897b9fSKevin Wolf desc[DESC_SIZE - 1] = '\0'; 295019d6b8fSAnthony Liguori tmp_str = strstr(desc, "parentCID"); 29693897b9fSKevin Wolf if (tmp_str == NULL) { 297965415ebSFam Zheng ret = -EINVAL; 298965415ebSFam Zheng goto out; 29993897b9fSKevin Wolf } 30093897b9fSKevin Wolf 301965415ebSFam Zheng pstrcpy(tmp_desc, DESC_SIZE, tmp_str); 302ae261c86SFam Zheng p_name = strstr(desc, "CID"); 303ae261c86SFam Zheng if (p_name != NULL) { 304019d6b8fSAnthony Liguori p_name += sizeof("CID"); 305965415ebSFam Zheng snprintf(p_name, DESC_SIZE - (p_name - desc), "%" PRIx32 "\n", cid); 306965415ebSFam Zheng pstrcat(desc, DESC_SIZE, tmp_desc); 307019d6b8fSAnthony Liguori } 308019d6b8fSAnthony Liguori 3099a4f4c31SKevin Wolf ret = bdrv_pwrite_sync(bs->file->bs, s->desc_offset, desc, DESC_SIZE); 31099f1835dSKevin Wolf 311965415ebSFam Zheng out: 312965415ebSFam Zheng g_free(desc); 313965415ebSFam Zheng g_free(tmp_desc); 314965415ebSFam Zheng return ret; 315019d6b8fSAnthony Liguori } 316019d6b8fSAnthony Liguori 317019d6b8fSAnthony Liguori static int vmdk_is_cid_valid(BlockDriverState *bs) 318019d6b8fSAnthony Liguori { 319019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 320019d6b8fSAnthony Liguori uint32_t cur_pcid; 321019d6b8fSAnthony Liguori 322760e0063SKevin Wolf if (!s->cid_checked && bs->backing) { 323760e0063SKevin Wolf BlockDriverState *p_bs = bs->backing->bs; 324760e0063SKevin Wolf 325019d6b8fSAnthony Liguori cur_pcid = vmdk_read_cid(p_bs, 0); 326ae261c86SFam Zheng if (s->parent_cid != cur_pcid) { 327ae261c86SFam Zheng /* CID not valid */ 328019d6b8fSAnthony Liguori return 0; 329019d6b8fSAnthony Liguori } 330ae261c86SFam Zheng } 331c338b6adSFam Zheng s->cid_checked = true; 332ae261c86SFam Zheng /* CID valid */ 333019d6b8fSAnthony Liguori return 1; 334019d6b8fSAnthony Liguori } 335019d6b8fSAnthony Liguori 33667251a31SKevin Wolf /* We have nothing to do for VMDK reopen, stubs just return success */ 3373897575fSJeff Cody static int vmdk_reopen_prepare(BDRVReopenState *state, 3383897575fSJeff Cody BlockReopenQueue *queue, Error **errp) 3393897575fSJeff Cody { 3403897575fSJeff Cody assert(state != NULL); 3413897575fSJeff Cody assert(state->bs != NULL); 34267251a31SKevin Wolf return 0; 3433897575fSJeff Cody } 3443897575fSJeff Cody 3459949f97eSKevin Wolf static int vmdk_parent_open(BlockDriverState *bs) 346019d6b8fSAnthony Liguori { 347019d6b8fSAnthony Liguori char *p_name; 34871968dbfSFam Zheng char *desc; 349e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 350588b65a3SPaolo Bonzini int ret; 351019d6b8fSAnthony Liguori 35271968dbfSFam Zheng desc = g_malloc0(DESC_SIZE + 1); 3539a4f4c31SKevin Wolf ret = bdrv_pread(bs->file->bs, s->desc_offset, desc, DESC_SIZE); 354588b65a3SPaolo Bonzini if (ret < 0) { 35571968dbfSFam Zheng goto out; 356e1da9b24SFam Zheng } 35771968dbfSFam Zheng ret = 0; 358019d6b8fSAnthony Liguori 359ae261c86SFam Zheng p_name = strstr(desc, "parentFileNameHint"); 360ae261c86SFam Zheng if (p_name != NULL) { 361019d6b8fSAnthony Liguori char *end_name; 362019d6b8fSAnthony Liguori 363019d6b8fSAnthony Liguori p_name += sizeof("parentFileNameHint") + 1; 364ae261c86SFam Zheng end_name = strchr(p_name, '\"'); 365ae261c86SFam Zheng if (end_name == NULL) { 36671968dbfSFam Zheng ret = -EINVAL; 36771968dbfSFam Zheng goto out; 368ae261c86SFam Zheng } 369ae261c86SFam Zheng if ((end_name - p_name) > sizeof(bs->backing_file) - 1) { 37071968dbfSFam Zheng ret = -EINVAL; 37171968dbfSFam Zheng goto out; 372ae261c86SFam Zheng } 373019d6b8fSAnthony Liguori 374b171271aSKevin Wolf pstrcpy(bs->backing_file, end_name - p_name + 1, p_name); 375019d6b8fSAnthony Liguori } 376019d6b8fSAnthony Liguori 37771968dbfSFam Zheng out: 37871968dbfSFam Zheng g_free(desc); 37971968dbfSFam Zheng return ret; 380019d6b8fSAnthony Liguori } 381019d6b8fSAnthony Liguori 382b3976d3cSFam Zheng /* Create and append extent to the extent array. Return the added VmdkExtent 383b3976d3cSFam Zheng * address. return NULL if allocation failed. */ 3848aa1331cSFam Zheng static int vmdk_add_extent(BlockDriverState *bs, 38524bc15d1SKevin Wolf BdrvChild *file, bool flat, int64_t sectors, 386b3976d3cSFam Zheng int64_t l1_offset, int64_t l1_backup_offset, 387b3976d3cSFam Zheng uint32_t l1_size, 3888aa1331cSFam Zheng int l2_size, uint64_t cluster_sectors, 3894823970bSFam Zheng VmdkExtent **new_extent, 3904823970bSFam Zheng Error **errp) 391b3976d3cSFam Zheng { 392b3976d3cSFam Zheng VmdkExtent *extent; 393b3976d3cSFam Zheng BDRVVmdkState *s = bs->opaque; 3940a156f7cSMarkus Armbruster int64_t nb_sectors; 395b3976d3cSFam Zheng 3968aa1331cSFam Zheng if (cluster_sectors > 0x200000) { 3978aa1331cSFam Zheng /* 0x200000 * 512Bytes = 1GB for one cluster is unrealistic */ 3984823970bSFam Zheng error_setg(errp, "Invalid granularity, image may be corrupt"); 3994823970bSFam Zheng return -EFBIG; 4008aa1331cSFam Zheng } 401b0651b8cSFam Zheng if (l1_size > 512 * 1024 * 1024) { 402b0651b8cSFam Zheng /* Although with big capacity and small l1_entry_sectors, we can get a 403b0651b8cSFam Zheng * big l1_size, we don't want unbounded value to allocate the table. 404b0651b8cSFam Zheng * Limit it to 512M, which is 16PB for default cluster and L2 table 405b0651b8cSFam Zheng * size */ 4064823970bSFam Zheng error_setg(errp, "L1 size too big"); 407b0651b8cSFam Zheng return -EFBIG; 408b0651b8cSFam Zheng } 4098aa1331cSFam Zheng 41024bc15d1SKevin Wolf nb_sectors = bdrv_nb_sectors(file->bs); 4110a156f7cSMarkus Armbruster if (nb_sectors < 0) { 4120a156f7cSMarkus Armbruster return nb_sectors; 413c6ac36e1SFam Zheng } 414c6ac36e1SFam Zheng 4155839e53bSMarkus Armbruster s->extents = g_renew(VmdkExtent, s->extents, s->num_extents + 1); 416b3976d3cSFam Zheng extent = &s->extents[s->num_extents]; 417b3976d3cSFam Zheng s->num_extents++; 418b3976d3cSFam Zheng 419b3976d3cSFam Zheng memset(extent, 0, sizeof(VmdkExtent)); 420b3976d3cSFam Zheng extent->file = file; 421b3976d3cSFam Zheng extent->flat = flat; 422b3976d3cSFam Zheng extent->sectors = sectors; 423b3976d3cSFam Zheng extent->l1_table_offset = l1_offset; 424b3976d3cSFam Zheng extent->l1_backup_table_offset = l1_backup_offset; 425b3976d3cSFam Zheng extent->l1_size = l1_size; 426b3976d3cSFam Zheng extent->l1_entry_sectors = l2_size * cluster_sectors; 427b3976d3cSFam Zheng extent->l2_size = l2_size; 428301c7d38SFam Zheng extent->cluster_sectors = flat ? sectors : cluster_sectors; 4290a156f7cSMarkus Armbruster extent->next_cluster_sector = ROUND_UP(nb_sectors, cluster_sectors); 430b3976d3cSFam Zheng 431b3976d3cSFam Zheng if (s->num_extents > 1) { 432b3976d3cSFam Zheng extent->end_sector = (*(extent - 1)).end_sector + extent->sectors; 433b3976d3cSFam Zheng } else { 434b3976d3cSFam Zheng extent->end_sector = extent->sectors; 435b3976d3cSFam Zheng } 436b3976d3cSFam Zheng bs->total_sectors = extent->end_sector; 4378aa1331cSFam Zheng if (new_extent) { 4388aa1331cSFam Zheng *new_extent = extent; 4398aa1331cSFam Zheng } 4408aa1331cSFam Zheng return 0; 441b3976d3cSFam Zheng } 442b3976d3cSFam Zheng 4434823970bSFam Zheng static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, 4444823970bSFam Zheng Error **errp) 445019d6b8fSAnthony Liguori { 446b4b3ab14SFam Zheng int ret; 44713c4941cSFam Zheng size_t l1_size; 44813c4941cSFam Zheng int i; 449b4b3ab14SFam Zheng 450b4b3ab14SFam Zheng /* read the L1 table */ 451b4b3ab14SFam Zheng l1_size = extent->l1_size * sizeof(uint32_t); 452d6e59931SKevin Wolf extent->l1_table = g_try_malloc(l1_size); 453d6e59931SKevin Wolf if (l1_size && extent->l1_table == NULL) { 454d6e59931SKevin Wolf return -ENOMEM; 455d6e59931SKevin Wolf } 456d6e59931SKevin Wolf 45724bc15d1SKevin Wolf ret = bdrv_pread(extent->file->bs, 458b4b3ab14SFam Zheng extent->l1_table_offset, 459b4b3ab14SFam Zheng extent->l1_table, 460b4b3ab14SFam Zheng l1_size); 461b4b3ab14SFam Zheng if (ret < 0) { 4624823970bSFam Zheng error_setg_errno(errp, -ret, 4634823970bSFam Zheng "Could not read l1 table from extent '%s'", 46424bc15d1SKevin Wolf extent->file->bs->filename); 465b4b3ab14SFam Zheng goto fail_l1; 466b4b3ab14SFam Zheng } 467b4b3ab14SFam Zheng for (i = 0; i < extent->l1_size; i++) { 468b4b3ab14SFam Zheng le32_to_cpus(&extent->l1_table[i]); 469b4b3ab14SFam Zheng } 470b4b3ab14SFam Zheng 471b4b3ab14SFam Zheng if (extent->l1_backup_table_offset) { 472d6e59931SKevin Wolf extent->l1_backup_table = g_try_malloc(l1_size); 473d6e59931SKevin Wolf if (l1_size && extent->l1_backup_table == NULL) { 474d6e59931SKevin Wolf ret = -ENOMEM; 475d6e59931SKevin Wolf goto fail_l1; 476d6e59931SKevin Wolf } 47724bc15d1SKevin Wolf ret = bdrv_pread(extent->file->bs, 478b4b3ab14SFam Zheng extent->l1_backup_table_offset, 479b4b3ab14SFam Zheng extent->l1_backup_table, 480b4b3ab14SFam Zheng l1_size); 481b4b3ab14SFam Zheng if (ret < 0) { 4824823970bSFam Zheng error_setg_errno(errp, -ret, 4834823970bSFam Zheng "Could not read l1 backup table from extent '%s'", 48424bc15d1SKevin Wolf extent->file->bs->filename); 485b4b3ab14SFam Zheng goto fail_l1b; 486b4b3ab14SFam Zheng } 487b4b3ab14SFam Zheng for (i = 0; i < extent->l1_size; i++) { 488b4b3ab14SFam Zheng le32_to_cpus(&extent->l1_backup_table[i]); 489b4b3ab14SFam Zheng } 490b4b3ab14SFam Zheng } 491b4b3ab14SFam Zheng 492b4b3ab14SFam Zheng extent->l2_cache = 4935839e53bSMarkus Armbruster g_new(uint32_t, extent->l2_size * L2_CACHE_SIZE); 494b4b3ab14SFam Zheng return 0; 495b4b3ab14SFam Zheng fail_l1b: 4967267c094SAnthony Liguori g_free(extent->l1_backup_table); 497b4b3ab14SFam Zheng fail_l1: 4987267c094SAnthony Liguori g_free(extent->l1_table); 499b4b3ab14SFam Zheng return ret; 500b4b3ab14SFam Zheng } 501b4b3ab14SFam Zheng 502daac8fdcSFam Zheng static int vmdk_open_vmfs_sparse(BlockDriverState *bs, 50324bc15d1SKevin Wolf BdrvChild *file, 5044823970bSFam Zheng int flags, Error **errp) 505b4b3ab14SFam Zheng { 506b4b3ab14SFam Zheng int ret; 507019d6b8fSAnthony Liguori uint32_t magic; 508019d6b8fSAnthony Liguori VMDK3Header header; 509b4b3ab14SFam Zheng VmdkExtent *extent; 510b4b3ab14SFam Zheng 51124bc15d1SKevin Wolf ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header)); 512b4b3ab14SFam Zheng if (ret < 0) { 5134823970bSFam Zheng error_setg_errno(errp, -ret, 5144823970bSFam Zheng "Could not read header from file '%s'", 51524bc15d1SKevin Wolf file->bs->filename); 51686c6b429SFam Zheng return ret; 517b3976d3cSFam Zheng } 518f6b61e54SFam Zheng ret = vmdk_add_extent(bs, file, false, 519b3976d3cSFam Zheng le32_to_cpu(header.disk_sectors), 5207237aecdSFam Zheng (int64_t)le32_to_cpu(header.l1dir_offset) << 9, 521f6b61e54SFam Zheng 0, 522f6b61e54SFam Zheng le32_to_cpu(header.l1dir_size), 523f6b61e54SFam Zheng 4096, 5248aa1331cSFam Zheng le32_to_cpu(header.granularity), 5254823970bSFam Zheng &extent, 5264823970bSFam Zheng errp); 5278aa1331cSFam Zheng if (ret < 0) { 5288aa1331cSFam Zheng return ret; 5298aa1331cSFam Zheng } 5304823970bSFam Zheng ret = vmdk_init_tables(bs, extent, errp); 531b4b3ab14SFam Zheng if (ret) { 53286c6b429SFam Zheng /* free extent allocated by vmdk_add_extent */ 53386c6b429SFam Zheng vmdk_free_last_extent(bs); 534b4b3ab14SFam Zheng } 535b4b3ab14SFam Zheng return ret; 536b4b3ab14SFam Zheng } 537b4b3ab14SFam Zheng 538d1833ef5SPaolo Bonzini static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, 539a6468367SKevin Wolf QDict *options, Error **errp); 540f16f509dSFam Zheng 541a8842e6dSPaolo Bonzini static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset, 542a8842e6dSPaolo Bonzini Error **errp) 543a8842e6dSPaolo Bonzini { 544a8842e6dSPaolo Bonzini int64_t size; 545a8842e6dSPaolo Bonzini char *buf; 546a8842e6dSPaolo Bonzini int ret; 547a8842e6dSPaolo Bonzini 548a8842e6dSPaolo Bonzini size = bdrv_getlength(file); 549a8842e6dSPaolo Bonzini if (size < 0) { 550a8842e6dSPaolo Bonzini error_setg_errno(errp, -size, "Could not access file"); 551a8842e6dSPaolo Bonzini return NULL; 552a8842e6dSPaolo Bonzini } 553a8842e6dSPaolo Bonzini 55403c3359dSFam Zheng if (size < 4) { 55503c3359dSFam Zheng /* Both descriptor file and sparse image must be much larger than 4 55603c3359dSFam Zheng * bytes, also callers of vmdk_read_desc want to compare the first 4 55703c3359dSFam Zheng * bytes with VMDK4_MAGIC, let's error out if less is read. */ 55803c3359dSFam Zheng error_setg(errp, "File is too small, not a valid image"); 55903c3359dSFam Zheng return NULL; 56003c3359dSFam Zheng } 56103c3359dSFam Zheng 56273b7bcadSFam Zheng size = MIN(size, (1 << 20) - 1); /* avoid unbounded allocation */ 56373b7bcadSFam Zheng buf = g_malloc(size + 1); 564a8842e6dSPaolo Bonzini 565a8842e6dSPaolo Bonzini ret = bdrv_pread(file, desc_offset, buf, size); 566a8842e6dSPaolo Bonzini if (ret < 0) { 567a8842e6dSPaolo Bonzini error_setg_errno(errp, -ret, "Could not read from file"); 568a8842e6dSPaolo Bonzini g_free(buf); 569a8842e6dSPaolo Bonzini return NULL; 570a8842e6dSPaolo Bonzini } 57173b7bcadSFam Zheng buf[ret] = 0; 572a8842e6dSPaolo Bonzini 573a8842e6dSPaolo Bonzini return buf; 574a8842e6dSPaolo Bonzini } 575a8842e6dSPaolo Bonzini 57686c6b429SFam Zheng static int vmdk_open_vmdk4(BlockDriverState *bs, 57724bc15d1SKevin Wolf BdrvChild *file, 578a6468367SKevin Wolf int flags, QDict *options, Error **errp) 579b4b3ab14SFam Zheng { 580b4b3ab14SFam Zheng int ret; 581b4b3ab14SFam Zheng uint32_t magic; 582b4b3ab14SFam Zheng uint32_t l1_size, l1_entry_sectors; 583019d6b8fSAnthony Liguori VMDK4Header header; 584b4b3ab14SFam Zheng VmdkExtent *extent; 585f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 586bb45ded9SFam Zheng int64_t l1_backup_offset = 0; 5873db1d98aSFam Zheng bool compressed; 588b4b3ab14SFam Zheng 58924bc15d1SKevin Wolf ret = bdrv_pread(file->bs, sizeof(magic), &header, sizeof(header)); 590b4b3ab14SFam Zheng if (ret < 0) { 5914823970bSFam Zheng error_setg_errno(errp, -ret, 5924823970bSFam Zheng "Could not read header from file '%s'", 59324bc15d1SKevin Wolf file->bs->filename); 59489ac8480SPaolo Bonzini return -EINVAL; 595b3976d3cSFam Zheng } 5965a394b9eSStefan Hajnoczi if (header.capacity == 0) { 597e98768d4SFam Zheng uint64_t desc_offset = le64_to_cpu(header.desc_offset); 5985a394b9eSStefan Hajnoczi if (desc_offset) { 59924bc15d1SKevin Wolf char *buf = vmdk_read_desc(file->bs, desc_offset << 9, errp); 600d1833ef5SPaolo Bonzini if (!buf) { 601d1833ef5SPaolo Bonzini return -EINVAL; 602d1833ef5SPaolo Bonzini } 603a6468367SKevin Wolf ret = vmdk_open_desc_file(bs, flags, buf, options, errp); 604d1833ef5SPaolo Bonzini g_free(buf); 605d1833ef5SPaolo Bonzini return ret; 6065a394b9eSStefan Hajnoczi } 607f16f509dSFam Zheng } 60865bd155cSKevin Wolf 609f4c129a3SFam Zheng if (!s->create_type) { 610f4c129a3SFam Zheng s->create_type = g_strdup("monolithicSparse"); 611f4c129a3SFam Zheng } 612f4c129a3SFam Zheng 61365bd155cSKevin Wolf if (le64_to_cpu(header.gd_offset) == VMDK4_GD_AT_END) { 61465bd155cSKevin Wolf /* 61565bd155cSKevin Wolf * The footer takes precedence over the header, so read it in. The 61665bd155cSKevin Wolf * footer starts at offset -1024 from the end: One sector for the 61765bd155cSKevin Wolf * footer, and another one for the end-of-stream marker. 61865bd155cSKevin Wolf */ 61965bd155cSKevin Wolf struct { 62065bd155cSKevin Wolf struct { 62165bd155cSKevin Wolf uint64_t val; 62265bd155cSKevin Wolf uint32_t size; 62365bd155cSKevin Wolf uint32_t type; 62465bd155cSKevin Wolf uint8_t pad[512 - 16]; 62565bd155cSKevin Wolf } QEMU_PACKED footer_marker; 62665bd155cSKevin Wolf 62765bd155cSKevin Wolf uint32_t magic; 62865bd155cSKevin Wolf VMDK4Header header; 62965bd155cSKevin Wolf uint8_t pad[512 - 4 - sizeof(VMDK4Header)]; 63065bd155cSKevin Wolf 63165bd155cSKevin Wolf struct { 63265bd155cSKevin Wolf uint64_t val; 63365bd155cSKevin Wolf uint32_t size; 63465bd155cSKevin Wolf uint32_t type; 63565bd155cSKevin Wolf uint8_t pad[512 - 16]; 63665bd155cSKevin Wolf } QEMU_PACKED eos_marker; 63765bd155cSKevin Wolf } QEMU_PACKED footer; 63865bd155cSKevin Wolf 63924bc15d1SKevin Wolf ret = bdrv_pread(file->bs, 6409a4f4c31SKevin Wolf bs->file->bs->total_sectors * 512 - 1536, 64165bd155cSKevin Wolf &footer, sizeof(footer)); 64265bd155cSKevin Wolf if (ret < 0) { 643d899d2e2SFam Zheng error_setg_errno(errp, -ret, "Failed to read footer"); 64465bd155cSKevin Wolf return ret; 64565bd155cSKevin Wolf } 64665bd155cSKevin Wolf 64765bd155cSKevin Wolf /* Some sanity checks for the footer */ 64865bd155cSKevin Wolf if (be32_to_cpu(footer.magic) != VMDK4_MAGIC || 64965bd155cSKevin Wolf le32_to_cpu(footer.footer_marker.size) != 0 || 65065bd155cSKevin Wolf le32_to_cpu(footer.footer_marker.type) != MARKER_FOOTER || 65165bd155cSKevin Wolf le64_to_cpu(footer.eos_marker.val) != 0 || 65265bd155cSKevin Wolf le32_to_cpu(footer.eos_marker.size) != 0 || 65365bd155cSKevin Wolf le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM) 65465bd155cSKevin Wolf { 655d899d2e2SFam Zheng error_setg(errp, "Invalid footer"); 65665bd155cSKevin Wolf return -EINVAL; 65765bd155cSKevin Wolf } 65865bd155cSKevin Wolf 65965bd155cSKevin Wolf header = footer.header; 66065bd155cSKevin Wolf } 66165bd155cSKevin Wolf 6623db1d98aSFam Zheng compressed = 6633db1d98aSFam Zheng le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; 664509d39aaSFam Zheng if (le32_to_cpu(header.version) > 3) { 665a55448b3SMax Reitz error_setg(errp, "Unsupported VMDK version %" PRIu32, 66696c51eb5SFam Zheng le32_to_cpu(header.version)); 66796c51eb5SFam Zheng return -ENOTSUP; 6683db1d98aSFam Zheng } else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR) && 6693db1d98aSFam Zheng !compressed) { 670509d39aaSFam Zheng /* VMware KB 2064959 explains that version 3 added support for 671509d39aaSFam Zheng * persistent changed block tracking (CBT), and backup software can 672509d39aaSFam Zheng * read it as version=1 if it doesn't care about the changed area 673509d39aaSFam Zheng * information. So we are safe to enable read only. */ 674509d39aaSFam Zheng error_setg(errp, "VMDK version 3 must be read only"); 675509d39aaSFam Zheng return -EINVAL; 67696c51eb5SFam Zheng } 67796c51eb5SFam Zheng 678ca8804ceSFam Zheng if (le32_to_cpu(header.num_gtes_per_gt) > 512) { 67989ac8480SPaolo Bonzini error_setg(errp, "L2 table size too big"); 680f8ce0403SFam Zheng return -EINVAL; 681f8ce0403SFam Zheng } 682f8ce0403SFam Zheng 683ca8804ceSFam Zheng l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt) 684b3976d3cSFam Zheng * le64_to_cpu(header.granularity); 68575d12341SStefan Weil if (l1_entry_sectors == 0) { 686d899d2e2SFam Zheng error_setg(errp, "L1 entry size is invalid"); 68786c6b429SFam Zheng return -EINVAL; 68886c6b429SFam Zheng } 689b3976d3cSFam Zheng l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1) 690b3976d3cSFam Zheng / l1_entry_sectors; 691bb45ded9SFam Zheng if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) { 692bb45ded9SFam Zheng l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9; 693bb45ded9SFam Zheng } 69424bc15d1SKevin Wolf if (bdrv_nb_sectors(file->bs) < le64_to_cpu(header.grain_offset)) { 6954ab9dab5SFam Zheng error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes", 6964ab9dab5SFam Zheng (int64_t)(le64_to_cpu(header.grain_offset) 6974ab9dab5SFam Zheng * BDRV_SECTOR_SIZE)); 69834ceed81SFam Zheng return -EINVAL; 69934ceed81SFam Zheng } 70034ceed81SFam Zheng 7018aa1331cSFam Zheng ret = vmdk_add_extent(bs, file, false, 702b3976d3cSFam Zheng le64_to_cpu(header.capacity), 703b3976d3cSFam Zheng le64_to_cpu(header.gd_offset) << 9, 704bb45ded9SFam Zheng l1_backup_offset, 705b3976d3cSFam Zheng l1_size, 706ca8804ceSFam Zheng le32_to_cpu(header.num_gtes_per_gt), 7078aa1331cSFam Zheng le64_to_cpu(header.granularity), 7084823970bSFam Zheng &extent, 7094823970bSFam Zheng errp); 7108aa1331cSFam Zheng if (ret < 0) { 7118aa1331cSFam Zheng return ret; 7128aa1331cSFam Zheng } 713432bb170SFam Zheng extent->compressed = 714432bb170SFam Zheng le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; 715d8a7b061SFam Zheng if (extent->compressed) { 716d8a7b061SFam Zheng g_free(s->create_type); 717d8a7b061SFam Zheng s->create_type = g_strdup("streamOptimized"); 718d8a7b061SFam Zheng } 719432bb170SFam Zheng extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER; 72014ead646SFam Zheng extent->version = le32_to_cpu(header.version); 72114ead646SFam Zheng extent->has_zero_grain = le32_to_cpu(header.flags) & VMDK4_FLAG_ZERO_GRAIN; 7224823970bSFam Zheng ret = vmdk_init_tables(bs, extent, errp); 723b4b3ab14SFam Zheng if (ret) { 72486c6b429SFam Zheng /* free extent allocated by vmdk_add_extent */ 72586c6b429SFam Zheng vmdk_free_last_extent(bs); 726019d6b8fSAnthony Liguori } 727b4b3ab14SFam Zheng return ret; 728b4b3ab14SFam Zheng } 729b4b3ab14SFam Zheng 7307fa60fa3SFam Zheng /* find an option value out of descriptor file */ 7317fa60fa3SFam Zheng static int vmdk_parse_description(const char *desc, const char *opt_name, 7327fa60fa3SFam Zheng char *buf, int buf_size) 7337fa60fa3SFam Zheng { 7347fa60fa3SFam Zheng char *opt_pos, *opt_end; 7357fa60fa3SFam Zheng const char *end = desc + strlen(desc); 7367fa60fa3SFam Zheng 7377fa60fa3SFam Zheng opt_pos = strstr(desc, opt_name); 7387fa60fa3SFam Zheng if (!opt_pos) { 73965f74725SFam Zheng return VMDK_ERROR; 7407fa60fa3SFam Zheng } 7417fa60fa3SFam Zheng /* Skip "=\"" following opt_name */ 7427fa60fa3SFam Zheng opt_pos += strlen(opt_name) + 2; 7437fa60fa3SFam Zheng if (opt_pos >= end) { 74465f74725SFam Zheng return VMDK_ERROR; 7457fa60fa3SFam Zheng } 7467fa60fa3SFam Zheng opt_end = opt_pos; 7477fa60fa3SFam Zheng while (opt_end < end && *opt_end != '"') { 7487fa60fa3SFam Zheng opt_end++; 7497fa60fa3SFam Zheng } 7507fa60fa3SFam Zheng if (opt_end == end || buf_size < opt_end - opt_pos + 1) { 75165f74725SFam Zheng return VMDK_ERROR; 7527fa60fa3SFam Zheng } 7537fa60fa3SFam Zheng pstrcpy(buf, opt_end - opt_pos + 1, opt_pos); 75465f74725SFam Zheng return VMDK_OK; 7557fa60fa3SFam Zheng } 7567fa60fa3SFam Zheng 75786c6b429SFam Zheng /* Open an extent file and append to bs array */ 75824bc15d1SKevin Wolf static int vmdk_open_sparse(BlockDriverState *bs, BdrvChild *file, int flags, 759a6468367SKevin Wolf char *buf, QDict *options, Error **errp) 76086c6b429SFam Zheng { 76186c6b429SFam Zheng uint32_t magic; 76286c6b429SFam Zheng 763d1833ef5SPaolo Bonzini magic = ldl_be_p(buf); 76486c6b429SFam Zheng switch (magic) { 76586c6b429SFam Zheng case VMDK3_MAGIC: 7664823970bSFam Zheng return vmdk_open_vmfs_sparse(bs, file, flags, errp); 76786c6b429SFam Zheng break; 76886c6b429SFam Zheng case VMDK4_MAGIC: 769a6468367SKevin Wolf return vmdk_open_vmdk4(bs, file, flags, options, errp); 77086c6b429SFam Zheng break; 77186c6b429SFam Zheng default: 77276abe407SPaolo Bonzini error_setg(errp, "Image not in VMDK format"); 77376abe407SPaolo Bonzini return -EINVAL; 77486c6b429SFam Zheng break; 77586c6b429SFam Zheng } 77686c6b429SFam Zheng } 77786c6b429SFam Zheng 778e4937694SMarkus Armbruster static const char *next_line(const char *s) 779e4937694SMarkus Armbruster { 780e4937694SMarkus Armbruster while (*s) { 781e4937694SMarkus Armbruster if (*s == '\n') { 782e4937694SMarkus Armbruster return s + 1; 783e4937694SMarkus Armbruster } 784e4937694SMarkus Armbruster s++; 785e4937694SMarkus Armbruster } 786e4937694SMarkus Armbruster return s; 787e4937694SMarkus Armbruster } 788e4937694SMarkus Armbruster 7897fa60fa3SFam Zheng static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, 790a6468367SKevin Wolf const char *desc_file_path, QDict *options, 791a6468367SKevin Wolf Error **errp) 7927fa60fa3SFam Zheng { 7937fa60fa3SFam Zheng int ret; 794395a22faSJeff Cody int matches; 7957fa60fa3SFam Zheng char access[11]; 7967fa60fa3SFam Zheng char type[11]; 7977fa60fa3SFam Zheng char fname[512]; 798d28d737fSMarkus Armbruster const char *p, *np; 7997fa60fa3SFam Zheng int64_t sectors = 0; 8007fa60fa3SFam Zheng int64_t flat_offset; 801fe206562SJeff Cody char *extent_path; 80224bc15d1SKevin Wolf BdrvChild *extent_file; 803f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 804f4c129a3SFam Zheng VmdkExtent *extent; 805a6468367SKevin Wolf char extent_opt_prefix[32]; 80624bc15d1SKevin Wolf Error *local_err = NULL; 8077fa60fa3SFam Zheng 808e4937694SMarkus Armbruster for (p = desc; *p; p = next_line(p)) { 8098a3e0bc3SFam Zheng /* parse extent line in one of below formats: 8108a3e0bc3SFam Zheng * 8117fa60fa3SFam Zheng * RW [size in sectors] FLAT "file-name.vmdk" OFFSET 8127fa60fa3SFam Zheng * RW [size in sectors] SPARSE "file-name.vmdk" 8138a3e0bc3SFam Zheng * RW [size in sectors] VMFS "file-name.vmdk" 8148a3e0bc3SFam Zheng * RW [size in sectors] VMFSSPARSE "file-name.vmdk" 8157fa60fa3SFam Zheng */ 8167fa60fa3SFam Zheng flat_offset = -1; 817395a22faSJeff Cody matches = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, 8187fa60fa3SFam Zheng access, §ors, type, fname, &flat_offset); 819395a22faSJeff Cody if (matches < 4 || strcmp(access, "RW")) { 820e4937694SMarkus Armbruster continue; 8217fa60fa3SFam Zheng } else if (!strcmp(type, "FLAT")) { 822395a22faSJeff Cody if (matches != 5 || flat_offset < 0) { 823d28d737fSMarkus Armbruster goto invalid; 8247fa60fa3SFam Zheng } 825dbbcaa8dSFam Zheng } else if (!strcmp(type, "VMFS")) { 826395a22faSJeff Cody if (matches == 4) { 827dbbcaa8dSFam Zheng flat_offset = 0; 828b47053bdSFam Zheng } else { 829d28d737fSMarkus Armbruster goto invalid; 830b47053bdSFam Zheng } 831395a22faSJeff Cody } else if (matches != 4) { 832d28d737fSMarkus Armbruster goto invalid; 8337fa60fa3SFam Zheng } 8347fa60fa3SFam Zheng 8357fa60fa3SFam Zheng if (sectors <= 0 || 836daac8fdcSFam Zheng (strcmp(type, "FLAT") && strcmp(type, "SPARSE") && 83704d542c8SPaolo Bonzini strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) || 8387fa60fa3SFam Zheng (strcmp(access, "RW"))) { 839e4937694SMarkus Armbruster continue; 8407fa60fa3SFam Zheng } 8417fa60fa3SFam Zheng 8425c98415bSMax Reitz if (!path_is_absolute(fname) && !path_has_protocol(fname) && 8435c98415bSMax Reitz !desc_file_path[0]) 8445c98415bSMax Reitz { 8455c98415bSMax Reitz error_setg(errp, "Cannot use relative extent paths with VMDK " 8469a4f4c31SKevin Wolf "descriptor file '%s'", bs->file->bs->filename); 8475c98415bSMax Reitz return -EINVAL; 8485c98415bSMax Reitz } 8495c98415bSMax Reitz 850fe206562SJeff Cody extent_path = g_malloc0(PATH_MAX); 851a7be17beSJeff Cody path_combine(extent_path, PATH_MAX, desc_file_path, fname); 852a6468367SKevin Wolf 853a6468367SKevin Wolf ret = snprintf(extent_opt_prefix, 32, "extents.%d", s->num_extents); 854a6468367SKevin Wolf assert(ret < 32); 855a6468367SKevin Wolf 85624bc15d1SKevin Wolf extent_file = bdrv_open_child(extent_path, options, extent_opt_prefix, 85724bc15d1SKevin Wolf bs, &child_file, false, &local_err); 858fe206562SJeff Cody g_free(extent_path); 85924bc15d1SKevin Wolf if (local_err) { 86024bc15d1SKevin Wolf error_propagate(errp, local_err); 86124bc15d1SKevin Wolf return -EINVAL; 8627fa60fa3SFam Zheng } 86386c6b429SFam Zheng 86486c6b429SFam Zheng /* save to extents array */ 86504d542c8SPaolo Bonzini if (!strcmp(type, "FLAT") || !strcmp(type, "VMFS")) { 86686c6b429SFam Zheng /* FLAT extent */ 86786c6b429SFam Zheng 8688aa1331cSFam Zheng ret = vmdk_add_extent(bs, extent_file, true, sectors, 8694823970bSFam Zheng 0, 0, 0, 0, 0, &extent, errp); 8708aa1331cSFam Zheng if (ret < 0) { 87124bc15d1SKevin Wolf bdrv_unref_child(bs, extent_file); 8728aa1331cSFam Zheng return ret; 8738aa1331cSFam Zheng } 874f16f509dSFam Zheng extent->flat_start_offset = flat_offset << 9; 875daac8fdcSFam Zheng } else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) { 876daac8fdcSFam Zheng /* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/ 87724bc15d1SKevin Wolf char *buf = vmdk_read_desc(extent_file->bs, 0, errp); 878d1833ef5SPaolo Bonzini if (!buf) { 879d1833ef5SPaolo Bonzini ret = -EINVAL; 880d1833ef5SPaolo Bonzini } else { 881a6468367SKevin Wolf ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, buf, 882a6468367SKevin Wolf options, errp); 883d1833ef5SPaolo Bonzini } 884d1833ef5SPaolo Bonzini g_free(buf); 885b6b1d31fSStefan Hajnoczi if (ret) { 88624bc15d1SKevin Wolf bdrv_unref_child(bs, extent_file); 88786c6b429SFam Zheng return ret; 88886c6b429SFam Zheng } 889f4c129a3SFam Zheng extent = &s->extents[s->num_extents - 1]; 8907fa60fa3SFam Zheng } else { 8914823970bSFam Zheng error_setg(errp, "Unsupported extent type '%s'", type); 89224bc15d1SKevin Wolf bdrv_unref_child(bs, extent_file); 8937fa60fa3SFam Zheng return -ENOTSUP; 8947fa60fa3SFam Zheng } 895f4c129a3SFam Zheng extent->type = g_strdup(type); 896899f1ae2SFam Zheng } 8977fa60fa3SFam Zheng return 0; 898d28d737fSMarkus Armbruster 899d28d737fSMarkus Armbruster invalid: 900d28d737fSMarkus Armbruster np = next_line(p); 901d28d737fSMarkus Armbruster assert(np != p); 902d28d737fSMarkus Armbruster if (np[-1] == '\n') { 903d28d737fSMarkus Armbruster np--; 904d28d737fSMarkus Armbruster } 905d28d737fSMarkus Armbruster error_setg(errp, "Invalid extent line: %.*s", (int)(np - p), p); 906d28d737fSMarkus Armbruster return -EINVAL; 9077fa60fa3SFam Zheng } 9087fa60fa3SFam Zheng 909d1833ef5SPaolo Bonzini static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, 910a6468367SKevin Wolf QDict *options, Error **errp) 9117fa60fa3SFam Zheng { 9127fa60fa3SFam Zheng int ret; 9137fa60fa3SFam Zheng char ct[128]; 9147fa60fa3SFam Zheng BDRVVmdkState *s = bs->opaque; 9157fa60fa3SFam Zheng 9167fa60fa3SFam Zheng if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) { 91776abe407SPaolo Bonzini error_setg(errp, "invalid VMDK image descriptor"); 91876abe407SPaolo Bonzini ret = -EINVAL; 9190bed087dSEvgeny Budilovsky goto exit; 9207fa60fa3SFam Zheng } 9216398de51SFam Zheng if (strcmp(ct, "monolithicFlat") && 92204d542c8SPaolo Bonzini strcmp(ct, "vmfs") && 923daac8fdcSFam Zheng strcmp(ct, "vmfsSparse") && 92486c6b429SFam Zheng strcmp(ct, "twoGbMaxExtentSparse") && 9256398de51SFam Zheng strcmp(ct, "twoGbMaxExtentFlat")) { 9264823970bSFam Zheng error_setg(errp, "Unsupported image type '%s'", ct); 9270bed087dSEvgeny Budilovsky ret = -ENOTSUP; 9280bed087dSEvgeny Budilovsky goto exit; 9297fa60fa3SFam Zheng } 930f4c129a3SFam Zheng s->create_type = g_strdup(ct); 9317fa60fa3SFam Zheng s->desc_offset = 0; 9329a4f4c31SKevin Wolf ret = vmdk_parse_extents(buf, bs, bs->file->bs->exact_filename, options, 9339a4f4c31SKevin Wolf errp); 9340bed087dSEvgeny Budilovsky exit: 9350bed087dSEvgeny Budilovsky return ret; 9367fa60fa3SFam Zheng } 9377fa60fa3SFam Zheng 938015a1036SMax Reitz static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, 939015a1036SMax Reitz Error **errp) 940b4b3ab14SFam Zheng { 9419aeecbbcSFam Zheng char *buf; 94286c6b429SFam Zheng int ret; 94386c6b429SFam Zheng BDRVVmdkState *s = bs->opaque; 94437f09e5eSPaolo Bonzini uint32_t magic; 945b4b3ab14SFam Zheng 9469a4f4c31SKevin Wolf buf = vmdk_read_desc(bs->file->bs, 0, errp); 947d1833ef5SPaolo Bonzini if (!buf) { 948d1833ef5SPaolo Bonzini return -EINVAL; 949d1833ef5SPaolo Bonzini } 950d1833ef5SPaolo Bonzini 95137f09e5eSPaolo Bonzini magic = ldl_be_p(buf); 95237f09e5eSPaolo Bonzini switch (magic) { 95337f09e5eSPaolo Bonzini case VMDK3_MAGIC: 95437f09e5eSPaolo Bonzini case VMDK4_MAGIC: 9559a4f4c31SKevin Wolf ret = vmdk_open_sparse(bs, bs->file, flags, buf, options, 95624bc15d1SKevin Wolf errp); 95786c6b429SFam Zheng s->desc_offset = 0x200; 95837f09e5eSPaolo Bonzini break; 95937f09e5eSPaolo Bonzini default: 960a6468367SKevin Wolf ret = vmdk_open_desc_file(bs, flags, buf, options, errp); 96137f09e5eSPaolo Bonzini break; 96237f09e5eSPaolo Bonzini } 963bae0a0ccSPaolo Bonzini if (ret) { 964bae0a0ccSPaolo Bonzini goto fail; 965bae0a0ccSPaolo Bonzini } 96637f09e5eSPaolo Bonzini 96786c6b429SFam Zheng /* try to open parent images, if exist */ 96886c6b429SFam Zheng ret = vmdk_parent_open(bs); 96986c6b429SFam Zheng if (ret) { 970bae0a0ccSPaolo Bonzini goto fail; 971b4b3ab14SFam Zheng } 972f4c129a3SFam Zheng s->cid = vmdk_read_cid(bs, 0); 97386c6b429SFam Zheng s->parent_cid = vmdk_read_cid(bs, 1); 974848c66e8SPaolo Bonzini qemu_co_mutex_init(&s->lock); 9752bc3166cSKevin Wolf 9762bc3166cSKevin Wolf /* Disable migration when VMDK images are used */ 97781e5f78aSAlberto Garcia error_setg(&s->migration_blocker, "The vmdk format used by node '%s' " 97881e5f78aSAlberto Garcia "does not support live migration", 97981e5f78aSAlberto Garcia bdrv_get_device_or_node_name(bs)); 9802bc3166cSKevin Wolf migrate_add_blocker(s->migration_blocker); 981d1833ef5SPaolo Bonzini g_free(buf); 9822bc3166cSKevin Wolf return 0; 983bae0a0ccSPaolo Bonzini 984bae0a0ccSPaolo Bonzini fail: 985d1833ef5SPaolo Bonzini g_free(buf); 986f4c129a3SFam Zheng g_free(s->create_type); 987f4c129a3SFam Zheng s->create_type = NULL; 988bae0a0ccSPaolo Bonzini vmdk_free_extents(bs); 989bae0a0ccSPaolo Bonzini return ret; 990019d6b8fSAnthony Liguori } 991019d6b8fSAnthony Liguori 992d34682cdSKevin Wolf 9933baca891SKevin Wolf static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp) 994d34682cdSKevin Wolf { 995d34682cdSKevin Wolf BDRVVmdkState *s = bs->opaque; 996d34682cdSKevin Wolf int i; 997d34682cdSKevin Wolf 998d34682cdSKevin Wolf for (i = 0; i < s->num_extents; i++) { 999d34682cdSKevin Wolf if (!s->extents[i].flat) { 1000d34682cdSKevin Wolf bs->bl.write_zeroes_alignment = 1001d34682cdSKevin Wolf MAX(bs->bl.write_zeroes_alignment, 1002d34682cdSKevin Wolf s->extents[i].cluster_sectors); 1003d34682cdSKevin Wolf } 1004d34682cdSKevin Wolf } 1005d34682cdSKevin Wolf } 1006d34682cdSKevin Wolf 1007c6ac36e1SFam Zheng /** 1008c6ac36e1SFam Zheng * get_whole_cluster 1009c6ac36e1SFam Zheng * 1010c6ac36e1SFam Zheng * Copy backing file's cluster that covers @sector_num, otherwise write zero, 1011c6ac36e1SFam Zheng * to the cluster at @cluster_sector_num. 1012c6ac36e1SFam Zheng * 1013c6ac36e1SFam Zheng * If @skip_start_sector < @skip_end_sector, the relative range 1014c6ac36e1SFam Zheng * [@skip_start_sector, @skip_end_sector) is not copied or written, and leave 1015c6ac36e1SFam Zheng * it for call to write user data in the request. 1016c6ac36e1SFam Zheng */ 1017b3976d3cSFam Zheng static int get_whole_cluster(BlockDriverState *bs, 1018b3976d3cSFam Zheng VmdkExtent *extent, 1019c6ac36e1SFam Zheng uint64_t cluster_sector_num, 1020c6ac36e1SFam Zheng uint64_t sector_num, 1021c6ac36e1SFam Zheng uint64_t skip_start_sector, 1022c6ac36e1SFam Zheng uint64_t skip_end_sector) 1023019d6b8fSAnthony Liguori { 1024bf81507dSFam Zheng int ret = VMDK_OK; 1025c6ac36e1SFam Zheng int64_t cluster_bytes; 1026c6ac36e1SFam Zheng uint8_t *whole_grain; 1027019d6b8fSAnthony Liguori 1028c6ac36e1SFam Zheng /* For COW, align request sector_num to cluster start */ 1029c6ac36e1SFam Zheng sector_num = QEMU_ALIGN_DOWN(sector_num, extent->cluster_sectors); 1030c6ac36e1SFam Zheng cluster_bytes = extent->cluster_sectors << BDRV_SECTOR_BITS; 1031c6ac36e1SFam Zheng whole_grain = qemu_blockalign(bs, cluster_bytes); 1032c6ac36e1SFam Zheng 1033760e0063SKevin Wolf if (!bs->backing) { 1034c6ac36e1SFam Zheng memset(whole_grain, 0, skip_start_sector << BDRV_SECTOR_BITS); 1035c6ac36e1SFam Zheng memset(whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 0, 1036c6ac36e1SFam Zheng cluster_bytes - (skip_end_sector << BDRV_SECTOR_BITS)); 1037c6ac36e1SFam Zheng } 1038c6ac36e1SFam Zheng 1039c6ac36e1SFam Zheng assert(skip_end_sector <= extent->cluster_sectors); 10400e69c543SFam Zheng /* we will be here if it's first write on non-exist grain(cluster). 10410e69c543SFam Zheng * try to read from parent image, if exist */ 1042760e0063SKevin Wolf if (bs->backing && !vmdk_is_cid_valid(bs)) { 1043c6ac36e1SFam Zheng ret = VMDK_ERROR; 1044c6ac36e1SFam Zheng goto exit; 1045c6ac36e1SFam Zheng } 1046c6ac36e1SFam Zheng 1047c6ac36e1SFam Zheng /* Read backing data before skip range */ 1048c6ac36e1SFam Zheng if (skip_start_sector > 0) { 1049760e0063SKevin Wolf if (bs->backing) { 1050760e0063SKevin Wolf ret = bdrv_read(bs->backing->bs, sector_num, 1051c6ac36e1SFam Zheng whole_grain, skip_start_sector); 1052c336500dSKevin Wolf if (ret < 0) { 1053bf81507dSFam Zheng ret = VMDK_ERROR; 1054bf81507dSFam Zheng goto exit; 1055019d6b8fSAnthony Liguori } 1056019d6b8fSAnthony Liguori } 105724bc15d1SKevin Wolf ret = bdrv_write(extent->file->bs, cluster_sector_num, whole_grain, 1058c6ac36e1SFam Zheng skip_start_sector); 1059c6ac36e1SFam Zheng if (ret < 0) { 1060c6ac36e1SFam Zheng ret = VMDK_ERROR; 1061c6ac36e1SFam Zheng goto exit; 1062c6ac36e1SFam Zheng } 1063c6ac36e1SFam Zheng } 1064c6ac36e1SFam Zheng /* Read backing data after skip range */ 1065c6ac36e1SFam Zheng if (skip_end_sector < extent->cluster_sectors) { 1066760e0063SKevin Wolf if (bs->backing) { 1067760e0063SKevin Wolf ret = bdrv_read(bs->backing->bs, sector_num + skip_end_sector, 1068c6ac36e1SFam Zheng whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 1069c6ac36e1SFam Zheng extent->cluster_sectors - skip_end_sector); 1070c6ac36e1SFam Zheng if (ret < 0) { 1071c6ac36e1SFam Zheng ret = VMDK_ERROR; 1072c6ac36e1SFam Zheng goto exit; 1073c6ac36e1SFam Zheng } 1074c6ac36e1SFam Zheng } 107524bc15d1SKevin Wolf ret = bdrv_write(extent->file->bs, cluster_sector_num + skip_end_sector, 1076c6ac36e1SFam Zheng whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 1077c6ac36e1SFam Zheng extent->cluster_sectors - skip_end_sector); 1078c6ac36e1SFam Zheng if (ret < 0) { 1079c6ac36e1SFam Zheng ret = VMDK_ERROR; 1080c6ac36e1SFam Zheng goto exit; 1081c6ac36e1SFam Zheng } 1082c6ac36e1SFam Zheng } 1083c6ac36e1SFam Zheng 1084bf81507dSFam Zheng exit: 1085bf81507dSFam Zheng qemu_vfree(whole_grain); 1086bf81507dSFam Zheng return ret; 1087019d6b8fSAnthony Liguori } 1088019d6b8fSAnthony Liguori 1089c6ac36e1SFam Zheng static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, 1090c6ac36e1SFam Zheng uint32_t offset) 1091019d6b8fSAnthony Liguori { 1092c6ac36e1SFam Zheng offset = cpu_to_le32(offset); 1093019d6b8fSAnthony Liguori /* update L2 table */ 1094b3976d3cSFam Zheng if (bdrv_pwrite_sync( 109524bc15d1SKevin Wolf extent->file->bs, 1096b3976d3cSFam Zheng ((int64_t)m_data->l2_offset * 512) 1097c6ac36e1SFam Zheng + (m_data->l2_index * sizeof(offset)), 1098e304e8e5SFam Zheng &offset, sizeof(offset)) < 0) { 109965f74725SFam Zheng return VMDK_ERROR; 1100b3976d3cSFam Zheng } 1101019d6b8fSAnthony Liguori /* update backup L2 table */ 1102b3976d3cSFam Zheng if (extent->l1_backup_table_offset != 0) { 1103b3976d3cSFam Zheng m_data->l2_offset = extent->l1_backup_table[m_data->l1_index]; 1104b3976d3cSFam Zheng if (bdrv_pwrite_sync( 110524bc15d1SKevin Wolf extent->file->bs, 1106b3976d3cSFam Zheng ((int64_t)m_data->l2_offset * 512) 1107c6ac36e1SFam Zheng + (m_data->l2_index * sizeof(offset)), 1108e304e8e5SFam Zheng &offset, sizeof(offset)) < 0) { 110965f74725SFam Zheng return VMDK_ERROR; 1110019d6b8fSAnthony Liguori } 1111b3976d3cSFam Zheng } 1112cdeaf1f1SFam Zheng if (m_data->l2_cache_entry) { 1113cdeaf1f1SFam Zheng *m_data->l2_cache_entry = offset; 1114cdeaf1f1SFam Zheng } 1115019d6b8fSAnthony Liguori 111665f74725SFam Zheng return VMDK_OK; 1117019d6b8fSAnthony Liguori } 1118019d6b8fSAnthony Liguori 1119c6ac36e1SFam Zheng /** 1120c6ac36e1SFam Zheng * get_cluster_offset 1121c6ac36e1SFam Zheng * 1122c6ac36e1SFam Zheng * Look up cluster offset in extent file by sector number, and store in 1123c6ac36e1SFam Zheng * @cluster_offset. 1124c6ac36e1SFam Zheng * 1125c6ac36e1SFam Zheng * For flat extents, the start offset as parsed from the description file is 1126c6ac36e1SFam Zheng * returned. 1127c6ac36e1SFam Zheng * 1128c6ac36e1SFam Zheng * For sparse extents, look up in L1, L2 table. If allocate is true, return an 1129c6ac36e1SFam Zheng * offset for a new cluster and update L2 cache. If there is a backing file, 1130c6ac36e1SFam Zheng * COW is done before returning; otherwise, zeroes are written to the allocated 1131c6ac36e1SFam Zheng * cluster. Both COW and zero writing skips the sector range 1132c6ac36e1SFam Zheng * [@skip_start_sector, @skip_end_sector) passed in by caller, because caller 1133c6ac36e1SFam Zheng * has new data to write there. 1134c6ac36e1SFam Zheng * 1135c6ac36e1SFam Zheng * Returns: VMDK_OK if cluster exists and mapped in the image. 1136c6ac36e1SFam Zheng * VMDK_UNALLOC if cluster is not mapped and @allocate is false. 1137c6ac36e1SFam Zheng * VMDK_ERROR if failed. 1138c6ac36e1SFam Zheng */ 113991b85bd3SFam Zheng static int get_cluster_offset(BlockDriverState *bs, 1140b3976d3cSFam Zheng VmdkExtent *extent, 1141b3976d3cSFam Zheng VmdkMetaData *m_data, 114291b85bd3SFam Zheng uint64_t offset, 1143c6ac36e1SFam Zheng bool allocate, 1144c6ac36e1SFam Zheng uint64_t *cluster_offset, 1145c6ac36e1SFam Zheng uint64_t skip_start_sector, 1146c6ac36e1SFam Zheng uint64_t skip_end_sector) 1147019d6b8fSAnthony Liguori { 1148019d6b8fSAnthony Liguori unsigned int l1_index, l2_offset, l2_index; 1149019d6b8fSAnthony Liguori int min_index, i, j; 1150e304e8e5SFam Zheng uint32_t min_count, *l2_table; 115114ead646SFam Zheng bool zeroed = false; 1152c6ac36e1SFam Zheng int64_t ret; 1153d1319b07SFam Zheng int64_t cluster_sector; 1154019d6b8fSAnthony Liguori 1155ae261c86SFam Zheng if (m_data) { 1156019d6b8fSAnthony Liguori m_data->valid = 0; 1157ae261c86SFam Zheng } 115891b85bd3SFam Zheng if (extent->flat) { 11597fa60fa3SFam Zheng *cluster_offset = extent->flat_start_offset; 116065f74725SFam Zheng return VMDK_OK; 116191b85bd3SFam Zheng } 1162019d6b8fSAnthony Liguori 11636398de51SFam Zheng offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE; 1164b3976d3cSFam Zheng l1_index = (offset >> 9) / extent->l1_entry_sectors; 1165b3976d3cSFam Zheng if (l1_index >= extent->l1_size) { 116665f74725SFam Zheng return VMDK_ERROR; 1167b3976d3cSFam Zheng } 1168b3976d3cSFam Zheng l2_offset = extent->l1_table[l1_index]; 1169b3976d3cSFam Zheng if (!l2_offset) { 117065f74725SFam Zheng return VMDK_UNALLOC; 1171b3976d3cSFam Zheng } 1172019d6b8fSAnthony Liguori for (i = 0; i < L2_CACHE_SIZE; i++) { 1173b3976d3cSFam Zheng if (l2_offset == extent->l2_cache_offsets[i]) { 1174019d6b8fSAnthony Liguori /* increment the hit count */ 1175b3976d3cSFam Zheng if (++extent->l2_cache_counts[i] == 0xffffffff) { 1176019d6b8fSAnthony Liguori for (j = 0; j < L2_CACHE_SIZE; j++) { 1177b3976d3cSFam Zheng extent->l2_cache_counts[j] >>= 1; 1178019d6b8fSAnthony Liguori } 1179019d6b8fSAnthony Liguori } 1180b3976d3cSFam Zheng l2_table = extent->l2_cache + (i * extent->l2_size); 1181019d6b8fSAnthony Liguori goto found; 1182019d6b8fSAnthony Liguori } 1183019d6b8fSAnthony Liguori } 1184019d6b8fSAnthony Liguori /* not found: load a new entry in the least used one */ 1185019d6b8fSAnthony Liguori min_index = 0; 1186019d6b8fSAnthony Liguori min_count = 0xffffffff; 1187019d6b8fSAnthony Liguori for (i = 0; i < L2_CACHE_SIZE; i++) { 1188b3976d3cSFam Zheng if (extent->l2_cache_counts[i] < min_count) { 1189b3976d3cSFam Zheng min_count = extent->l2_cache_counts[i]; 1190019d6b8fSAnthony Liguori min_index = i; 1191019d6b8fSAnthony Liguori } 1192019d6b8fSAnthony Liguori } 1193b3976d3cSFam Zheng l2_table = extent->l2_cache + (min_index * extent->l2_size); 1194b3976d3cSFam Zheng if (bdrv_pread( 119524bc15d1SKevin Wolf extent->file->bs, 1196b3976d3cSFam Zheng (int64_t)l2_offset * 512, 1197b3976d3cSFam Zheng l2_table, 1198b3976d3cSFam Zheng extent->l2_size * sizeof(uint32_t) 1199b3976d3cSFam Zheng ) != extent->l2_size * sizeof(uint32_t)) { 120065f74725SFam Zheng return VMDK_ERROR; 1201b3976d3cSFam Zheng } 1202019d6b8fSAnthony Liguori 1203b3976d3cSFam Zheng extent->l2_cache_offsets[min_index] = l2_offset; 1204b3976d3cSFam Zheng extent->l2_cache_counts[min_index] = 1; 1205019d6b8fSAnthony Liguori found: 1206b3976d3cSFam Zheng l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size; 1207c6ac36e1SFam Zheng cluster_sector = le32_to_cpu(l2_table[l2_index]); 1208019d6b8fSAnthony Liguori 1209cdeaf1f1SFam Zheng if (m_data) { 1210cdeaf1f1SFam Zheng m_data->valid = 1; 1211cdeaf1f1SFam Zheng m_data->l1_index = l1_index; 1212cdeaf1f1SFam Zheng m_data->l2_index = l2_index; 1213cdeaf1f1SFam Zheng m_data->l2_offset = l2_offset; 1214cdeaf1f1SFam Zheng m_data->l2_cache_entry = &l2_table[l2_index]; 1215cdeaf1f1SFam Zheng } 1216c6ac36e1SFam Zheng if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) { 121714ead646SFam Zheng zeroed = true; 121814ead646SFam Zheng } 121914ead646SFam Zheng 1220c6ac36e1SFam Zheng if (!cluster_sector || zeroed) { 122191b85bd3SFam Zheng if (!allocate) { 122214ead646SFam Zheng return zeroed ? VMDK_ZEROED : VMDK_UNALLOC; 122391b85bd3SFam Zheng } 12249949f97eSKevin Wolf 1225c6ac36e1SFam Zheng cluster_sector = extent->next_cluster_sector; 1226c6ac36e1SFam Zheng extent->next_cluster_sector += extent->cluster_sectors; 12279949f97eSKevin Wolf 1228019d6b8fSAnthony Liguori /* First of all we write grain itself, to avoid race condition 1229019d6b8fSAnthony Liguori * that may to corrupt the image. 1230019d6b8fSAnthony Liguori * This problem may occur because of insufficient space on host disk 1231019d6b8fSAnthony Liguori * or inappropriate VM shutdown. 1232019d6b8fSAnthony Liguori */ 1233c6ac36e1SFam Zheng ret = get_whole_cluster(bs, extent, 1234c6ac36e1SFam Zheng cluster_sector, 1235c6ac36e1SFam Zheng offset >> BDRV_SECTOR_BITS, 1236c6ac36e1SFam Zheng skip_start_sector, skip_end_sector); 1237c6ac36e1SFam Zheng if (ret) { 1238c6ac36e1SFam Zheng return ret; 1239019d6b8fSAnthony Liguori } 1240019d6b8fSAnthony Liguori } 1241c6ac36e1SFam Zheng *cluster_offset = cluster_sector << BDRV_SECTOR_BITS; 124265f74725SFam Zheng return VMDK_OK; 1243019d6b8fSAnthony Liguori } 1244019d6b8fSAnthony Liguori 1245b3976d3cSFam Zheng static VmdkExtent *find_extent(BDRVVmdkState *s, 1246b3976d3cSFam Zheng int64_t sector_num, VmdkExtent *start_hint) 1247b3976d3cSFam Zheng { 1248b3976d3cSFam Zheng VmdkExtent *extent = start_hint; 1249b3976d3cSFam Zheng 1250b3976d3cSFam Zheng if (!extent) { 1251b3976d3cSFam Zheng extent = &s->extents[0]; 1252b3976d3cSFam Zheng } 1253b3976d3cSFam Zheng while (extent < &s->extents[s->num_extents]) { 1254b3976d3cSFam Zheng if (sector_num < extent->end_sector) { 1255b3976d3cSFam Zheng return extent; 1256b3976d3cSFam Zheng } 1257b3976d3cSFam Zheng extent++; 1258b3976d3cSFam Zheng } 1259b3976d3cSFam Zheng return NULL; 1260b3976d3cSFam Zheng } 1261b3976d3cSFam Zheng 126261f0ed1dSFam Zheng static inline uint64_t vmdk_find_index_in_cluster(VmdkExtent *extent, 126361f0ed1dSFam Zheng int64_t sector_num) 126461f0ed1dSFam Zheng { 126561f0ed1dSFam Zheng uint64_t index_in_cluster, extent_begin_sector, extent_relative_sector_num; 126661f0ed1dSFam Zheng 126761f0ed1dSFam Zheng extent_begin_sector = extent->end_sector - extent->sectors; 126861f0ed1dSFam Zheng extent_relative_sector_num = sector_num - extent_begin_sector; 126961f0ed1dSFam Zheng index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; 127061f0ed1dSFam Zheng return index_in_cluster; 127161f0ed1dSFam Zheng } 127261f0ed1dSFam Zheng 1273b6b8a333SPaolo Bonzini static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs, 127467a0fd2aSFam Zheng int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file) 1275019d6b8fSAnthony Liguori { 1276019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1277b3976d3cSFam Zheng int64_t index_in_cluster, n, ret; 1278b3976d3cSFam Zheng uint64_t offset; 1279b3976d3cSFam Zheng VmdkExtent *extent; 1280b3976d3cSFam Zheng 1281b3976d3cSFam Zheng extent = find_extent(s, sector_num, NULL); 1282b3976d3cSFam Zheng if (!extent) { 1283b3976d3cSFam Zheng return 0; 1284b3976d3cSFam Zheng } 1285f8a2e5e3SStefan Hajnoczi qemu_co_mutex_lock(&s->lock); 128691b85bd3SFam Zheng ret = get_cluster_offset(bs, extent, NULL, 1287c6ac36e1SFam Zheng sector_num * 512, false, &offset, 1288c6ac36e1SFam Zheng 0, 0); 1289f8a2e5e3SStefan Hajnoczi qemu_co_mutex_unlock(&s->lock); 129014ead646SFam Zheng 1291d0a18f10SFam Zheng index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num); 12924bc74be9SPaolo Bonzini switch (ret) { 12934bc74be9SPaolo Bonzini case VMDK_ERROR: 12944bc74be9SPaolo Bonzini ret = -EIO; 12954bc74be9SPaolo Bonzini break; 12964bc74be9SPaolo Bonzini case VMDK_UNALLOC: 12974bc74be9SPaolo Bonzini ret = 0; 12984bc74be9SPaolo Bonzini break; 12994bc74be9SPaolo Bonzini case VMDK_ZEROED: 13004bc74be9SPaolo Bonzini ret = BDRV_BLOCK_ZERO; 13014bc74be9SPaolo Bonzini break; 13024bc74be9SPaolo Bonzini case VMDK_OK: 13034bc74be9SPaolo Bonzini ret = BDRV_BLOCK_DATA; 1304e0f100f5SFam Zheng if (!extent->compressed) { 1305d0a18f10SFam Zheng ret |= BDRV_BLOCK_OFFSET_VALID; 1306d0a18f10SFam Zheng ret |= (offset + (index_in_cluster << BDRV_SECTOR_BITS)) 1307d0a18f10SFam Zheng & BDRV_BLOCK_OFFSET_MASK; 13084bc74be9SPaolo Bonzini } 1309e0f100f5SFam Zheng *file = extent->file->bs; 13104bc74be9SPaolo Bonzini break; 13114bc74be9SPaolo Bonzini } 131291b85bd3SFam Zheng 1313b3976d3cSFam Zheng n = extent->cluster_sectors - index_in_cluster; 1314ae261c86SFam Zheng if (n > nb_sectors) { 1315019d6b8fSAnthony Liguori n = nb_sectors; 1316ae261c86SFam Zheng } 1317019d6b8fSAnthony Liguori *pnum = n; 1318b3976d3cSFam Zheng return ret; 1319019d6b8fSAnthony Liguori } 1320019d6b8fSAnthony Liguori 1321dd3f6ee2SFam Zheng static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, 1322dd3f6ee2SFam Zheng int64_t offset_in_cluster, const uint8_t *buf, 1323dd3f6ee2SFam Zheng int nb_sectors, int64_t sector_num) 1324dd3f6ee2SFam Zheng { 1325dd3f6ee2SFam Zheng int ret; 13262b2c8c5dSFam Zheng VmdkGrainMarker *data = NULL; 13272b2c8c5dSFam Zheng uLongf buf_len; 1328dd3f6ee2SFam Zheng const uint8_t *write_buf = buf; 1329dd3f6ee2SFam Zheng int write_len = nb_sectors * 512; 13305e82a31eSFam Zheng int64_t write_offset; 13315e82a31eSFam Zheng int64_t write_end_sector; 1332dd3f6ee2SFam Zheng 13332b2c8c5dSFam Zheng if (extent->compressed) { 13342b2c8c5dSFam Zheng if (!extent->has_marker) { 13352b2c8c5dSFam Zheng ret = -EINVAL; 13362b2c8c5dSFam Zheng goto out; 13372b2c8c5dSFam Zheng } 13382b2c8c5dSFam Zheng buf_len = (extent->cluster_sectors << 9) * 2; 13392b2c8c5dSFam Zheng data = g_malloc(buf_len + sizeof(VmdkGrainMarker)); 13402b2c8c5dSFam Zheng if (compress(data->data, &buf_len, buf, nb_sectors << 9) != Z_OK || 13412b2c8c5dSFam Zheng buf_len == 0) { 13422b2c8c5dSFam Zheng ret = -EINVAL; 13432b2c8c5dSFam Zheng goto out; 13442b2c8c5dSFam Zheng } 13452b2c8c5dSFam Zheng data->lba = sector_num; 13462b2c8c5dSFam Zheng data->size = buf_len; 13472b2c8c5dSFam Zheng write_buf = (uint8_t *)data; 13482b2c8c5dSFam Zheng write_len = buf_len + sizeof(VmdkGrainMarker); 13492b2c8c5dSFam Zheng } 13505e82a31eSFam Zheng write_offset = cluster_offset + offset_in_cluster, 135124bc15d1SKevin Wolf ret = bdrv_pwrite(extent->file->bs, write_offset, write_buf, write_len); 13525e82a31eSFam Zheng 13535e82a31eSFam Zheng write_end_sector = DIV_ROUND_UP(write_offset + write_len, BDRV_SECTOR_SIZE); 13545e82a31eSFam Zheng 13553efffc32SRadoslav Gerganov if (extent->compressed) { 13563efffc32SRadoslav Gerganov extent->next_cluster_sector = write_end_sector; 13573efffc32SRadoslav Gerganov } else { 13585e82a31eSFam Zheng extent->next_cluster_sector = MAX(extent->next_cluster_sector, 13595e82a31eSFam Zheng write_end_sector); 13603efffc32SRadoslav Gerganov } 13615e82a31eSFam Zheng 1362dd3f6ee2SFam Zheng if (ret != write_len) { 1363dd3f6ee2SFam Zheng ret = ret < 0 ? ret : -EIO; 1364dd3f6ee2SFam Zheng goto out; 1365dd3f6ee2SFam Zheng } 1366dd3f6ee2SFam Zheng ret = 0; 1367dd3f6ee2SFam Zheng out: 13682b2c8c5dSFam Zheng g_free(data); 1369dd3f6ee2SFam Zheng return ret; 1370dd3f6ee2SFam Zheng } 1371dd3f6ee2SFam Zheng 1372dd3f6ee2SFam Zheng static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, 1373dd3f6ee2SFam Zheng int64_t offset_in_cluster, uint8_t *buf, 1374dd3f6ee2SFam Zheng int nb_sectors) 1375dd3f6ee2SFam Zheng { 1376dd3f6ee2SFam Zheng int ret; 13772b2c8c5dSFam Zheng int cluster_bytes, buf_bytes; 13782b2c8c5dSFam Zheng uint8_t *cluster_buf, *compressed_data; 13792b2c8c5dSFam Zheng uint8_t *uncomp_buf; 13802b2c8c5dSFam Zheng uint32_t data_len; 13812b2c8c5dSFam Zheng VmdkGrainMarker *marker; 13822b2c8c5dSFam Zheng uLongf buf_len; 1383dd3f6ee2SFam Zheng 13842b2c8c5dSFam Zheng 13852b2c8c5dSFam Zheng if (!extent->compressed) { 138624bc15d1SKevin Wolf ret = bdrv_pread(extent->file->bs, 1387dd3f6ee2SFam Zheng cluster_offset + offset_in_cluster, 1388dd3f6ee2SFam Zheng buf, nb_sectors * 512); 1389dd3f6ee2SFam Zheng if (ret == nb_sectors * 512) { 1390dd3f6ee2SFam Zheng return 0; 1391dd3f6ee2SFam Zheng } else { 1392dd3f6ee2SFam Zheng return -EIO; 1393dd3f6ee2SFam Zheng } 1394dd3f6ee2SFam Zheng } 13952b2c8c5dSFam Zheng cluster_bytes = extent->cluster_sectors * 512; 13962b2c8c5dSFam Zheng /* Read two clusters in case GrainMarker + compressed data > one cluster */ 13972b2c8c5dSFam Zheng buf_bytes = cluster_bytes * 2; 13982b2c8c5dSFam Zheng cluster_buf = g_malloc(buf_bytes); 13992b2c8c5dSFam Zheng uncomp_buf = g_malloc(cluster_bytes); 140024bc15d1SKevin Wolf ret = bdrv_pread(extent->file->bs, 14012b2c8c5dSFam Zheng cluster_offset, 14022b2c8c5dSFam Zheng cluster_buf, buf_bytes); 14032b2c8c5dSFam Zheng if (ret < 0) { 14042b2c8c5dSFam Zheng goto out; 14052b2c8c5dSFam Zheng } 14062b2c8c5dSFam Zheng compressed_data = cluster_buf; 14072b2c8c5dSFam Zheng buf_len = cluster_bytes; 14082b2c8c5dSFam Zheng data_len = cluster_bytes; 14092b2c8c5dSFam Zheng if (extent->has_marker) { 14102b2c8c5dSFam Zheng marker = (VmdkGrainMarker *)cluster_buf; 14112b2c8c5dSFam Zheng compressed_data = marker->data; 14122b2c8c5dSFam Zheng data_len = le32_to_cpu(marker->size); 14132b2c8c5dSFam Zheng } 14142b2c8c5dSFam Zheng if (!data_len || data_len > buf_bytes) { 14152b2c8c5dSFam Zheng ret = -EINVAL; 14162b2c8c5dSFam Zheng goto out; 14172b2c8c5dSFam Zheng } 14182b2c8c5dSFam Zheng ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len); 14192b2c8c5dSFam Zheng if (ret != Z_OK) { 14202b2c8c5dSFam Zheng ret = -EINVAL; 14212b2c8c5dSFam Zheng goto out; 14222b2c8c5dSFam Zheng 14232b2c8c5dSFam Zheng } 14242b2c8c5dSFam Zheng if (offset_in_cluster < 0 || 14252b2c8c5dSFam Zheng offset_in_cluster + nb_sectors * 512 > buf_len) { 14262b2c8c5dSFam Zheng ret = -EINVAL; 14272b2c8c5dSFam Zheng goto out; 14282b2c8c5dSFam Zheng } 14292b2c8c5dSFam Zheng memcpy(buf, uncomp_buf + offset_in_cluster, nb_sectors * 512); 14302b2c8c5dSFam Zheng ret = 0; 14312b2c8c5dSFam Zheng 14322b2c8c5dSFam Zheng out: 14332b2c8c5dSFam Zheng g_free(uncomp_buf); 14342b2c8c5dSFam Zheng g_free(cluster_buf); 14352b2c8c5dSFam Zheng return ret; 14362b2c8c5dSFam Zheng } 1437dd3f6ee2SFam Zheng 1438019d6b8fSAnthony Liguori static int vmdk_read(BlockDriverState *bs, int64_t sector_num, 1439019d6b8fSAnthony Liguori uint8_t *buf, int nb_sectors) 1440019d6b8fSAnthony Liguori { 1441019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1442b3976d3cSFam Zheng int ret; 1443b3976d3cSFam Zheng uint64_t n, index_in_cluster; 1444b3976d3cSFam Zheng VmdkExtent *extent = NULL; 1445019d6b8fSAnthony Liguori uint64_t cluster_offset; 1446019d6b8fSAnthony Liguori 1447019d6b8fSAnthony Liguori while (nb_sectors > 0) { 1448b3976d3cSFam Zheng extent = find_extent(s, sector_num, extent); 1449b3976d3cSFam Zheng if (!extent) { 1450b3976d3cSFam Zheng return -EIO; 1451b3976d3cSFam Zheng } 1452c6ac36e1SFam Zheng ret = get_cluster_offset(bs, extent, NULL, 1453c6ac36e1SFam Zheng sector_num << 9, false, &cluster_offset, 1454c6ac36e1SFam Zheng 0, 0); 145590df601fSFam Zheng index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num); 1456b3976d3cSFam Zheng n = extent->cluster_sectors - index_in_cluster; 1457ae261c86SFam Zheng if (n > nb_sectors) { 1458019d6b8fSAnthony Liguori n = nb_sectors; 1459ae261c86SFam Zheng } 146014ead646SFam Zheng if (ret != VMDK_OK) { 146191b85bd3SFam Zheng /* if not allocated, try to read from parent image, if exist */ 1462760e0063SKevin Wolf if (bs->backing && ret != VMDK_ZEROED) { 1463ae261c86SFam Zheng if (!vmdk_is_cid_valid(bs)) { 14647fa60fa3SFam Zheng return -EINVAL; 1465ae261c86SFam Zheng } 1466760e0063SKevin Wolf ret = bdrv_read(bs->backing->bs, sector_num, buf, n); 1467ae261c86SFam Zheng if (ret < 0) { 14687fa60fa3SFam Zheng return ret; 1469ae261c86SFam Zheng } 1470019d6b8fSAnthony Liguori } else { 1471019d6b8fSAnthony Liguori memset(buf, 0, 512 * n); 1472019d6b8fSAnthony Liguori } 1473019d6b8fSAnthony Liguori } else { 1474dd3f6ee2SFam Zheng ret = vmdk_read_extent(extent, 1475dd3f6ee2SFam Zheng cluster_offset, index_in_cluster * 512, 1476dd3f6ee2SFam Zheng buf, n); 1477dd3f6ee2SFam Zheng if (ret) { 14787fa60fa3SFam Zheng return ret; 14797fa60fa3SFam Zheng } 1480019d6b8fSAnthony Liguori } 1481019d6b8fSAnthony Liguori nb_sectors -= n; 1482019d6b8fSAnthony Liguori sector_num += n; 1483019d6b8fSAnthony Liguori buf += n * 512; 1484019d6b8fSAnthony Liguori } 1485019d6b8fSAnthony Liguori return 0; 1486019d6b8fSAnthony Liguori } 1487019d6b8fSAnthony Liguori 14882914caa0SPaolo Bonzini static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num, 14892914caa0SPaolo Bonzini uint8_t *buf, int nb_sectors) 14902914caa0SPaolo Bonzini { 14912914caa0SPaolo Bonzini int ret; 14922914caa0SPaolo Bonzini BDRVVmdkState *s = bs->opaque; 14932914caa0SPaolo Bonzini qemu_co_mutex_lock(&s->lock); 14942914caa0SPaolo Bonzini ret = vmdk_read(bs, sector_num, buf, nb_sectors); 14952914caa0SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 14962914caa0SPaolo Bonzini return ret; 14972914caa0SPaolo Bonzini } 14982914caa0SPaolo Bonzini 1499cdeaf1f1SFam Zheng /** 1500cdeaf1f1SFam Zheng * vmdk_write: 1501cdeaf1f1SFam Zheng * @zeroed: buf is ignored (data is zero), use zeroed_grain GTE feature 1502cdeaf1f1SFam Zheng * if possible, otherwise return -ENOTSUP. 15038e507243SFam Zheng * @zero_dry_run: used for zeroed == true only, don't update L2 table, just try 15048e507243SFam Zheng * with each cluster. By dry run we can find if the zero write 15058e507243SFam Zheng * is possible without modifying image data. 1506cdeaf1f1SFam Zheng * 1507cdeaf1f1SFam Zheng * Returns: error code with 0 for success. 1508cdeaf1f1SFam Zheng */ 1509019d6b8fSAnthony Liguori static int vmdk_write(BlockDriverState *bs, int64_t sector_num, 1510cdeaf1f1SFam Zheng const uint8_t *buf, int nb_sectors, 1511cdeaf1f1SFam Zheng bool zeroed, bool zero_dry_run) 1512019d6b8fSAnthony Liguori { 1513019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1514b3976d3cSFam Zheng VmdkExtent *extent = NULL; 1515585ea0c8SFam Zheng int ret; 1516585ea0c8SFam Zheng int64_t index_in_cluster, n; 1517019d6b8fSAnthony Liguori uint64_t cluster_offset; 1518b3976d3cSFam Zheng VmdkMetaData m_data; 1519019d6b8fSAnthony Liguori 1520019d6b8fSAnthony Liguori if (sector_num > bs->total_sectors) { 15214823970bSFam Zheng error_report("Wrong offset: sector_num=0x%" PRIx64 15229af9e0feSMarkus Armbruster " total_sectors=0x%" PRIx64, 1523019d6b8fSAnthony Liguori sector_num, bs->total_sectors); 15247fa60fa3SFam Zheng return -EIO; 1525019d6b8fSAnthony Liguori } 1526019d6b8fSAnthony Liguori 1527019d6b8fSAnthony Liguori while (nb_sectors > 0) { 1528b3976d3cSFam Zheng extent = find_extent(s, sector_num, extent); 1529b3976d3cSFam Zheng if (!extent) { 1530b3976d3cSFam Zheng return -EIO; 1531b3976d3cSFam Zheng } 153290df601fSFam Zheng index_in_cluster = vmdk_find_index_in_cluster(extent, sector_num); 1533c6ac36e1SFam Zheng n = extent->cluster_sectors - index_in_cluster; 1534c6ac36e1SFam Zheng if (n > nb_sectors) { 1535c6ac36e1SFam Zheng n = nb_sectors; 1536c6ac36e1SFam Zheng } 1537c6ac36e1SFam Zheng ret = get_cluster_offset(bs, extent, &m_data, sector_num << 9, 1538c6ac36e1SFam Zheng !(extent->compressed || zeroed), 1539c6ac36e1SFam Zheng &cluster_offset, 1540c6ac36e1SFam Zheng index_in_cluster, index_in_cluster + n); 15412b2c8c5dSFam Zheng if (extent->compressed) { 154265f74725SFam Zheng if (ret == VMDK_OK) { 15432b2c8c5dSFam Zheng /* Refuse write to allocated cluster for streamOptimized */ 15444823970bSFam Zheng error_report("Could not write to allocated cluster" 15454823970bSFam Zheng " for streamOptimized"); 15462b2c8c5dSFam Zheng return -EIO; 15472b2c8c5dSFam Zheng } else { 15482b2c8c5dSFam Zheng /* allocate */ 1549c6ac36e1SFam Zheng ret = get_cluster_offset(bs, extent, &m_data, sector_num << 9, 1550c6ac36e1SFam Zheng true, &cluster_offset, 0, 0); 15512b2c8c5dSFam Zheng } 15522b2c8c5dSFam Zheng } 1553cdeaf1f1SFam Zheng if (ret == VMDK_ERROR) { 155491b85bd3SFam Zheng return -EINVAL; 1555b3976d3cSFam Zheng } 1556cdeaf1f1SFam Zheng if (zeroed) { 1557cdeaf1f1SFam Zheng /* Do zeroed write, buf is ignored */ 1558cdeaf1f1SFam Zheng if (extent->has_zero_grain && 1559cdeaf1f1SFam Zheng index_in_cluster == 0 && 1560cdeaf1f1SFam Zheng n >= extent->cluster_sectors) { 1561cdeaf1f1SFam Zheng n = extent->cluster_sectors; 1562cdeaf1f1SFam Zheng if (!zero_dry_run) { 1563cdeaf1f1SFam Zheng /* update L2 tables */ 1564c6ac36e1SFam Zheng if (vmdk_L2update(extent, &m_data, VMDK_GTE_ZEROED) 1565c6ac36e1SFam Zheng != VMDK_OK) { 1566cdeaf1f1SFam Zheng return -EIO; 1567cdeaf1f1SFam Zheng } 1568cdeaf1f1SFam Zheng } 1569cdeaf1f1SFam Zheng } else { 1570cdeaf1f1SFam Zheng return -ENOTSUP; 1571cdeaf1f1SFam Zheng } 1572cdeaf1f1SFam Zheng } else { 1573dd3f6ee2SFam Zheng ret = vmdk_write_extent(extent, 1574dd3f6ee2SFam Zheng cluster_offset, index_in_cluster * 512, 1575dd3f6ee2SFam Zheng buf, n, sector_num); 1576dd3f6ee2SFam Zheng if (ret) { 15777fa60fa3SFam Zheng return ret; 1578b3976d3cSFam Zheng } 1579019d6b8fSAnthony Liguori if (m_data.valid) { 1580019d6b8fSAnthony Liguori /* update L2 tables */ 1581c6ac36e1SFam Zheng if (vmdk_L2update(extent, &m_data, 1582c6ac36e1SFam Zheng cluster_offset >> BDRV_SECTOR_BITS) 1583c6ac36e1SFam Zheng != VMDK_OK) { 15847fa60fa3SFam Zheng return -EIO; 1585019d6b8fSAnthony Liguori } 1586b3976d3cSFam Zheng } 1587cdeaf1f1SFam Zheng } 1588019d6b8fSAnthony Liguori nb_sectors -= n; 1589019d6b8fSAnthony Liguori sector_num += n; 1590019d6b8fSAnthony Liguori buf += n * 512; 1591019d6b8fSAnthony Liguori 1592ae261c86SFam Zheng /* update CID on the first write every time the virtual disk is 1593ae261c86SFam Zheng * opened */ 159469b4d86dSFam Zheng if (!s->cid_updated) { 1595e5dc64b8SFam Zheng ret = vmdk_write_cid(bs, g_random_int()); 159699f1835dSKevin Wolf if (ret < 0) { 159799f1835dSKevin Wolf return ret; 159899f1835dSKevin Wolf } 159969b4d86dSFam Zheng s->cid_updated = true; 1600019d6b8fSAnthony Liguori } 1601019d6b8fSAnthony Liguori } 1602019d6b8fSAnthony Liguori return 0; 1603019d6b8fSAnthony Liguori } 1604019d6b8fSAnthony Liguori 1605e183ef75SPaolo Bonzini static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num, 1606e183ef75SPaolo Bonzini const uint8_t *buf, int nb_sectors) 1607e183ef75SPaolo Bonzini { 1608e183ef75SPaolo Bonzini int ret; 1609e183ef75SPaolo Bonzini BDRVVmdkState *s = bs->opaque; 1610e183ef75SPaolo Bonzini qemu_co_mutex_lock(&s->lock); 1611cdeaf1f1SFam Zheng ret = vmdk_write(bs, sector_num, buf, nb_sectors, false, false); 1612cdeaf1f1SFam Zheng qemu_co_mutex_unlock(&s->lock); 1613cdeaf1f1SFam Zheng return ret; 1614cdeaf1f1SFam Zheng } 1615cdeaf1f1SFam Zheng 1616ba0ad89eSFam Zheng static int vmdk_write_compressed(BlockDriverState *bs, 1617ba0ad89eSFam Zheng int64_t sector_num, 1618ba0ad89eSFam Zheng const uint8_t *buf, 1619ba0ad89eSFam Zheng int nb_sectors) 1620ba0ad89eSFam Zheng { 1621ba0ad89eSFam Zheng BDRVVmdkState *s = bs->opaque; 1622ba0ad89eSFam Zheng if (s->num_extents == 1 && s->extents[0].compressed) { 1623ba0ad89eSFam Zheng return vmdk_write(bs, sector_num, buf, nb_sectors, false, false); 1624ba0ad89eSFam Zheng } else { 1625ba0ad89eSFam Zheng return -ENOTSUP; 1626ba0ad89eSFam Zheng } 1627ba0ad89eSFam Zheng } 1628ba0ad89eSFam Zheng 1629cdeaf1f1SFam Zheng static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs, 1630cdeaf1f1SFam Zheng int64_t sector_num, 1631aa7bfbffSPeter Lieven int nb_sectors, 1632aa7bfbffSPeter Lieven BdrvRequestFlags flags) 1633cdeaf1f1SFam Zheng { 1634cdeaf1f1SFam Zheng int ret; 1635cdeaf1f1SFam Zheng BDRVVmdkState *s = bs->opaque; 1636cdeaf1f1SFam Zheng qemu_co_mutex_lock(&s->lock); 16378e507243SFam Zheng /* write zeroes could fail if sectors not aligned to cluster, test it with 16388e507243SFam Zheng * dry_run == true before really updating image */ 1639cdeaf1f1SFam Zheng ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, true); 1640cdeaf1f1SFam Zheng if (!ret) { 1641cdeaf1f1SFam Zheng ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, false); 1642cdeaf1f1SFam Zheng } 1643e183ef75SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 1644e183ef75SPaolo Bonzini return ret; 1645e183ef75SPaolo Bonzini } 1646e183ef75SPaolo Bonzini 16476c031aacSFam Zheng static int vmdk_create_extent(const char *filename, int64_t filesize, 1648917703c1SFam Zheng bool flat, bool compress, bool zeroed_grain, 16494ab15590SChunyan Liu QemuOpts *opts, Error **errp) 1650019d6b8fSAnthony Liguori { 1651f66fd6c3SFam Zheng int ret, i; 1652c4bea169SKevin Wolf BlockBackend *blk = NULL; 1653019d6b8fSAnthony Liguori VMDK4Header header; 1654c13959c7SFam Zheng Error *local_err = NULL; 1655917703c1SFam Zheng uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count; 1656917703c1SFam Zheng uint32_t *gd_buf = NULL; 1657917703c1SFam Zheng int gd_buf_size; 16580e7e1989SKevin Wolf 16594ab15590SChunyan Liu ret = bdrv_create_file(filename, opts, &local_err); 1660f66fd6c3SFam Zheng if (ret < 0) { 1661917703c1SFam Zheng error_propagate(errp, local_err); 1662917703c1SFam Zheng goto exit; 1663917703c1SFam Zheng } 1664917703c1SFam Zheng 1665efaa7c4eSMax Reitz blk = blk_new_open(filename, NULL, NULL, 1666*72e775c7SKevin Wolf BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err); 1667c4bea169SKevin Wolf if (blk == NULL) { 1668917703c1SFam Zheng error_propagate(errp, local_err); 1669c4bea169SKevin Wolf ret = -EIO; 1670917703c1SFam Zheng goto exit; 1671917703c1SFam Zheng } 1672917703c1SFam Zheng 1673c4bea169SKevin Wolf blk_set_allow_write_beyond_eof(blk, true); 1674c4bea169SKevin Wolf 1675917703c1SFam Zheng if (flat) { 1676c4bea169SKevin Wolf ret = blk_truncate(blk, filesize); 1677917703c1SFam Zheng if (ret < 0) { 167839a611a3SJeff Cody error_setg_errno(errp, -ret, "Could not truncate file"); 1679f66fd6c3SFam Zheng } 1680f66fd6c3SFam Zheng goto exit; 1681f66fd6c3SFam Zheng } 1682019d6b8fSAnthony Liguori magic = cpu_to_be32(VMDK4_MAGIC); 1683019d6b8fSAnthony Liguori memset(&header, 0, sizeof(header)); 1684d62d9dc4SFam Zheng if (compress) { 1685d62d9dc4SFam Zheng header.version = 3; 1686d62d9dc4SFam Zheng } else if (zeroed_grain) { 1687d62d9dc4SFam Zheng header.version = 2; 1688d62d9dc4SFam Zheng } else { 1689d62d9dc4SFam Zheng header.version = 1; 1690d62d9dc4SFam Zheng } 169195b0aa42SFam Zheng header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT 169269e0b6dfSFam Zheng | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0) 169369e0b6dfSFam Zheng | (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0); 16946c031aacSFam Zheng header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0; 1695917703c1SFam Zheng header.capacity = filesize / BDRV_SECTOR_SIZE; 169616372ff0SAlexander Graf header.granularity = 128; 1697917703c1SFam Zheng header.num_gtes_per_gt = BDRV_SECTOR_SIZE; 1698019d6b8fSAnthony Liguori 1699917703c1SFam Zheng grains = DIV_ROUND_UP(filesize / BDRV_SECTOR_SIZE, header.granularity); 1700917703c1SFam Zheng gt_size = DIV_ROUND_UP(header.num_gtes_per_gt * sizeof(uint32_t), 1701917703c1SFam Zheng BDRV_SECTOR_SIZE); 1702917703c1SFam Zheng gt_count = DIV_ROUND_UP(grains, header.num_gtes_per_gt); 1703917703c1SFam Zheng gd_sectors = DIV_ROUND_UP(gt_count * sizeof(uint32_t), BDRV_SECTOR_SIZE); 1704019d6b8fSAnthony Liguori 1705019d6b8fSAnthony Liguori header.desc_offset = 1; 1706019d6b8fSAnthony Liguori header.desc_size = 20; 1707019d6b8fSAnthony Liguori header.rgd_offset = header.desc_offset + header.desc_size; 1708917703c1SFam Zheng header.gd_offset = header.rgd_offset + gd_sectors + (gt_size * gt_count); 1709019d6b8fSAnthony Liguori header.grain_offset = 1710917703c1SFam Zheng ROUND_UP(header.gd_offset + gd_sectors + (gt_size * gt_count), 1711917703c1SFam Zheng header.granularity); 171216372ff0SAlexander Graf /* swap endianness for all header fields */ 171316372ff0SAlexander Graf header.version = cpu_to_le32(header.version); 171416372ff0SAlexander Graf header.flags = cpu_to_le32(header.flags); 171516372ff0SAlexander Graf header.capacity = cpu_to_le64(header.capacity); 171616372ff0SAlexander Graf header.granularity = cpu_to_le64(header.granularity); 1717ca8804ceSFam Zheng header.num_gtes_per_gt = cpu_to_le32(header.num_gtes_per_gt); 1718019d6b8fSAnthony Liguori header.desc_offset = cpu_to_le64(header.desc_offset); 1719019d6b8fSAnthony Liguori header.desc_size = cpu_to_le64(header.desc_size); 1720019d6b8fSAnthony Liguori header.rgd_offset = cpu_to_le64(header.rgd_offset); 1721019d6b8fSAnthony Liguori header.gd_offset = cpu_to_le64(header.gd_offset); 1722019d6b8fSAnthony Liguori header.grain_offset = cpu_to_le64(header.grain_offset); 17236c031aacSFam Zheng header.compressAlgorithm = cpu_to_le16(header.compressAlgorithm); 1724019d6b8fSAnthony Liguori 1725019d6b8fSAnthony Liguori header.check_bytes[0] = 0xa; 1726019d6b8fSAnthony Liguori header.check_bytes[1] = 0x20; 1727019d6b8fSAnthony Liguori header.check_bytes[2] = 0xd; 1728019d6b8fSAnthony Liguori header.check_bytes[3] = 0xa; 1729019d6b8fSAnthony Liguori 1730019d6b8fSAnthony Liguori /* write all the data */ 1731c4bea169SKevin Wolf ret = blk_pwrite(blk, 0, &magic, sizeof(magic)); 1732917703c1SFam Zheng if (ret < 0) { 1733c6bd8c70SMarkus Armbruster error_setg(errp, QERR_IO_ERROR); 17341640366cSKirill A. Shutemov goto exit; 17351640366cSKirill A. Shutemov } 1736c4bea169SKevin Wolf ret = blk_pwrite(blk, sizeof(magic), &header, sizeof(header)); 1737917703c1SFam Zheng if (ret < 0) { 1738c6bd8c70SMarkus Armbruster error_setg(errp, QERR_IO_ERROR); 17391640366cSKirill A. Shutemov goto exit; 17401640366cSKirill A. Shutemov } 1741019d6b8fSAnthony Liguori 1742c4bea169SKevin Wolf ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9); 17431640366cSKirill A. Shutemov if (ret < 0) { 174439a611a3SJeff Cody error_setg_errno(errp, -ret, "Could not truncate file"); 17451640366cSKirill A. Shutemov goto exit; 17461640366cSKirill A. Shutemov } 1747019d6b8fSAnthony Liguori 1748019d6b8fSAnthony Liguori /* write grain directory */ 1749917703c1SFam Zheng gd_buf_size = gd_sectors * BDRV_SECTOR_SIZE; 1750917703c1SFam Zheng gd_buf = g_malloc0(gd_buf_size); 1751917703c1SFam Zheng for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_sectors; 17521640366cSKirill A. Shutemov i < gt_count; i++, tmp += gt_size) { 1753917703c1SFam Zheng gd_buf[i] = cpu_to_le32(tmp); 17541640366cSKirill A. Shutemov } 1755c4bea169SKevin Wolf ret = blk_pwrite(blk, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE, 1756917703c1SFam Zheng gd_buf, gd_buf_size); 1757917703c1SFam Zheng if (ret < 0) { 1758c6bd8c70SMarkus Armbruster error_setg(errp, QERR_IO_ERROR); 1759917703c1SFam Zheng goto exit; 17601640366cSKirill A. Shutemov } 1761019d6b8fSAnthony Liguori 1762019d6b8fSAnthony Liguori /* write backup grain directory */ 1763917703c1SFam Zheng for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_sectors; 17641640366cSKirill A. Shutemov i < gt_count; i++, tmp += gt_size) { 1765917703c1SFam Zheng gd_buf[i] = cpu_to_le32(tmp); 17661640366cSKirill A. Shutemov } 1767c4bea169SKevin Wolf ret = blk_pwrite(blk, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE, 1768917703c1SFam Zheng gd_buf, gd_buf_size); 1769917703c1SFam Zheng if (ret < 0) { 1770c6bd8c70SMarkus Armbruster error_setg(errp, QERR_IO_ERROR); 1771917703c1SFam Zheng goto exit; 17721640366cSKirill A. Shutemov } 1773019d6b8fSAnthony Liguori 1774f66fd6c3SFam Zheng ret = 0; 1775f66fd6c3SFam Zheng exit: 1776c4bea169SKevin Wolf if (blk) { 1777c4bea169SKevin Wolf blk_unref(blk); 1778917703c1SFam Zheng } 1779917703c1SFam Zheng g_free(gd_buf); 1780f66fd6c3SFam Zheng return ret; 1781f66fd6c3SFam Zheng } 1782019d6b8fSAnthony Liguori 1783f66fd6c3SFam Zheng static int filename_decompose(const char *filename, char *path, char *prefix, 17844823970bSFam Zheng char *postfix, size_t buf_len, Error **errp) 1785f66fd6c3SFam Zheng { 1786f66fd6c3SFam Zheng const char *p, *q; 1787f66fd6c3SFam Zheng 1788f66fd6c3SFam Zheng if (filename == NULL || !strlen(filename)) { 17894823970bSFam Zheng error_setg(errp, "No filename provided"); 179065f74725SFam Zheng return VMDK_ERROR; 1791f66fd6c3SFam Zheng } 1792f66fd6c3SFam Zheng p = strrchr(filename, '/'); 1793f66fd6c3SFam Zheng if (p == NULL) { 1794f66fd6c3SFam Zheng p = strrchr(filename, '\\'); 1795f66fd6c3SFam Zheng } 1796f66fd6c3SFam Zheng if (p == NULL) { 1797f66fd6c3SFam Zheng p = strrchr(filename, ':'); 1798f66fd6c3SFam Zheng } 1799f66fd6c3SFam Zheng if (p != NULL) { 1800f66fd6c3SFam Zheng p++; 1801f66fd6c3SFam Zheng if (p - filename >= buf_len) { 180265f74725SFam Zheng return VMDK_ERROR; 1803f66fd6c3SFam Zheng } 1804f66fd6c3SFam Zheng pstrcpy(path, p - filename + 1, filename); 1805f66fd6c3SFam Zheng } else { 1806f66fd6c3SFam Zheng p = filename; 1807f66fd6c3SFam Zheng path[0] = '\0'; 1808f66fd6c3SFam Zheng } 1809f66fd6c3SFam Zheng q = strrchr(p, '.'); 1810f66fd6c3SFam Zheng if (q == NULL) { 1811f66fd6c3SFam Zheng pstrcpy(prefix, buf_len, p); 1812f66fd6c3SFam Zheng postfix[0] = '\0'; 1813f66fd6c3SFam Zheng } else { 1814f66fd6c3SFam Zheng if (q - p >= buf_len) { 181565f74725SFam Zheng return VMDK_ERROR; 1816f66fd6c3SFam Zheng } 1817f66fd6c3SFam Zheng pstrcpy(prefix, q - p + 1, p); 1818f66fd6c3SFam Zheng pstrcpy(postfix, buf_len, q); 1819f66fd6c3SFam Zheng } 182065f74725SFam Zheng return VMDK_OK; 1821f66fd6c3SFam Zheng } 1822f66fd6c3SFam Zheng 18235820f1daSChunyan Liu static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) 1824f66fd6c3SFam Zheng { 1825917703c1SFam Zheng int idx = 0; 1826c4bea169SKevin Wolf BlockBackend *new_blk = NULL; 1827c13959c7SFam Zheng Error *local_err = NULL; 1828af057fe7SFam Zheng char *desc = NULL; 1829f66fd6c3SFam Zheng int64_t total_size = 0, filesize; 18305820f1daSChunyan Liu char *adapter_type = NULL; 18315820f1daSChunyan Liu char *backing_file = NULL; 18325820f1daSChunyan Liu char *fmt = NULL; 1833f66fd6c3SFam Zheng int flags = 0; 1834f66fd6c3SFam Zheng int ret = 0; 18356c031aacSFam Zheng bool flat, split, compress; 1836af057fe7SFam Zheng GString *ext_desc_lines; 1837fe206562SJeff Cody char *path = g_malloc0(PATH_MAX); 1838fe206562SJeff Cody char *prefix = g_malloc0(PATH_MAX); 1839fe206562SJeff Cody char *postfix = g_malloc0(PATH_MAX); 1840fe206562SJeff Cody char *desc_line = g_malloc0(BUF_SIZE); 1841fe206562SJeff Cody char *ext_filename = g_malloc0(PATH_MAX); 1842fe206562SJeff Cody char *desc_filename = g_malloc0(PATH_MAX); 1843f66fd6c3SFam Zheng const int64_t split_size = 0x80000000; /* VMDK has constant split size */ 1844f66fd6c3SFam Zheng const char *desc_extent_line; 1845fe206562SJeff Cody char *parent_desc_line = g_malloc0(BUF_SIZE); 1846f66fd6c3SFam Zheng uint32_t parent_cid = 0xffffffff; 18477f2039f6SOthmar Pasteka uint32_t number_heads = 16; 184869e0b6dfSFam Zheng bool zeroed_grain = false; 1849917703c1SFam Zheng uint32_t desc_offset = 0, desc_len; 1850f66fd6c3SFam Zheng const char desc_template[] = 1851f66fd6c3SFam Zheng "# Disk DescriptorFile\n" 1852f66fd6c3SFam Zheng "version=1\n" 18539b17031aSFam Zheng "CID=%" PRIx32 "\n" 18549b17031aSFam Zheng "parentCID=%" PRIx32 "\n" 1855f66fd6c3SFam Zheng "createType=\"%s\"\n" 1856f66fd6c3SFam Zheng "%s" 1857f66fd6c3SFam Zheng "\n" 1858f66fd6c3SFam Zheng "# Extent description\n" 1859f66fd6c3SFam Zheng "%s" 1860f66fd6c3SFam Zheng "\n" 1861f66fd6c3SFam Zheng "# The Disk Data Base\n" 1862f66fd6c3SFam Zheng "#DDB\n" 1863f66fd6c3SFam Zheng "\n" 1864f66fd6c3SFam Zheng "ddb.virtualHWVersion = \"%d\"\n" 1865f66fd6c3SFam Zheng "ddb.geometry.cylinders = \"%" PRId64 "\"\n" 18664ab9dab5SFam Zheng "ddb.geometry.heads = \"%" PRIu32 "\"\n" 1867f66fd6c3SFam Zheng "ddb.geometry.sectors = \"63\"\n" 18687f2039f6SOthmar Pasteka "ddb.adapterType = \"%s\"\n"; 1869f66fd6c3SFam Zheng 1870af057fe7SFam Zheng ext_desc_lines = g_string_new(NULL); 1871af057fe7SFam Zheng 18724823970bSFam Zheng if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) { 1873af057fe7SFam Zheng ret = -EINVAL; 1874af057fe7SFam Zheng goto exit; 1875f66fd6c3SFam Zheng } 1876f66fd6c3SFam Zheng /* Read out options */ 1877c2eb918eSHu Tao total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), 1878c2eb918eSHu Tao BDRV_SECTOR_SIZE); 18795820f1daSChunyan Liu adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE); 18805820f1daSChunyan Liu backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); 18815820f1daSChunyan Liu if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) { 18825820f1daSChunyan Liu flags |= BLOCK_FLAG_COMPAT6; 1883f66fd6c3SFam Zheng } 18845820f1daSChunyan Liu fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); 18855820f1daSChunyan Liu if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false)) { 18865820f1daSChunyan Liu zeroed_grain = true; 1887f66fd6c3SFam Zheng } 18885820f1daSChunyan Liu 18897f2039f6SOthmar Pasteka if (!adapter_type) { 18905820f1daSChunyan Liu adapter_type = g_strdup("ide"); 18917f2039f6SOthmar Pasteka } else if (strcmp(adapter_type, "ide") && 18927f2039f6SOthmar Pasteka strcmp(adapter_type, "buslogic") && 18937f2039f6SOthmar Pasteka strcmp(adapter_type, "lsilogic") && 18947f2039f6SOthmar Pasteka strcmp(adapter_type, "legacyESX")) { 18954823970bSFam Zheng error_setg(errp, "Unknown adapter type: '%s'", adapter_type); 1896af057fe7SFam Zheng ret = -EINVAL; 1897af057fe7SFam Zheng goto exit; 18987f2039f6SOthmar Pasteka } 18997f2039f6SOthmar Pasteka if (strcmp(adapter_type, "ide") != 0) { 19007f2039f6SOthmar Pasteka /* that's the number of heads with which vmware operates when 19017f2039f6SOthmar Pasteka creating, exporting, etc. vmdk files with a non-ide adapter type */ 19027f2039f6SOthmar Pasteka number_heads = 255; 19037f2039f6SOthmar Pasteka } 1904f66fd6c3SFam Zheng if (!fmt) { 1905f66fd6c3SFam Zheng /* Default format to monolithicSparse */ 19065820f1daSChunyan Liu fmt = g_strdup("monolithicSparse"); 1907f66fd6c3SFam Zheng } else if (strcmp(fmt, "monolithicFlat") && 1908f66fd6c3SFam Zheng strcmp(fmt, "monolithicSparse") && 1909f66fd6c3SFam Zheng strcmp(fmt, "twoGbMaxExtentSparse") && 19106c031aacSFam Zheng strcmp(fmt, "twoGbMaxExtentFlat") && 19116c031aacSFam Zheng strcmp(fmt, "streamOptimized")) { 19124823970bSFam Zheng error_setg(errp, "Unknown subformat: '%s'", fmt); 1913af057fe7SFam Zheng ret = -EINVAL; 1914af057fe7SFam Zheng goto exit; 1915f66fd6c3SFam Zheng } 1916f66fd6c3SFam Zheng split = !(strcmp(fmt, "twoGbMaxExtentFlat") && 1917f66fd6c3SFam Zheng strcmp(fmt, "twoGbMaxExtentSparse")); 1918f66fd6c3SFam Zheng flat = !(strcmp(fmt, "monolithicFlat") && 1919f66fd6c3SFam Zheng strcmp(fmt, "twoGbMaxExtentFlat")); 19206c031aacSFam Zheng compress = !strcmp(fmt, "streamOptimized"); 1921f66fd6c3SFam Zheng if (flat) { 19224ab9dab5SFam Zheng desc_extent_line = "RW %" PRId64 " FLAT \"%s\" 0\n"; 1923f66fd6c3SFam Zheng } else { 19244ab9dab5SFam Zheng desc_extent_line = "RW %" PRId64 " SPARSE \"%s\"\n"; 1925f66fd6c3SFam Zheng } 1926f66fd6c3SFam Zheng if (flat && backing_file) { 19274823970bSFam Zheng error_setg(errp, "Flat image can't have backing file"); 1928af057fe7SFam Zheng ret = -ENOTSUP; 1929af057fe7SFam Zheng goto exit; 1930f66fd6c3SFam Zheng } 193152c8d629SFam Zheng if (flat && zeroed_grain) { 193252c8d629SFam Zheng error_setg(errp, "Flat image can't enable zeroed grain"); 1933af057fe7SFam Zheng ret = -ENOTSUP; 1934af057fe7SFam Zheng goto exit; 193552c8d629SFam Zheng } 1936f66fd6c3SFam Zheng if (backing_file) { 1937c4bea169SKevin Wolf BlockBackend *blk; 19381085daf9SMax Reitz char *full_backing = g_new0(char, PATH_MAX); 19391085daf9SMax Reitz bdrv_get_full_backing_filename_from_filename(filename, backing_file, 19401085daf9SMax Reitz full_backing, PATH_MAX, 19411085daf9SMax Reitz &local_err); 19421085daf9SMax Reitz if (local_err) { 19431085daf9SMax Reitz g_free(full_backing); 19441085daf9SMax Reitz error_propagate(errp, local_err); 19451085daf9SMax Reitz ret = -ENOENT; 19461085daf9SMax Reitz goto exit; 19471085daf9SMax Reitz } 1948c4bea169SKevin Wolf 1949efaa7c4eSMax Reitz blk = blk_new_open(full_backing, NULL, NULL, 1950*72e775c7SKevin Wolf BDRV_O_NO_BACKING, errp); 19511085daf9SMax Reitz g_free(full_backing); 1952c4bea169SKevin Wolf if (blk == NULL) { 1953c4bea169SKevin Wolf ret = -EIO; 1954af057fe7SFam Zheng goto exit; 1955f66fd6c3SFam Zheng } 1956c4bea169SKevin Wolf if (strcmp(blk_bs(blk)->drv->format_name, "vmdk")) { 1957c4bea169SKevin Wolf blk_unref(blk); 1958af057fe7SFam Zheng ret = -EINVAL; 1959af057fe7SFam Zheng goto exit; 1960f66fd6c3SFam Zheng } 1961c4bea169SKevin Wolf parent_cid = vmdk_read_cid(blk_bs(blk), 0); 1962c4bea169SKevin Wolf blk_unref(blk); 1963fe206562SJeff Cody snprintf(parent_desc_line, BUF_SIZE, 19648ed610a1SFam Zheng "parentFileNameHint=\"%s\"", backing_file); 1965f66fd6c3SFam Zheng } 1966f66fd6c3SFam Zheng 1967f66fd6c3SFam Zheng /* Create extents */ 1968f66fd6c3SFam Zheng filesize = total_size; 1969f66fd6c3SFam Zheng while (filesize > 0) { 1970f66fd6c3SFam Zheng int64_t size = filesize; 1971f66fd6c3SFam Zheng 1972f66fd6c3SFam Zheng if (split && size > split_size) { 1973f66fd6c3SFam Zheng size = split_size; 1974f66fd6c3SFam Zheng } 1975f66fd6c3SFam Zheng if (split) { 1976fe206562SJeff Cody snprintf(desc_filename, PATH_MAX, "%s-%c%03d%s", 1977f66fd6c3SFam Zheng prefix, flat ? 'f' : 's', ++idx, postfix); 1978f66fd6c3SFam Zheng } else if (flat) { 1979fe206562SJeff Cody snprintf(desc_filename, PATH_MAX, "%s-flat%s", prefix, postfix); 1980f66fd6c3SFam Zheng } else { 1981fe206562SJeff Cody snprintf(desc_filename, PATH_MAX, "%s%s", prefix, postfix); 1982f66fd6c3SFam Zheng } 1983fe206562SJeff Cody snprintf(ext_filename, PATH_MAX, "%s%s", path, desc_filename); 1984f66fd6c3SFam Zheng 198569e0b6dfSFam Zheng if (vmdk_create_extent(ext_filename, size, 19864ab15590SChunyan Liu flat, compress, zeroed_grain, opts, errp)) { 1987af057fe7SFam Zheng ret = -EINVAL; 1988af057fe7SFam Zheng goto exit; 1989f66fd6c3SFam Zheng } 1990f66fd6c3SFam Zheng filesize -= size; 1991f66fd6c3SFam Zheng 1992f66fd6c3SFam Zheng /* Format description line */ 1993fe206562SJeff Cody snprintf(desc_line, BUF_SIZE, 1994917703c1SFam Zheng desc_extent_line, size / BDRV_SECTOR_SIZE, desc_filename); 1995af057fe7SFam Zheng g_string_append(ext_desc_lines, desc_line); 1996f66fd6c3SFam Zheng } 1997f66fd6c3SFam Zheng /* generate descriptor file */ 1998af057fe7SFam Zheng desc = g_strdup_printf(desc_template, 1999e5dc64b8SFam Zheng g_random_int(), 2000f66fd6c3SFam Zheng parent_cid, 2001f66fd6c3SFam Zheng fmt, 2002f66fd6c3SFam Zheng parent_desc_line, 2003af057fe7SFam Zheng ext_desc_lines->str, 2004f66fd6c3SFam Zheng (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), 2005917703c1SFam Zheng total_size / 2006917703c1SFam Zheng (int64_t)(63 * number_heads * BDRV_SECTOR_SIZE), 2007af057fe7SFam Zheng number_heads, 20087f2039f6SOthmar Pasteka adapter_type); 2009917703c1SFam Zheng desc_len = strlen(desc); 2010917703c1SFam Zheng /* the descriptor offset = 0x200 */ 2011917703c1SFam Zheng if (!split && !flat) { 2012917703c1SFam Zheng desc_offset = 0x200; 2013f66fd6c3SFam Zheng } else { 2014c282e1fdSChunyan Liu ret = bdrv_create_file(filename, opts, &local_err); 2015917703c1SFam Zheng if (ret < 0) { 2016c13959c7SFam Zheng error_propagate(errp, local_err); 2017af057fe7SFam Zheng goto exit; 2018f66fd6c3SFam Zheng } 2019f66fd6c3SFam Zheng } 2020c4bea169SKevin Wolf 2021efaa7c4eSMax Reitz new_blk = blk_new_open(filename, NULL, NULL, 2022*72e775c7SKevin Wolf BDRV_O_RDWR | BDRV_O_PROTOCOL, &local_err); 2023c4bea169SKevin Wolf if (new_blk == NULL) { 2024c13959c7SFam Zheng error_propagate(errp, local_err); 2025c4bea169SKevin Wolf ret = -EIO; 2026917703c1SFam Zheng goto exit; 20271640366cSKirill A. Shutemov } 2028c4bea169SKevin Wolf 2029c4bea169SKevin Wolf blk_set_allow_write_beyond_eof(new_blk, true); 2030c4bea169SKevin Wolf 2031c4bea169SKevin Wolf ret = blk_pwrite(new_blk, desc_offset, desc, desc_len); 2032917703c1SFam Zheng if (ret < 0) { 2033917703c1SFam Zheng error_setg_errno(errp, -ret, "Could not write description"); 2034917703c1SFam Zheng goto exit; 2035917703c1SFam Zheng } 2036917703c1SFam Zheng /* bdrv_pwrite write padding zeros to align to sector, we don't need that 2037917703c1SFam Zheng * for description file */ 2038917703c1SFam Zheng if (desc_offset == 0) { 2039c4bea169SKevin Wolf ret = blk_truncate(new_blk, desc_len); 2040917703c1SFam Zheng if (ret < 0) { 204139a611a3SJeff Cody error_setg_errno(errp, -ret, "Could not truncate file"); 2042917703c1SFam Zheng } 2043917703c1SFam Zheng } 2044af057fe7SFam Zheng exit: 2045c4bea169SKevin Wolf if (new_blk) { 2046c4bea169SKevin Wolf blk_unref(new_blk); 2047917703c1SFam Zheng } 20485820f1daSChunyan Liu g_free(adapter_type); 20495820f1daSChunyan Liu g_free(backing_file); 20505820f1daSChunyan Liu g_free(fmt); 2051af057fe7SFam Zheng g_free(desc); 2052fe206562SJeff Cody g_free(path); 2053fe206562SJeff Cody g_free(prefix); 2054fe206562SJeff Cody g_free(postfix); 2055fe206562SJeff Cody g_free(desc_line); 2056fe206562SJeff Cody g_free(ext_filename); 2057fe206562SJeff Cody g_free(desc_filename); 2058fe206562SJeff Cody g_free(parent_desc_line); 2059af057fe7SFam Zheng g_string_free(ext_desc_lines, true); 20601640366cSKirill A. Shutemov return ret; 2061019d6b8fSAnthony Liguori } 2062019d6b8fSAnthony Liguori 2063019d6b8fSAnthony Liguori static void vmdk_close(BlockDriverState *bs) 2064019d6b8fSAnthony Liguori { 20652bc3166cSKevin Wolf BDRVVmdkState *s = bs->opaque; 20662bc3166cSKevin Wolf 2067b3976d3cSFam Zheng vmdk_free_extents(bs); 2068f4c129a3SFam Zheng g_free(s->create_type); 20692bc3166cSKevin Wolf 20702bc3166cSKevin Wolf migrate_del_blocker(s->migration_blocker); 20712bc3166cSKevin Wolf error_free(s->migration_blocker); 2072019d6b8fSAnthony Liguori } 2073019d6b8fSAnthony Liguori 20748b94ff85SPaolo Bonzini static coroutine_fn int vmdk_co_flush(BlockDriverState *bs) 2075019d6b8fSAnthony Liguori { 2076333c574dSFam Zheng BDRVVmdkState *s = bs->opaque; 207729cdb251SPaolo Bonzini int i, err; 207829cdb251SPaolo Bonzini int ret = 0; 2079333c574dSFam Zheng 2080333c574dSFam Zheng for (i = 0; i < s->num_extents; i++) { 208124bc15d1SKevin Wolf err = bdrv_co_flush(s->extents[i].file->bs); 2082333c574dSFam Zheng if (err < 0) { 2083333c574dSFam Zheng ret = err; 2084333c574dSFam Zheng } 2085333c574dSFam Zheng } 2086333c574dSFam Zheng return ret; 2087019d6b8fSAnthony Liguori } 2088019d6b8fSAnthony Liguori 20894a1d5e1fSFam Zheng static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) 20904a1d5e1fSFam Zheng { 20914a1d5e1fSFam Zheng int i; 20924a1d5e1fSFam Zheng int64_t ret = 0; 20934a1d5e1fSFam Zheng int64_t r; 20944a1d5e1fSFam Zheng BDRVVmdkState *s = bs->opaque; 20954a1d5e1fSFam Zheng 20969a4f4c31SKevin Wolf ret = bdrv_get_allocated_file_size(bs->file->bs); 20974a1d5e1fSFam Zheng if (ret < 0) { 20984a1d5e1fSFam Zheng return ret; 20994a1d5e1fSFam Zheng } 21004a1d5e1fSFam Zheng for (i = 0; i < s->num_extents; i++) { 21019a4f4c31SKevin Wolf if (s->extents[i].file == bs->file) { 21024a1d5e1fSFam Zheng continue; 21034a1d5e1fSFam Zheng } 210424bc15d1SKevin Wolf r = bdrv_get_allocated_file_size(s->extents[i].file->bs); 21054a1d5e1fSFam Zheng if (r < 0) { 21064a1d5e1fSFam Zheng return r; 21074a1d5e1fSFam Zheng } 21084a1d5e1fSFam Zheng ret += r; 21094a1d5e1fSFam Zheng } 21104a1d5e1fSFam Zheng return ret; 21114a1d5e1fSFam Zheng } 21120e7e1989SKevin Wolf 2113da7a50f9SFam Zheng static int vmdk_has_zero_init(BlockDriverState *bs) 2114da7a50f9SFam Zheng { 2115da7a50f9SFam Zheng int i; 2116da7a50f9SFam Zheng BDRVVmdkState *s = bs->opaque; 2117da7a50f9SFam Zheng 2118da7a50f9SFam Zheng /* If has a flat extent and its underlying storage doesn't have zero init, 2119da7a50f9SFam Zheng * return 0. */ 2120da7a50f9SFam Zheng for (i = 0; i < s->num_extents; i++) { 2121da7a50f9SFam Zheng if (s->extents[i].flat) { 212224bc15d1SKevin Wolf if (!bdrv_has_zero_init(s->extents[i].file->bs)) { 2123da7a50f9SFam Zheng return 0; 2124da7a50f9SFam Zheng } 2125da7a50f9SFam Zheng } 2126da7a50f9SFam Zheng } 2127da7a50f9SFam Zheng return 1; 2128da7a50f9SFam Zheng } 2129da7a50f9SFam Zheng 2130f4c129a3SFam Zheng static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) 2131f4c129a3SFam Zheng { 2132f4c129a3SFam Zheng ImageInfo *info = g_new0(ImageInfo, 1); 2133f4c129a3SFam Zheng 2134f4c129a3SFam Zheng *info = (ImageInfo){ 213524bc15d1SKevin Wolf .filename = g_strdup(extent->file->bs->filename), 2136f4c129a3SFam Zheng .format = g_strdup(extent->type), 2137f4c129a3SFam Zheng .virtual_size = extent->sectors * BDRV_SECTOR_SIZE, 2138f4c129a3SFam Zheng .compressed = extent->compressed, 2139f4c129a3SFam Zheng .has_compressed = extent->compressed, 2140f4c129a3SFam Zheng .cluster_size = extent->cluster_sectors * BDRV_SECTOR_SIZE, 2141f4c129a3SFam Zheng .has_cluster_size = !extent->flat, 2142f4c129a3SFam Zheng }; 2143f4c129a3SFam Zheng 2144f4c129a3SFam Zheng return info; 2145f4c129a3SFam Zheng } 2146f4c129a3SFam Zheng 2147f43aa8e1SPeter Lieven static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result, 2148f43aa8e1SPeter Lieven BdrvCheckMode fix) 2149f43aa8e1SPeter Lieven { 2150f43aa8e1SPeter Lieven BDRVVmdkState *s = bs->opaque; 2151f43aa8e1SPeter Lieven VmdkExtent *extent = NULL; 2152f43aa8e1SPeter Lieven int64_t sector_num = 0; 215357322b78SMarkus Armbruster int64_t total_sectors = bdrv_nb_sectors(bs); 2154f43aa8e1SPeter Lieven int ret; 2155f43aa8e1SPeter Lieven uint64_t cluster_offset; 2156f43aa8e1SPeter Lieven 2157f43aa8e1SPeter Lieven if (fix) { 2158f43aa8e1SPeter Lieven return -ENOTSUP; 2159f43aa8e1SPeter Lieven } 2160f43aa8e1SPeter Lieven 2161f43aa8e1SPeter Lieven for (;;) { 2162f43aa8e1SPeter Lieven if (sector_num >= total_sectors) { 2163f43aa8e1SPeter Lieven return 0; 2164f43aa8e1SPeter Lieven } 2165f43aa8e1SPeter Lieven extent = find_extent(s, sector_num, extent); 2166f43aa8e1SPeter Lieven if (!extent) { 2167f43aa8e1SPeter Lieven fprintf(stderr, 2168f43aa8e1SPeter Lieven "ERROR: could not find extent for sector %" PRId64 "\n", 2169f43aa8e1SPeter Lieven sector_num); 2170f43aa8e1SPeter Lieven break; 2171f43aa8e1SPeter Lieven } 2172f43aa8e1SPeter Lieven ret = get_cluster_offset(bs, extent, NULL, 2173f43aa8e1SPeter Lieven sector_num << BDRV_SECTOR_BITS, 2174c6ac36e1SFam Zheng false, &cluster_offset, 0, 0); 2175f43aa8e1SPeter Lieven if (ret == VMDK_ERROR) { 2176f43aa8e1SPeter Lieven fprintf(stderr, 2177f43aa8e1SPeter Lieven "ERROR: could not get cluster_offset for sector %" 2178f43aa8e1SPeter Lieven PRId64 "\n", sector_num); 2179f43aa8e1SPeter Lieven break; 2180f43aa8e1SPeter Lieven } 218124bc15d1SKevin Wolf if (ret == VMDK_OK && 218224bc15d1SKevin Wolf cluster_offset >= bdrv_getlength(extent->file->bs)) 218324bc15d1SKevin Wolf { 2184f43aa8e1SPeter Lieven fprintf(stderr, 2185f43aa8e1SPeter Lieven "ERROR: cluster offset for sector %" 2186f43aa8e1SPeter Lieven PRId64 " points after EOF\n", sector_num); 2187f43aa8e1SPeter Lieven break; 2188f43aa8e1SPeter Lieven } 2189f43aa8e1SPeter Lieven sector_num += extent->cluster_sectors; 2190f43aa8e1SPeter Lieven } 2191f43aa8e1SPeter Lieven 2192f43aa8e1SPeter Lieven result->corruptions++; 2193f43aa8e1SPeter Lieven return 0; 2194f43aa8e1SPeter Lieven } 2195f43aa8e1SPeter Lieven 2196f4c129a3SFam Zheng static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs) 2197f4c129a3SFam Zheng { 2198f4c129a3SFam Zheng int i; 2199f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 2200f4c129a3SFam Zheng ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1); 2201f4c129a3SFam Zheng ImageInfoList **next; 2202f4c129a3SFam Zheng 2203f4c129a3SFam Zheng *spec_info = (ImageInfoSpecific){ 22046a8f9661SEric Blake .type = IMAGE_INFO_SPECIFIC_KIND_VMDK, 220532bafa8fSEric Blake .u = { 220632bafa8fSEric Blake .vmdk.data = g_new0(ImageInfoSpecificVmdk, 1), 2207f4c129a3SFam Zheng }, 2208f4c129a3SFam Zheng }; 2209f4c129a3SFam Zheng 221032bafa8fSEric Blake *spec_info->u.vmdk.data = (ImageInfoSpecificVmdk) { 2211f4c129a3SFam Zheng .create_type = g_strdup(s->create_type), 2212f4c129a3SFam Zheng .cid = s->cid, 2213f4c129a3SFam Zheng .parent_cid = s->parent_cid, 2214f4c129a3SFam Zheng }; 2215f4c129a3SFam Zheng 221632bafa8fSEric Blake next = &spec_info->u.vmdk.data->extents; 2217f4c129a3SFam Zheng for (i = 0; i < s->num_extents; i++) { 2218f4c129a3SFam Zheng *next = g_new0(ImageInfoList, 1); 2219f4c129a3SFam Zheng (*next)->value = vmdk_get_extent_info(&s->extents[i]); 2220f4c129a3SFam Zheng (*next)->next = NULL; 2221f4c129a3SFam Zheng next = &(*next)->next; 2222f4c129a3SFam Zheng } 2223f4c129a3SFam Zheng 2224f4c129a3SFam Zheng return spec_info; 2225f4c129a3SFam Zheng } 2226f4c129a3SFam Zheng 22275f583307SFam Zheng static bool vmdk_extents_type_eq(const VmdkExtent *a, const VmdkExtent *b) 22285f583307SFam Zheng { 22295f583307SFam Zheng return a->flat == b->flat && 22305f583307SFam Zheng a->compressed == b->compressed && 22315f583307SFam Zheng (a->flat || a->cluster_sectors == b->cluster_sectors); 22325f583307SFam Zheng } 22335f583307SFam Zheng 223474fe188cSFam Zheng static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) 223574fe188cSFam Zheng { 223674fe188cSFam Zheng int i; 223774fe188cSFam Zheng BDRVVmdkState *s = bs->opaque; 223874fe188cSFam Zheng assert(s->num_extents); 22395f583307SFam Zheng 22405f583307SFam Zheng /* See if we have multiple extents but they have different cases */ 22415f583307SFam Zheng for (i = 1; i < s->num_extents; i++) { 22425f583307SFam Zheng if (!vmdk_extents_type_eq(&s->extents[0], &s->extents[i])) { 22435f583307SFam Zheng return -ENOTSUP; 22445f583307SFam Zheng } 22455f583307SFam Zheng } 224674fe188cSFam Zheng bdi->needs_compressed_writes = s->extents[0].compressed; 224774fe188cSFam Zheng if (!s->extents[0].flat) { 224874fe188cSFam Zheng bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS; 224974fe188cSFam Zheng } 225074fe188cSFam Zheng return 0; 225174fe188cSFam Zheng } 225274fe188cSFam Zheng 2253c75f3bdfSStefan Hajnoczi static void vmdk_detach_aio_context(BlockDriverState *bs) 2254c75f3bdfSStefan Hajnoczi { 2255c75f3bdfSStefan Hajnoczi BDRVVmdkState *s = bs->opaque; 2256c75f3bdfSStefan Hajnoczi int i; 2257c75f3bdfSStefan Hajnoczi 2258c75f3bdfSStefan Hajnoczi for (i = 0; i < s->num_extents; i++) { 225924bc15d1SKevin Wolf bdrv_detach_aio_context(s->extents[i].file->bs); 2260c75f3bdfSStefan Hajnoczi } 2261c75f3bdfSStefan Hajnoczi } 2262c75f3bdfSStefan Hajnoczi 2263c75f3bdfSStefan Hajnoczi static void vmdk_attach_aio_context(BlockDriverState *bs, 2264c75f3bdfSStefan Hajnoczi AioContext *new_context) 2265c75f3bdfSStefan Hajnoczi { 2266c75f3bdfSStefan Hajnoczi BDRVVmdkState *s = bs->opaque; 2267c75f3bdfSStefan Hajnoczi int i; 2268c75f3bdfSStefan Hajnoczi 2269c75f3bdfSStefan Hajnoczi for (i = 0; i < s->num_extents; i++) { 227024bc15d1SKevin Wolf bdrv_attach_aio_context(s->extents[i].file->bs, new_context); 2271c75f3bdfSStefan Hajnoczi } 2272c75f3bdfSStefan Hajnoczi } 2273c75f3bdfSStefan Hajnoczi 22745820f1daSChunyan Liu static QemuOptsList vmdk_create_opts = { 22755820f1daSChunyan Liu .name = "vmdk-create-opts", 22765820f1daSChunyan Liu .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head), 22775820f1daSChunyan Liu .desc = { 2278db08adf5SKevin Wolf { 2279db08adf5SKevin Wolf .name = BLOCK_OPT_SIZE, 22805820f1daSChunyan Liu .type = QEMU_OPT_SIZE, 2281db08adf5SKevin Wolf .help = "Virtual disk size" 2282db08adf5SKevin Wolf }, 2283db08adf5SKevin Wolf { 22847f2039f6SOthmar Pasteka .name = BLOCK_OPT_ADAPTER_TYPE, 22855820f1daSChunyan Liu .type = QEMU_OPT_STRING, 22867f2039f6SOthmar Pasteka .help = "Virtual adapter type, can be one of " 22877f2039f6SOthmar Pasteka "ide (default), lsilogic, buslogic or legacyESX" 22887f2039f6SOthmar Pasteka }, 22897f2039f6SOthmar Pasteka { 2290db08adf5SKevin Wolf .name = BLOCK_OPT_BACKING_FILE, 22915820f1daSChunyan Liu .type = QEMU_OPT_STRING, 2292db08adf5SKevin Wolf .help = "File name of a base image" 2293db08adf5SKevin Wolf }, 2294db08adf5SKevin Wolf { 2295db08adf5SKevin Wolf .name = BLOCK_OPT_COMPAT6, 22965820f1daSChunyan Liu .type = QEMU_OPT_BOOL, 22975820f1daSChunyan Liu .help = "VMDK version 6 image", 22985820f1daSChunyan Liu .def_value_str = "off" 2299db08adf5SKevin Wolf }, 2300f66fd6c3SFam Zheng { 2301f66fd6c3SFam Zheng .name = BLOCK_OPT_SUBFMT, 23025820f1daSChunyan Liu .type = QEMU_OPT_STRING, 2303f66fd6c3SFam Zheng .help = 2304f66fd6c3SFam Zheng "VMDK flat extent format, can be one of " 23056c031aacSFam Zheng "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} " 2306f66fd6c3SFam Zheng }, 230769e0b6dfSFam Zheng { 230869e0b6dfSFam Zheng .name = BLOCK_OPT_ZEROED_GRAIN, 23095820f1daSChunyan Liu .type = QEMU_OPT_BOOL, 23105820f1daSChunyan Liu .help = "Enable efficient zero writes " 23115820f1daSChunyan Liu "using the zeroed-grain GTE feature" 231269e0b6dfSFam Zheng }, 23135820f1daSChunyan Liu { /* end of list */ } 23145820f1daSChunyan Liu } 23150e7e1989SKevin Wolf }; 23160e7e1989SKevin Wolf 2317019d6b8fSAnthony Liguori static BlockDriver bdrv_vmdk = { 2318019d6b8fSAnthony Liguori .format_name = "vmdk", 2319019d6b8fSAnthony Liguori .instance_size = sizeof(BDRVVmdkState), 2320019d6b8fSAnthony Liguori .bdrv_probe = vmdk_probe, 23216511ef77SKevin Wolf .bdrv_open = vmdk_open, 2322f43aa8e1SPeter Lieven .bdrv_check = vmdk_check, 23233897575fSJeff Cody .bdrv_reopen_prepare = vmdk_reopen_prepare, 23242914caa0SPaolo Bonzini .bdrv_read = vmdk_co_read, 2325e183ef75SPaolo Bonzini .bdrv_write = vmdk_co_write, 2326ba0ad89eSFam Zheng .bdrv_write_compressed = vmdk_write_compressed, 2327cdeaf1f1SFam Zheng .bdrv_co_write_zeroes = vmdk_co_write_zeroes, 2328019d6b8fSAnthony Liguori .bdrv_close = vmdk_close, 2329c282e1fdSChunyan Liu .bdrv_create = vmdk_create, 2330c68b89acSKevin Wolf .bdrv_co_flush_to_disk = vmdk_co_flush, 2331b6b8a333SPaolo Bonzini .bdrv_co_get_block_status = vmdk_co_get_block_status, 23324a1d5e1fSFam Zheng .bdrv_get_allocated_file_size = vmdk_get_allocated_file_size, 2333da7a50f9SFam Zheng .bdrv_has_zero_init = vmdk_has_zero_init, 2334f4c129a3SFam Zheng .bdrv_get_specific_info = vmdk_get_specific_info, 2335d34682cdSKevin Wolf .bdrv_refresh_limits = vmdk_refresh_limits, 233674fe188cSFam Zheng .bdrv_get_info = vmdk_get_info, 2337c75f3bdfSStefan Hajnoczi .bdrv_detach_aio_context = vmdk_detach_aio_context, 2338c75f3bdfSStefan Hajnoczi .bdrv_attach_aio_context = vmdk_attach_aio_context, 23390e7e1989SKevin Wolf 23408ee79e70SKevin Wolf .supports_backing = true, 23415820f1daSChunyan Liu .create_opts = &vmdk_create_opts, 2342019d6b8fSAnthony Liguori }; 2343019d6b8fSAnthony Liguori 2344019d6b8fSAnthony Liguori static void bdrv_vmdk_init(void) 2345019d6b8fSAnthony Liguori { 2346019d6b8fSAnthony Liguori bdrv_register(&bdrv_vmdk); 2347019d6b8fSAnthony Liguori } 2348019d6b8fSAnthony Liguori 2349019d6b8fSAnthony Liguori block_init(bdrv_vmdk_init); 2350