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 26019d6b8fSAnthony Liguori #include "qemu-common.h" 27737e150eSPaolo Bonzini #include "block/block_int.h" 281de7afc9SPaolo Bonzini #include "qemu/module.h" 29caf71f86SPaolo Bonzini #include "migration/migration.h" 302923d34fSStefan Weil #include <zlib.h> 31e5dc64b8SFam Zheng #include <glib.h> 32019d6b8fSAnthony Liguori 33019d6b8fSAnthony Liguori #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') 34019d6b8fSAnthony Liguori #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') 35432bb170SFam Zheng #define VMDK4_COMPRESSION_DEFLATE 1 3695b0aa42SFam Zheng #define VMDK4_FLAG_NL_DETECT (1 << 0) 37bb45ded9SFam Zheng #define VMDK4_FLAG_RGD (1 << 1) 3814ead646SFam Zheng /* Zeroed-grain enable bit */ 3914ead646SFam Zheng #define VMDK4_FLAG_ZERO_GRAIN (1 << 2) 40432bb170SFam Zheng #define VMDK4_FLAG_COMPRESS (1 << 16) 41432bb170SFam Zheng #define VMDK4_FLAG_MARKER (1 << 17) 4265bd155cSKevin Wolf #define VMDK4_GD_AT_END 0xffffffffffffffffULL 43019d6b8fSAnthony Liguori 4414ead646SFam Zheng #define VMDK_GTE_ZEROED 0x1 4565f74725SFam Zheng 4665f74725SFam Zheng /* VMDK internal error codes */ 4765f74725SFam Zheng #define VMDK_OK 0 4865f74725SFam Zheng #define VMDK_ERROR (-1) 4965f74725SFam Zheng /* Cluster not allocated */ 5065f74725SFam Zheng #define VMDK_UNALLOC (-2) 5165f74725SFam Zheng #define VMDK_ZEROED (-3) 5265f74725SFam Zheng 5369e0b6dfSFam Zheng #define BLOCK_OPT_ZEROED_GRAIN "zeroed_grain" 5469e0b6dfSFam Zheng 55019d6b8fSAnthony Liguori typedef struct { 56019d6b8fSAnthony Liguori uint32_t version; 57019d6b8fSAnthony Liguori uint32_t flags; 58019d6b8fSAnthony Liguori uint32_t disk_sectors; 59019d6b8fSAnthony Liguori uint32_t granularity; 60019d6b8fSAnthony Liguori uint32_t l1dir_offset; 61019d6b8fSAnthony Liguori uint32_t l1dir_size; 62019d6b8fSAnthony Liguori uint32_t file_sectors; 63019d6b8fSAnthony Liguori uint32_t cylinders; 64019d6b8fSAnthony Liguori uint32_t heads; 65019d6b8fSAnthony Liguori uint32_t sectors_per_track; 665d8caa54SFam Zheng } QEMU_PACKED VMDK3Header; 67019d6b8fSAnthony Liguori 68019d6b8fSAnthony Liguori typedef struct { 69019d6b8fSAnthony Liguori uint32_t version; 70019d6b8fSAnthony Liguori uint32_t flags; 71e98768d4SFam Zheng uint64_t capacity; 72e98768d4SFam Zheng uint64_t granularity; 73e98768d4SFam Zheng uint64_t desc_offset; 74e98768d4SFam Zheng uint64_t desc_size; 75ca8804ceSFam Zheng /* Number of GrainTableEntries per GrainTable */ 76ca8804ceSFam Zheng uint32_t num_gtes_per_gt; 77e98768d4SFam Zheng uint64_t rgd_offset; 78e98768d4SFam Zheng uint64_t gd_offset; 79e98768d4SFam Zheng uint64_t grain_offset; 80019d6b8fSAnthony Liguori char filler[1]; 81019d6b8fSAnthony Liguori char check_bytes[4]; 82432bb170SFam Zheng uint16_t compressAlgorithm; 83541dc0d4SStefan Weil } QEMU_PACKED VMDK4Header; 84019d6b8fSAnthony Liguori 85019d6b8fSAnthony Liguori #define L2_CACHE_SIZE 16 86019d6b8fSAnthony Liguori 87b3976d3cSFam Zheng typedef struct VmdkExtent { 88b3976d3cSFam Zheng BlockDriverState *file; 89b3976d3cSFam Zheng bool flat; 90432bb170SFam Zheng bool compressed; 91432bb170SFam Zheng bool has_marker; 9214ead646SFam Zheng bool has_zero_grain; 9314ead646SFam Zheng int version; 94b3976d3cSFam Zheng int64_t sectors; 95b3976d3cSFam Zheng int64_t end_sector; 967fa60fa3SFam Zheng int64_t flat_start_offset; 97019d6b8fSAnthony Liguori int64_t l1_table_offset; 98019d6b8fSAnthony Liguori int64_t l1_backup_table_offset; 99019d6b8fSAnthony Liguori uint32_t *l1_table; 100019d6b8fSAnthony Liguori uint32_t *l1_backup_table; 101019d6b8fSAnthony Liguori unsigned int l1_size; 102019d6b8fSAnthony Liguori uint32_t l1_entry_sectors; 103019d6b8fSAnthony Liguori 104019d6b8fSAnthony Liguori unsigned int l2_size; 105019d6b8fSAnthony Liguori uint32_t *l2_cache; 106019d6b8fSAnthony Liguori uint32_t l2_cache_offsets[L2_CACHE_SIZE]; 107019d6b8fSAnthony Liguori uint32_t l2_cache_counts[L2_CACHE_SIZE]; 108019d6b8fSAnthony Liguori 109301c7d38SFam Zheng int64_t cluster_sectors; 110c6ac36e1SFam Zheng int64_t next_cluster_sector; 111f4c129a3SFam Zheng char *type; 112b3976d3cSFam Zheng } VmdkExtent; 113b3976d3cSFam Zheng 114b3976d3cSFam Zheng typedef struct BDRVVmdkState { 115848c66e8SPaolo Bonzini CoMutex lock; 116e98768d4SFam Zheng uint64_t desc_offset; 11769b4d86dSFam Zheng bool cid_updated; 118c338b6adSFam Zheng bool cid_checked; 119f4c129a3SFam Zheng uint32_t cid; 120019d6b8fSAnthony Liguori uint32_t parent_cid; 121b3976d3cSFam Zheng int num_extents; 122b3976d3cSFam Zheng /* Extent array with num_extents entries, ascend ordered by address */ 123b3976d3cSFam Zheng VmdkExtent *extents; 1242bc3166cSKevin Wolf Error *migration_blocker; 125f4c129a3SFam Zheng char *create_type; 126019d6b8fSAnthony Liguori } BDRVVmdkState; 127019d6b8fSAnthony Liguori 128019d6b8fSAnthony Liguori typedef struct VmdkMetaData { 129019d6b8fSAnthony Liguori unsigned int l1_index; 130019d6b8fSAnthony Liguori unsigned int l2_index; 131019d6b8fSAnthony Liguori unsigned int l2_offset; 132019d6b8fSAnthony Liguori int valid; 133cdeaf1f1SFam Zheng uint32_t *l2_cache_entry; 134019d6b8fSAnthony Liguori } VmdkMetaData; 135019d6b8fSAnthony Liguori 136432bb170SFam Zheng typedef struct VmdkGrainMarker { 137432bb170SFam Zheng uint64_t lba; 138432bb170SFam Zheng uint32_t size; 139432bb170SFam Zheng uint8_t data[0]; 1405d8caa54SFam Zheng } QEMU_PACKED VmdkGrainMarker; 141432bb170SFam Zheng 14265bd155cSKevin Wolf enum { 14365bd155cSKevin Wolf MARKER_END_OF_STREAM = 0, 14465bd155cSKevin Wolf MARKER_GRAIN_TABLE = 1, 14565bd155cSKevin Wolf MARKER_GRAIN_DIRECTORY = 2, 14665bd155cSKevin Wolf MARKER_FOOTER = 3, 14765bd155cSKevin Wolf }; 14865bd155cSKevin Wolf 149019d6b8fSAnthony Liguori static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) 150019d6b8fSAnthony Liguori { 151019d6b8fSAnthony Liguori uint32_t magic; 152019d6b8fSAnthony Liguori 153ae261c86SFam Zheng if (buf_size < 4) { 154019d6b8fSAnthony Liguori return 0; 155ae261c86SFam Zheng } 156019d6b8fSAnthony Liguori magic = be32_to_cpu(*(uint32_t *)buf); 157019d6b8fSAnthony Liguori if (magic == VMDK3_MAGIC || 15801fc99d6SFam Zheng magic == VMDK4_MAGIC) { 159019d6b8fSAnthony Liguori return 100; 16001fc99d6SFam Zheng } else { 16101fc99d6SFam Zheng const char *p = (const char *)buf; 16201fc99d6SFam Zheng const char *end = p + buf_size; 16301fc99d6SFam Zheng while (p < end) { 16401fc99d6SFam Zheng if (*p == '#') { 16501fc99d6SFam Zheng /* skip comment line */ 16601fc99d6SFam Zheng while (p < end && *p != '\n') { 16701fc99d6SFam Zheng p++; 16801fc99d6SFam Zheng } 16901fc99d6SFam Zheng p++; 17001fc99d6SFam Zheng continue; 17101fc99d6SFam Zheng } 17201fc99d6SFam Zheng if (*p == ' ') { 17301fc99d6SFam Zheng while (p < end && *p == ' ') { 17401fc99d6SFam Zheng p++; 17501fc99d6SFam Zheng } 17601fc99d6SFam Zheng /* skip '\r' if windows line endings used. */ 17701fc99d6SFam Zheng if (p < end && *p == '\r') { 17801fc99d6SFam Zheng p++; 17901fc99d6SFam Zheng } 18001fc99d6SFam Zheng /* only accept blank lines before 'version=' line */ 18101fc99d6SFam Zheng if (p == end || *p != '\n') { 182019d6b8fSAnthony Liguori return 0; 183019d6b8fSAnthony Liguori } 18401fc99d6SFam Zheng p++; 18501fc99d6SFam Zheng continue; 18601fc99d6SFam Zheng } 18701fc99d6SFam Zheng if (end - p >= strlen("version=X\n")) { 18801fc99d6SFam Zheng if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 || 18901fc99d6SFam Zheng strncmp("version=2\n", p, strlen("version=2\n")) == 0) { 19001fc99d6SFam Zheng return 100; 19101fc99d6SFam Zheng } 19201fc99d6SFam Zheng } 19301fc99d6SFam Zheng if (end - p >= strlen("version=X\r\n")) { 19401fc99d6SFam Zheng if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 || 19501fc99d6SFam Zheng strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) { 19601fc99d6SFam Zheng return 100; 19701fc99d6SFam Zheng } 19801fc99d6SFam Zheng } 19901fc99d6SFam Zheng return 0; 20001fc99d6SFam Zheng } 20101fc99d6SFam Zheng return 0; 20201fc99d6SFam Zheng } 20301fc99d6SFam Zheng } 204019d6b8fSAnthony Liguori 205019d6b8fSAnthony Liguori #define SECTOR_SIZE 512 206f66fd6c3SFam Zheng #define DESC_SIZE (20 * SECTOR_SIZE) /* 20 sectors of 512 bytes each */ 207f66fd6c3SFam Zheng #define BUF_SIZE 4096 208f66fd6c3SFam Zheng #define HEADER_SIZE 512 /* first sector of 512 bytes */ 209019d6b8fSAnthony Liguori 210b3976d3cSFam Zheng static void vmdk_free_extents(BlockDriverState *bs) 211b3976d3cSFam Zheng { 212b3976d3cSFam Zheng int i; 213b3976d3cSFam Zheng BDRVVmdkState *s = bs->opaque; 214b3c0bfb6SFam Zheng VmdkExtent *e; 215b3976d3cSFam Zheng 216b3976d3cSFam Zheng for (i = 0; i < s->num_extents; i++) { 217b3c0bfb6SFam Zheng e = &s->extents[i]; 218b3c0bfb6SFam Zheng g_free(e->l1_table); 219b3c0bfb6SFam Zheng g_free(e->l2_cache); 220b3c0bfb6SFam Zheng g_free(e->l1_backup_table); 221f4c129a3SFam Zheng g_free(e->type); 222b3c0bfb6SFam Zheng if (e->file != bs->file) { 2234f6fd349SFam Zheng bdrv_unref(e->file); 224b3c0bfb6SFam Zheng } 225b3976d3cSFam Zheng } 2267267c094SAnthony Liguori g_free(s->extents); 227b3976d3cSFam Zheng } 228b3976d3cSFam Zheng 22986c6b429SFam Zheng static void vmdk_free_last_extent(BlockDriverState *bs) 23086c6b429SFam Zheng { 23186c6b429SFam Zheng BDRVVmdkState *s = bs->opaque; 23286c6b429SFam Zheng 23386c6b429SFam Zheng if (s->num_extents == 0) { 23486c6b429SFam Zheng return; 23586c6b429SFam Zheng } 23686c6b429SFam Zheng s->num_extents--; 2375839e53bSMarkus Armbruster s->extents = g_renew(VmdkExtent, s->extents, s->num_extents); 23886c6b429SFam Zheng } 23986c6b429SFam Zheng 240019d6b8fSAnthony Liguori static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) 241019d6b8fSAnthony Liguori { 242019d6b8fSAnthony Liguori char desc[DESC_SIZE]; 2438379e46dSPavel Borzenkov uint32_t cid = 0xffffffff; 244019d6b8fSAnthony Liguori const char *p_name, *cid_str; 245019d6b8fSAnthony Liguori size_t cid_str_size; 246e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 24799f1835dSKevin Wolf int ret; 248019d6b8fSAnthony Liguori 24999f1835dSKevin Wolf ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); 25099f1835dSKevin Wolf if (ret < 0) { 251019d6b8fSAnthony Liguori return 0; 252e1da9b24SFam Zheng } 253019d6b8fSAnthony Liguori 254019d6b8fSAnthony Liguori if (parent) { 255019d6b8fSAnthony Liguori cid_str = "parentCID"; 256019d6b8fSAnthony Liguori cid_str_size = sizeof("parentCID"); 257019d6b8fSAnthony Liguori } else { 258019d6b8fSAnthony Liguori cid_str = "CID"; 259019d6b8fSAnthony Liguori cid_str_size = sizeof("CID"); 260019d6b8fSAnthony Liguori } 261019d6b8fSAnthony Liguori 26293897b9fSKevin Wolf desc[DESC_SIZE - 1] = '\0'; 263ae261c86SFam Zheng p_name = strstr(desc, cid_str); 264ae261c86SFam Zheng if (p_name != NULL) { 265019d6b8fSAnthony Liguori p_name += cid_str_size; 2669b17031aSFam Zheng sscanf(p_name, "%" SCNx32, &cid); 267019d6b8fSAnthony Liguori } 268019d6b8fSAnthony Liguori 269019d6b8fSAnthony Liguori return cid; 270019d6b8fSAnthony Liguori } 271019d6b8fSAnthony Liguori 272019d6b8fSAnthony Liguori static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) 273019d6b8fSAnthony Liguori { 274019d6b8fSAnthony Liguori char desc[DESC_SIZE], tmp_desc[DESC_SIZE]; 275019d6b8fSAnthony Liguori char *p_name, *tmp_str; 276e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 27799f1835dSKevin Wolf int ret; 278019d6b8fSAnthony Liguori 27999f1835dSKevin Wolf ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); 28099f1835dSKevin Wolf if (ret < 0) { 28199f1835dSKevin Wolf return ret; 282e1da9b24SFam Zheng } 283019d6b8fSAnthony Liguori 28493897b9fSKevin Wolf desc[DESC_SIZE - 1] = '\0'; 285019d6b8fSAnthony Liguori tmp_str = strstr(desc, "parentCID"); 28693897b9fSKevin Wolf if (tmp_str == NULL) { 28793897b9fSKevin Wolf return -EINVAL; 28893897b9fSKevin Wolf } 28993897b9fSKevin Wolf 290019d6b8fSAnthony Liguori pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str); 291ae261c86SFam Zheng p_name = strstr(desc, "CID"); 292ae261c86SFam Zheng if (p_name != NULL) { 293019d6b8fSAnthony Liguori p_name += sizeof("CID"); 2949b17031aSFam Zheng snprintf(p_name, sizeof(desc) - (p_name - desc), "%" PRIx32 "\n", cid); 295019d6b8fSAnthony Liguori pstrcat(desc, sizeof(desc), tmp_desc); 296019d6b8fSAnthony Liguori } 297019d6b8fSAnthony Liguori 29899f1835dSKevin Wolf ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE); 29999f1835dSKevin Wolf if (ret < 0) { 30099f1835dSKevin Wolf return ret; 301e1da9b24SFam Zheng } 30299f1835dSKevin Wolf 303019d6b8fSAnthony Liguori return 0; 304019d6b8fSAnthony Liguori } 305019d6b8fSAnthony Liguori 306019d6b8fSAnthony Liguori static int vmdk_is_cid_valid(BlockDriverState *bs) 307019d6b8fSAnthony Liguori { 308019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 309b171271aSKevin Wolf BlockDriverState *p_bs = bs->backing_hd; 310019d6b8fSAnthony Liguori uint32_t cur_pcid; 311019d6b8fSAnthony Liguori 312c338b6adSFam Zheng if (!s->cid_checked && p_bs) { 313019d6b8fSAnthony Liguori cur_pcid = vmdk_read_cid(p_bs, 0); 314ae261c86SFam Zheng if (s->parent_cid != cur_pcid) { 315ae261c86SFam Zheng /* CID not valid */ 316019d6b8fSAnthony Liguori return 0; 317019d6b8fSAnthony Liguori } 318ae261c86SFam Zheng } 319c338b6adSFam Zheng s->cid_checked = true; 320ae261c86SFam Zheng /* CID valid */ 321019d6b8fSAnthony Liguori return 1; 322019d6b8fSAnthony Liguori } 323019d6b8fSAnthony Liguori 3243897575fSJeff Cody /* Queue extents, if any, for reopen() */ 3253897575fSJeff Cody static int vmdk_reopen_prepare(BDRVReopenState *state, 3263897575fSJeff Cody BlockReopenQueue *queue, Error **errp) 3273897575fSJeff Cody { 3283897575fSJeff Cody BDRVVmdkState *s; 3293897575fSJeff Cody int ret = -1; 3303897575fSJeff Cody int i; 3313897575fSJeff Cody VmdkExtent *e; 3323897575fSJeff Cody 3333897575fSJeff Cody assert(state != NULL); 3343897575fSJeff Cody assert(state->bs != NULL); 3353897575fSJeff Cody 3363897575fSJeff Cody if (queue == NULL) { 3374823970bSFam Zheng error_setg(errp, "No reopen queue for VMDK extents"); 3383897575fSJeff Cody goto exit; 3393897575fSJeff Cody } 3403897575fSJeff Cody 3413897575fSJeff Cody s = state->bs->opaque; 3423897575fSJeff Cody 3433897575fSJeff Cody assert(s != NULL); 3443897575fSJeff Cody 3453897575fSJeff Cody for (i = 0; i < s->num_extents; i++) { 3463897575fSJeff Cody e = &s->extents[i]; 3473897575fSJeff Cody if (e->file != state->bs->file) { 3483897575fSJeff Cody bdrv_reopen_queue(queue, e->file, state->flags); 3493897575fSJeff Cody } 3503897575fSJeff Cody } 3513897575fSJeff Cody ret = 0; 3523897575fSJeff Cody 3533897575fSJeff Cody exit: 3543897575fSJeff Cody return ret; 3553897575fSJeff Cody } 3563897575fSJeff Cody 3579949f97eSKevin Wolf static int vmdk_parent_open(BlockDriverState *bs) 358019d6b8fSAnthony Liguori { 359019d6b8fSAnthony Liguori char *p_name; 3607fa60fa3SFam Zheng char desc[DESC_SIZE + 1]; 361e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 362588b65a3SPaolo Bonzini int ret; 363019d6b8fSAnthony Liguori 3647fa60fa3SFam Zheng desc[DESC_SIZE] = '\0'; 365588b65a3SPaolo Bonzini ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); 366588b65a3SPaolo Bonzini if (ret < 0) { 367588b65a3SPaolo Bonzini return ret; 368e1da9b24SFam Zheng } 369019d6b8fSAnthony Liguori 370ae261c86SFam Zheng p_name = strstr(desc, "parentFileNameHint"); 371ae261c86SFam Zheng if (p_name != NULL) { 372019d6b8fSAnthony Liguori char *end_name; 373019d6b8fSAnthony Liguori 374019d6b8fSAnthony Liguori p_name += sizeof("parentFileNameHint") + 1; 375ae261c86SFam Zheng end_name = strchr(p_name, '\"'); 376ae261c86SFam Zheng if (end_name == NULL) { 377588b65a3SPaolo Bonzini return -EINVAL; 378ae261c86SFam Zheng } 379ae261c86SFam Zheng if ((end_name - p_name) > sizeof(bs->backing_file) - 1) { 380588b65a3SPaolo Bonzini return -EINVAL; 381ae261c86SFam Zheng } 382019d6b8fSAnthony Liguori 383b171271aSKevin Wolf pstrcpy(bs->backing_file, end_name - p_name + 1, p_name); 384019d6b8fSAnthony Liguori } 385019d6b8fSAnthony Liguori 386019d6b8fSAnthony Liguori return 0; 387019d6b8fSAnthony Liguori } 388019d6b8fSAnthony Liguori 389b3976d3cSFam Zheng /* Create and append extent to the extent array. Return the added VmdkExtent 390b3976d3cSFam Zheng * address. return NULL if allocation failed. */ 3918aa1331cSFam Zheng static int vmdk_add_extent(BlockDriverState *bs, 392b3976d3cSFam Zheng BlockDriverState *file, bool flat, int64_t sectors, 393b3976d3cSFam Zheng int64_t l1_offset, int64_t l1_backup_offset, 394b3976d3cSFam Zheng uint32_t l1_size, 3958aa1331cSFam Zheng int l2_size, uint64_t cluster_sectors, 3964823970bSFam Zheng VmdkExtent **new_extent, 3974823970bSFam Zheng Error **errp) 398b3976d3cSFam Zheng { 399b3976d3cSFam Zheng VmdkExtent *extent; 400b3976d3cSFam Zheng BDRVVmdkState *s = bs->opaque; 4010a156f7cSMarkus Armbruster int64_t nb_sectors; 402b3976d3cSFam Zheng 4038aa1331cSFam Zheng if (cluster_sectors > 0x200000) { 4048aa1331cSFam Zheng /* 0x200000 * 512Bytes = 1GB for one cluster is unrealistic */ 4054823970bSFam Zheng error_setg(errp, "Invalid granularity, image may be corrupt"); 4064823970bSFam Zheng return -EFBIG; 4078aa1331cSFam Zheng } 408b0651b8cSFam Zheng if (l1_size > 512 * 1024 * 1024) { 409b0651b8cSFam Zheng /* Although with big capacity and small l1_entry_sectors, we can get a 410b0651b8cSFam Zheng * big l1_size, we don't want unbounded value to allocate the table. 411b0651b8cSFam Zheng * Limit it to 512M, which is 16PB for default cluster and L2 table 412b0651b8cSFam Zheng * size */ 4134823970bSFam Zheng error_setg(errp, "L1 size too big"); 414b0651b8cSFam Zheng return -EFBIG; 415b0651b8cSFam Zheng } 4168aa1331cSFam Zheng 4170a156f7cSMarkus Armbruster nb_sectors = bdrv_nb_sectors(file); 4180a156f7cSMarkus Armbruster if (nb_sectors < 0) { 4190a156f7cSMarkus Armbruster return nb_sectors; 420c6ac36e1SFam Zheng } 421c6ac36e1SFam Zheng 4225839e53bSMarkus Armbruster s->extents = g_renew(VmdkExtent, s->extents, s->num_extents + 1); 423b3976d3cSFam Zheng extent = &s->extents[s->num_extents]; 424b3976d3cSFam Zheng s->num_extents++; 425b3976d3cSFam Zheng 426b3976d3cSFam Zheng memset(extent, 0, sizeof(VmdkExtent)); 427b3976d3cSFam Zheng extent->file = file; 428b3976d3cSFam Zheng extent->flat = flat; 429b3976d3cSFam Zheng extent->sectors = sectors; 430b3976d3cSFam Zheng extent->l1_table_offset = l1_offset; 431b3976d3cSFam Zheng extent->l1_backup_table_offset = l1_backup_offset; 432b3976d3cSFam Zheng extent->l1_size = l1_size; 433b3976d3cSFam Zheng extent->l1_entry_sectors = l2_size * cluster_sectors; 434b3976d3cSFam Zheng extent->l2_size = l2_size; 435301c7d38SFam Zheng extent->cluster_sectors = flat ? sectors : cluster_sectors; 4360a156f7cSMarkus Armbruster extent->next_cluster_sector = ROUND_UP(nb_sectors, cluster_sectors); 437b3976d3cSFam Zheng 438b3976d3cSFam Zheng if (s->num_extents > 1) { 439b3976d3cSFam Zheng extent->end_sector = (*(extent - 1)).end_sector + extent->sectors; 440b3976d3cSFam Zheng } else { 441b3976d3cSFam Zheng extent->end_sector = extent->sectors; 442b3976d3cSFam Zheng } 443b3976d3cSFam Zheng bs->total_sectors = extent->end_sector; 4448aa1331cSFam Zheng if (new_extent) { 4458aa1331cSFam Zheng *new_extent = extent; 4468aa1331cSFam Zheng } 4478aa1331cSFam Zheng return 0; 448b3976d3cSFam Zheng } 449b3976d3cSFam Zheng 4504823970bSFam Zheng static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, 4514823970bSFam Zheng Error **errp) 452019d6b8fSAnthony Liguori { 453b4b3ab14SFam Zheng int ret; 454b4b3ab14SFam Zheng int l1_size, i; 455b4b3ab14SFam Zheng 456b4b3ab14SFam Zheng /* read the L1 table */ 457b4b3ab14SFam Zheng l1_size = extent->l1_size * sizeof(uint32_t); 458d6e59931SKevin Wolf extent->l1_table = g_try_malloc(l1_size); 459d6e59931SKevin Wolf if (l1_size && extent->l1_table == NULL) { 460d6e59931SKevin Wolf return -ENOMEM; 461d6e59931SKevin Wolf } 462d6e59931SKevin Wolf 463b4b3ab14SFam Zheng ret = bdrv_pread(extent->file, 464b4b3ab14SFam Zheng extent->l1_table_offset, 465b4b3ab14SFam Zheng extent->l1_table, 466b4b3ab14SFam Zheng l1_size); 467b4b3ab14SFam Zheng if (ret < 0) { 4684823970bSFam Zheng error_setg_errno(errp, -ret, 4694823970bSFam Zheng "Could not read l1 table from extent '%s'", 4704823970bSFam Zheng extent->file->filename); 471b4b3ab14SFam Zheng goto fail_l1; 472b4b3ab14SFam Zheng } 473b4b3ab14SFam Zheng for (i = 0; i < extent->l1_size; i++) { 474b4b3ab14SFam Zheng le32_to_cpus(&extent->l1_table[i]); 475b4b3ab14SFam Zheng } 476b4b3ab14SFam Zheng 477b4b3ab14SFam Zheng if (extent->l1_backup_table_offset) { 478d6e59931SKevin Wolf extent->l1_backup_table = g_try_malloc(l1_size); 479d6e59931SKevin Wolf if (l1_size && extent->l1_backup_table == NULL) { 480d6e59931SKevin Wolf ret = -ENOMEM; 481d6e59931SKevin Wolf goto fail_l1; 482d6e59931SKevin Wolf } 483b4b3ab14SFam Zheng ret = bdrv_pread(extent->file, 484b4b3ab14SFam Zheng extent->l1_backup_table_offset, 485b4b3ab14SFam Zheng extent->l1_backup_table, 486b4b3ab14SFam Zheng l1_size); 487b4b3ab14SFam Zheng if (ret < 0) { 4884823970bSFam Zheng error_setg_errno(errp, -ret, 4894823970bSFam Zheng "Could not read l1 backup table from extent '%s'", 4904823970bSFam Zheng extent->file->filename); 491b4b3ab14SFam Zheng goto fail_l1b; 492b4b3ab14SFam Zheng } 493b4b3ab14SFam Zheng for (i = 0; i < extent->l1_size; i++) { 494b4b3ab14SFam Zheng le32_to_cpus(&extent->l1_backup_table[i]); 495b4b3ab14SFam Zheng } 496b4b3ab14SFam Zheng } 497b4b3ab14SFam Zheng 498b4b3ab14SFam Zheng extent->l2_cache = 4995839e53bSMarkus Armbruster g_new(uint32_t, extent->l2_size * L2_CACHE_SIZE); 500b4b3ab14SFam Zheng return 0; 501b4b3ab14SFam Zheng fail_l1b: 5027267c094SAnthony Liguori g_free(extent->l1_backup_table); 503b4b3ab14SFam Zheng fail_l1: 5047267c094SAnthony Liguori g_free(extent->l1_table); 505b4b3ab14SFam Zheng return ret; 506b4b3ab14SFam Zheng } 507b4b3ab14SFam Zheng 508daac8fdcSFam Zheng static int vmdk_open_vmfs_sparse(BlockDriverState *bs, 50986c6b429SFam Zheng BlockDriverState *file, 5104823970bSFam Zheng int flags, Error **errp) 511b4b3ab14SFam Zheng { 512b4b3ab14SFam Zheng int ret; 513019d6b8fSAnthony Liguori uint32_t magic; 514019d6b8fSAnthony Liguori VMDK3Header header; 515b4b3ab14SFam Zheng VmdkExtent *extent; 516b4b3ab14SFam Zheng 51786c6b429SFam Zheng ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); 518b4b3ab14SFam Zheng if (ret < 0) { 5194823970bSFam Zheng error_setg_errno(errp, -ret, 5204823970bSFam Zheng "Could not read header from file '%s'", 5214823970bSFam Zheng file->filename); 52286c6b429SFam Zheng return ret; 523b3976d3cSFam Zheng } 524f6b61e54SFam Zheng ret = vmdk_add_extent(bs, file, false, 525b3976d3cSFam Zheng le32_to_cpu(header.disk_sectors), 526b4b3ab14SFam Zheng le32_to_cpu(header.l1dir_offset) << 9, 527f6b61e54SFam Zheng 0, 528f6b61e54SFam Zheng le32_to_cpu(header.l1dir_size), 529f6b61e54SFam Zheng 4096, 5308aa1331cSFam Zheng le32_to_cpu(header.granularity), 5314823970bSFam Zheng &extent, 5324823970bSFam Zheng errp); 5338aa1331cSFam Zheng if (ret < 0) { 5348aa1331cSFam Zheng return ret; 5358aa1331cSFam Zheng } 5364823970bSFam Zheng ret = vmdk_init_tables(bs, extent, errp); 537b4b3ab14SFam Zheng if (ret) { 53886c6b429SFam Zheng /* free extent allocated by vmdk_add_extent */ 53986c6b429SFam Zheng vmdk_free_last_extent(bs); 540b4b3ab14SFam Zheng } 541b4b3ab14SFam Zheng return ret; 542b4b3ab14SFam Zheng } 543b4b3ab14SFam Zheng 544d1833ef5SPaolo Bonzini static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, 545d1833ef5SPaolo Bonzini Error **errp); 546f16f509dSFam Zheng 547a8842e6dSPaolo Bonzini static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset, 548a8842e6dSPaolo Bonzini Error **errp) 549a8842e6dSPaolo Bonzini { 550a8842e6dSPaolo Bonzini int64_t size; 551a8842e6dSPaolo Bonzini char *buf; 552a8842e6dSPaolo Bonzini int ret; 553a8842e6dSPaolo Bonzini 554a8842e6dSPaolo Bonzini size = bdrv_getlength(file); 555a8842e6dSPaolo Bonzini if (size < 0) { 556a8842e6dSPaolo Bonzini error_setg_errno(errp, -size, "Could not access file"); 557a8842e6dSPaolo Bonzini return NULL; 558a8842e6dSPaolo Bonzini } 559a8842e6dSPaolo Bonzini 56003c3359dSFam Zheng if (size < 4) { 56103c3359dSFam Zheng /* Both descriptor file and sparse image must be much larger than 4 56203c3359dSFam Zheng * bytes, also callers of vmdk_read_desc want to compare the first 4 56303c3359dSFam Zheng * bytes with VMDK4_MAGIC, let's error out if less is read. */ 56403c3359dSFam Zheng error_setg(errp, "File is too small, not a valid image"); 56503c3359dSFam Zheng return NULL; 56603c3359dSFam Zheng } 56703c3359dSFam Zheng 56873b7bcadSFam Zheng size = MIN(size, (1 << 20) - 1); /* avoid unbounded allocation */ 56973b7bcadSFam Zheng buf = g_malloc(size + 1); 570a8842e6dSPaolo Bonzini 571a8842e6dSPaolo Bonzini ret = bdrv_pread(file, desc_offset, buf, size); 572a8842e6dSPaolo Bonzini if (ret < 0) { 573a8842e6dSPaolo Bonzini error_setg_errno(errp, -ret, "Could not read from file"); 574a8842e6dSPaolo Bonzini g_free(buf); 575a8842e6dSPaolo Bonzini return NULL; 576a8842e6dSPaolo Bonzini } 57773b7bcadSFam Zheng buf[ret] = 0; 578a8842e6dSPaolo Bonzini 579a8842e6dSPaolo Bonzini return buf; 580a8842e6dSPaolo Bonzini } 581a8842e6dSPaolo Bonzini 58286c6b429SFam Zheng static int vmdk_open_vmdk4(BlockDriverState *bs, 58386c6b429SFam Zheng BlockDriverState *file, 5844823970bSFam Zheng int flags, Error **errp) 585b4b3ab14SFam Zheng { 586b4b3ab14SFam Zheng int ret; 587b4b3ab14SFam Zheng uint32_t magic; 588b4b3ab14SFam Zheng uint32_t l1_size, l1_entry_sectors; 589019d6b8fSAnthony Liguori VMDK4Header header; 590b4b3ab14SFam Zheng VmdkExtent *extent; 591f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 592bb45ded9SFam Zheng int64_t l1_backup_offset = 0; 593b4b3ab14SFam Zheng 59486c6b429SFam Zheng ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); 595b4b3ab14SFam Zheng if (ret < 0) { 5964823970bSFam Zheng error_setg_errno(errp, -ret, 5974823970bSFam Zheng "Could not read header from file '%s'", 5984823970bSFam Zheng file->filename); 59989ac8480SPaolo Bonzini return -EINVAL; 600b3976d3cSFam Zheng } 6015a394b9eSStefan Hajnoczi if (header.capacity == 0) { 602e98768d4SFam Zheng uint64_t desc_offset = le64_to_cpu(header.desc_offset); 6035a394b9eSStefan Hajnoczi if (desc_offset) { 604d1833ef5SPaolo Bonzini char *buf = vmdk_read_desc(file, desc_offset << 9, errp); 605d1833ef5SPaolo Bonzini if (!buf) { 606d1833ef5SPaolo Bonzini return -EINVAL; 607d1833ef5SPaolo Bonzini } 608d1833ef5SPaolo Bonzini ret = vmdk_open_desc_file(bs, flags, buf, errp); 609d1833ef5SPaolo Bonzini g_free(buf); 610d1833ef5SPaolo Bonzini return ret; 6115a394b9eSStefan Hajnoczi } 612f16f509dSFam Zheng } 61365bd155cSKevin Wolf 614f4c129a3SFam Zheng if (!s->create_type) { 615f4c129a3SFam Zheng s->create_type = g_strdup("monolithicSparse"); 616f4c129a3SFam Zheng } 617f4c129a3SFam Zheng 61865bd155cSKevin Wolf if (le64_to_cpu(header.gd_offset) == VMDK4_GD_AT_END) { 61965bd155cSKevin Wolf /* 62065bd155cSKevin Wolf * The footer takes precedence over the header, so read it in. The 62165bd155cSKevin Wolf * footer starts at offset -1024 from the end: One sector for the 62265bd155cSKevin Wolf * footer, and another one for the end-of-stream marker. 62365bd155cSKevin Wolf */ 62465bd155cSKevin Wolf struct { 62565bd155cSKevin Wolf struct { 62665bd155cSKevin Wolf uint64_t val; 62765bd155cSKevin Wolf uint32_t size; 62865bd155cSKevin Wolf uint32_t type; 62965bd155cSKevin Wolf uint8_t pad[512 - 16]; 63065bd155cSKevin Wolf } QEMU_PACKED footer_marker; 63165bd155cSKevin Wolf 63265bd155cSKevin Wolf uint32_t magic; 63365bd155cSKevin Wolf VMDK4Header header; 63465bd155cSKevin Wolf uint8_t pad[512 - 4 - sizeof(VMDK4Header)]; 63565bd155cSKevin Wolf 63665bd155cSKevin Wolf struct { 63765bd155cSKevin Wolf uint64_t val; 63865bd155cSKevin Wolf uint32_t size; 63965bd155cSKevin Wolf uint32_t type; 64065bd155cSKevin Wolf uint8_t pad[512 - 16]; 64165bd155cSKevin Wolf } QEMU_PACKED eos_marker; 64265bd155cSKevin Wolf } QEMU_PACKED footer; 64365bd155cSKevin Wolf 64465bd155cSKevin Wolf ret = bdrv_pread(file, 64565bd155cSKevin Wolf bs->file->total_sectors * 512 - 1536, 64665bd155cSKevin Wolf &footer, sizeof(footer)); 64765bd155cSKevin Wolf if (ret < 0) { 648d899d2e2SFam Zheng error_setg_errno(errp, -ret, "Failed to read footer"); 64965bd155cSKevin Wolf return ret; 65065bd155cSKevin Wolf } 65165bd155cSKevin Wolf 65265bd155cSKevin Wolf /* Some sanity checks for the footer */ 65365bd155cSKevin Wolf if (be32_to_cpu(footer.magic) != VMDK4_MAGIC || 65465bd155cSKevin Wolf le32_to_cpu(footer.footer_marker.size) != 0 || 65565bd155cSKevin Wolf le32_to_cpu(footer.footer_marker.type) != MARKER_FOOTER || 65665bd155cSKevin Wolf le64_to_cpu(footer.eos_marker.val) != 0 || 65765bd155cSKevin Wolf le32_to_cpu(footer.eos_marker.size) != 0 || 65865bd155cSKevin Wolf le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM) 65965bd155cSKevin Wolf { 660d899d2e2SFam Zheng error_setg(errp, "Invalid footer"); 66165bd155cSKevin Wolf return -EINVAL; 66265bd155cSKevin Wolf } 66365bd155cSKevin Wolf 66465bd155cSKevin Wolf header = footer.header; 66565bd155cSKevin Wolf } 66665bd155cSKevin Wolf 667509d39aaSFam Zheng if (le32_to_cpu(header.version) > 3) { 66896c51eb5SFam Zheng char buf[64]; 6694ab9dab5SFam Zheng snprintf(buf, sizeof(buf), "VMDK version %" PRId32, 67096c51eb5SFam Zheng le32_to_cpu(header.version)); 67189ac8480SPaolo Bonzini error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, 672bfb197e0SMarkus Armbruster bdrv_get_device_name(bs), "vmdk", buf); 67396c51eb5SFam Zheng return -ENOTSUP; 674509d39aaSFam Zheng } else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) { 675509d39aaSFam Zheng /* VMware KB 2064959 explains that version 3 added support for 676509d39aaSFam Zheng * persistent changed block tracking (CBT), and backup software can 677509d39aaSFam Zheng * read it as version=1 if it doesn't care about the changed area 678509d39aaSFam Zheng * information. So we are safe to enable read only. */ 679509d39aaSFam Zheng error_setg(errp, "VMDK version 3 must be read only"); 680509d39aaSFam Zheng return -EINVAL; 68196c51eb5SFam Zheng } 68296c51eb5SFam Zheng 683ca8804ceSFam Zheng if (le32_to_cpu(header.num_gtes_per_gt) > 512) { 68489ac8480SPaolo Bonzini error_setg(errp, "L2 table size too big"); 685f8ce0403SFam Zheng return -EINVAL; 686f8ce0403SFam Zheng } 687f8ce0403SFam Zheng 688ca8804ceSFam Zheng l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt) 689b3976d3cSFam Zheng * le64_to_cpu(header.granularity); 69075d12341SStefan Weil if (l1_entry_sectors == 0) { 691d899d2e2SFam Zheng error_setg(errp, "L1 entry size is invalid"); 69286c6b429SFam Zheng return -EINVAL; 69386c6b429SFam Zheng } 694b3976d3cSFam Zheng l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1) 695b3976d3cSFam Zheng / l1_entry_sectors; 696bb45ded9SFam Zheng if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) { 697bb45ded9SFam Zheng l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9; 698bb45ded9SFam Zheng } 69957322b78SMarkus Armbruster if (bdrv_nb_sectors(file) < le64_to_cpu(header.grain_offset)) { 7004ab9dab5SFam Zheng error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes", 7014ab9dab5SFam Zheng (int64_t)(le64_to_cpu(header.grain_offset) 7024ab9dab5SFam Zheng * BDRV_SECTOR_SIZE)); 70334ceed81SFam Zheng return -EINVAL; 70434ceed81SFam Zheng } 70534ceed81SFam Zheng 7068aa1331cSFam Zheng ret = vmdk_add_extent(bs, file, false, 707b3976d3cSFam Zheng le64_to_cpu(header.capacity), 708b3976d3cSFam Zheng le64_to_cpu(header.gd_offset) << 9, 709bb45ded9SFam Zheng l1_backup_offset, 710b3976d3cSFam Zheng l1_size, 711ca8804ceSFam Zheng le32_to_cpu(header.num_gtes_per_gt), 7128aa1331cSFam Zheng le64_to_cpu(header.granularity), 7134823970bSFam Zheng &extent, 7144823970bSFam Zheng errp); 7158aa1331cSFam Zheng if (ret < 0) { 7168aa1331cSFam Zheng return ret; 7178aa1331cSFam Zheng } 718432bb170SFam Zheng extent->compressed = 719432bb170SFam Zheng le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; 720d8a7b061SFam Zheng if (extent->compressed) { 721d8a7b061SFam Zheng g_free(s->create_type); 722d8a7b061SFam Zheng s->create_type = g_strdup("streamOptimized"); 723d8a7b061SFam Zheng } 724432bb170SFam Zheng extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER; 72514ead646SFam Zheng extent->version = le32_to_cpu(header.version); 72614ead646SFam Zheng extent->has_zero_grain = le32_to_cpu(header.flags) & VMDK4_FLAG_ZERO_GRAIN; 7274823970bSFam Zheng ret = vmdk_init_tables(bs, extent, errp); 728b4b3ab14SFam Zheng if (ret) { 72986c6b429SFam Zheng /* free extent allocated by vmdk_add_extent */ 73086c6b429SFam Zheng vmdk_free_last_extent(bs); 731019d6b8fSAnthony Liguori } 732b4b3ab14SFam Zheng return ret; 733b4b3ab14SFam Zheng } 734b4b3ab14SFam Zheng 7357fa60fa3SFam Zheng /* find an option value out of descriptor file */ 7367fa60fa3SFam Zheng static int vmdk_parse_description(const char *desc, const char *opt_name, 7377fa60fa3SFam Zheng char *buf, int buf_size) 7387fa60fa3SFam Zheng { 7397fa60fa3SFam Zheng char *opt_pos, *opt_end; 7407fa60fa3SFam Zheng const char *end = desc + strlen(desc); 7417fa60fa3SFam Zheng 7427fa60fa3SFam Zheng opt_pos = strstr(desc, opt_name); 7437fa60fa3SFam Zheng if (!opt_pos) { 74465f74725SFam Zheng return VMDK_ERROR; 7457fa60fa3SFam Zheng } 7467fa60fa3SFam Zheng /* Skip "=\"" following opt_name */ 7477fa60fa3SFam Zheng opt_pos += strlen(opt_name) + 2; 7487fa60fa3SFam Zheng if (opt_pos >= end) { 74965f74725SFam Zheng return VMDK_ERROR; 7507fa60fa3SFam Zheng } 7517fa60fa3SFam Zheng opt_end = opt_pos; 7527fa60fa3SFam Zheng while (opt_end < end && *opt_end != '"') { 7537fa60fa3SFam Zheng opt_end++; 7547fa60fa3SFam Zheng } 7557fa60fa3SFam Zheng if (opt_end == end || buf_size < opt_end - opt_pos + 1) { 75665f74725SFam Zheng return VMDK_ERROR; 7577fa60fa3SFam Zheng } 7587fa60fa3SFam Zheng pstrcpy(buf, opt_end - opt_pos + 1, opt_pos); 75965f74725SFam Zheng return VMDK_OK; 7607fa60fa3SFam Zheng } 7617fa60fa3SFam Zheng 76286c6b429SFam Zheng /* Open an extent file and append to bs array */ 76386c6b429SFam Zheng static int vmdk_open_sparse(BlockDriverState *bs, 764d1833ef5SPaolo Bonzini BlockDriverState *file, int flags, 765d1833ef5SPaolo Bonzini char *buf, Error **errp) 76686c6b429SFam Zheng { 76786c6b429SFam Zheng uint32_t magic; 76886c6b429SFam Zheng 769d1833ef5SPaolo Bonzini magic = ldl_be_p(buf); 77086c6b429SFam Zheng switch (magic) { 77186c6b429SFam Zheng case VMDK3_MAGIC: 7724823970bSFam Zheng return vmdk_open_vmfs_sparse(bs, file, flags, errp); 77386c6b429SFam Zheng break; 77486c6b429SFam Zheng case VMDK4_MAGIC: 7754823970bSFam Zheng return vmdk_open_vmdk4(bs, file, flags, errp); 77686c6b429SFam Zheng break; 77786c6b429SFam Zheng default: 77876abe407SPaolo Bonzini error_setg(errp, "Image not in VMDK format"); 77976abe407SPaolo Bonzini return -EINVAL; 78086c6b429SFam Zheng break; 78186c6b429SFam Zheng } 78286c6b429SFam Zheng } 78386c6b429SFam Zheng 7847fa60fa3SFam Zheng static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, 7854823970bSFam Zheng const char *desc_file_path, Error **errp) 7867fa60fa3SFam Zheng { 7877fa60fa3SFam Zheng int ret; 788*395a22faSJeff Cody int matches; 7897fa60fa3SFam Zheng char access[11]; 7907fa60fa3SFam Zheng char type[11]; 7917fa60fa3SFam Zheng char fname[512]; 7927fa60fa3SFam Zheng const char *p = desc; 7937fa60fa3SFam Zheng int64_t sectors = 0; 7947fa60fa3SFam Zheng int64_t flat_offset; 79586c6b429SFam Zheng char extent_path[PATH_MAX]; 79686c6b429SFam Zheng BlockDriverState *extent_file; 797f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 798f4c129a3SFam Zheng VmdkExtent *extent; 7997fa60fa3SFam Zheng 800*395a22faSJeff Cody 8017fa60fa3SFam Zheng while (*p) { 8028a3e0bc3SFam Zheng /* parse extent line in one of below formats: 8038a3e0bc3SFam Zheng * 8047fa60fa3SFam Zheng * RW [size in sectors] FLAT "file-name.vmdk" OFFSET 8057fa60fa3SFam Zheng * RW [size in sectors] SPARSE "file-name.vmdk" 8068a3e0bc3SFam Zheng * RW [size in sectors] VMFS "file-name.vmdk" 8078a3e0bc3SFam Zheng * RW [size in sectors] VMFSSPARSE "file-name.vmdk" 8087fa60fa3SFam Zheng */ 8097fa60fa3SFam Zheng flat_offset = -1; 810*395a22faSJeff Cody matches = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, 8117fa60fa3SFam Zheng access, §ors, type, fname, &flat_offset); 812*395a22faSJeff Cody if (matches < 4 || strcmp(access, "RW")) { 8137fa60fa3SFam Zheng goto next_line; 8147fa60fa3SFam Zheng } else if (!strcmp(type, "FLAT")) { 815*395a22faSJeff Cody if (matches != 5 || flat_offset < 0) { 8164823970bSFam Zheng error_setg(errp, "Invalid extent lines: \n%s", p); 8177fa60fa3SFam Zheng return -EINVAL; 8187fa60fa3SFam Zheng } 819dbbcaa8dSFam Zheng } else if (!strcmp(type, "VMFS")) { 820*395a22faSJeff Cody if (matches == 4) { 821dbbcaa8dSFam Zheng flat_offset = 0; 822b47053bdSFam Zheng } else { 823b47053bdSFam Zheng error_setg(errp, "Invalid extent lines:\n%s", p); 824b47053bdSFam Zheng return -EINVAL; 825b47053bdSFam Zheng } 826*395a22faSJeff Cody } else if (matches != 4) { 8274823970bSFam Zheng error_setg(errp, "Invalid extent lines:\n%s", p); 8287fa60fa3SFam Zheng return -EINVAL; 8297fa60fa3SFam Zheng } 8307fa60fa3SFam Zheng 8317fa60fa3SFam Zheng if (sectors <= 0 || 832daac8fdcSFam Zheng (strcmp(type, "FLAT") && strcmp(type, "SPARSE") && 83304d542c8SPaolo Bonzini strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) || 8347fa60fa3SFam Zheng (strcmp(access, "RW"))) { 8357fa60fa3SFam Zheng goto next_line; 8367fa60fa3SFam Zheng } 8377fa60fa3SFam Zheng 8385c98415bSMax Reitz if (!path_is_absolute(fname) && !path_has_protocol(fname) && 8395c98415bSMax Reitz !desc_file_path[0]) 8405c98415bSMax Reitz { 8415c98415bSMax Reitz error_setg(errp, "Cannot use relative extent paths with VMDK " 8425c98415bSMax Reitz "descriptor file '%s'", bs->file->filename); 8435c98415bSMax Reitz return -EINVAL; 8445c98415bSMax Reitz } 8455c98415bSMax Reitz 8467fa60fa3SFam Zheng path_combine(extent_path, sizeof(extent_path), 8477fa60fa3SFam Zheng desc_file_path, fname); 8482e40134bSMax Reitz extent_file = NULL; 8492e40134bSMax Reitz ret = bdrv_open(&extent_file, extent_path, NULL, NULL, 8502e40134bSMax Reitz bs->open_flags | BDRV_O_PROTOCOL, NULL, errp); 8517fa60fa3SFam Zheng if (ret) { 8527fa60fa3SFam Zheng return ret; 8537fa60fa3SFam Zheng } 85486c6b429SFam Zheng 85586c6b429SFam Zheng /* save to extents array */ 85604d542c8SPaolo Bonzini if (!strcmp(type, "FLAT") || !strcmp(type, "VMFS")) { 85786c6b429SFam Zheng /* FLAT extent */ 85886c6b429SFam Zheng 8598aa1331cSFam Zheng ret = vmdk_add_extent(bs, extent_file, true, sectors, 8604823970bSFam Zheng 0, 0, 0, 0, 0, &extent, errp); 8618aa1331cSFam Zheng if (ret < 0) { 862ff74f33cSStefan Hajnoczi bdrv_unref(extent_file); 8638aa1331cSFam Zheng return ret; 8648aa1331cSFam Zheng } 865f16f509dSFam Zheng extent->flat_start_offset = flat_offset << 9; 866daac8fdcSFam Zheng } else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) { 867daac8fdcSFam Zheng /* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/ 868d1833ef5SPaolo Bonzini char *buf = vmdk_read_desc(extent_file, 0, errp); 869d1833ef5SPaolo Bonzini if (!buf) { 870d1833ef5SPaolo Bonzini ret = -EINVAL; 871d1833ef5SPaolo Bonzini } else { 872d1833ef5SPaolo Bonzini ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, buf, errp); 873d1833ef5SPaolo Bonzini } 874d1833ef5SPaolo Bonzini g_free(buf); 875b6b1d31fSStefan Hajnoczi if (ret) { 8764f6fd349SFam Zheng bdrv_unref(extent_file); 87786c6b429SFam Zheng return ret; 87886c6b429SFam Zheng } 879f4c129a3SFam Zheng extent = &s->extents[s->num_extents - 1]; 8807fa60fa3SFam Zheng } else { 8814823970bSFam Zheng error_setg(errp, "Unsupported extent type '%s'", type); 882ff74f33cSStefan Hajnoczi bdrv_unref(extent_file); 8837fa60fa3SFam Zheng return -ENOTSUP; 8847fa60fa3SFam Zheng } 885f4c129a3SFam Zheng extent->type = g_strdup(type); 8867fa60fa3SFam Zheng next_line: 8877fa60fa3SFam Zheng /* move to next line */ 888899f1ae2SFam Zheng while (*p) { 889899f1ae2SFam Zheng if (*p == '\n') { 8907fa60fa3SFam Zheng p++; 891899f1ae2SFam Zheng break; 8927fa60fa3SFam Zheng } 8937fa60fa3SFam Zheng p++; 8947fa60fa3SFam Zheng } 895899f1ae2SFam Zheng } 8967fa60fa3SFam Zheng return 0; 8977fa60fa3SFam Zheng } 8987fa60fa3SFam Zheng 899d1833ef5SPaolo Bonzini static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, 900d1833ef5SPaolo Bonzini Error **errp) 9017fa60fa3SFam Zheng { 9027fa60fa3SFam Zheng int ret; 9037fa60fa3SFam Zheng char ct[128]; 9047fa60fa3SFam Zheng BDRVVmdkState *s = bs->opaque; 9057fa60fa3SFam Zheng 9067fa60fa3SFam Zheng if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) { 90776abe407SPaolo Bonzini error_setg(errp, "invalid VMDK image descriptor"); 90876abe407SPaolo Bonzini ret = -EINVAL; 9090bed087dSEvgeny Budilovsky goto exit; 9107fa60fa3SFam Zheng } 9116398de51SFam Zheng if (strcmp(ct, "monolithicFlat") && 91204d542c8SPaolo Bonzini strcmp(ct, "vmfs") && 913daac8fdcSFam Zheng strcmp(ct, "vmfsSparse") && 91486c6b429SFam Zheng strcmp(ct, "twoGbMaxExtentSparse") && 9156398de51SFam Zheng strcmp(ct, "twoGbMaxExtentFlat")) { 9164823970bSFam Zheng error_setg(errp, "Unsupported image type '%s'", ct); 9170bed087dSEvgeny Budilovsky ret = -ENOTSUP; 9180bed087dSEvgeny Budilovsky goto exit; 9197fa60fa3SFam Zheng } 920f4c129a3SFam Zheng s->create_type = g_strdup(ct); 9217fa60fa3SFam Zheng s->desc_offset = 0; 9225c98415bSMax Reitz ret = vmdk_parse_extents(buf, bs, bs->file->exact_filename, errp); 9230bed087dSEvgeny Budilovsky exit: 9240bed087dSEvgeny Budilovsky return ret; 9257fa60fa3SFam Zheng } 9267fa60fa3SFam Zheng 927015a1036SMax Reitz static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, 928015a1036SMax Reitz Error **errp) 929b4b3ab14SFam Zheng { 9309aeecbbcSFam Zheng char *buf; 93186c6b429SFam Zheng int ret; 93286c6b429SFam Zheng BDRVVmdkState *s = bs->opaque; 93337f09e5eSPaolo Bonzini uint32_t magic; 934b4b3ab14SFam Zheng 935d1833ef5SPaolo Bonzini buf = vmdk_read_desc(bs->file, 0, errp); 936d1833ef5SPaolo Bonzini if (!buf) { 937d1833ef5SPaolo Bonzini return -EINVAL; 938d1833ef5SPaolo Bonzini } 939d1833ef5SPaolo Bonzini 94037f09e5eSPaolo Bonzini magic = ldl_be_p(buf); 94137f09e5eSPaolo Bonzini switch (magic) { 94237f09e5eSPaolo Bonzini case VMDK3_MAGIC: 94337f09e5eSPaolo Bonzini case VMDK4_MAGIC: 94437f09e5eSPaolo Bonzini ret = vmdk_open_sparse(bs, bs->file, flags, buf, errp); 94586c6b429SFam Zheng s->desc_offset = 0x200; 94637f09e5eSPaolo Bonzini break; 94737f09e5eSPaolo Bonzini default: 948d1833ef5SPaolo Bonzini ret = vmdk_open_desc_file(bs, flags, buf, errp); 94937f09e5eSPaolo Bonzini break; 95037f09e5eSPaolo Bonzini } 951bae0a0ccSPaolo Bonzini if (ret) { 952bae0a0ccSPaolo Bonzini goto fail; 953bae0a0ccSPaolo Bonzini } 95437f09e5eSPaolo Bonzini 95586c6b429SFam Zheng /* try to open parent images, if exist */ 95686c6b429SFam Zheng ret = vmdk_parent_open(bs); 95786c6b429SFam Zheng if (ret) { 958bae0a0ccSPaolo Bonzini goto fail; 959b4b3ab14SFam Zheng } 960f4c129a3SFam Zheng s->cid = vmdk_read_cid(bs, 0); 96186c6b429SFam Zheng s->parent_cid = vmdk_read_cid(bs, 1); 962848c66e8SPaolo Bonzini qemu_co_mutex_init(&s->lock); 9632bc3166cSKevin Wolf 9642bc3166cSKevin Wolf /* Disable migration when VMDK images are used */ 9652bc3166cSKevin Wolf error_set(&s->migration_blocker, 9662bc3166cSKevin Wolf QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, 967bfb197e0SMarkus Armbruster "vmdk", bdrv_get_device_name(bs), "live migration"); 9682bc3166cSKevin Wolf migrate_add_blocker(s->migration_blocker); 969d1833ef5SPaolo Bonzini g_free(buf); 9702bc3166cSKevin Wolf return 0; 971bae0a0ccSPaolo Bonzini 972bae0a0ccSPaolo Bonzini fail: 973d1833ef5SPaolo Bonzini g_free(buf); 974f4c129a3SFam Zheng g_free(s->create_type); 975f4c129a3SFam Zheng s->create_type = NULL; 976bae0a0ccSPaolo Bonzini vmdk_free_extents(bs); 977bae0a0ccSPaolo Bonzini return ret; 978019d6b8fSAnthony Liguori } 979019d6b8fSAnthony Liguori 980d34682cdSKevin Wolf 9813baca891SKevin Wolf static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp) 982d34682cdSKevin Wolf { 983d34682cdSKevin Wolf BDRVVmdkState *s = bs->opaque; 984d34682cdSKevin Wolf int i; 985d34682cdSKevin Wolf 986d34682cdSKevin Wolf for (i = 0; i < s->num_extents; i++) { 987d34682cdSKevin Wolf if (!s->extents[i].flat) { 988d34682cdSKevin Wolf bs->bl.write_zeroes_alignment = 989d34682cdSKevin Wolf MAX(bs->bl.write_zeroes_alignment, 990d34682cdSKevin Wolf s->extents[i].cluster_sectors); 991d34682cdSKevin Wolf } 992d34682cdSKevin Wolf } 993d34682cdSKevin Wolf } 994d34682cdSKevin Wolf 995c6ac36e1SFam Zheng /** 996c6ac36e1SFam Zheng * get_whole_cluster 997c6ac36e1SFam Zheng * 998c6ac36e1SFam Zheng * Copy backing file's cluster that covers @sector_num, otherwise write zero, 999c6ac36e1SFam Zheng * to the cluster at @cluster_sector_num. 1000c6ac36e1SFam Zheng * 1001c6ac36e1SFam Zheng * If @skip_start_sector < @skip_end_sector, the relative range 1002c6ac36e1SFam Zheng * [@skip_start_sector, @skip_end_sector) is not copied or written, and leave 1003c6ac36e1SFam Zheng * it for call to write user data in the request. 1004c6ac36e1SFam Zheng */ 1005b3976d3cSFam Zheng static int get_whole_cluster(BlockDriverState *bs, 1006b3976d3cSFam Zheng VmdkExtent *extent, 1007c6ac36e1SFam Zheng uint64_t cluster_sector_num, 1008c6ac36e1SFam Zheng uint64_t sector_num, 1009c6ac36e1SFam Zheng uint64_t skip_start_sector, 1010c6ac36e1SFam Zheng uint64_t skip_end_sector) 1011019d6b8fSAnthony Liguori { 1012bf81507dSFam Zheng int ret = VMDK_OK; 1013c6ac36e1SFam Zheng int64_t cluster_bytes; 1014c6ac36e1SFam Zheng uint8_t *whole_grain; 1015019d6b8fSAnthony Liguori 1016c6ac36e1SFam Zheng /* For COW, align request sector_num to cluster start */ 1017c6ac36e1SFam Zheng sector_num = QEMU_ALIGN_DOWN(sector_num, extent->cluster_sectors); 1018c6ac36e1SFam Zheng cluster_bytes = extent->cluster_sectors << BDRV_SECTOR_BITS; 1019c6ac36e1SFam Zheng whole_grain = qemu_blockalign(bs, cluster_bytes); 1020c6ac36e1SFam Zheng 1021c6ac36e1SFam Zheng if (!bs->backing_hd) { 1022c6ac36e1SFam Zheng memset(whole_grain, 0, skip_start_sector << BDRV_SECTOR_BITS); 1023c6ac36e1SFam Zheng memset(whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 0, 1024c6ac36e1SFam Zheng cluster_bytes - (skip_end_sector << BDRV_SECTOR_BITS)); 1025c6ac36e1SFam Zheng } 1026c6ac36e1SFam Zheng 1027c6ac36e1SFam Zheng assert(skip_end_sector <= extent->cluster_sectors); 10280e69c543SFam Zheng /* we will be here if it's first write on non-exist grain(cluster). 10290e69c543SFam Zheng * try to read from parent image, if exist */ 1030c6ac36e1SFam Zheng if (bs->backing_hd && !vmdk_is_cid_valid(bs)) { 1031c6ac36e1SFam Zheng ret = VMDK_ERROR; 1032c6ac36e1SFam Zheng goto exit; 1033c6ac36e1SFam Zheng } 1034c6ac36e1SFam Zheng 1035c6ac36e1SFam Zheng /* Read backing data before skip range */ 1036c6ac36e1SFam Zheng if (skip_start_sector > 0) { 1037b171271aSKevin Wolf if (bs->backing_hd) { 1038c6ac36e1SFam Zheng ret = bdrv_read(bs->backing_hd, sector_num, 1039c6ac36e1SFam Zheng whole_grain, skip_start_sector); 1040c336500dSKevin Wolf if (ret < 0) { 1041bf81507dSFam Zheng ret = VMDK_ERROR; 1042bf81507dSFam Zheng goto exit; 1043019d6b8fSAnthony Liguori } 1044019d6b8fSAnthony Liguori } 1045c6ac36e1SFam Zheng ret = bdrv_write(extent->file, cluster_sector_num, whole_grain, 1046c6ac36e1SFam Zheng skip_start_sector); 1047c6ac36e1SFam Zheng if (ret < 0) { 1048c6ac36e1SFam Zheng ret = VMDK_ERROR; 1049c6ac36e1SFam Zheng goto exit; 1050c6ac36e1SFam Zheng } 1051c6ac36e1SFam Zheng } 1052c6ac36e1SFam Zheng /* Read backing data after skip range */ 1053c6ac36e1SFam Zheng if (skip_end_sector < extent->cluster_sectors) { 1054c6ac36e1SFam Zheng if (bs->backing_hd) { 1055c6ac36e1SFam Zheng ret = bdrv_read(bs->backing_hd, sector_num + skip_end_sector, 1056c6ac36e1SFam Zheng whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 1057c6ac36e1SFam Zheng extent->cluster_sectors - skip_end_sector); 1058c6ac36e1SFam Zheng if (ret < 0) { 1059c6ac36e1SFam Zheng ret = VMDK_ERROR; 1060c6ac36e1SFam Zheng goto exit; 1061c6ac36e1SFam Zheng } 1062c6ac36e1SFam Zheng } 1063c6ac36e1SFam Zheng ret = bdrv_write(extent->file, cluster_sector_num + skip_end_sector, 1064c6ac36e1SFam Zheng whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 1065c6ac36e1SFam Zheng extent->cluster_sectors - skip_end_sector); 1066c6ac36e1SFam Zheng if (ret < 0) { 1067c6ac36e1SFam Zheng ret = VMDK_ERROR; 1068c6ac36e1SFam Zheng goto exit; 1069c6ac36e1SFam Zheng } 1070c6ac36e1SFam Zheng } 1071c6ac36e1SFam Zheng 1072bf81507dSFam Zheng exit: 1073bf81507dSFam Zheng qemu_vfree(whole_grain); 1074bf81507dSFam Zheng return ret; 1075019d6b8fSAnthony Liguori } 1076019d6b8fSAnthony Liguori 1077c6ac36e1SFam Zheng static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data, 1078c6ac36e1SFam Zheng uint32_t offset) 1079019d6b8fSAnthony Liguori { 1080c6ac36e1SFam Zheng offset = cpu_to_le32(offset); 1081019d6b8fSAnthony Liguori /* update L2 table */ 1082b3976d3cSFam Zheng if (bdrv_pwrite_sync( 1083b3976d3cSFam Zheng extent->file, 1084b3976d3cSFam Zheng ((int64_t)m_data->l2_offset * 512) 1085c6ac36e1SFam Zheng + (m_data->l2_index * sizeof(offset)), 1086e304e8e5SFam Zheng &offset, sizeof(offset)) < 0) { 108765f74725SFam Zheng return VMDK_ERROR; 1088b3976d3cSFam Zheng } 1089019d6b8fSAnthony Liguori /* update backup L2 table */ 1090b3976d3cSFam Zheng if (extent->l1_backup_table_offset != 0) { 1091b3976d3cSFam Zheng m_data->l2_offset = extent->l1_backup_table[m_data->l1_index]; 1092b3976d3cSFam Zheng if (bdrv_pwrite_sync( 1093b3976d3cSFam Zheng extent->file, 1094b3976d3cSFam Zheng ((int64_t)m_data->l2_offset * 512) 1095c6ac36e1SFam Zheng + (m_data->l2_index * sizeof(offset)), 1096e304e8e5SFam Zheng &offset, sizeof(offset)) < 0) { 109765f74725SFam Zheng return VMDK_ERROR; 1098019d6b8fSAnthony Liguori } 1099b3976d3cSFam Zheng } 1100cdeaf1f1SFam Zheng if (m_data->l2_cache_entry) { 1101cdeaf1f1SFam Zheng *m_data->l2_cache_entry = offset; 1102cdeaf1f1SFam Zheng } 1103019d6b8fSAnthony Liguori 110465f74725SFam Zheng return VMDK_OK; 1105019d6b8fSAnthony Liguori } 1106019d6b8fSAnthony Liguori 1107c6ac36e1SFam Zheng /** 1108c6ac36e1SFam Zheng * get_cluster_offset 1109c6ac36e1SFam Zheng * 1110c6ac36e1SFam Zheng * Look up cluster offset in extent file by sector number, and store in 1111c6ac36e1SFam Zheng * @cluster_offset. 1112c6ac36e1SFam Zheng * 1113c6ac36e1SFam Zheng * For flat extents, the start offset as parsed from the description file is 1114c6ac36e1SFam Zheng * returned. 1115c6ac36e1SFam Zheng * 1116c6ac36e1SFam Zheng * For sparse extents, look up in L1, L2 table. If allocate is true, return an 1117c6ac36e1SFam Zheng * offset for a new cluster and update L2 cache. If there is a backing file, 1118c6ac36e1SFam Zheng * COW is done before returning; otherwise, zeroes are written to the allocated 1119c6ac36e1SFam Zheng * cluster. Both COW and zero writing skips the sector range 1120c6ac36e1SFam Zheng * [@skip_start_sector, @skip_end_sector) passed in by caller, because caller 1121c6ac36e1SFam Zheng * has new data to write there. 1122c6ac36e1SFam Zheng * 1123c6ac36e1SFam Zheng * Returns: VMDK_OK if cluster exists and mapped in the image. 1124c6ac36e1SFam Zheng * VMDK_UNALLOC if cluster is not mapped and @allocate is false. 1125c6ac36e1SFam Zheng * VMDK_ERROR if failed. 1126c6ac36e1SFam Zheng */ 112791b85bd3SFam Zheng static int get_cluster_offset(BlockDriverState *bs, 1128b3976d3cSFam Zheng VmdkExtent *extent, 1129b3976d3cSFam Zheng VmdkMetaData *m_data, 113091b85bd3SFam Zheng uint64_t offset, 1131c6ac36e1SFam Zheng bool allocate, 1132c6ac36e1SFam Zheng uint64_t *cluster_offset, 1133c6ac36e1SFam Zheng uint64_t skip_start_sector, 1134c6ac36e1SFam Zheng uint64_t skip_end_sector) 1135019d6b8fSAnthony Liguori { 1136019d6b8fSAnthony Liguori unsigned int l1_index, l2_offset, l2_index; 1137019d6b8fSAnthony Liguori int min_index, i, j; 1138e304e8e5SFam Zheng uint32_t min_count, *l2_table; 113914ead646SFam Zheng bool zeroed = false; 1140c6ac36e1SFam Zheng int64_t ret; 1141d1319b07SFam Zheng int64_t cluster_sector; 1142019d6b8fSAnthony Liguori 1143ae261c86SFam Zheng if (m_data) { 1144019d6b8fSAnthony Liguori m_data->valid = 0; 1145ae261c86SFam Zheng } 114691b85bd3SFam Zheng if (extent->flat) { 11477fa60fa3SFam Zheng *cluster_offset = extent->flat_start_offset; 114865f74725SFam Zheng return VMDK_OK; 114991b85bd3SFam Zheng } 1150019d6b8fSAnthony Liguori 11516398de51SFam Zheng offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE; 1152b3976d3cSFam Zheng l1_index = (offset >> 9) / extent->l1_entry_sectors; 1153b3976d3cSFam Zheng if (l1_index >= extent->l1_size) { 115465f74725SFam Zheng return VMDK_ERROR; 1155b3976d3cSFam Zheng } 1156b3976d3cSFam Zheng l2_offset = extent->l1_table[l1_index]; 1157b3976d3cSFam Zheng if (!l2_offset) { 115865f74725SFam Zheng return VMDK_UNALLOC; 1159b3976d3cSFam Zheng } 1160019d6b8fSAnthony Liguori for (i = 0; i < L2_CACHE_SIZE; i++) { 1161b3976d3cSFam Zheng if (l2_offset == extent->l2_cache_offsets[i]) { 1162019d6b8fSAnthony Liguori /* increment the hit count */ 1163b3976d3cSFam Zheng if (++extent->l2_cache_counts[i] == 0xffffffff) { 1164019d6b8fSAnthony Liguori for (j = 0; j < L2_CACHE_SIZE; j++) { 1165b3976d3cSFam Zheng extent->l2_cache_counts[j] >>= 1; 1166019d6b8fSAnthony Liguori } 1167019d6b8fSAnthony Liguori } 1168b3976d3cSFam Zheng l2_table = extent->l2_cache + (i * extent->l2_size); 1169019d6b8fSAnthony Liguori goto found; 1170019d6b8fSAnthony Liguori } 1171019d6b8fSAnthony Liguori } 1172019d6b8fSAnthony Liguori /* not found: load a new entry in the least used one */ 1173019d6b8fSAnthony Liguori min_index = 0; 1174019d6b8fSAnthony Liguori min_count = 0xffffffff; 1175019d6b8fSAnthony Liguori for (i = 0; i < L2_CACHE_SIZE; i++) { 1176b3976d3cSFam Zheng if (extent->l2_cache_counts[i] < min_count) { 1177b3976d3cSFam Zheng min_count = extent->l2_cache_counts[i]; 1178019d6b8fSAnthony Liguori min_index = i; 1179019d6b8fSAnthony Liguori } 1180019d6b8fSAnthony Liguori } 1181b3976d3cSFam Zheng l2_table = extent->l2_cache + (min_index * extent->l2_size); 1182b3976d3cSFam Zheng if (bdrv_pread( 1183b3976d3cSFam Zheng extent->file, 1184b3976d3cSFam Zheng (int64_t)l2_offset * 512, 1185b3976d3cSFam Zheng l2_table, 1186b3976d3cSFam Zheng extent->l2_size * sizeof(uint32_t) 1187b3976d3cSFam Zheng ) != extent->l2_size * sizeof(uint32_t)) { 118865f74725SFam Zheng return VMDK_ERROR; 1189b3976d3cSFam Zheng } 1190019d6b8fSAnthony Liguori 1191b3976d3cSFam Zheng extent->l2_cache_offsets[min_index] = l2_offset; 1192b3976d3cSFam Zheng extent->l2_cache_counts[min_index] = 1; 1193019d6b8fSAnthony Liguori found: 1194b3976d3cSFam Zheng l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size; 1195c6ac36e1SFam Zheng cluster_sector = le32_to_cpu(l2_table[l2_index]); 1196019d6b8fSAnthony Liguori 1197cdeaf1f1SFam Zheng if (m_data) { 1198cdeaf1f1SFam Zheng m_data->valid = 1; 1199cdeaf1f1SFam Zheng m_data->l1_index = l1_index; 1200cdeaf1f1SFam Zheng m_data->l2_index = l2_index; 1201cdeaf1f1SFam Zheng m_data->l2_offset = l2_offset; 1202cdeaf1f1SFam Zheng m_data->l2_cache_entry = &l2_table[l2_index]; 1203cdeaf1f1SFam Zheng } 1204c6ac36e1SFam Zheng if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) { 120514ead646SFam Zheng zeroed = true; 120614ead646SFam Zheng } 120714ead646SFam Zheng 1208c6ac36e1SFam Zheng if (!cluster_sector || zeroed) { 120991b85bd3SFam Zheng if (!allocate) { 121014ead646SFam Zheng return zeroed ? VMDK_ZEROED : VMDK_UNALLOC; 121191b85bd3SFam Zheng } 12129949f97eSKevin Wolf 1213c6ac36e1SFam Zheng cluster_sector = extent->next_cluster_sector; 1214c6ac36e1SFam Zheng extent->next_cluster_sector += extent->cluster_sectors; 12159949f97eSKevin Wolf 1216019d6b8fSAnthony Liguori /* First of all we write grain itself, to avoid race condition 1217019d6b8fSAnthony Liguori * that may to corrupt the image. 1218019d6b8fSAnthony Liguori * This problem may occur because of insufficient space on host disk 1219019d6b8fSAnthony Liguori * or inappropriate VM shutdown. 1220019d6b8fSAnthony Liguori */ 1221c6ac36e1SFam Zheng ret = get_whole_cluster(bs, extent, 1222c6ac36e1SFam Zheng cluster_sector, 1223c6ac36e1SFam Zheng offset >> BDRV_SECTOR_BITS, 1224c6ac36e1SFam Zheng skip_start_sector, skip_end_sector); 1225c6ac36e1SFam Zheng if (ret) { 1226c6ac36e1SFam Zheng return ret; 1227019d6b8fSAnthony Liguori } 1228019d6b8fSAnthony Liguori } 1229c6ac36e1SFam Zheng *cluster_offset = cluster_sector << BDRV_SECTOR_BITS; 123065f74725SFam Zheng return VMDK_OK; 1231019d6b8fSAnthony Liguori } 1232019d6b8fSAnthony Liguori 1233b3976d3cSFam Zheng static VmdkExtent *find_extent(BDRVVmdkState *s, 1234b3976d3cSFam Zheng int64_t sector_num, VmdkExtent *start_hint) 1235b3976d3cSFam Zheng { 1236b3976d3cSFam Zheng VmdkExtent *extent = start_hint; 1237b3976d3cSFam Zheng 1238b3976d3cSFam Zheng if (!extent) { 1239b3976d3cSFam Zheng extent = &s->extents[0]; 1240b3976d3cSFam Zheng } 1241b3976d3cSFam Zheng while (extent < &s->extents[s->num_extents]) { 1242b3976d3cSFam Zheng if (sector_num < extent->end_sector) { 1243b3976d3cSFam Zheng return extent; 1244b3976d3cSFam Zheng } 1245b3976d3cSFam Zheng extent++; 1246b3976d3cSFam Zheng } 1247b3976d3cSFam Zheng return NULL; 1248b3976d3cSFam Zheng } 1249b3976d3cSFam Zheng 1250b6b8a333SPaolo Bonzini static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs, 1251f8a2e5e3SStefan Hajnoczi int64_t sector_num, int nb_sectors, int *pnum) 1252019d6b8fSAnthony Liguori { 1253019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1254b3976d3cSFam Zheng int64_t index_in_cluster, n, ret; 1255b3976d3cSFam Zheng uint64_t offset; 1256b3976d3cSFam Zheng VmdkExtent *extent; 1257b3976d3cSFam Zheng 1258b3976d3cSFam Zheng extent = find_extent(s, sector_num, NULL); 1259b3976d3cSFam Zheng if (!extent) { 1260b3976d3cSFam Zheng return 0; 1261b3976d3cSFam Zheng } 1262f8a2e5e3SStefan Hajnoczi qemu_co_mutex_lock(&s->lock); 126391b85bd3SFam Zheng ret = get_cluster_offset(bs, extent, NULL, 1264c6ac36e1SFam Zheng sector_num * 512, false, &offset, 1265c6ac36e1SFam Zheng 0, 0); 1266f8a2e5e3SStefan Hajnoczi qemu_co_mutex_unlock(&s->lock); 126714ead646SFam Zheng 12684bc74be9SPaolo Bonzini switch (ret) { 12694bc74be9SPaolo Bonzini case VMDK_ERROR: 12704bc74be9SPaolo Bonzini ret = -EIO; 12714bc74be9SPaolo Bonzini break; 12724bc74be9SPaolo Bonzini case VMDK_UNALLOC: 12734bc74be9SPaolo Bonzini ret = 0; 12744bc74be9SPaolo Bonzini break; 12754bc74be9SPaolo Bonzini case VMDK_ZEROED: 12764bc74be9SPaolo Bonzini ret = BDRV_BLOCK_ZERO; 12774bc74be9SPaolo Bonzini break; 12784bc74be9SPaolo Bonzini case VMDK_OK: 12794bc74be9SPaolo Bonzini ret = BDRV_BLOCK_DATA; 12803eba13ecSPeter Lieven if (extent->file == bs->file && !extent->compressed) { 12814bc74be9SPaolo Bonzini ret |= BDRV_BLOCK_OFFSET_VALID | offset; 12824bc74be9SPaolo Bonzini } 12834bc74be9SPaolo Bonzini 12844bc74be9SPaolo Bonzini break; 12854bc74be9SPaolo Bonzini } 128691b85bd3SFam Zheng 1287b3976d3cSFam Zheng index_in_cluster = sector_num % extent->cluster_sectors; 1288b3976d3cSFam Zheng n = extent->cluster_sectors - index_in_cluster; 1289ae261c86SFam Zheng if (n > nb_sectors) { 1290019d6b8fSAnthony Liguori n = nb_sectors; 1291ae261c86SFam Zheng } 1292019d6b8fSAnthony Liguori *pnum = n; 1293b3976d3cSFam Zheng return ret; 1294019d6b8fSAnthony Liguori } 1295019d6b8fSAnthony Liguori 1296dd3f6ee2SFam Zheng static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, 1297dd3f6ee2SFam Zheng int64_t offset_in_cluster, const uint8_t *buf, 1298dd3f6ee2SFam Zheng int nb_sectors, int64_t sector_num) 1299dd3f6ee2SFam Zheng { 1300dd3f6ee2SFam Zheng int ret; 13012b2c8c5dSFam Zheng VmdkGrainMarker *data = NULL; 13022b2c8c5dSFam Zheng uLongf buf_len; 1303dd3f6ee2SFam Zheng const uint8_t *write_buf = buf; 1304dd3f6ee2SFam Zheng int write_len = nb_sectors * 512; 1305dd3f6ee2SFam Zheng 13062b2c8c5dSFam Zheng if (extent->compressed) { 13072b2c8c5dSFam Zheng if (!extent->has_marker) { 13082b2c8c5dSFam Zheng ret = -EINVAL; 13092b2c8c5dSFam Zheng goto out; 13102b2c8c5dSFam Zheng } 13112b2c8c5dSFam Zheng buf_len = (extent->cluster_sectors << 9) * 2; 13122b2c8c5dSFam Zheng data = g_malloc(buf_len + sizeof(VmdkGrainMarker)); 13132b2c8c5dSFam Zheng if (compress(data->data, &buf_len, buf, nb_sectors << 9) != Z_OK || 13142b2c8c5dSFam Zheng buf_len == 0) { 13152b2c8c5dSFam Zheng ret = -EINVAL; 13162b2c8c5dSFam Zheng goto out; 13172b2c8c5dSFam Zheng } 13182b2c8c5dSFam Zheng data->lba = sector_num; 13192b2c8c5dSFam Zheng data->size = buf_len; 13202b2c8c5dSFam Zheng write_buf = (uint8_t *)data; 13212b2c8c5dSFam Zheng write_len = buf_len + sizeof(VmdkGrainMarker); 13222b2c8c5dSFam Zheng } 1323dd3f6ee2SFam Zheng ret = bdrv_pwrite(extent->file, 1324dd3f6ee2SFam Zheng cluster_offset + offset_in_cluster, 1325dd3f6ee2SFam Zheng write_buf, 1326dd3f6ee2SFam Zheng write_len); 1327dd3f6ee2SFam Zheng if (ret != write_len) { 1328dd3f6ee2SFam Zheng ret = ret < 0 ? ret : -EIO; 1329dd3f6ee2SFam Zheng goto out; 1330dd3f6ee2SFam Zheng } 1331dd3f6ee2SFam Zheng ret = 0; 1332dd3f6ee2SFam Zheng out: 13332b2c8c5dSFam Zheng g_free(data); 1334dd3f6ee2SFam Zheng return ret; 1335dd3f6ee2SFam Zheng } 1336dd3f6ee2SFam Zheng 1337dd3f6ee2SFam Zheng static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, 1338dd3f6ee2SFam Zheng int64_t offset_in_cluster, uint8_t *buf, 1339dd3f6ee2SFam Zheng int nb_sectors) 1340dd3f6ee2SFam Zheng { 1341dd3f6ee2SFam Zheng int ret; 13422b2c8c5dSFam Zheng int cluster_bytes, buf_bytes; 13432b2c8c5dSFam Zheng uint8_t *cluster_buf, *compressed_data; 13442b2c8c5dSFam Zheng uint8_t *uncomp_buf; 13452b2c8c5dSFam Zheng uint32_t data_len; 13462b2c8c5dSFam Zheng VmdkGrainMarker *marker; 13472b2c8c5dSFam Zheng uLongf buf_len; 1348dd3f6ee2SFam Zheng 13492b2c8c5dSFam Zheng 13502b2c8c5dSFam Zheng if (!extent->compressed) { 1351dd3f6ee2SFam Zheng ret = bdrv_pread(extent->file, 1352dd3f6ee2SFam Zheng cluster_offset + offset_in_cluster, 1353dd3f6ee2SFam Zheng buf, nb_sectors * 512); 1354dd3f6ee2SFam Zheng if (ret == nb_sectors * 512) { 1355dd3f6ee2SFam Zheng return 0; 1356dd3f6ee2SFam Zheng } else { 1357dd3f6ee2SFam Zheng return -EIO; 1358dd3f6ee2SFam Zheng } 1359dd3f6ee2SFam Zheng } 13602b2c8c5dSFam Zheng cluster_bytes = extent->cluster_sectors * 512; 13612b2c8c5dSFam Zheng /* Read two clusters in case GrainMarker + compressed data > one cluster */ 13622b2c8c5dSFam Zheng buf_bytes = cluster_bytes * 2; 13632b2c8c5dSFam Zheng cluster_buf = g_malloc(buf_bytes); 13642b2c8c5dSFam Zheng uncomp_buf = g_malloc(cluster_bytes); 13652b2c8c5dSFam Zheng ret = bdrv_pread(extent->file, 13662b2c8c5dSFam Zheng cluster_offset, 13672b2c8c5dSFam Zheng cluster_buf, buf_bytes); 13682b2c8c5dSFam Zheng if (ret < 0) { 13692b2c8c5dSFam Zheng goto out; 13702b2c8c5dSFam Zheng } 13712b2c8c5dSFam Zheng compressed_data = cluster_buf; 13722b2c8c5dSFam Zheng buf_len = cluster_bytes; 13732b2c8c5dSFam Zheng data_len = cluster_bytes; 13742b2c8c5dSFam Zheng if (extent->has_marker) { 13752b2c8c5dSFam Zheng marker = (VmdkGrainMarker *)cluster_buf; 13762b2c8c5dSFam Zheng compressed_data = marker->data; 13772b2c8c5dSFam Zheng data_len = le32_to_cpu(marker->size); 13782b2c8c5dSFam Zheng } 13792b2c8c5dSFam Zheng if (!data_len || data_len > buf_bytes) { 13802b2c8c5dSFam Zheng ret = -EINVAL; 13812b2c8c5dSFam Zheng goto out; 13822b2c8c5dSFam Zheng } 13832b2c8c5dSFam Zheng ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len); 13842b2c8c5dSFam Zheng if (ret != Z_OK) { 13852b2c8c5dSFam Zheng ret = -EINVAL; 13862b2c8c5dSFam Zheng goto out; 13872b2c8c5dSFam Zheng 13882b2c8c5dSFam Zheng } 13892b2c8c5dSFam Zheng if (offset_in_cluster < 0 || 13902b2c8c5dSFam Zheng offset_in_cluster + nb_sectors * 512 > buf_len) { 13912b2c8c5dSFam Zheng ret = -EINVAL; 13922b2c8c5dSFam Zheng goto out; 13932b2c8c5dSFam Zheng } 13942b2c8c5dSFam Zheng memcpy(buf, uncomp_buf + offset_in_cluster, nb_sectors * 512); 13952b2c8c5dSFam Zheng ret = 0; 13962b2c8c5dSFam Zheng 13972b2c8c5dSFam Zheng out: 13982b2c8c5dSFam Zheng g_free(uncomp_buf); 13992b2c8c5dSFam Zheng g_free(cluster_buf); 14002b2c8c5dSFam Zheng return ret; 14012b2c8c5dSFam Zheng } 1402dd3f6ee2SFam Zheng 1403019d6b8fSAnthony Liguori static int vmdk_read(BlockDriverState *bs, int64_t sector_num, 1404019d6b8fSAnthony Liguori uint8_t *buf, int nb_sectors) 1405019d6b8fSAnthony Liguori { 1406019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1407b3976d3cSFam Zheng int ret; 1408b3976d3cSFam Zheng uint64_t n, index_in_cluster; 1409b1649faeSGerhard Wiesinger uint64_t extent_begin_sector, extent_relative_sector_num; 1410b3976d3cSFam Zheng VmdkExtent *extent = NULL; 1411019d6b8fSAnthony Liguori uint64_t cluster_offset; 1412019d6b8fSAnthony Liguori 1413019d6b8fSAnthony Liguori while (nb_sectors > 0) { 1414b3976d3cSFam Zheng extent = find_extent(s, sector_num, extent); 1415b3976d3cSFam Zheng if (!extent) { 1416b3976d3cSFam Zheng return -EIO; 1417b3976d3cSFam Zheng } 1418c6ac36e1SFam Zheng ret = get_cluster_offset(bs, extent, NULL, 1419c6ac36e1SFam Zheng sector_num << 9, false, &cluster_offset, 1420c6ac36e1SFam Zheng 0, 0); 1421b1649faeSGerhard Wiesinger extent_begin_sector = extent->end_sector - extent->sectors; 1422b1649faeSGerhard Wiesinger extent_relative_sector_num = sector_num - extent_begin_sector; 1423b1649faeSGerhard Wiesinger index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; 1424b3976d3cSFam Zheng n = extent->cluster_sectors - index_in_cluster; 1425ae261c86SFam Zheng if (n > nb_sectors) { 1426019d6b8fSAnthony Liguori n = nb_sectors; 1427ae261c86SFam Zheng } 142814ead646SFam Zheng if (ret != VMDK_OK) { 142991b85bd3SFam Zheng /* if not allocated, try to read from parent image, if exist */ 143014ead646SFam Zheng if (bs->backing_hd && ret != VMDK_ZEROED) { 1431ae261c86SFam Zheng if (!vmdk_is_cid_valid(bs)) { 14327fa60fa3SFam Zheng return -EINVAL; 1433ae261c86SFam Zheng } 1434b171271aSKevin Wolf ret = bdrv_read(bs->backing_hd, sector_num, buf, n); 1435ae261c86SFam Zheng if (ret < 0) { 14367fa60fa3SFam Zheng return ret; 1437ae261c86SFam Zheng } 1438019d6b8fSAnthony Liguori } else { 1439019d6b8fSAnthony Liguori memset(buf, 0, 512 * n); 1440019d6b8fSAnthony Liguori } 1441019d6b8fSAnthony Liguori } else { 1442dd3f6ee2SFam Zheng ret = vmdk_read_extent(extent, 1443dd3f6ee2SFam Zheng cluster_offset, index_in_cluster * 512, 1444dd3f6ee2SFam Zheng buf, n); 1445dd3f6ee2SFam Zheng if (ret) { 14467fa60fa3SFam Zheng return ret; 14477fa60fa3SFam Zheng } 1448019d6b8fSAnthony Liguori } 1449019d6b8fSAnthony Liguori nb_sectors -= n; 1450019d6b8fSAnthony Liguori sector_num += n; 1451019d6b8fSAnthony Liguori buf += n * 512; 1452019d6b8fSAnthony Liguori } 1453019d6b8fSAnthony Liguori return 0; 1454019d6b8fSAnthony Liguori } 1455019d6b8fSAnthony Liguori 14562914caa0SPaolo Bonzini static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num, 14572914caa0SPaolo Bonzini uint8_t *buf, int nb_sectors) 14582914caa0SPaolo Bonzini { 14592914caa0SPaolo Bonzini int ret; 14602914caa0SPaolo Bonzini BDRVVmdkState *s = bs->opaque; 14612914caa0SPaolo Bonzini qemu_co_mutex_lock(&s->lock); 14622914caa0SPaolo Bonzini ret = vmdk_read(bs, sector_num, buf, nb_sectors); 14632914caa0SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 14642914caa0SPaolo Bonzini return ret; 14652914caa0SPaolo Bonzini } 14662914caa0SPaolo Bonzini 1467cdeaf1f1SFam Zheng /** 1468cdeaf1f1SFam Zheng * vmdk_write: 1469cdeaf1f1SFam Zheng * @zeroed: buf is ignored (data is zero), use zeroed_grain GTE feature 1470cdeaf1f1SFam Zheng * if possible, otherwise return -ENOTSUP. 14718e507243SFam Zheng * @zero_dry_run: used for zeroed == true only, don't update L2 table, just try 14728e507243SFam Zheng * with each cluster. By dry run we can find if the zero write 14738e507243SFam Zheng * is possible without modifying image data. 1474cdeaf1f1SFam Zheng * 1475cdeaf1f1SFam Zheng * Returns: error code with 0 for success. 1476cdeaf1f1SFam Zheng */ 1477019d6b8fSAnthony Liguori static int vmdk_write(BlockDriverState *bs, int64_t sector_num, 1478cdeaf1f1SFam Zheng const uint8_t *buf, int nb_sectors, 1479cdeaf1f1SFam Zheng bool zeroed, bool zero_dry_run) 1480019d6b8fSAnthony Liguori { 1481019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1482b3976d3cSFam Zheng VmdkExtent *extent = NULL; 1483585ea0c8SFam Zheng int ret; 1484585ea0c8SFam Zheng int64_t index_in_cluster, n; 1485b1649faeSGerhard Wiesinger uint64_t extent_begin_sector, extent_relative_sector_num; 1486019d6b8fSAnthony Liguori uint64_t cluster_offset; 1487b3976d3cSFam Zheng VmdkMetaData m_data; 1488019d6b8fSAnthony Liguori 1489019d6b8fSAnthony Liguori if (sector_num > bs->total_sectors) { 14904823970bSFam Zheng error_report("Wrong offset: sector_num=0x%" PRIx64 1491019d6b8fSAnthony Liguori " total_sectors=0x%" PRIx64 "\n", 1492019d6b8fSAnthony Liguori sector_num, bs->total_sectors); 14937fa60fa3SFam Zheng return -EIO; 1494019d6b8fSAnthony Liguori } 1495019d6b8fSAnthony Liguori 1496019d6b8fSAnthony Liguori while (nb_sectors > 0) { 1497b3976d3cSFam Zheng extent = find_extent(s, sector_num, extent); 1498b3976d3cSFam Zheng if (!extent) { 1499b3976d3cSFam Zheng return -EIO; 1500b3976d3cSFam Zheng } 1501c6ac36e1SFam Zheng extent_begin_sector = extent->end_sector - extent->sectors; 1502c6ac36e1SFam Zheng extent_relative_sector_num = sector_num - extent_begin_sector; 1503c6ac36e1SFam Zheng index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; 1504c6ac36e1SFam Zheng n = extent->cluster_sectors - index_in_cluster; 1505c6ac36e1SFam Zheng if (n > nb_sectors) { 1506c6ac36e1SFam Zheng n = nb_sectors; 1507c6ac36e1SFam Zheng } 1508c6ac36e1SFam Zheng ret = get_cluster_offset(bs, extent, &m_data, sector_num << 9, 1509c6ac36e1SFam Zheng !(extent->compressed || zeroed), 1510c6ac36e1SFam Zheng &cluster_offset, 1511c6ac36e1SFam Zheng index_in_cluster, index_in_cluster + n); 15122b2c8c5dSFam Zheng if (extent->compressed) { 151365f74725SFam Zheng if (ret == VMDK_OK) { 15142b2c8c5dSFam Zheng /* Refuse write to allocated cluster for streamOptimized */ 15154823970bSFam Zheng error_report("Could not write to allocated cluster" 15164823970bSFam Zheng " for streamOptimized"); 15172b2c8c5dSFam Zheng return -EIO; 15182b2c8c5dSFam Zheng } else { 15192b2c8c5dSFam Zheng /* allocate */ 1520c6ac36e1SFam Zheng ret = get_cluster_offset(bs, extent, &m_data, sector_num << 9, 1521c6ac36e1SFam Zheng true, &cluster_offset, 0, 0); 15222b2c8c5dSFam Zheng } 15232b2c8c5dSFam Zheng } 1524cdeaf1f1SFam Zheng if (ret == VMDK_ERROR) { 152591b85bd3SFam Zheng return -EINVAL; 1526b3976d3cSFam Zheng } 1527cdeaf1f1SFam Zheng if (zeroed) { 1528cdeaf1f1SFam Zheng /* Do zeroed write, buf is ignored */ 1529cdeaf1f1SFam Zheng if (extent->has_zero_grain && 1530cdeaf1f1SFam Zheng index_in_cluster == 0 && 1531cdeaf1f1SFam Zheng n >= extent->cluster_sectors) { 1532cdeaf1f1SFam Zheng n = extent->cluster_sectors; 1533cdeaf1f1SFam Zheng if (!zero_dry_run) { 1534cdeaf1f1SFam Zheng /* update L2 tables */ 1535c6ac36e1SFam Zheng if (vmdk_L2update(extent, &m_data, VMDK_GTE_ZEROED) 1536c6ac36e1SFam Zheng != VMDK_OK) { 1537cdeaf1f1SFam Zheng return -EIO; 1538cdeaf1f1SFam Zheng } 1539cdeaf1f1SFam Zheng } 1540cdeaf1f1SFam Zheng } else { 1541cdeaf1f1SFam Zheng return -ENOTSUP; 1542cdeaf1f1SFam Zheng } 1543cdeaf1f1SFam Zheng } else { 1544dd3f6ee2SFam Zheng ret = vmdk_write_extent(extent, 1545dd3f6ee2SFam Zheng cluster_offset, index_in_cluster * 512, 1546dd3f6ee2SFam Zheng buf, n, sector_num); 1547dd3f6ee2SFam Zheng if (ret) { 15487fa60fa3SFam Zheng return ret; 1549b3976d3cSFam Zheng } 1550019d6b8fSAnthony Liguori if (m_data.valid) { 1551019d6b8fSAnthony Liguori /* update L2 tables */ 1552c6ac36e1SFam Zheng if (vmdk_L2update(extent, &m_data, 1553c6ac36e1SFam Zheng cluster_offset >> BDRV_SECTOR_BITS) 1554c6ac36e1SFam Zheng != VMDK_OK) { 15557fa60fa3SFam Zheng return -EIO; 1556019d6b8fSAnthony Liguori } 1557b3976d3cSFam Zheng } 1558cdeaf1f1SFam Zheng } 1559019d6b8fSAnthony Liguori nb_sectors -= n; 1560019d6b8fSAnthony Liguori sector_num += n; 1561019d6b8fSAnthony Liguori buf += n * 512; 1562019d6b8fSAnthony Liguori 1563ae261c86SFam Zheng /* update CID on the first write every time the virtual disk is 1564ae261c86SFam Zheng * opened */ 156569b4d86dSFam Zheng if (!s->cid_updated) { 1566e5dc64b8SFam Zheng ret = vmdk_write_cid(bs, g_random_int()); 156799f1835dSKevin Wolf if (ret < 0) { 156899f1835dSKevin Wolf return ret; 156999f1835dSKevin Wolf } 157069b4d86dSFam Zheng s->cid_updated = true; 1571019d6b8fSAnthony Liguori } 1572019d6b8fSAnthony Liguori } 1573019d6b8fSAnthony Liguori return 0; 1574019d6b8fSAnthony Liguori } 1575019d6b8fSAnthony Liguori 1576e183ef75SPaolo Bonzini static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num, 1577e183ef75SPaolo Bonzini const uint8_t *buf, int nb_sectors) 1578e183ef75SPaolo Bonzini { 1579e183ef75SPaolo Bonzini int ret; 1580e183ef75SPaolo Bonzini BDRVVmdkState *s = bs->opaque; 1581e183ef75SPaolo Bonzini qemu_co_mutex_lock(&s->lock); 1582cdeaf1f1SFam Zheng ret = vmdk_write(bs, sector_num, buf, nb_sectors, false, false); 1583cdeaf1f1SFam Zheng qemu_co_mutex_unlock(&s->lock); 1584cdeaf1f1SFam Zheng return ret; 1585cdeaf1f1SFam Zheng } 1586cdeaf1f1SFam Zheng 1587ba0ad89eSFam Zheng static int vmdk_write_compressed(BlockDriverState *bs, 1588ba0ad89eSFam Zheng int64_t sector_num, 1589ba0ad89eSFam Zheng const uint8_t *buf, 1590ba0ad89eSFam Zheng int nb_sectors) 1591ba0ad89eSFam Zheng { 1592ba0ad89eSFam Zheng BDRVVmdkState *s = bs->opaque; 1593ba0ad89eSFam Zheng if (s->num_extents == 1 && s->extents[0].compressed) { 1594ba0ad89eSFam Zheng return vmdk_write(bs, sector_num, buf, nb_sectors, false, false); 1595ba0ad89eSFam Zheng } else { 1596ba0ad89eSFam Zheng return -ENOTSUP; 1597ba0ad89eSFam Zheng } 1598ba0ad89eSFam Zheng } 1599ba0ad89eSFam Zheng 1600cdeaf1f1SFam Zheng static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs, 1601cdeaf1f1SFam Zheng int64_t sector_num, 1602aa7bfbffSPeter Lieven int nb_sectors, 1603aa7bfbffSPeter Lieven BdrvRequestFlags flags) 1604cdeaf1f1SFam Zheng { 1605cdeaf1f1SFam Zheng int ret; 1606cdeaf1f1SFam Zheng BDRVVmdkState *s = bs->opaque; 1607cdeaf1f1SFam Zheng qemu_co_mutex_lock(&s->lock); 16088e507243SFam Zheng /* write zeroes could fail if sectors not aligned to cluster, test it with 16098e507243SFam Zheng * dry_run == true before really updating image */ 1610cdeaf1f1SFam Zheng ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, true); 1611cdeaf1f1SFam Zheng if (!ret) { 1612cdeaf1f1SFam Zheng ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, false); 1613cdeaf1f1SFam Zheng } 1614e183ef75SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 1615e183ef75SPaolo Bonzini return ret; 1616e183ef75SPaolo Bonzini } 1617e183ef75SPaolo Bonzini 16186c031aacSFam Zheng static int vmdk_create_extent(const char *filename, int64_t filesize, 1619917703c1SFam Zheng bool flat, bool compress, bool zeroed_grain, 16204ab15590SChunyan Liu QemuOpts *opts, Error **errp) 1621019d6b8fSAnthony Liguori { 1622f66fd6c3SFam Zheng int ret, i; 1623917703c1SFam Zheng BlockDriverState *bs = NULL; 1624019d6b8fSAnthony Liguori VMDK4Header header; 1625c13959c7SFam Zheng Error *local_err = NULL; 1626917703c1SFam Zheng uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count; 1627917703c1SFam Zheng uint32_t *gd_buf = NULL; 1628917703c1SFam Zheng int gd_buf_size; 16290e7e1989SKevin Wolf 16304ab15590SChunyan Liu ret = bdrv_create_file(filename, opts, &local_err); 1631f66fd6c3SFam Zheng if (ret < 0) { 1632917703c1SFam Zheng error_propagate(errp, local_err); 1633917703c1SFam Zheng goto exit; 1634917703c1SFam Zheng } 1635917703c1SFam Zheng 16362e40134bSMax Reitz assert(bs == NULL); 16372e40134bSMax Reitz ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, 16382e40134bSMax Reitz NULL, &local_err); 1639917703c1SFam Zheng if (ret < 0) { 1640917703c1SFam Zheng error_propagate(errp, local_err); 1641917703c1SFam Zheng goto exit; 1642917703c1SFam Zheng } 1643917703c1SFam Zheng 1644917703c1SFam Zheng if (flat) { 1645917703c1SFam Zheng ret = bdrv_truncate(bs, filesize); 1646917703c1SFam Zheng if (ret < 0) { 164739a611a3SJeff Cody error_setg_errno(errp, -ret, "Could not truncate file"); 1648f66fd6c3SFam Zheng } 1649f66fd6c3SFam Zheng goto exit; 1650f66fd6c3SFam Zheng } 1651019d6b8fSAnthony Liguori magic = cpu_to_be32(VMDK4_MAGIC); 1652019d6b8fSAnthony Liguori memset(&header, 0, sizeof(header)); 165369e0b6dfSFam Zheng header.version = zeroed_grain ? 2 : 1; 165495b0aa42SFam Zheng header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT 165569e0b6dfSFam Zheng | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0) 165669e0b6dfSFam Zheng | (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0); 16576c031aacSFam Zheng header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0; 1658917703c1SFam Zheng header.capacity = filesize / BDRV_SECTOR_SIZE; 165916372ff0SAlexander Graf header.granularity = 128; 1660917703c1SFam Zheng header.num_gtes_per_gt = BDRV_SECTOR_SIZE; 1661019d6b8fSAnthony Liguori 1662917703c1SFam Zheng grains = DIV_ROUND_UP(filesize / BDRV_SECTOR_SIZE, header.granularity); 1663917703c1SFam Zheng gt_size = DIV_ROUND_UP(header.num_gtes_per_gt * sizeof(uint32_t), 1664917703c1SFam Zheng BDRV_SECTOR_SIZE); 1665917703c1SFam Zheng gt_count = DIV_ROUND_UP(grains, header.num_gtes_per_gt); 1666917703c1SFam Zheng gd_sectors = DIV_ROUND_UP(gt_count * sizeof(uint32_t), BDRV_SECTOR_SIZE); 1667019d6b8fSAnthony Liguori 1668019d6b8fSAnthony Liguori header.desc_offset = 1; 1669019d6b8fSAnthony Liguori header.desc_size = 20; 1670019d6b8fSAnthony Liguori header.rgd_offset = header.desc_offset + header.desc_size; 1671917703c1SFam Zheng header.gd_offset = header.rgd_offset + gd_sectors + (gt_size * gt_count); 1672019d6b8fSAnthony Liguori header.grain_offset = 1673917703c1SFam Zheng ROUND_UP(header.gd_offset + gd_sectors + (gt_size * gt_count), 1674917703c1SFam Zheng header.granularity); 167516372ff0SAlexander Graf /* swap endianness for all header fields */ 167616372ff0SAlexander Graf header.version = cpu_to_le32(header.version); 167716372ff0SAlexander Graf header.flags = cpu_to_le32(header.flags); 167816372ff0SAlexander Graf header.capacity = cpu_to_le64(header.capacity); 167916372ff0SAlexander Graf header.granularity = cpu_to_le64(header.granularity); 1680ca8804ceSFam Zheng header.num_gtes_per_gt = cpu_to_le32(header.num_gtes_per_gt); 1681019d6b8fSAnthony Liguori header.desc_offset = cpu_to_le64(header.desc_offset); 1682019d6b8fSAnthony Liguori header.desc_size = cpu_to_le64(header.desc_size); 1683019d6b8fSAnthony Liguori header.rgd_offset = cpu_to_le64(header.rgd_offset); 1684019d6b8fSAnthony Liguori header.gd_offset = cpu_to_le64(header.gd_offset); 1685019d6b8fSAnthony Liguori header.grain_offset = cpu_to_le64(header.grain_offset); 16866c031aacSFam Zheng header.compressAlgorithm = cpu_to_le16(header.compressAlgorithm); 1687019d6b8fSAnthony Liguori 1688019d6b8fSAnthony Liguori header.check_bytes[0] = 0xa; 1689019d6b8fSAnthony Liguori header.check_bytes[1] = 0x20; 1690019d6b8fSAnthony Liguori header.check_bytes[2] = 0xd; 1691019d6b8fSAnthony Liguori header.check_bytes[3] = 0xa; 1692019d6b8fSAnthony Liguori 1693019d6b8fSAnthony Liguori /* write all the data */ 1694917703c1SFam Zheng ret = bdrv_pwrite(bs, 0, &magic, sizeof(magic)); 1695917703c1SFam Zheng if (ret < 0) { 1696917703c1SFam Zheng error_set(errp, QERR_IO_ERROR); 16971640366cSKirill A. Shutemov goto exit; 16981640366cSKirill A. Shutemov } 1699917703c1SFam Zheng ret = bdrv_pwrite(bs, sizeof(magic), &header, sizeof(header)); 1700917703c1SFam Zheng if (ret < 0) { 1701917703c1SFam Zheng error_set(errp, QERR_IO_ERROR); 17021640366cSKirill A. Shutemov goto exit; 17031640366cSKirill A. Shutemov } 1704019d6b8fSAnthony Liguori 1705917703c1SFam Zheng ret = bdrv_truncate(bs, le64_to_cpu(header.grain_offset) << 9); 17061640366cSKirill A. Shutemov if (ret < 0) { 170739a611a3SJeff Cody error_setg_errno(errp, -ret, "Could not truncate file"); 17081640366cSKirill A. Shutemov goto exit; 17091640366cSKirill A. Shutemov } 1710019d6b8fSAnthony Liguori 1711019d6b8fSAnthony Liguori /* write grain directory */ 1712917703c1SFam Zheng gd_buf_size = gd_sectors * BDRV_SECTOR_SIZE; 1713917703c1SFam Zheng gd_buf = g_malloc0(gd_buf_size); 1714917703c1SFam Zheng for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_sectors; 17151640366cSKirill A. Shutemov i < gt_count; i++, tmp += gt_size) { 1716917703c1SFam Zheng gd_buf[i] = cpu_to_le32(tmp); 17171640366cSKirill A. Shutemov } 1718917703c1SFam Zheng ret = bdrv_pwrite(bs, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE, 1719917703c1SFam Zheng gd_buf, gd_buf_size); 1720917703c1SFam Zheng if (ret < 0) { 1721917703c1SFam Zheng error_set(errp, QERR_IO_ERROR); 1722917703c1SFam Zheng goto exit; 17231640366cSKirill A. Shutemov } 1724019d6b8fSAnthony Liguori 1725019d6b8fSAnthony Liguori /* write backup grain directory */ 1726917703c1SFam Zheng for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_sectors; 17271640366cSKirill A. Shutemov i < gt_count; i++, tmp += gt_size) { 1728917703c1SFam Zheng gd_buf[i] = cpu_to_le32(tmp); 17291640366cSKirill A. Shutemov } 1730917703c1SFam Zheng ret = bdrv_pwrite(bs, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE, 1731917703c1SFam Zheng gd_buf, gd_buf_size); 1732917703c1SFam Zheng if (ret < 0) { 1733917703c1SFam Zheng error_set(errp, QERR_IO_ERROR); 1734917703c1SFam Zheng goto exit; 17351640366cSKirill A. Shutemov } 1736019d6b8fSAnthony Liguori 1737f66fd6c3SFam Zheng ret = 0; 1738f66fd6c3SFam Zheng exit: 1739917703c1SFam Zheng if (bs) { 1740917703c1SFam Zheng bdrv_unref(bs); 1741917703c1SFam Zheng } 1742917703c1SFam Zheng g_free(gd_buf); 1743f66fd6c3SFam Zheng return ret; 1744f66fd6c3SFam Zheng } 1745019d6b8fSAnthony Liguori 1746f66fd6c3SFam Zheng static int filename_decompose(const char *filename, char *path, char *prefix, 17474823970bSFam Zheng char *postfix, size_t buf_len, Error **errp) 1748f66fd6c3SFam Zheng { 1749f66fd6c3SFam Zheng const char *p, *q; 1750f66fd6c3SFam Zheng 1751f66fd6c3SFam Zheng if (filename == NULL || !strlen(filename)) { 17524823970bSFam Zheng error_setg(errp, "No filename provided"); 175365f74725SFam Zheng return VMDK_ERROR; 1754f66fd6c3SFam Zheng } 1755f66fd6c3SFam Zheng p = strrchr(filename, '/'); 1756f66fd6c3SFam Zheng if (p == NULL) { 1757f66fd6c3SFam Zheng p = strrchr(filename, '\\'); 1758f66fd6c3SFam Zheng } 1759f66fd6c3SFam Zheng if (p == NULL) { 1760f66fd6c3SFam Zheng p = strrchr(filename, ':'); 1761f66fd6c3SFam Zheng } 1762f66fd6c3SFam Zheng if (p != NULL) { 1763f66fd6c3SFam Zheng p++; 1764f66fd6c3SFam Zheng if (p - filename >= buf_len) { 176565f74725SFam Zheng return VMDK_ERROR; 1766f66fd6c3SFam Zheng } 1767f66fd6c3SFam Zheng pstrcpy(path, p - filename + 1, filename); 1768f66fd6c3SFam Zheng } else { 1769f66fd6c3SFam Zheng p = filename; 1770f66fd6c3SFam Zheng path[0] = '\0'; 1771f66fd6c3SFam Zheng } 1772f66fd6c3SFam Zheng q = strrchr(p, '.'); 1773f66fd6c3SFam Zheng if (q == NULL) { 1774f66fd6c3SFam Zheng pstrcpy(prefix, buf_len, p); 1775f66fd6c3SFam Zheng postfix[0] = '\0'; 1776f66fd6c3SFam Zheng } else { 1777f66fd6c3SFam Zheng if (q - p >= buf_len) { 177865f74725SFam Zheng return VMDK_ERROR; 1779f66fd6c3SFam Zheng } 1780f66fd6c3SFam Zheng pstrcpy(prefix, q - p + 1, p); 1781f66fd6c3SFam Zheng pstrcpy(postfix, buf_len, q); 1782f66fd6c3SFam Zheng } 178365f74725SFam Zheng return VMDK_OK; 1784f66fd6c3SFam Zheng } 1785f66fd6c3SFam Zheng 17865820f1daSChunyan Liu static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) 1787f66fd6c3SFam Zheng { 1788917703c1SFam Zheng int idx = 0; 1789917703c1SFam Zheng BlockDriverState *new_bs = NULL; 1790c13959c7SFam Zheng Error *local_err = NULL; 1791af057fe7SFam Zheng char *desc = NULL; 1792f66fd6c3SFam Zheng int64_t total_size = 0, filesize; 17935820f1daSChunyan Liu char *adapter_type = NULL; 17945820f1daSChunyan Liu char *backing_file = NULL; 17955820f1daSChunyan Liu char *fmt = NULL; 1796f66fd6c3SFam Zheng int flags = 0; 1797f66fd6c3SFam Zheng int ret = 0; 17986c031aacSFam Zheng bool flat, split, compress; 1799af057fe7SFam Zheng GString *ext_desc_lines; 1800f66fd6c3SFam Zheng char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX]; 1801f66fd6c3SFam Zheng const int64_t split_size = 0x80000000; /* VMDK has constant split size */ 1802f66fd6c3SFam Zheng const char *desc_extent_line; 1803f66fd6c3SFam Zheng char parent_desc_line[BUF_SIZE] = ""; 1804f66fd6c3SFam Zheng uint32_t parent_cid = 0xffffffff; 18057f2039f6SOthmar Pasteka uint32_t number_heads = 16; 180669e0b6dfSFam Zheng bool zeroed_grain = false; 1807917703c1SFam Zheng uint32_t desc_offset = 0, desc_len; 1808f66fd6c3SFam Zheng const char desc_template[] = 1809f66fd6c3SFam Zheng "# Disk DescriptorFile\n" 1810f66fd6c3SFam Zheng "version=1\n" 18119b17031aSFam Zheng "CID=%" PRIx32 "\n" 18129b17031aSFam Zheng "parentCID=%" PRIx32 "\n" 1813f66fd6c3SFam Zheng "createType=\"%s\"\n" 1814f66fd6c3SFam Zheng "%s" 1815f66fd6c3SFam Zheng "\n" 1816f66fd6c3SFam Zheng "# Extent description\n" 1817f66fd6c3SFam Zheng "%s" 1818f66fd6c3SFam Zheng "\n" 1819f66fd6c3SFam Zheng "# The Disk Data Base\n" 1820f66fd6c3SFam Zheng "#DDB\n" 1821f66fd6c3SFam Zheng "\n" 1822f66fd6c3SFam Zheng "ddb.virtualHWVersion = \"%d\"\n" 1823f66fd6c3SFam Zheng "ddb.geometry.cylinders = \"%" PRId64 "\"\n" 18244ab9dab5SFam Zheng "ddb.geometry.heads = \"%" PRIu32 "\"\n" 1825f66fd6c3SFam Zheng "ddb.geometry.sectors = \"63\"\n" 18267f2039f6SOthmar Pasteka "ddb.adapterType = \"%s\"\n"; 1827f66fd6c3SFam Zheng 1828af057fe7SFam Zheng ext_desc_lines = g_string_new(NULL); 1829af057fe7SFam Zheng 18304823970bSFam Zheng if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) { 1831af057fe7SFam Zheng ret = -EINVAL; 1832af057fe7SFam Zheng goto exit; 1833f66fd6c3SFam Zheng } 1834f66fd6c3SFam Zheng /* Read out options */ 1835c2eb918eSHu Tao total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), 1836c2eb918eSHu Tao BDRV_SECTOR_SIZE); 18375820f1daSChunyan Liu adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE); 18385820f1daSChunyan Liu backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); 18395820f1daSChunyan Liu if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) { 18405820f1daSChunyan Liu flags |= BLOCK_FLAG_COMPAT6; 1841f66fd6c3SFam Zheng } 18425820f1daSChunyan Liu fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); 18435820f1daSChunyan Liu if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false)) { 18445820f1daSChunyan Liu zeroed_grain = true; 1845f66fd6c3SFam Zheng } 18465820f1daSChunyan Liu 18477f2039f6SOthmar Pasteka if (!adapter_type) { 18485820f1daSChunyan Liu adapter_type = g_strdup("ide"); 18497f2039f6SOthmar Pasteka } else if (strcmp(adapter_type, "ide") && 18507f2039f6SOthmar Pasteka strcmp(adapter_type, "buslogic") && 18517f2039f6SOthmar Pasteka strcmp(adapter_type, "lsilogic") && 18527f2039f6SOthmar Pasteka strcmp(adapter_type, "legacyESX")) { 18534823970bSFam Zheng error_setg(errp, "Unknown adapter type: '%s'", adapter_type); 1854af057fe7SFam Zheng ret = -EINVAL; 1855af057fe7SFam Zheng goto exit; 18567f2039f6SOthmar Pasteka } 18577f2039f6SOthmar Pasteka if (strcmp(adapter_type, "ide") != 0) { 18587f2039f6SOthmar Pasteka /* that's the number of heads with which vmware operates when 18597f2039f6SOthmar Pasteka creating, exporting, etc. vmdk files with a non-ide adapter type */ 18607f2039f6SOthmar Pasteka number_heads = 255; 18617f2039f6SOthmar Pasteka } 1862f66fd6c3SFam Zheng if (!fmt) { 1863f66fd6c3SFam Zheng /* Default format to monolithicSparse */ 18645820f1daSChunyan Liu fmt = g_strdup("monolithicSparse"); 1865f66fd6c3SFam Zheng } else if (strcmp(fmt, "monolithicFlat") && 1866f66fd6c3SFam Zheng strcmp(fmt, "monolithicSparse") && 1867f66fd6c3SFam Zheng strcmp(fmt, "twoGbMaxExtentSparse") && 18686c031aacSFam Zheng strcmp(fmt, "twoGbMaxExtentFlat") && 18696c031aacSFam Zheng strcmp(fmt, "streamOptimized")) { 18704823970bSFam Zheng error_setg(errp, "Unknown subformat: '%s'", fmt); 1871af057fe7SFam Zheng ret = -EINVAL; 1872af057fe7SFam Zheng goto exit; 1873f66fd6c3SFam Zheng } 1874f66fd6c3SFam Zheng split = !(strcmp(fmt, "twoGbMaxExtentFlat") && 1875f66fd6c3SFam Zheng strcmp(fmt, "twoGbMaxExtentSparse")); 1876f66fd6c3SFam Zheng flat = !(strcmp(fmt, "monolithicFlat") && 1877f66fd6c3SFam Zheng strcmp(fmt, "twoGbMaxExtentFlat")); 18786c031aacSFam Zheng compress = !strcmp(fmt, "streamOptimized"); 1879f66fd6c3SFam Zheng if (flat) { 18804ab9dab5SFam Zheng desc_extent_line = "RW %" PRId64 " FLAT \"%s\" 0\n"; 1881f66fd6c3SFam Zheng } else { 18824ab9dab5SFam Zheng desc_extent_line = "RW %" PRId64 " SPARSE \"%s\"\n"; 1883f66fd6c3SFam Zheng } 1884f66fd6c3SFam Zheng if (flat && backing_file) { 18854823970bSFam Zheng error_setg(errp, "Flat image can't have backing file"); 1886af057fe7SFam Zheng ret = -ENOTSUP; 1887af057fe7SFam Zheng goto exit; 1888f66fd6c3SFam Zheng } 188952c8d629SFam Zheng if (flat && zeroed_grain) { 189052c8d629SFam Zheng error_setg(errp, "Flat image can't enable zeroed grain"); 1891af057fe7SFam Zheng ret = -ENOTSUP; 1892af057fe7SFam Zheng goto exit; 189352c8d629SFam Zheng } 1894f66fd6c3SFam Zheng if (backing_file) { 1895f67503e5SMax Reitz BlockDriverState *bs = NULL; 18961085daf9SMax Reitz char *full_backing = g_new0(char, PATH_MAX); 18971085daf9SMax Reitz bdrv_get_full_backing_filename_from_filename(filename, backing_file, 18981085daf9SMax Reitz full_backing, PATH_MAX, 18991085daf9SMax Reitz &local_err); 19001085daf9SMax Reitz if (local_err) { 19011085daf9SMax Reitz g_free(full_backing); 19021085daf9SMax Reitz error_propagate(errp, local_err); 19031085daf9SMax Reitz ret = -ENOENT; 19041085daf9SMax Reitz goto exit; 19051085daf9SMax Reitz } 19061085daf9SMax Reitz ret = bdrv_open(&bs, full_backing, NULL, NULL, BDRV_O_NO_BACKING, NULL, 1907ddf5636dSMax Reitz errp); 19081085daf9SMax Reitz g_free(full_backing); 1909f66fd6c3SFam Zheng if (ret != 0) { 1910af057fe7SFam Zheng goto exit; 1911f66fd6c3SFam Zheng } 1912f66fd6c3SFam Zheng if (strcmp(bs->drv->format_name, "vmdk")) { 19134f6fd349SFam Zheng bdrv_unref(bs); 1914af057fe7SFam Zheng ret = -EINVAL; 1915af057fe7SFam Zheng goto exit; 1916f66fd6c3SFam Zheng } 1917f66fd6c3SFam Zheng parent_cid = vmdk_read_cid(bs, 0); 19184f6fd349SFam Zheng bdrv_unref(bs); 1919f66fd6c3SFam Zheng snprintf(parent_desc_line, sizeof(parent_desc_line), 19208ed610a1SFam Zheng "parentFileNameHint=\"%s\"", backing_file); 1921f66fd6c3SFam Zheng } 1922f66fd6c3SFam Zheng 1923f66fd6c3SFam Zheng /* Create extents */ 1924f66fd6c3SFam Zheng filesize = total_size; 1925f66fd6c3SFam Zheng while (filesize > 0) { 1926f66fd6c3SFam Zheng char desc_line[BUF_SIZE]; 1927f66fd6c3SFam Zheng char ext_filename[PATH_MAX]; 1928f66fd6c3SFam Zheng char desc_filename[PATH_MAX]; 1929f66fd6c3SFam Zheng int64_t size = filesize; 1930f66fd6c3SFam Zheng 1931f66fd6c3SFam Zheng if (split && size > split_size) { 1932f66fd6c3SFam Zheng size = split_size; 1933f66fd6c3SFam Zheng } 1934f66fd6c3SFam Zheng if (split) { 1935f66fd6c3SFam Zheng snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s", 1936f66fd6c3SFam Zheng prefix, flat ? 'f' : 's', ++idx, postfix); 1937f66fd6c3SFam Zheng } else if (flat) { 1938f66fd6c3SFam Zheng snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s", 1939f66fd6c3SFam Zheng prefix, postfix); 1940f66fd6c3SFam Zheng } else { 1941f66fd6c3SFam Zheng snprintf(desc_filename, sizeof(desc_filename), "%s%s", 1942f66fd6c3SFam Zheng prefix, postfix); 1943f66fd6c3SFam Zheng } 1944f66fd6c3SFam Zheng snprintf(ext_filename, sizeof(ext_filename), "%s%s", 1945f66fd6c3SFam Zheng path, desc_filename); 1946f66fd6c3SFam Zheng 194769e0b6dfSFam Zheng if (vmdk_create_extent(ext_filename, size, 19484ab15590SChunyan Liu flat, compress, zeroed_grain, opts, errp)) { 1949af057fe7SFam Zheng ret = -EINVAL; 1950af057fe7SFam Zheng goto exit; 1951f66fd6c3SFam Zheng } 1952f66fd6c3SFam Zheng filesize -= size; 1953f66fd6c3SFam Zheng 1954f66fd6c3SFam Zheng /* Format description line */ 1955f66fd6c3SFam Zheng snprintf(desc_line, sizeof(desc_line), 1956917703c1SFam Zheng desc_extent_line, size / BDRV_SECTOR_SIZE, desc_filename); 1957af057fe7SFam Zheng g_string_append(ext_desc_lines, desc_line); 1958f66fd6c3SFam Zheng } 1959f66fd6c3SFam Zheng /* generate descriptor file */ 1960af057fe7SFam Zheng desc = g_strdup_printf(desc_template, 1961e5dc64b8SFam Zheng g_random_int(), 1962f66fd6c3SFam Zheng parent_cid, 1963f66fd6c3SFam Zheng fmt, 1964f66fd6c3SFam Zheng parent_desc_line, 1965af057fe7SFam Zheng ext_desc_lines->str, 1966f66fd6c3SFam Zheng (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), 1967917703c1SFam Zheng total_size / 1968917703c1SFam Zheng (int64_t)(63 * number_heads * BDRV_SECTOR_SIZE), 1969af057fe7SFam Zheng number_heads, 19707f2039f6SOthmar Pasteka adapter_type); 1971917703c1SFam Zheng desc_len = strlen(desc); 1972917703c1SFam Zheng /* the descriptor offset = 0x200 */ 1973917703c1SFam Zheng if (!split && !flat) { 1974917703c1SFam Zheng desc_offset = 0x200; 1975f66fd6c3SFam Zheng } else { 1976c282e1fdSChunyan Liu ret = bdrv_create_file(filename, opts, &local_err); 1977917703c1SFam Zheng if (ret < 0) { 1978c13959c7SFam Zheng error_propagate(errp, local_err); 1979af057fe7SFam Zheng goto exit; 1980f66fd6c3SFam Zheng } 1981f66fd6c3SFam Zheng } 19822e40134bSMax Reitz assert(new_bs == NULL); 19832e40134bSMax Reitz ret = bdrv_open(&new_bs, filename, NULL, NULL, 19842e40134bSMax Reitz BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); 1985917703c1SFam Zheng if (ret < 0) { 1986c13959c7SFam Zheng error_propagate(errp, local_err); 1987917703c1SFam Zheng goto exit; 19881640366cSKirill A. Shutemov } 1989917703c1SFam Zheng ret = bdrv_pwrite(new_bs, desc_offset, desc, desc_len); 1990917703c1SFam Zheng if (ret < 0) { 1991917703c1SFam Zheng error_setg_errno(errp, -ret, "Could not write description"); 1992917703c1SFam Zheng goto exit; 1993917703c1SFam Zheng } 1994917703c1SFam Zheng /* bdrv_pwrite write padding zeros to align to sector, we don't need that 1995917703c1SFam Zheng * for description file */ 1996917703c1SFam Zheng if (desc_offset == 0) { 1997917703c1SFam Zheng ret = bdrv_truncate(new_bs, desc_len); 1998917703c1SFam Zheng if (ret < 0) { 199939a611a3SJeff Cody error_setg_errno(errp, -ret, "Could not truncate file"); 2000917703c1SFam Zheng } 2001917703c1SFam Zheng } 2002af057fe7SFam Zheng exit: 2003917703c1SFam Zheng if (new_bs) { 2004917703c1SFam Zheng bdrv_unref(new_bs); 2005917703c1SFam Zheng } 20065820f1daSChunyan Liu g_free(adapter_type); 20075820f1daSChunyan Liu g_free(backing_file); 20085820f1daSChunyan Liu g_free(fmt); 2009af057fe7SFam Zheng g_free(desc); 2010af057fe7SFam Zheng g_string_free(ext_desc_lines, true); 20111640366cSKirill A. Shutemov return ret; 2012019d6b8fSAnthony Liguori } 2013019d6b8fSAnthony Liguori 2014019d6b8fSAnthony Liguori static void vmdk_close(BlockDriverState *bs) 2015019d6b8fSAnthony Liguori { 20162bc3166cSKevin Wolf BDRVVmdkState *s = bs->opaque; 20172bc3166cSKevin Wolf 2018b3976d3cSFam Zheng vmdk_free_extents(bs); 2019f4c129a3SFam Zheng g_free(s->create_type); 20202bc3166cSKevin Wolf 20212bc3166cSKevin Wolf migrate_del_blocker(s->migration_blocker); 20222bc3166cSKevin Wolf error_free(s->migration_blocker); 2023019d6b8fSAnthony Liguori } 2024019d6b8fSAnthony Liguori 20258b94ff85SPaolo Bonzini static coroutine_fn int vmdk_co_flush(BlockDriverState *bs) 2026019d6b8fSAnthony Liguori { 2027333c574dSFam Zheng BDRVVmdkState *s = bs->opaque; 202829cdb251SPaolo Bonzini int i, err; 202929cdb251SPaolo Bonzini int ret = 0; 2030333c574dSFam Zheng 2031333c574dSFam Zheng for (i = 0; i < s->num_extents; i++) { 20328b94ff85SPaolo Bonzini err = bdrv_co_flush(s->extents[i].file); 2033333c574dSFam Zheng if (err < 0) { 2034333c574dSFam Zheng ret = err; 2035333c574dSFam Zheng } 2036333c574dSFam Zheng } 2037333c574dSFam Zheng return ret; 2038019d6b8fSAnthony Liguori } 2039019d6b8fSAnthony Liguori 20404a1d5e1fSFam Zheng static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) 20414a1d5e1fSFam Zheng { 20424a1d5e1fSFam Zheng int i; 20434a1d5e1fSFam Zheng int64_t ret = 0; 20444a1d5e1fSFam Zheng int64_t r; 20454a1d5e1fSFam Zheng BDRVVmdkState *s = bs->opaque; 20464a1d5e1fSFam Zheng 20474a1d5e1fSFam Zheng ret = bdrv_get_allocated_file_size(bs->file); 20484a1d5e1fSFam Zheng if (ret < 0) { 20494a1d5e1fSFam Zheng return ret; 20504a1d5e1fSFam Zheng } 20514a1d5e1fSFam Zheng for (i = 0; i < s->num_extents; i++) { 20524a1d5e1fSFam Zheng if (s->extents[i].file == bs->file) { 20534a1d5e1fSFam Zheng continue; 20544a1d5e1fSFam Zheng } 20554a1d5e1fSFam Zheng r = bdrv_get_allocated_file_size(s->extents[i].file); 20564a1d5e1fSFam Zheng if (r < 0) { 20574a1d5e1fSFam Zheng return r; 20584a1d5e1fSFam Zheng } 20594a1d5e1fSFam Zheng ret += r; 20604a1d5e1fSFam Zheng } 20614a1d5e1fSFam Zheng return ret; 20624a1d5e1fSFam Zheng } 20630e7e1989SKevin Wolf 2064da7a50f9SFam Zheng static int vmdk_has_zero_init(BlockDriverState *bs) 2065da7a50f9SFam Zheng { 2066da7a50f9SFam Zheng int i; 2067da7a50f9SFam Zheng BDRVVmdkState *s = bs->opaque; 2068da7a50f9SFam Zheng 2069da7a50f9SFam Zheng /* If has a flat extent and its underlying storage doesn't have zero init, 2070da7a50f9SFam Zheng * return 0. */ 2071da7a50f9SFam Zheng for (i = 0; i < s->num_extents; i++) { 2072da7a50f9SFam Zheng if (s->extents[i].flat) { 2073da7a50f9SFam Zheng if (!bdrv_has_zero_init(s->extents[i].file)) { 2074da7a50f9SFam Zheng return 0; 2075da7a50f9SFam Zheng } 2076da7a50f9SFam Zheng } 2077da7a50f9SFam Zheng } 2078da7a50f9SFam Zheng return 1; 2079da7a50f9SFam Zheng } 2080da7a50f9SFam Zheng 2081f4c129a3SFam Zheng static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) 2082f4c129a3SFam Zheng { 2083f4c129a3SFam Zheng ImageInfo *info = g_new0(ImageInfo, 1); 2084f4c129a3SFam Zheng 2085f4c129a3SFam Zheng *info = (ImageInfo){ 2086f4c129a3SFam Zheng .filename = g_strdup(extent->file->filename), 2087f4c129a3SFam Zheng .format = g_strdup(extent->type), 2088f4c129a3SFam Zheng .virtual_size = extent->sectors * BDRV_SECTOR_SIZE, 2089f4c129a3SFam Zheng .compressed = extent->compressed, 2090f4c129a3SFam Zheng .has_compressed = extent->compressed, 2091f4c129a3SFam Zheng .cluster_size = extent->cluster_sectors * BDRV_SECTOR_SIZE, 2092f4c129a3SFam Zheng .has_cluster_size = !extent->flat, 2093f4c129a3SFam Zheng }; 2094f4c129a3SFam Zheng 2095f4c129a3SFam Zheng return info; 2096f4c129a3SFam Zheng } 2097f4c129a3SFam Zheng 2098f43aa8e1SPeter Lieven static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result, 2099f43aa8e1SPeter Lieven BdrvCheckMode fix) 2100f43aa8e1SPeter Lieven { 2101f43aa8e1SPeter Lieven BDRVVmdkState *s = bs->opaque; 2102f43aa8e1SPeter Lieven VmdkExtent *extent = NULL; 2103f43aa8e1SPeter Lieven int64_t sector_num = 0; 210457322b78SMarkus Armbruster int64_t total_sectors = bdrv_nb_sectors(bs); 2105f43aa8e1SPeter Lieven int ret; 2106f43aa8e1SPeter Lieven uint64_t cluster_offset; 2107f43aa8e1SPeter Lieven 2108f43aa8e1SPeter Lieven if (fix) { 2109f43aa8e1SPeter Lieven return -ENOTSUP; 2110f43aa8e1SPeter Lieven } 2111f43aa8e1SPeter Lieven 2112f43aa8e1SPeter Lieven for (;;) { 2113f43aa8e1SPeter Lieven if (sector_num >= total_sectors) { 2114f43aa8e1SPeter Lieven return 0; 2115f43aa8e1SPeter Lieven } 2116f43aa8e1SPeter Lieven extent = find_extent(s, sector_num, extent); 2117f43aa8e1SPeter Lieven if (!extent) { 2118f43aa8e1SPeter Lieven fprintf(stderr, 2119f43aa8e1SPeter Lieven "ERROR: could not find extent for sector %" PRId64 "\n", 2120f43aa8e1SPeter Lieven sector_num); 2121f43aa8e1SPeter Lieven break; 2122f43aa8e1SPeter Lieven } 2123f43aa8e1SPeter Lieven ret = get_cluster_offset(bs, extent, NULL, 2124f43aa8e1SPeter Lieven sector_num << BDRV_SECTOR_BITS, 2125c6ac36e1SFam Zheng false, &cluster_offset, 0, 0); 2126f43aa8e1SPeter Lieven if (ret == VMDK_ERROR) { 2127f43aa8e1SPeter Lieven fprintf(stderr, 2128f43aa8e1SPeter Lieven "ERROR: could not get cluster_offset for sector %" 2129f43aa8e1SPeter Lieven PRId64 "\n", sector_num); 2130f43aa8e1SPeter Lieven break; 2131f43aa8e1SPeter Lieven } 2132f43aa8e1SPeter Lieven if (ret == VMDK_OK && cluster_offset >= bdrv_getlength(extent->file)) { 2133f43aa8e1SPeter Lieven fprintf(stderr, 2134f43aa8e1SPeter Lieven "ERROR: cluster offset for sector %" 2135f43aa8e1SPeter Lieven PRId64 " points after EOF\n", sector_num); 2136f43aa8e1SPeter Lieven break; 2137f43aa8e1SPeter Lieven } 2138f43aa8e1SPeter Lieven sector_num += extent->cluster_sectors; 2139f43aa8e1SPeter Lieven } 2140f43aa8e1SPeter Lieven 2141f43aa8e1SPeter Lieven result->corruptions++; 2142f43aa8e1SPeter Lieven return 0; 2143f43aa8e1SPeter Lieven } 2144f43aa8e1SPeter Lieven 2145f4c129a3SFam Zheng static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs) 2146f4c129a3SFam Zheng { 2147f4c129a3SFam Zheng int i; 2148f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 2149f4c129a3SFam Zheng ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1); 2150f4c129a3SFam Zheng ImageInfoList **next; 2151f4c129a3SFam Zheng 2152f4c129a3SFam Zheng *spec_info = (ImageInfoSpecific){ 2153f4c129a3SFam Zheng .kind = IMAGE_INFO_SPECIFIC_KIND_VMDK, 2154f4c129a3SFam Zheng { 2155f4c129a3SFam Zheng .vmdk = g_new0(ImageInfoSpecificVmdk, 1), 2156f4c129a3SFam Zheng }, 2157f4c129a3SFam Zheng }; 2158f4c129a3SFam Zheng 2159f4c129a3SFam Zheng *spec_info->vmdk = (ImageInfoSpecificVmdk) { 2160f4c129a3SFam Zheng .create_type = g_strdup(s->create_type), 2161f4c129a3SFam Zheng .cid = s->cid, 2162f4c129a3SFam Zheng .parent_cid = s->parent_cid, 2163f4c129a3SFam Zheng }; 2164f4c129a3SFam Zheng 2165f4c129a3SFam Zheng next = &spec_info->vmdk->extents; 2166f4c129a3SFam Zheng for (i = 0; i < s->num_extents; i++) { 2167f4c129a3SFam Zheng *next = g_new0(ImageInfoList, 1); 2168f4c129a3SFam Zheng (*next)->value = vmdk_get_extent_info(&s->extents[i]); 2169f4c129a3SFam Zheng (*next)->next = NULL; 2170f4c129a3SFam Zheng next = &(*next)->next; 2171f4c129a3SFam Zheng } 2172f4c129a3SFam Zheng 2173f4c129a3SFam Zheng return spec_info; 2174f4c129a3SFam Zheng } 2175f4c129a3SFam Zheng 21765f583307SFam Zheng static bool vmdk_extents_type_eq(const VmdkExtent *a, const VmdkExtent *b) 21775f583307SFam Zheng { 21785f583307SFam Zheng return a->flat == b->flat && 21795f583307SFam Zheng a->compressed == b->compressed && 21805f583307SFam Zheng (a->flat || a->cluster_sectors == b->cluster_sectors); 21815f583307SFam Zheng } 21825f583307SFam Zheng 218374fe188cSFam Zheng static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) 218474fe188cSFam Zheng { 218574fe188cSFam Zheng int i; 218674fe188cSFam Zheng BDRVVmdkState *s = bs->opaque; 218774fe188cSFam Zheng assert(s->num_extents); 21885f583307SFam Zheng 21895f583307SFam Zheng /* See if we have multiple extents but they have different cases */ 21905f583307SFam Zheng for (i = 1; i < s->num_extents; i++) { 21915f583307SFam Zheng if (!vmdk_extents_type_eq(&s->extents[0], &s->extents[i])) { 21925f583307SFam Zheng return -ENOTSUP; 21935f583307SFam Zheng } 21945f583307SFam Zheng } 219574fe188cSFam Zheng bdi->needs_compressed_writes = s->extents[0].compressed; 219674fe188cSFam Zheng if (!s->extents[0].flat) { 219774fe188cSFam Zheng bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS; 219874fe188cSFam Zheng } 219974fe188cSFam Zheng return 0; 220074fe188cSFam Zheng } 220174fe188cSFam Zheng 2202c75f3bdfSStefan Hajnoczi static void vmdk_detach_aio_context(BlockDriverState *bs) 2203c75f3bdfSStefan Hajnoczi { 2204c75f3bdfSStefan Hajnoczi BDRVVmdkState *s = bs->opaque; 2205c75f3bdfSStefan Hajnoczi int i; 2206c75f3bdfSStefan Hajnoczi 2207c75f3bdfSStefan Hajnoczi for (i = 0; i < s->num_extents; i++) { 2208c75f3bdfSStefan Hajnoczi bdrv_detach_aio_context(s->extents[i].file); 2209c75f3bdfSStefan Hajnoczi } 2210c75f3bdfSStefan Hajnoczi } 2211c75f3bdfSStefan Hajnoczi 2212c75f3bdfSStefan Hajnoczi static void vmdk_attach_aio_context(BlockDriverState *bs, 2213c75f3bdfSStefan Hajnoczi AioContext *new_context) 2214c75f3bdfSStefan Hajnoczi { 2215c75f3bdfSStefan Hajnoczi BDRVVmdkState *s = bs->opaque; 2216c75f3bdfSStefan Hajnoczi int i; 2217c75f3bdfSStefan Hajnoczi 2218c75f3bdfSStefan Hajnoczi for (i = 0; i < s->num_extents; i++) { 2219c75f3bdfSStefan Hajnoczi bdrv_attach_aio_context(s->extents[i].file, new_context); 2220c75f3bdfSStefan Hajnoczi } 2221c75f3bdfSStefan Hajnoczi } 2222c75f3bdfSStefan Hajnoczi 22235820f1daSChunyan Liu static QemuOptsList vmdk_create_opts = { 22245820f1daSChunyan Liu .name = "vmdk-create-opts", 22255820f1daSChunyan Liu .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head), 22265820f1daSChunyan Liu .desc = { 2227db08adf5SKevin Wolf { 2228db08adf5SKevin Wolf .name = BLOCK_OPT_SIZE, 22295820f1daSChunyan Liu .type = QEMU_OPT_SIZE, 2230db08adf5SKevin Wolf .help = "Virtual disk size" 2231db08adf5SKevin Wolf }, 2232db08adf5SKevin Wolf { 22337f2039f6SOthmar Pasteka .name = BLOCK_OPT_ADAPTER_TYPE, 22345820f1daSChunyan Liu .type = QEMU_OPT_STRING, 22357f2039f6SOthmar Pasteka .help = "Virtual adapter type, can be one of " 22367f2039f6SOthmar Pasteka "ide (default), lsilogic, buslogic or legacyESX" 22377f2039f6SOthmar Pasteka }, 22387f2039f6SOthmar Pasteka { 2239db08adf5SKevin Wolf .name = BLOCK_OPT_BACKING_FILE, 22405820f1daSChunyan Liu .type = QEMU_OPT_STRING, 2241db08adf5SKevin Wolf .help = "File name of a base image" 2242db08adf5SKevin Wolf }, 2243db08adf5SKevin Wolf { 2244db08adf5SKevin Wolf .name = BLOCK_OPT_COMPAT6, 22455820f1daSChunyan Liu .type = QEMU_OPT_BOOL, 22465820f1daSChunyan Liu .help = "VMDK version 6 image", 22475820f1daSChunyan Liu .def_value_str = "off" 2248db08adf5SKevin Wolf }, 2249f66fd6c3SFam Zheng { 2250f66fd6c3SFam Zheng .name = BLOCK_OPT_SUBFMT, 22515820f1daSChunyan Liu .type = QEMU_OPT_STRING, 2252f66fd6c3SFam Zheng .help = 2253f66fd6c3SFam Zheng "VMDK flat extent format, can be one of " 22546c031aacSFam Zheng "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} " 2255f66fd6c3SFam Zheng }, 225669e0b6dfSFam Zheng { 225769e0b6dfSFam Zheng .name = BLOCK_OPT_ZEROED_GRAIN, 22585820f1daSChunyan Liu .type = QEMU_OPT_BOOL, 22595820f1daSChunyan Liu .help = "Enable efficient zero writes " 22605820f1daSChunyan Liu "using the zeroed-grain GTE feature" 226169e0b6dfSFam Zheng }, 22625820f1daSChunyan Liu { /* end of list */ } 22635820f1daSChunyan Liu } 22640e7e1989SKevin Wolf }; 22650e7e1989SKevin Wolf 2266019d6b8fSAnthony Liguori static BlockDriver bdrv_vmdk = { 2267019d6b8fSAnthony Liguori .format_name = "vmdk", 2268019d6b8fSAnthony Liguori .instance_size = sizeof(BDRVVmdkState), 2269019d6b8fSAnthony Liguori .bdrv_probe = vmdk_probe, 22706511ef77SKevin Wolf .bdrv_open = vmdk_open, 2271f43aa8e1SPeter Lieven .bdrv_check = vmdk_check, 22723897575fSJeff Cody .bdrv_reopen_prepare = vmdk_reopen_prepare, 22732914caa0SPaolo Bonzini .bdrv_read = vmdk_co_read, 2274e183ef75SPaolo Bonzini .bdrv_write = vmdk_co_write, 2275ba0ad89eSFam Zheng .bdrv_write_compressed = vmdk_write_compressed, 2276cdeaf1f1SFam Zheng .bdrv_co_write_zeroes = vmdk_co_write_zeroes, 2277019d6b8fSAnthony Liguori .bdrv_close = vmdk_close, 2278c282e1fdSChunyan Liu .bdrv_create = vmdk_create, 2279c68b89acSKevin Wolf .bdrv_co_flush_to_disk = vmdk_co_flush, 2280b6b8a333SPaolo Bonzini .bdrv_co_get_block_status = vmdk_co_get_block_status, 22814a1d5e1fSFam Zheng .bdrv_get_allocated_file_size = vmdk_get_allocated_file_size, 2282da7a50f9SFam Zheng .bdrv_has_zero_init = vmdk_has_zero_init, 2283f4c129a3SFam Zheng .bdrv_get_specific_info = vmdk_get_specific_info, 2284d34682cdSKevin Wolf .bdrv_refresh_limits = vmdk_refresh_limits, 228574fe188cSFam Zheng .bdrv_get_info = vmdk_get_info, 2286c75f3bdfSStefan Hajnoczi .bdrv_detach_aio_context = vmdk_detach_aio_context, 2287c75f3bdfSStefan Hajnoczi .bdrv_attach_aio_context = vmdk_attach_aio_context, 22880e7e1989SKevin Wolf 22898ee79e70SKevin Wolf .supports_backing = true, 22905820f1daSChunyan Liu .create_opts = &vmdk_create_opts, 2291019d6b8fSAnthony Liguori }; 2292019d6b8fSAnthony Liguori 2293019d6b8fSAnthony Liguori static void bdrv_vmdk_init(void) 2294019d6b8fSAnthony Liguori { 2295019d6b8fSAnthony Liguori bdrv_register(&bdrv_vmdk); 2296019d6b8fSAnthony Liguori } 2297019d6b8fSAnthony Liguori 2298019d6b8fSAnthony Liguori block_init(bdrv_vmdk_init); 2299