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> 31019d6b8fSAnthony Liguori 32019d6b8fSAnthony Liguori #define VMDK3_MAGIC (('C' << 24) | ('O' << 16) | ('W' << 8) | 'D') 33019d6b8fSAnthony Liguori #define VMDK4_MAGIC (('K' << 24) | ('D' << 16) | ('M' << 8) | 'V') 34432bb170SFam Zheng #define VMDK4_COMPRESSION_DEFLATE 1 3595b0aa42SFam Zheng #define VMDK4_FLAG_NL_DETECT (1 << 0) 36bb45ded9SFam Zheng #define VMDK4_FLAG_RGD (1 << 1) 3714ead646SFam Zheng /* Zeroed-grain enable bit */ 3814ead646SFam Zheng #define VMDK4_FLAG_ZERO_GRAIN (1 << 2) 39432bb170SFam Zheng #define VMDK4_FLAG_COMPRESS (1 << 16) 40432bb170SFam Zheng #define VMDK4_FLAG_MARKER (1 << 17) 4165bd155cSKevin Wolf #define VMDK4_GD_AT_END 0xffffffffffffffffULL 42019d6b8fSAnthony Liguori 4314ead646SFam Zheng #define VMDK_GTE_ZEROED 0x1 4465f74725SFam Zheng 4565f74725SFam Zheng /* VMDK internal error codes */ 4665f74725SFam Zheng #define VMDK_OK 0 4765f74725SFam Zheng #define VMDK_ERROR (-1) 4865f74725SFam Zheng /* Cluster not allocated */ 4965f74725SFam Zheng #define VMDK_UNALLOC (-2) 5065f74725SFam Zheng #define VMDK_ZEROED (-3) 5165f74725SFam Zheng 5269e0b6dfSFam Zheng #define BLOCK_OPT_ZEROED_GRAIN "zeroed_grain" 5369e0b6dfSFam Zheng 54019d6b8fSAnthony Liguori typedef struct { 55019d6b8fSAnthony Liguori uint32_t version; 56019d6b8fSAnthony Liguori uint32_t flags; 57019d6b8fSAnthony Liguori uint32_t disk_sectors; 58019d6b8fSAnthony Liguori uint32_t granularity; 59019d6b8fSAnthony Liguori uint32_t l1dir_offset; 60019d6b8fSAnthony Liguori uint32_t l1dir_size; 61019d6b8fSAnthony Liguori uint32_t file_sectors; 62019d6b8fSAnthony Liguori uint32_t cylinders; 63019d6b8fSAnthony Liguori uint32_t heads; 64019d6b8fSAnthony Liguori uint32_t sectors_per_track; 655d8caa54SFam Zheng } QEMU_PACKED VMDK3Header; 66019d6b8fSAnthony Liguori 67019d6b8fSAnthony Liguori typedef struct { 68019d6b8fSAnthony Liguori uint32_t version; 69019d6b8fSAnthony Liguori uint32_t flags; 70e98768d4SFam Zheng uint64_t capacity; 71e98768d4SFam Zheng uint64_t granularity; 72e98768d4SFam Zheng uint64_t desc_offset; 73e98768d4SFam Zheng uint64_t desc_size; 74ca8804ceSFam Zheng /* Number of GrainTableEntries per GrainTable */ 75ca8804ceSFam Zheng uint32_t num_gtes_per_gt; 76e98768d4SFam Zheng uint64_t rgd_offset; 77e98768d4SFam Zheng uint64_t gd_offset; 78e98768d4SFam Zheng uint64_t grain_offset; 79019d6b8fSAnthony Liguori char filler[1]; 80019d6b8fSAnthony Liguori char check_bytes[4]; 81432bb170SFam Zheng uint16_t compressAlgorithm; 82541dc0d4SStefan Weil } QEMU_PACKED VMDK4Header; 83019d6b8fSAnthony Liguori 84019d6b8fSAnthony Liguori #define L2_CACHE_SIZE 16 85019d6b8fSAnthony Liguori 86b3976d3cSFam Zheng typedef struct VmdkExtent { 87b3976d3cSFam Zheng BlockDriverState *file; 88b3976d3cSFam Zheng bool flat; 89432bb170SFam Zheng bool compressed; 90432bb170SFam Zheng bool has_marker; 9114ead646SFam Zheng bool has_zero_grain; 9214ead646SFam Zheng int version; 93b3976d3cSFam Zheng int64_t sectors; 94b3976d3cSFam Zheng int64_t end_sector; 957fa60fa3SFam Zheng int64_t flat_start_offset; 96019d6b8fSAnthony Liguori int64_t l1_table_offset; 97019d6b8fSAnthony Liguori int64_t l1_backup_table_offset; 98019d6b8fSAnthony Liguori uint32_t *l1_table; 99019d6b8fSAnthony Liguori uint32_t *l1_backup_table; 100019d6b8fSAnthony Liguori unsigned int l1_size; 101019d6b8fSAnthony Liguori uint32_t l1_entry_sectors; 102019d6b8fSAnthony Liguori 103019d6b8fSAnthony Liguori unsigned int l2_size; 104019d6b8fSAnthony Liguori uint32_t *l2_cache; 105019d6b8fSAnthony Liguori uint32_t l2_cache_offsets[L2_CACHE_SIZE]; 106019d6b8fSAnthony Liguori uint32_t l2_cache_counts[L2_CACHE_SIZE]; 107019d6b8fSAnthony Liguori 108301c7d38SFam Zheng int64_t cluster_sectors; 109f4c129a3SFam Zheng char *type; 110b3976d3cSFam Zheng } VmdkExtent; 111b3976d3cSFam Zheng 112b3976d3cSFam Zheng typedef struct BDRVVmdkState { 113848c66e8SPaolo Bonzini CoMutex lock; 114e98768d4SFam Zheng uint64_t desc_offset; 11569b4d86dSFam Zheng bool cid_updated; 116c338b6adSFam Zheng bool cid_checked; 117f4c129a3SFam Zheng uint32_t cid; 118019d6b8fSAnthony Liguori uint32_t parent_cid; 119b3976d3cSFam Zheng int num_extents; 120b3976d3cSFam Zheng /* Extent array with num_extents entries, ascend ordered by address */ 121b3976d3cSFam Zheng VmdkExtent *extents; 1222bc3166cSKevin Wolf Error *migration_blocker; 123f4c129a3SFam Zheng char *create_type; 124019d6b8fSAnthony Liguori } BDRVVmdkState; 125019d6b8fSAnthony Liguori 126019d6b8fSAnthony Liguori typedef struct VmdkMetaData { 127019d6b8fSAnthony Liguori uint32_t offset; 128019d6b8fSAnthony Liguori unsigned int l1_index; 129019d6b8fSAnthony Liguori unsigned int l2_index; 130019d6b8fSAnthony Liguori unsigned int l2_offset; 131019d6b8fSAnthony Liguori int valid; 132cdeaf1f1SFam Zheng uint32_t *l2_cache_entry; 133019d6b8fSAnthony Liguori } VmdkMetaData; 134019d6b8fSAnthony Liguori 135432bb170SFam Zheng typedef struct VmdkGrainMarker { 136432bb170SFam Zheng uint64_t lba; 137432bb170SFam Zheng uint32_t size; 138432bb170SFam Zheng uint8_t data[0]; 1395d8caa54SFam Zheng } QEMU_PACKED VmdkGrainMarker; 140432bb170SFam Zheng 14165bd155cSKevin Wolf enum { 14265bd155cSKevin Wolf MARKER_END_OF_STREAM = 0, 14365bd155cSKevin Wolf MARKER_GRAIN_TABLE = 1, 14465bd155cSKevin Wolf MARKER_GRAIN_DIRECTORY = 2, 14565bd155cSKevin Wolf MARKER_FOOTER = 3, 14665bd155cSKevin Wolf }; 14765bd155cSKevin Wolf 148019d6b8fSAnthony Liguori static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) 149019d6b8fSAnthony Liguori { 150019d6b8fSAnthony Liguori uint32_t magic; 151019d6b8fSAnthony Liguori 152ae261c86SFam Zheng if (buf_size < 4) { 153019d6b8fSAnthony Liguori return 0; 154ae261c86SFam Zheng } 155019d6b8fSAnthony Liguori magic = be32_to_cpu(*(uint32_t *)buf); 156019d6b8fSAnthony Liguori if (magic == VMDK3_MAGIC || 15701fc99d6SFam Zheng magic == VMDK4_MAGIC) { 158019d6b8fSAnthony Liguori return 100; 15901fc99d6SFam Zheng } else { 16001fc99d6SFam Zheng const char *p = (const char *)buf; 16101fc99d6SFam Zheng const char *end = p + buf_size; 16201fc99d6SFam Zheng while (p < end) { 16301fc99d6SFam Zheng if (*p == '#') { 16401fc99d6SFam Zheng /* skip comment line */ 16501fc99d6SFam Zheng while (p < end && *p != '\n') { 16601fc99d6SFam Zheng p++; 16701fc99d6SFam Zheng } 16801fc99d6SFam Zheng p++; 16901fc99d6SFam Zheng continue; 17001fc99d6SFam Zheng } 17101fc99d6SFam Zheng if (*p == ' ') { 17201fc99d6SFam Zheng while (p < end && *p == ' ') { 17301fc99d6SFam Zheng p++; 17401fc99d6SFam Zheng } 17501fc99d6SFam Zheng /* skip '\r' if windows line endings used. */ 17601fc99d6SFam Zheng if (p < end && *p == '\r') { 17701fc99d6SFam Zheng p++; 17801fc99d6SFam Zheng } 17901fc99d6SFam Zheng /* only accept blank lines before 'version=' line */ 18001fc99d6SFam Zheng if (p == end || *p != '\n') { 181019d6b8fSAnthony Liguori return 0; 182019d6b8fSAnthony Liguori } 18301fc99d6SFam Zheng p++; 18401fc99d6SFam Zheng continue; 18501fc99d6SFam Zheng } 18601fc99d6SFam Zheng if (end - p >= strlen("version=X\n")) { 18701fc99d6SFam Zheng if (strncmp("version=1\n", p, strlen("version=1\n")) == 0 || 18801fc99d6SFam Zheng strncmp("version=2\n", p, strlen("version=2\n")) == 0) { 18901fc99d6SFam Zheng return 100; 19001fc99d6SFam Zheng } 19101fc99d6SFam Zheng } 19201fc99d6SFam Zheng if (end - p >= strlen("version=X\r\n")) { 19301fc99d6SFam Zheng if (strncmp("version=1\r\n", p, strlen("version=1\r\n")) == 0 || 19401fc99d6SFam Zheng strncmp("version=2\r\n", p, strlen("version=2\r\n")) == 0) { 19501fc99d6SFam Zheng return 100; 19601fc99d6SFam Zheng } 19701fc99d6SFam Zheng } 19801fc99d6SFam Zheng return 0; 19901fc99d6SFam Zheng } 20001fc99d6SFam Zheng return 0; 20101fc99d6SFam Zheng } 20201fc99d6SFam Zheng } 203019d6b8fSAnthony Liguori 204019d6b8fSAnthony Liguori #define SECTOR_SIZE 512 205f66fd6c3SFam Zheng #define DESC_SIZE (20 * SECTOR_SIZE) /* 20 sectors of 512 bytes each */ 206f66fd6c3SFam Zheng #define BUF_SIZE 4096 207f66fd6c3SFam Zheng #define HEADER_SIZE 512 /* first sector of 512 bytes */ 208019d6b8fSAnthony Liguori 209b3976d3cSFam Zheng static void vmdk_free_extents(BlockDriverState *bs) 210b3976d3cSFam Zheng { 211b3976d3cSFam Zheng int i; 212b3976d3cSFam Zheng BDRVVmdkState *s = bs->opaque; 213b3c0bfb6SFam Zheng VmdkExtent *e; 214b3976d3cSFam Zheng 215b3976d3cSFam Zheng for (i = 0; i < s->num_extents; i++) { 216b3c0bfb6SFam Zheng e = &s->extents[i]; 217b3c0bfb6SFam Zheng g_free(e->l1_table); 218b3c0bfb6SFam Zheng g_free(e->l2_cache); 219b3c0bfb6SFam Zheng g_free(e->l1_backup_table); 220f4c129a3SFam Zheng g_free(e->type); 221b3c0bfb6SFam Zheng if (e->file != bs->file) { 2224f6fd349SFam Zheng bdrv_unref(e->file); 223b3c0bfb6SFam Zheng } 224b3976d3cSFam Zheng } 2257267c094SAnthony Liguori g_free(s->extents); 226b3976d3cSFam Zheng } 227b3976d3cSFam Zheng 22886c6b429SFam Zheng static void vmdk_free_last_extent(BlockDriverState *bs) 22986c6b429SFam Zheng { 23086c6b429SFam Zheng BDRVVmdkState *s = bs->opaque; 23186c6b429SFam Zheng 23286c6b429SFam Zheng if (s->num_extents == 0) { 23386c6b429SFam Zheng return; 23486c6b429SFam Zheng } 23586c6b429SFam Zheng s->num_extents--; 23686c6b429SFam Zheng s->extents = g_realloc(s->extents, s->num_extents * sizeof(VmdkExtent)); 23786c6b429SFam Zheng } 23886c6b429SFam Zheng 239019d6b8fSAnthony Liguori static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) 240019d6b8fSAnthony Liguori { 241019d6b8fSAnthony Liguori char desc[DESC_SIZE]; 2428379e46dSPavel Borzenkov uint32_t cid = 0xffffffff; 243019d6b8fSAnthony Liguori const char *p_name, *cid_str; 244019d6b8fSAnthony Liguori size_t cid_str_size; 245e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 24699f1835dSKevin Wolf int ret; 247019d6b8fSAnthony Liguori 24899f1835dSKevin Wolf ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); 24999f1835dSKevin Wolf if (ret < 0) { 250019d6b8fSAnthony Liguori return 0; 251e1da9b24SFam Zheng } 252019d6b8fSAnthony Liguori 253019d6b8fSAnthony Liguori if (parent) { 254019d6b8fSAnthony Liguori cid_str = "parentCID"; 255019d6b8fSAnthony Liguori cid_str_size = sizeof("parentCID"); 256019d6b8fSAnthony Liguori } else { 257019d6b8fSAnthony Liguori cid_str = "CID"; 258019d6b8fSAnthony Liguori cid_str_size = sizeof("CID"); 259019d6b8fSAnthony Liguori } 260019d6b8fSAnthony Liguori 26193897b9fSKevin Wolf desc[DESC_SIZE - 1] = '\0'; 262ae261c86SFam Zheng p_name = strstr(desc, cid_str); 263ae261c86SFam Zheng if (p_name != NULL) { 264019d6b8fSAnthony Liguori p_name += cid_str_size; 2659b17031aSFam Zheng sscanf(p_name, "%" SCNx32, &cid); 266019d6b8fSAnthony Liguori } 267019d6b8fSAnthony Liguori 268019d6b8fSAnthony Liguori return cid; 269019d6b8fSAnthony Liguori } 270019d6b8fSAnthony Liguori 271019d6b8fSAnthony Liguori static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) 272019d6b8fSAnthony Liguori { 273019d6b8fSAnthony Liguori char desc[DESC_SIZE], tmp_desc[DESC_SIZE]; 274019d6b8fSAnthony Liguori char *p_name, *tmp_str; 275e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 27699f1835dSKevin Wolf int ret; 277019d6b8fSAnthony Liguori 27899f1835dSKevin Wolf ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); 27999f1835dSKevin Wolf if (ret < 0) { 28099f1835dSKevin Wolf return ret; 281e1da9b24SFam Zheng } 282019d6b8fSAnthony Liguori 28393897b9fSKevin Wolf desc[DESC_SIZE - 1] = '\0'; 284019d6b8fSAnthony Liguori tmp_str = strstr(desc, "parentCID"); 28593897b9fSKevin Wolf if (tmp_str == NULL) { 28693897b9fSKevin Wolf return -EINVAL; 28793897b9fSKevin Wolf } 28893897b9fSKevin Wolf 289019d6b8fSAnthony Liguori pstrcpy(tmp_desc, sizeof(tmp_desc), tmp_str); 290ae261c86SFam Zheng p_name = strstr(desc, "CID"); 291ae261c86SFam Zheng if (p_name != NULL) { 292019d6b8fSAnthony Liguori p_name += sizeof("CID"); 2939b17031aSFam Zheng snprintf(p_name, sizeof(desc) - (p_name - desc), "%" PRIx32 "\n", cid); 294019d6b8fSAnthony Liguori pstrcat(desc, sizeof(desc), tmp_desc); 295019d6b8fSAnthony Liguori } 296019d6b8fSAnthony Liguori 29799f1835dSKevin Wolf ret = bdrv_pwrite_sync(bs->file, s->desc_offset, desc, DESC_SIZE); 29899f1835dSKevin Wolf if (ret < 0) { 29999f1835dSKevin Wolf return ret; 300e1da9b24SFam Zheng } 30199f1835dSKevin Wolf 302019d6b8fSAnthony Liguori return 0; 303019d6b8fSAnthony Liguori } 304019d6b8fSAnthony Liguori 305019d6b8fSAnthony Liguori static int vmdk_is_cid_valid(BlockDriverState *bs) 306019d6b8fSAnthony Liguori { 307019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 308b171271aSKevin Wolf BlockDriverState *p_bs = bs->backing_hd; 309019d6b8fSAnthony Liguori uint32_t cur_pcid; 310019d6b8fSAnthony Liguori 311c338b6adSFam Zheng if (!s->cid_checked && p_bs) { 312019d6b8fSAnthony Liguori cur_pcid = vmdk_read_cid(p_bs, 0); 313ae261c86SFam Zheng if (s->parent_cid != cur_pcid) { 314ae261c86SFam Zheng /* CID not valid */ 315019d6b8fSAnthony Liguori return 0; 316019d6b8fSAnthony Liguori } 317ae261c86SFam Zheng } 318c338b6adSFam Zheng s->cid_checked = true; 319ae261c86SFam Zheng /* CID valid */ 320019d6b8fSAnthony Liguori return 1; 321019d6b8fSAnthony Liguori } 322019d6b8fSAnthony Liguori 3233897575fSJeff Cody /* Queue extents, if any, for reopen() */ 3243897575fSJeff Cody static int vmdk_reopen_prepare(BDRVReopenState *state, 3253897575fSJeff Cody BlockReopenQueue *queue, Error **errp) 3263897575fSJeff Cody { 3273897575fSJeff Cody BDRVVmdkState *s; 3283897575fSJeff Cody int ret = -1; 3293897575fSJeff Cody int i; 3303897575fSJeff Cody VmdkExtent *e; 3313897575fSJeff Cody 3323897575fSJeff Cody assert(state != NULL); 3333897575fSJeff Cody assert(state->bs != NULL); 3343897575fSJeff Cody 3353897575fSJeff Cody if (queue == NULL) { 3364823970bSFam Zheng error_setg(errp, "No reopen queue for VMDK extents"); 3373897575fSJeff Cody goto exit; 3383897575fSJeff Cody } 3393897575fSJeff Cody 3403897575fSJeff Cody s = state->bs->opaque; 3413897575fSJeff Cody 3423897575fSJeff Cody assert(s != NULL); 3433897575fSJeff Cody 3443897575fSJeff Cody for (i = 0; i < s->num_extents; i++) { 3453897575fSJeff Cody e = &s->extents[i]; 3463897575fSJeff Cody if (e->file != state->bs->file) { 3473897575fSJeff Cody bdrv_reopen_queue(queue, e->file, state->flags); 3483897575fSJeff Cody } 3493897575fSJeff Cody } 3503897575fSJeff Cody ret = 0; 3513897575fSJeff Cody 3523897575fSJeff Cody exit: 3533897575fSJeff Cody return ret; 3543897575fSJeff Cody } 3553897575fSJeff Cody 3569949f97eSKevin Wolf static int vmdk_parent_open(BlockDriverState *bs) 357019d6b8fSAnthony Liguori { 358019d6b8fSAnthony Liguori char *p_name; 3597fa60fa3SFam Zheng char desc[DESC_SIZE + 1]; 360e1da9b24SFam Zheng BDRVVmdkState *s = bs->opaque; 361588b65a3SPaolo Bonzini int ret; 362019d6b8fSAnthony Liguori 3637fa60fa3SFam Zheng desc[DESC_SIZE] = '\0'; 364588b65a3SPaolo Bonzini ret = bdrv_pread(bs->file, s->desc_offset, desc, DESC_SIZE); 365588b65a3SPaolo Bonzini if (ret < 0) { 366588b65a3SPaolo Bonzini return ret; 367e1da9b24SFam Zheng } 368019d6b8fSAnthony Liguori 369ae261c86SFam Zheng p_name = strstr(desc, "parentFileNameHint"); 370ae261c86SFam Zheng if (p_name != NULL) { 371019d6b8fSAnthony Liguori char *end_name; 372019d6b8fSAnthony Liguori 373019d6b8fSAnthony Liguori p_name += sizeof("parentFileNameHint") + 1; 374ae261c86SFam Zheng end_name = strchr(p_name, '\"'); 375ae261c86SFam Zheng if (end_name == NULL) { 376588b65a3SPaolo Bonzini return -EINVAL; 377ae261c86SFam Zheng } 378ae261c86SFam Zheng if ((end_name - p_name) > sizeof(bs->backing_file) - 1) { 379588b65a3SPaolo Bonzini return -EINVAL; 380ae261c86SFam Zheng } 381019d6b8fSAnthony Liguori 382b171271aSKevin Wolf pstrcpy(bs->backing_file, end_name - p_name + 1, p_name); 383019d6b8fSAnthony Liguori } 384019d6b8fSAnthony Liguori 385019d6b8fSAnthony Liguori return 0; 386019d6b8fSAnthony Liguori } 387019d6b8fSAnthony Liguori 388b3976d3cSFam Zheng /* Create and append extent to the extent array. Return the added VmdkExtent 389b3976d3cSFam Zheng * address. return NULL if allocation failed. */ 3908aa1331cSFam Zheng static int vmdk_add_extent(BlockDriverState *bs, 391b3976d3cSFam Zheng BlockDriverState *file, bool flat, int64_t sectors, 392b3976d3cSFam Zheng int64_t l1_offset, int64_t l1_backup_offset, 393b3976d3cSFam Zheng uint32_t l1_size, 3948aa1331cSFam Zheng int l2_size, uint64_t cluster_sectors, 3954823970bSFam Zheng VmdkExtent **new_extent, 3964823970bSFam Zheng Error **errp) 397b3976d3cSFam Zheng { 398b3976d3cSFam Zheng VmdkExtent *extent; 399b3976d3cSFam Zheng BDRVVmdkState *s = bs->opaque; 400b3976d3cSFam Zheng 4018aa1331cSFam Zheng if (cluster_sectors > 0x200000) { 4028aa1331cSFam Zheng /* 0x200000 * 512Bytes = 1GB for one cluster is unrealistic */ 4034823970bSFam Zheng error_setg(errp, "Invalid granularity, image may be corrupt"); 4044823970bSFam Zheng return -EFBIG; 4058aa1331cSFam Zheng } 406b0651b8cSFam Zheng if (l1_size > 512 * 1024 * 1024) { 407b0651b8cSFam Zheng /* Although with big capacity and small l1_entry_sectors, we can get a 408b0651b8cSFam Zheng * big l1_size, we don't want unbounded value to allocate the table. 409b0651b8cSFam Zheng * Limit it to 512M, which is 16PB for default cluster and L2 table 410b0651b8cSFam Zheng * size */ 4114823970bSFam Zheng error_setg(errp, "L1 size too big"); 412b0651b8cSFam Zheng return -EFBIG; 413b0651b8cSFam Zheng } 4148aa1331cSFam Zheng 4157267c094SAnthony Liguori s->extents = g_realloc(s->extents, 416b3976d3cSFam Zheng (s->num_extents + 1) * sizeof(VmdkExtent)); 417b3976d3cSFam Zheng extent = &s->extents[s->num_extents]; 418b3976d3cSFam Zheng s->num_extents++; 419b3976d3cSFam Zheng 420b3976d3cSFam Zheng memset(extent, 0, sizeof(VmdkExtent)); 421b3976d3cSFam Zheng extent->file = file; 422b3976d3cSFam Zheng extent->flat = flat; 423b3976d3cSFam Zheng extent->sectors = sectors; 424b3976d3cSFam Zheng extent->l1_table_offset = l1_offset; 425b3976d3cSFam Zheng extent->l1_backup_table_offset = l1_backup_offset; 426b3976d3cSFam Zheng extent->l1_size = l1_size; 427b3976d3cSFam Zheng extent->l1_entry_sectors = l2_size * cluster_sectors; 428b3976d3cSFam Zheng extent->l2_size = l2_size; 429301c7d38SFam Zheng extent->cluster_sectors = flat ? sectors : cluster_sectors; 430b3976d3cSFam Zheng 431b3976d3cSFam Zheng if (s->num_extents > 1) { 432b3976d3cSFam Zheng extent->end_sector = (*(extent - 1)).end_sector + extent->sectors; 433b3976d3cSFam Zheng } else { 434b3976d3cSFam Zheng extent->end_sector = extent->sectors; 435b3976d3cSFam Zheng } 436b3976d3cSFam Zheng bs->total_sectors = extent->end_sector; 4378aa1331cSFam Zheng if (new_extent) { 4388aa1331cSFam Zheng *new_extent = extent; 4398aa1331cSFam Zheng } 4408aa1331cSFam Zheng return 0; 441b3976d3cSFam Zheng } 442b3976d3cSFam Zheng 4434823970bSFam Zheng static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent, 4444823970bSFam Zheng Error **errp) 445019d6b8fSAnthony Liguori { 446b4b3ab14SFam Zheng int ret; 447b4b3ab14SFam Zheng int l1_size, i; 448b4b3ab14SFam Zheng 449b4b3ab14SFam Zheng /* read the L1 table */ 450b4b3ab14SFam Zheng l1_size = extent->l1_size * sizeof(uint32_t); 4517267c094SAnthony Liguori extent->l1_table = g_malloc(l1_size); 452b4b3ab14SFam Zheng ret = bdrv_pread(extent->file, 453b4b3ab14SFam Zheng extent->l1_table_offset, 454b4b3ab14SFam Zheng extent->l1_table, 455b4b3ab14SFam Zheng l1_size); 456b4b3ab14SFam Zheng if (ret < 0) { 4574823970bSFam Zheng error_setg_errno(errp, -ret, 4584823970bSFam Zheng "Could not read l1 table from extent '%s'", 4594823970bSFam Zheng extent->file->filename); 460b4b3ab14SFam Zheng goto fail_l1; 461b4b3ab14SFam Zheng } 462b4b3ab14SFam Zheng for (i = 0; i < extent->l1_size; i++) { 463b4b3ab14SFam Zheng le32_to_cpus(&extent->l1_table[i]); 464b4b3ab14SFam Zheng } 465b4b3ab14SFam Zheng 466b4b3ab14SFam Zheng if (extent->l1_backup_table_offset) { 4677267c094SAnthony Liguori extent->l1_backup_table = g_malloc(l1_size); 468b4b3ab14SFam Zheng ret = bdrv_pread(extent->file, 469b4b3ab14SFam Zheng extent->l1_backup_table_offset, 470b4b3ab14SFam Zheng extent->l1_backup_table, 471b4b3ab14SFam Zheng l1_size); 472b4b3ab14SFam Zheng if (ret < 0) { 4734823970bSFam Zheng error_setg_errno(errp, -ret, 4744823970bSFam Zheng "Could not read l1 backup table from extent '%s'", 4754823970bSFam Zheng extent->file->filename); 476b4b3ab14SFam Zheng goto fail_l1b; 477b4b3ab14SFam Zheng } 478b4b3ab14SFam Zheng for (i = 0; i < extent->l1_size; i++) { 479b4b3ab14SFam Zheng le32_to_cpus(&extent->l1_backup_table[i]); 480b4b3ab14SFam Zheng } 481b4b3ab14SFam Zheng } 482b4b3ab14SFam Zheng 483b4b3ab14SFam Zheng extent->l2_cache = 4847267c094SAnthony Liguori g_malloc(extent->l2_size * L2_CACHE_SIZE * sizeof(uint32_t)); 485b4b3ab14SFam Zheng return 0; 486b4b3ab14SFam Zheng fail_l1b: 4877267c094SAnthony Liguori g_free(extent->l1_backup_table); 488b4b3ab14SFam Zheng fail_l1: 4897267c094SAnthony Liguori g_free(extent->l1_table); 490b4b3ab14SFam Zheng return ret; 491b4b3ab14SFam Zheng } 492b4b3ab14SFam Zheng 493daac8fdcSFam Zheng static int vmdk_open_vmfs_sparse(BlockDriverState *bs, 49486c6b429SFam Zheng BlockDriverState *file, 4954823970bSFam Zheng int flags, Error **errp) 496b4b3ab14SFam Zheng { 497b4b3ab14SFam Zheng int ret; 498019d6b8fSAnthony Liguori uint32_t magic; 499019d6b8fSAnthony Liguori VMDK3Header header; 500b4b3ab14SFam Zheng VmdkExtent *extent; 501b4b3ab14SFam Zheng 50286c6b429SFam Zheng ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); 503b4b3ab14SFam Zheng if (ret < 0) { 5044823970bSFam Zheng error_setg_errno(errp, -ret, 5054823970bSFam Zheng "Could not read header from file '%s'", 5064823970bSFam Zheng file->filename); 50786c6b429SFam Zheng return ret; 508b3976d3cSFam Zheng } 509f6b61e54SFam Zheng ret = vmdk_add_extent(bs, file, false, 510b3976d3cSFam Zheng le32_to_cpu(header.disk_sectors), 511b4b3ab14SFam Zheng le32_to_cpu(header.l1dir_offset) << 9, 512f6b61e54SFam Zheng 0, 513f6b61e54SFam Zheng le32_to_cpu(header.l1dir_size), 514f6b61e54SFam Zheng 4096, 5158aa1331cSFam Zheng le32_to_cpu(header.granularity), 5164823970bSFam Zheng &extent, 5174823970bSFam Zheng errp); 5188aa1331cSFam Zheng if (ret < 0) { 5198aa1331cSFam Zheng return ret; 5208aa1331cSFam Zheng } 5214823970bSFam Zheng ret = vmdk_init_tables(bs, extent, errp); 522b4b3ab14SFam Zheng if (ret) { 52386c6b429SFam Zheng /* free extent allocated by vmdk_add_extent */ 52486c6b429SFam Zheng vmdk_free_last_extent(bs); 525b4b3ab14SFam Zheng } 526b4b3ab14SFam Zheng return ret; 527b4b3ab14SFam Zheng } 528b4b3ab14SFam Zheng 529d1833ef5SPaolo Bonzini static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, 530d1833ef5SPaolo Bonzini Error **errp); 531f16f509dSFam Zheng 532a8842e6dSPaolo Bonzini static char *vmdk_read_desc(BlockDriverState *file, uint64_t desc_offset, 533a8842e6dSPaolo Bonzini Error **errp) 534a8842e6dSPaolo Bonzini { 535a8842e6dSPaolo Bonzini int64_t size; 536a8842e6dSPaolo Bonzini char *buf; 537a8842e6dSPaolo Bonzini int ret; 538a8842e6dSPaolo Bonzini 539a8842e6dSPaolo Bonzini size = bdrv_getlength(file); 540a8842e6dSPaolo Bonzini if (size < 0) { 541a8842e6dSPaolo Bonzini error_setg_errno(errp, -size, "Could not access file"); 542a8842e6dSPaolo Bonzini return NULL; 543a8842e6dSPaolo Bonzini } 544a8842e6dSPaolo Bonzini 545a8842e6dSPaolo Bonzini size = MIN(size, 1 << 20); /* avoid unbounded allocation */ 546a8842e6dSPaolo Bonzini buf = g_malloc0(size + 1); 547a8842e6dSPaolo Bonzini 548a8842e6dSPaolo Bonzini ret = bdrv_pread(file, desc_offset, buf, size); 549a8842e6dSPaolo Bonzini if (ret < 0) { 550a8842e6dSPaolo Bonzini error_setg_errno(errp, -ret, "Could not read from file"); 551a8842e6dSPaolo Bonzini g_free(buf); 552a8842e6dSPaolo Bonzini return NULL; 553a8842e6dSPaolo Bonzini } 554a8842e6dSPaolo Bonzini 555a8842e6dSPaolo Bonzini return buf; 556a8842e6dSPaolo Bonzini } 557a8842e6dSPaolo Bonzini 55886c6b429SFam Zheng static int vmdk_open_vmdk4(BlockDriverState *bs, 55986c6b429SFam Zheng BlockDriverState *file, 5604823970bSFam Zheng int flags, Error **errp) 561b4b3ab14SFam Zheng { 562b4b3ab14SFam Zheng int ret; 563b4b3ab14SFam Zheng uint32_t magic; 564b4b3ab14SFam Zheng uint32_t l1_size, l1_entry_sectors; 565019d6b8fSAnthony Liguori VMDK4Header header; 566b4b3ab14SFam Zheng VmdkExtent *extent; 567f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 568bb45ded9SFam Zheng int64_t l1_backup_offset = 0; 569b4b3ab14SFam Zheng 57086c6b429SFam Zheng ret = bdrv_pread(file, sizeof(magic), &header, sizeof(header)); 571b4b3ab14SFam Zheng if (ret < 0) { 5724823970bSFam Zheng error_setg_errno(errp, -ret, 5734823970bSFam Zheng "Could not read header from file '%s'", 5744823970bSFam Zheng file->filename); 57589ac8480SPaolo Bonzini return -EINVAL; 576b3976d3cSFam Zheng } 5775a394b9eSStefan Hajnoczi if (header.capacity == 0) { 578e98768d4SFam Zheng uint64_t desc_offset = le64_to_cpu(header.desc_offset); 5795a394b9eSStefan Hajnoczi if (desc_offset) { 580d1833ef5SPaolo Bonzini char *buf = vmdk_read_desc(file, desc_offset << 9, errp); 581d1833ef5SPaolo Bonzini if (!buf) { 582d1833ef5SPaolo Bonzini return -EINVAL; 583d1833ef5SPaolo Bonzini } 584d1833ef5SPaolo Bonzini ret = vmdk_open_desc_file(bs, flags, buf, errp); 585d1833ef5SPaolo Bonzini g_free(buf); 586d1833ef5SPaolo Bonzini return ret; 5875a394b9eSStefan Hajnoczi } 588f16f509dSFam Zheng } 58965bd155cSKevin Wolf 590f4c129a3SFam Zheng if (!s->create_type) { 591f4c129a3SFam Zheng s->create_type = g_strdup("monolithicSparse"); 592f4c129a3SFam Zheng } 593f4c129a3SFam Zheng 59465bd155cSKevin Wolf if (le64_to_cpu(header.gd_offset) == VMDK4_GD_AT_END) { 59565bd155cSKevin Wolf /* 59665bd155cSKevin Wolf * The footer takes precedence over the header, so read it in. The 59765bd155cSKevin Wolf * footer starts at offset -1024 from the end: One sector for the 59865bd155cSKevin Wolf * footer, and another one for the end-of-stream marker. 59965bd155cSKevin Wolf */ 60065bd155cSKevin Wolf struct { 60165bd155cSKevin Wolf struct { 60265bd155cSKevin Wolf uint64_t val; 60365bd155cSKevin Wolf uint32_t size; 60465bd155cSKevin Wolf uint32_t type; 60565bd155cSKevin Wolf uint8_t pad[512 - 16]; 60665bd155cSKevin Wolf } QEMU_PACKED footer_marker; 60765bd155cSKevin Wolf 60865bd155cSKevin Wolf uint32_t magic; 60965bd155cSKevin Wolf VMDK4Header header; 61065bd155cSKevin Wolf uint8_t pad[512 - 4 - sizeof(VMDK4Header)]; 61165bd155cSKevin Wolf 61265bd155cSKevin Wolf struct { 61365bd155cSKevin Wolf uint64_t val; 61465bd155cSKevin Wolf uint32_t size; 61565bd155cSKevin Wolf uint32_t type; 61665bd155cSKevin Wolf uint8_t pad[512 - 16]; 61765bd155cSKevin Wolf } QEMU_PACKED eos_marker; 61865bd155cSKevin Wolf } QEMU_PACKED footer; 61965bd155cSKevin Wolf 62065bd155cSKevin Wolf ret = bdrv_pread(file, 62165bd155cSKevin Wolf bs->file->total_sectors * 512 - 1536, 62265bd155cSKevin Wolf &footer, sizeof(footer)); 62365bd155cSKevin Wolf if (ret < 0) { 62465bd155cSKevin Wolf return ret; 62565bd155cSKevin Wolf } 62665bd155cSKevin Wolf 62765bd155cSKevin Wolf /* Some sanity checks for the footer */ 62865bd155cSKevin Wolf if (be32_to_cpu(footer.magic) != VMDK4_MAGIC || 62965bd155cSKevin Wolf le32_to_cpu(footer.footer_marker.size) != 0 || 63065bd155cSKevin Wolf le32_to_cpu(footer.footer_marker.type) != MARKER_FOOTER || 63165bd155cSKevin Wolf le64_to_cpu(footer.eos_marker.val) != 0 || 63265bd155cSKevin Wolf le32_to_cpu(footer.eos_marker.size) != 0 || 63365bd155cSKevin Wolf le32_to_cpu(footer.eos_marker.type) != MARKER_END_OF_STREAM) 63465bd155cSKevin Wolf { 63565bd155cSKevin Wolf return -EINVAL; 63665bd155cSKevin Wolf } 63765bd155cSKevin Wolf 63865bd155cSKevin Wolf header = footer.header; 63965bd155cSKevin Wolf } 64065bd155cSKevin Wolf 641509d39aaSFam Zheng if (le32_to_cpu(header.version) > 3) { 64296c51eb5SFam Zheng char buf[64]; 6434ab9dab5SFam Zheng snprintf(buf, sizeof(buf), "VMDK version %" PRId32, 64496c51eb5SFam Zheng le32_to_cpu(header.version)); 64589ac8480SPaolo Bonzini error_set(errp, QERR_UNKNOWN_BLOCK_FORMAT_FEATURE, 64696c51eb5SFam Zheng bs->device_name, "vmdk", buf); 64796c51eb5SFam Zheng return -ENOTSUP; 648509d39aaSFam Zheng } else if (le32_to_cpu(header.version) == 3 && (flags & BDRV_O_RDWR)) { 649509d39aaSFam Zheng /* VMware KB 2064959 explains that version 3 added support for 650509d39aaSFam Zheng * persistent changed block tracking (CBT), and backup software can 651509d39aaSFam Zheng * read it as version=1 if it doesn't care about the changed area 652509d39aaSFam Zheng * information. So we are safe to enable read only. */ 653509d39aaSFam Zheng error_setg(errp, "VMDK version 3 must be read only"); 654509d39aaSFam Zheng return -EINVAL; 65596c51eb5SFam Zheng } 65696c51eb5SFam Zheng 657ca8804ceSFam Zheng if (le32_to_cpu(header.num_gtes_per_gt) > 512) { 65889ac8480SPaolo Bonzini error_setg(errp, "L2 table size too big"); 659f8ce0403SFam Zheng return -EINVAL; 660f8ce0403SFam Zheng } 661f8ce0403SFam Zheng 662ca8804ceSFam Zheng l1_entry_sectors = le32_to_cpu(header.num_gtes_per_gt) 663b3976d3cSFam Zheng * le64_to_cpu(header.granularity); 66475d12341SStefan Weil if (l1_entry_sectors == 0) { 66586c6b429SFam Zheng return -EINVAL; 66686c6b429SFam Zheng } 667b3976d3cSFam Zheng l1_size = (le64_to_cpu(header.capacity) + l1_entry_sectors - 1) 668b3976d3cSFam Zheng / l1_entry_sectors; 669bb45ded9SFam Zheng if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) { 670bb45ded9SFam Zheng l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9; 671bb45ded9SFam Zheng } 67234ceed81SFam Zheng if (bdrv_getlength(file) < 67334ceed81SFam Zheng le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) { 6744ab9dab5SFam Zheng error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes", 6754ab9dab5SFam Zheng (int64_t)(le64_to_cpu(header.grain_offset) 6764ab9dab5SFam Zheng * BDRV_SECTOR_SIZE)); 67734ceed81SFam Zheng return -EINVAL; 67834ceed81SFam Zheng } 67934ceed81SFam Zheng 6808aa1331cSFam Zheng ret = vmdk_add_extent(bs, file, false, 681b3976d3cSFam Zheng le64_to_cpu(header.capacity), 682b3976d3cSFam Zheng le64_to_cpu(header.gd_offset) << 9, 683bb45ded9SFam Zheng l1_backup_offset, 684b3976d3cSFam Zheng l1_size, 685ca8804ceSFam Zheng le32_to_cpu(header.num_gtes_per_gt), 6868aa1331cSFam Zheng le64_to_cpu(header.granularity), 6874823970bSFam Zheng &extent, 6884823970bSFam Zheng errp); 6898aa1331cSFam Zheng if (ret < 0) { 6908aa1331cSFam Zheng return ret; 6918aa1331cSFam Zheng } 692432bb170SFam Zheng extent->compressed = 693432bb170SFam Zheng le16_to_cpu(header.compressAlgorithm) == VMDK4_COMPRESSION_DEFLATE; 694d8a7b061SFam Zheng if (extent->compressed) { 695d8a7b061SFam Zheng g_free(s->create_type); 696d8a7b061SFam Zheng s->create_type = g_strdup("streamOptimized"); 697d8a7b061SFam Zheng } 698432bb170SFam Zheng extent->has_marker = le32_to_cpu(header.flags) & VMDK4_FLAG_MARKER; 69914ead646SFam Zheng extent->version = le32_to_cpu(header.version); 70014ead646SFam Zheng extent->has_zero_grain = le32_to_cpu(header.flags) & VMDK4_FLAG_ZERO_GRAIN; 7014823970bSFam Zheng ret = vmdk_init_tables(bs, extent, errp); 702b4b3ab14SFam Zheng if (ret) { 70386c6b429SFam Zheng /* free extent allocated by vmdk_add_extent */ 70486c6b429SFam Zheng vmdk_free_last_extent(bs); 705019d6b8fSAnthony Liguori } 706b4b3ab14SFam Zheng return ret; 707b4b3ab14SFam Zheng } 708b4b3ab14SFam Zheng 7097fa60fa3SFam Zheng /* find an option value out of descriptor file */ 7107fa60fa3SFam Zheng static int vmdk_parse_description(const char *desc, const char *opt_name, 7117fa60fa3SFam Zheng char *buf, int buf_size) 7127fa60fa3SFam Zheng { 7137fa60fa3SFam Zheng char *opt_pos, *opt_end; 7147fa60fa3SFam Zheng const char *end = desc + strlen(desc); 7157fa60fa3SFam Zheng 7167fa60fa3SFam Zheng opt_pos = strstr(desc, opt_name); 7177fa60fa3SFam Zheng if (!opt_pos) { 71865f74725SFam Zheng return VMDK_ERROR; 7197fa60fa3SFam Zheng } 7207fa60fa3SFam Zheng /* Skip "=\"" following opt_name */ 7217fa60fa3SFam Zheng opt_pos += strlen(opt_name) + 2; 7227fa60fa3SFam Zheng if (opt_pos >= end) { 72365f74725SFam Zheng return VMDK_ERROR; 7247fa60fa3SFam Zheng } 7257fa60fa3SFam Zheng opt_end = opt_pos; 7267fa60fa3SFam Zheng while (opt_end < end && *opt_end != '"') { 7277fa60fa3SFam Zheng opt_end++; 7287fa60fa3SFam Zheng } 7297fa60fa3SFam Zheng if (opt_end == end || buf_size < opt_end - opt_pos + 1) { 73065f74725SFam Zheng return VMDK_ERROR; 7317fa60fa3SFam Zheng } 7327fa60fa3SFam Zheng pstrcpy(buf, opt_end - opt_pos + 1, opt_pos); 73365f74725SFam Zheng return VMDK_OK; 7347fa60fa3SFam Zheng } 7357fa60fa3SFam Zheng 73686c6b429SFam Zheng /* Open an extent file and append to bs array */ 73786c6b429SFam Zheng static int vmdk_open_sparse(BlockDriverState *bs, 738d1833ef5SPaolo Bonzini BlockDriverState *file, int flags, 739d1833ef5SPaolo Bonzini char *buf, Error **errp) 74086c6b429SFam Zheng { 74186c6b429SFam Zheng uint32_t magic; 74286c6b429SFam Zheng 743d1833ef5SPaolo Bonzini magic = ldl_be_p(buf); 74486c6b429SFam Zheng switch (magic) { 74586c6b429SFam Zheng case VMDK3_MAGIC: 7464823970bSFam Zheng return vmdk_open_vmfs_sparse(bs, file, flags, errp); 74786c6b429SFam Zheng break; 74886c6b429SFam Zheng case VMDK4_MAGIC: 7494823970bSFam Zheng return vmdk_open_vmdk4(bs, file, flags, errp); 75086c6b429SFam Zheng break; 75186c6b429SFam Zheng default: 75276abe407SPaolo Bonzini error_setg(errp, "Image not in VMDK format"); 75376abe407SPaolo Bonzini return -EINVAL; 75486c6b429SFam Zheng break; 75586c6b429SFam Zheng } 75686c6b429SFam Zheng } 75786c6b429SFam Zheng 7587fa60fa3SFam Zheng static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, 7594823970bSFam Zheng const char *desc_file_path, Error **errp) 7607fa60fa3SFam Zheng { 7617fa60fa3SFam Zheng int ret; 7627fa60fa3SFam Zheng char access[11]; 7637fa60fa3SFam Zheng char type[11]; 7647fa60fa3SFam Zheng char fname[512]; 7657fa60fa3SFam Zheng const char *p = desc; 7667fa60fa3SFam Zheng int64_t sectors = 0; 7677fa60fa3SFam Zheng int64_t flat_offset; 76886c6b429SFam Zheng char extent_path[PATH_MAX]; 76986c6b429SFam Zheng BlockDriverState *extent_file; 770f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 771f4c129a3SFam Zheng VmdkExtent *extent; 7727fa60fa3SFam Zheng 7737fa60fa3SFam Zheng while (*p) { 7747fa60fa3SFam Zheng /* parse extent line: 7757fa60fa3SFam Zheng * RW [size in sectors] FLAT "file-name.vmdk" OFFSET 7767fa60fa3SFam Zheng * or 7777fa60fa3SFam Zheng * RW [size in sectors] SPARSE "file-name.vmdk" 7787fa60fa3SFam Zheng */ 7797fa60fa3SFam Zheng flat_offset = -1; 780cd923475SPhilipp Hahn ret = sscanf(p, "%10s %" SCNd64 " %10s \"%511[^\n\r\"]\" %" SCNd64, 7817fa60fa3SFam Zheng access, §ors, type, fname, &flat_offset); 7827fa60fa3SFam Zheng if (ret < 4 || strcmp(access, "RW")) { 7837fa60fa3SFam Zheng goto next_line; 7847fa60fa3SFam Zheng } else if (!strcmp(type, "FLAT")) { 7857fa60fa3SFam Zheng if (ret != 5 || flat_offset < 0) { 7864823970bSFam Zheng error_setg(errp, "Invalid extent lines: \n%s", p); 7877fa60fa3SFam Zheng return -EINVAL; 7887fa60fa3SFam Zheng } 789dbbcaa8dSFam Zheng } else if (!strcmp(type, "VMFS")) { 790b47053bdSFam Zheng if (ret == 4) { 791dbbcaa8dSFam Zheng flat_offset = 0; 792b47053bdSFam Zheng } else { 793b47053bdSFam Zheng error_setg(errp, "Invalid extent lines:\n%s", p); 794b47053bdSFam Zheng return -EINVAL; 795b47053bdSFam Zheng } 7967fa60fa3SFam Zheng } else if (ret != 4) { 7974823970bSFam Zheng error_setg(errp, "Invalid extent lines:\n%s", p); 7987fa60fa3SFam Zheng return -EINVAL; 7997fa60fa3SFam Zheng } 8007fa60fa3SFam Zheng 8017fa60fa3SFam Zheng if (sectors <= 0 || 802daac8fdcSFam Zheng (strcmp(type, "FLAT") && strcmp(type, "SPARSE") && 80304d542c8SPaolo Bonzini strcmp(type, "VMFS") && strcmp(type, "VMFSSPARSE")) || 8047fa60fa3SFam Zheng (strcmp(access, "RW"))) { 8057fa60fa3SFam Zheng goto next_line; 8067fa60fa3SFam Zheng } 8077fa60fa3SFam Zheng 8087fa60fa3SFam Zheng path_combine(extent_path, sizeof(extent_path), 8097fa60fa3SFam Zheng desc_file_path, fname); 8102e40134bSMax Reitz extent_file = NULL; 8112e40134bSMax Reitz ret = bdrv_open(&extent_file, extent_path, NULL, NULL, 8122e40134bSMax Reitz bs->open_flags | BDRV_O_PROTOCOL, NULL, errp); 8137fa60fa3SFam Zheng if (ret) { 8147fa60fa3SFam Zheng return ret; 8157fa60fa3SFam Zheng } 81686c6b429SFam Zheng 81786c6b429SFam Zheng /* save to extents array */ 81804d542c8SPaolo Bonzini if (!strcmp(type, "FLAT") || !strcmp(type, "VMFS")) { 81986c6b429SFam Zheng /* FLAT extent */ 82086c6b429SFam Zheng 8218aa1331cSFam Zheng ret = vmdk_add_extent(bs, extent_file, true, sectors, 8224823970bSFam Zheng 0, 0, 0, 0, 0, &extent, errp); 8238aa1331cSFam Zheng if (ret < 0) { 8248aa1331cSFam Zheng return ret; 8258aa1331cSFam Zheng } 826f16f509dSFam Zheng extent->flat_start_offset = flat_offset << 9; 827daac8fdcSFam Zheng } else if (!strcmp(type, "SPARSE") || !strcmp(type, "VMFSSPARSE")) { 828daac8fdcSFam Zheng /* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/ 829d1833ef5SPaolo Bonzini char *buf = vmdk_read_desc(extent_file, 0, errp); 830d1833ef5SPaolo Bonzini if (!buf) { 831d1833ef5SPaolo Bonzini ret = -EINVAL; 832d1833ef5SPaolo Bonzini } else { 833d1833ef5SPaolo Bonzini ret = vmdk_open_sparse(bs, extent_file, bs->open_flags, buf, errp); 834d1833ef5SPaolo Bonzini } 83586c6b429SFam Zheng if (ret) { 836d1833ef5SPaolo Bonzini g_free(buf); 8374f6fd349SFam Zheng bdrv_unref(extent_file); 83886c6b429SFam Zheng return ret; 83986c6b429SFam Zheng } 840f4c129a3SFam Zheng extent = &s->extents[s->num_extents - 1]; 8417fa60fa3SFam Zheng } else { 8424823970bSFam Zheng error_setg(errp, "Unsupported extent type '%s'", type); 8437fa60fa3SFam Zheng return -ENOTSUP; 8447fa60fa3SFam Zheng } 845f4c129a3SFam Zheng extent->type = g_strdup(type); 8467fa60fa3SFam Zheng next_line: 8477fa60fa3SFam Zheng /* move to next line */ 848899f1ae2SFam Zheng while (*p) { 849899f1ae2SFam Zheng if (*p == '\n') { 8507fa60fa3SFam Zheng p++; 851899f1ae2SFam Zheng break; 8527fa60fa3SFam Zheng } 8537fa60fa3SFam Zheng p++; 8547fa60fa3SFam Zheng } 855899f1ae2SFam Zheng } 8567fa60fa3SFam Zheng return 0; 8577fa60fa3SFam Zheng } 8587fa60fa3SFam Zheng 859d1833ef5SPaolo Bonzini static int vmdk_open_desc_file(BlockDriverState *bs, int flags, char *buf, 860d1833ef5SPaolo Bonzini Error **errp) 8617fa60fa3SFam Zheng { 8627fa60fa3SFam Zheng int ret; 8637fa60fa3SFam Zheng char ct[128]; 8647fa60fa3SFam Zheng BDRVVmdkState *s = bs->opaque; 8657fa60fa3SFam Zheng 8667fa60fa3SFam Zheng if (vmdk_parse_description(buf, "createType", ct, sizeof(ct))) { 86776abe407SPaolo Bonzini error_setg(errp, "invalid VMDK image descriptor"); 86876abe407SPaolo Bonzini ret = -EINVAL; 8690bed087dSEvgeny Budilovsky goto exit; 8707fa60fa3SFam Zheng } 8716398de51SFam Zheng if (strcmp(ct, "monolithicFlat") && 87204d542c8SPaolo Bonzini strcmp(ct, "vmfs") && 873daac8fdcSFam Zheng strcmp(ct, "vmfsSparse") && 87486c6b429SFam Zheng strcmp(ct, "twoGbMaxExtentSparse") && 8756398de51SFam Zheng strcmp(ct, "twoGbMaxExtentFlat")) { 8764823970bSFam Zheng error_setg(errp, "Unsupported image type '%s'", ct); 8770bed087dSEvgeny Budilovsky ret = -ENOTSUP; 8780bed087dSEvgeny Budilovsky goto exit; 8797fa60fa3SFam Zheng } 880f4c129a3SFam Zheng s->create_type = g_strdup(ct); 8817fa60fa3SFam Zheng s->desc_offset = 0; 8824823970bSFam Zheng ret = vmdk_parse_extents(buf, bs, bs->file->filename, errp); 8830bed087dSEvgeny Budilovsky exit: 8840bed087dSEvgeny Budilovsky return ret; 8857fa60fa3SFam Zheng } 8867fa60fa3SFam Zheng 887015a1036SMax Reitz static int vmdk_open(BlockDriverState *bs, QDict *options, int flags, 888015a1036SMax Reitz Error **errp) 889b4b3ab14SFam Zheng { 890d1833ef5SPaolo Bonzini char *buf = NULL; 89186c6b429SFam Zheng int ret; 89286c6b429SFam Zheng BDRVVmdkState *s = bs->opaque; 89337f09e5eSPaolo Bonzini uint32_t magic; 894b4b3ab14SFam Zheng 895d1833ef5SPaolo Bonzini buf = vmdk_read_desc(bs->file, 0, errp); 896d1833ef5SPaolo Bonzini if (!buf) { 897d1833ef5SPaolo Bonzini return -EINVAL; 898d1833ef5SPaolo Bonzini } 899d1833ef5SPaolo Bonzini 90037f09e5eSPaolo Bonzini magic = ldl_be_p(buf); 90137f09e5eSPaolo Bonzini switch (magic) { 90237f09e5eSPaolo Bonzini case VMDK3_MAGIC: 90337f09e5eSPaolo Bonzini case VMDK4_MAGIC: 90437f09e5eSPaolo Bonzini ret = vmdk_open_sparse(bs, bs->file, flags, buf, errp); 90586c6b429SFam Zheng s->desc_offset = 0x200; 90637f09e5eSPaolo Bonzini break; 90737f09e5eSPaolo Bonzini default: 908d1833ef5SPaolo Bonzini ret = vmdk_open_desc_file(bs, flags, buf, errp); 90937f09e5eSPaolo Bonzini break; 91037f09e5eSPaolo Bonzini } 911bae0a0ccSPaolo Bonzini if (ret) { 912bae0a0ccSPaolo Bonzini goto fail; 913bae0a0ccSPaolo Bonzini } 91437f09e5eSPaolo Bonzini 91586c6b429SFam Zheng /* try to open parent images, if exist */ 91686c6b429SFam Zheng ret = vmdk_parent_open(bs); 91786c6b429SFam Zheng if (ret) { 918bae0a0ccSPaolo Bonzini goto fail; 919b4b3ab14SFam Zheng } 920f4c129a3SFam Zheng s->cid = vmdk_read_cid(bs, 0); 92186c6b429SFam Zheng s->parent_cid = vmdk_read_cid(bs, 1); 922848c66e8SPaolo Bonzini qemu_co_mutex_init(&s->lock); 9232bc3166cSKevin Wolf 9242bc3166cSKevin Wolf /* Disable migration when VMDK images are used */ 9252bc3166cSKevin Wolf error_set(&s->migration_blocker, 9262bc3166cSKevin Wolf QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED, 9272bc3166cSKevin Wolf "vmdk", bs->device_name, "live migration"); 9282bc3166cSKevin Wolf migrate_add_blocker(s->migration_blocker); 929d1833ef5SPaolo Bonzini g_free(buf); 9302bc3166cSKevin Wolf return 0; 931bae0a0ccSPaolo Bonzini 932bae0a0ccSPaolo Bonzini fail: 933d1833ef5SPaolo Bonzini g_free(buf); 934f4c129a3SFam Zheng g_free(s->create_type); 935f4c129a3SFam Zheng s->create_type = NULL; 936bae0a0ccSPaolo Bonzini vmdk_free_extents(bs); 937bae0a0ccSPaolo Bonzini return ret; 938019d6b8fSAnthony Liguori } 939019d6b8fSAnthony Liguori 940d34682cdSKevin Wolf 941d34682cdSKevin Wolf static int vmdk_refresh_limits(BlockDriverState *bs) 942d34682cdSKevin Wolf { 943d34682cdSKevin Wolf BDRVVmdkState *s = bs->opaque; 944d34682cdSKevin Wolf int i; 945d34682cdSKevin Wolf 946d34682cdSKevin Wolf for (i = 0; i < s->num_extents; i++) { 947d34682cdSKevin Wolf if (!s->extents[i].flat) { 948d34682cdSKevin Wolf bs->bl.write_zeroes_alignment = 949d34682cdSKevin Wolf MAX(bs->bl.write_zeroes_alignment, 950d34682cdSKevin Wolf s->extents[i].cluster_sectors); 951d34682cdSKevin Wolf } 952d34682cdSKevin Wolf } 953d34682cdSKevin Wolf 954d34682cdSKevin Wolf return 0; 955d34682cdSKevin Wolf } 956d34682cdSKevin Wolf 957b3976d3cSFam Zheng static int get_whole_cluster(BlockDriverState *bs, 958b3976d3cSFam Zheng VmdkExtent *extent, 959b3976d3cSFam Zheng uint64_t cluster_offset, 960b3976d3cSFam Zheng uint64_t offset, 961b3976d3cSFam Zheng bool allocate) 962019d6b8fSAnthony Liguori { 963bf81507dSFam Zheng int ret = VMDK_OK; 964bf81507dSFam Zheng uint8_t *whole_grain = NULL; 965019d6b8fSAnthony Liguori 9660e69c543SFam Zheng /* we will be here if it's first write on non-exist grain(cluster). 9670e69c543SFam Zheng * try to read from parent image, if exist */ 968b171271aSKevin Wolf if (bs->backing_hd) { 969bf81507dSFam Zheng whole_grain = 970bf81507dSFam Zheng qemu_blockalign(bs, extent->cluster_sectors << BDRV_SECTOR_BITS); 971ae261c86SFam Zheng if (!vmdk_is_cid_valid(bs)) { 972bf81507dSFam Zheng ret = VMDK_ERROR; 973bf81507dSFam Zheng goto exit; 974ae261c86SFam Zheng } 975019d6b8fSAnthony Liguori 9760e69c543SFam Zheng /* floor offset to cluster */ 9770e69c543SFam Zheng offset -= offset % (extent->cluster_sectors * 512); 978c336500dSKevin Wolf ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain, 979b3976d3cSFam Zheng extent->cluster_sectors); 980c336500dSKevin Wolf if (ret < 0) { 981bf81507dSFam Zheng ret = VMDK_ERROR; 982bf81507dSFam Zheng goto exit; 983c336500dSKevin Wolf } 984019d6b8fSAnthony Liguori 9850e69c543SFam Zheng /* Write grain only into the active image */ 986b3976d3cSFam Zheng ret = bdrv_write(extent->file, cluster_offset, whole_grain, 987b3976d3cSFam Zheng extent->cluster_sectors); 988c336500dSKevin Wolf if (ret < 0) { 989bf81507dSFam Zheng ret = VMDK_ERROR; 990bf81507dSFam Zheng goto exit; 991019d6b8fSAnthony Liguori } 992019d6b8fSAnthony Liguori } 993bf81507dSFam Zheng exit: 994bf81507dSFam Zheng qemu_vfree(whole_grain); 995bf81507dSFam Zheng return ret; 996019d6b8fSAnthony Liguori } 997019d6b8fSAnthony Liguori 998b3976d3cSFam Zheng static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data) 999019d6b8fSAnthony Liguori { 1000e304e8e5SFam Zheng uint32_t offset; 1001e304e8e5SFam Zheng QEMU_BUILD_BUG_ON(sizeof(offset) != sizeof(m_data->offset)); 1002e304e8e5SFam Zheng offset = cpu_to_le32(m_data->offset); 1003019d6b8fSAnthony Liguori /* update L2 table */ 1004b3976d3cSFam Zheng if (bdrv_pwrite_sync( 1005b3976d3cSFam Zheng extent->file, 1006b3976d3cSFam Zheng ((int64_t)m_data->l2_offset * 512) 1007b3976d3cSFam Zheng + (m_data->l2_index * sizeof(m_data->offset)), 1008e304e8e5SFam Zheng &offset, sizeof(offset)) < 0) { 100965f74725SFam Zheng return VMDK_ERROR; 1010b3976d3cSFam Zheng } 1011019d6b8fSAnthony Liguori /* update backup L2 table */ 1012b3976d3cSFam Zheng if (extent->l1_backup_table_offset != 0) { 1013b3976d3cSFam Zheng m_data->l2_offset = extent->l1_backup_table[m_data->l1_index]; 1014b3976d3cSFam Zheng if (bdrv_pwrite_sync( 1015b3976d3cSFam Zheng extent->file, 1016b3976d3cSFam Zheng ((int64_t)m_data->l2_offset * 512) 1017b3976d3cSFam Zheng + (m_data->l2_index * sizeof(m_data->offset)), 1018e304e8e5SFam Zheng &offset, sizeof(offset)) < 0) { 101965f74725SFam Zheng return VMDK_ERROR; 1020019d6b8fSAnthony Liguori } 1021b3976d3cSFam Zheng } 1022cdeaf1f1SFam Zheng if (m_data->l2_cache_entry) { 1023cdeaf1f1SFam Zheng *m_data->l2_cache_entry = offset; 1024cdeaf1f1SFam Zheng } 1025019d6b8fSAnthony Liguori 102665f74725SFam Zheng return VMDK_OK; 1027019d6b8fSAnthony Liguori } 1028019d6b8fSAnthony Liguori 102991b85bd3SFam Zheng static int get_cluster_offset(BlockDriverState *bs, 1030b3976d3cSFam Zheng VmdkExtent *extent, 1031b3976d3cSFam Zheng VmdkMetaData *m_data, 103291b85bd3SFam Zheng uint64_t offset, 103391b85bd3SFam Zheng int allocate, 103491b85bd3SFam Zheng uint64_t *cluster_offset) 1035019d6b8fSAnthony Liguori { 1036019d6b8fSAnthony Liguori unsigned int l1_index, l2_offset, l2_index; 1037019d6b8fSAnthony Liguori int min_index, i, j; 1038e304e8e5SFam Zheng uint32_t min_count, *l2_table; 103914ead646SFam Zheng bool zeroed = false; 1040019d6b8fSAnthony Liguori 1041ae261c86SFam Zheng if (m_data) { 1042019d6b8fSAnthony Liguori m_data->valid = 0; 1043ae261c86SFam Zheng } 104491b85bd3SFam Zheng if (extent->flat) { 10457fa60fa3SFam Zheng *cluster_offset = extent->flat_start_offset; 104665f74725SFam Zheng return VMDK_OK; 104791b85bd3SFam Zheng } 1048019d6b8fSAnthony Liguori 10496398de51SFam Zheng offset -= (extent->end_sector - extent->sectors) * SECTOR_SIZE; 1050b3976d3cSFam Zheng l1_index = (offset >> 9) / extent->l1_entry_sectors; 1051b3976d3cSFam Zheng if (l1_index >= extent->l1_size) { 105265f74725SFam Zheng return VMDK_ERROR; 1053b3976d3cSFam Zheng } 1054b3976d3cSFam Zheng l2_offset = extent->l1_table[l1_index]; 1055b3976d3cSFam Zheng if (!l2_offset) { 105665f74725SFam Zheng return VMDK_UNALLOC; 1057b3976d3cSFam Zheng } 1058019d6b8fSAnthony Liguori for (i = 0; i < L2_CACHE_SIZE; i++) { 1059b3976d3cSFam Zheng if (l2_offset == extent->l2_cache_offsets[i]) { 1060019d6b8fSAnthony Liguori /* increment the hit count */ 1061b3976d3cSFam Zheng if (++extent->l2_cache_counts[i] == 0xffffffff) { 1062019d6b8fSAnthony Liguori for (j = 0; j < L2_CACHE_SIZE; j++) { 1063b3976d3cSFam Zheng extent->l2_cache_counts[j] >>= 1; 1064019d6b8fSAnthony Liguori } 1065019d6b8fSAnthony Liguori } 1066b3976d3cSFam Zheng l2_table = extent->l2_cache + (i * extent->l2_size); 1067019d6b8fSAnthony Liguori goto found; 1068019d6b8fSAnthony Liguori } 1069019d6b8fSAnthony Liguori } 1070019d6b8fSAnthony Liguori /* not found: load a new entry in the least used one */ 1071019d6b8fSAnthony Liguori min_index = 0; 1072019d6b8fSAnthony Liguori min_count = 0xffffffff; 1073019d6b8fSAnthony Liguori for (i = 0; i < L2_CACHE_SIZE; i++) { 1074b3976d3cSFam Zheng if (extent->l2_cache_counts[i] < min_count) { 1075b3976d3cSFam Zheng min_count = extent->l2_cache_counts[i]; 1076019d6b8fSAnthony Liguori min_index = i; 1077019d6b8fSAnthony Liguori } 1078019d6b8fSAnthony Liguori } 1079b3976d3cSFam Zheng l2_table = extent->l2_cache + (min_index * extent->l2_size); 1080b3976d3cSFam Zheng if (bdrv_pread( 1081b3976d3cSFam Zheng extent->file, 1082b3976d3cSFam Zheng (int64_t)l2_offset * 512, 1083b3976d3cSFam Zheng l2_table, 1084b3976d3cSFam Zheng extent->l2_size * sizeof(uint32_t) 1085b3976d3cSFam Zheng ) != extent->l2_size * sizeof(uint32_t)) { 108665f74725SFam Zheng return VMDK_ERROR; 1087b3976d3cSFam Zheng } 1088019d6b8fSAnthony Liguori 1089b3976d3cSFam Zheng extent->l2_cache_offsets[min_index] = l2_offset; 1090b3976d3cSFam Zheng extent->l2_cache_counts[min_index] = 1; 1091019d6b8fSAnthony Liguori found: 1092b3976d3cSFam Zheng l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size; 109391b85bd3SFam Zheng *cluster_offset = le32_to_cpu(l2_table[l2_index]); 1094019d6b8fSAnthony Liguori 1095cdeaf1f1SFam Zheng if (m_data) { 1096cdeaf1f1SFam Zheng m_data->valid = 1; 1097cdeaf1f1SFam Zheng m_data->l1_index = l1_index; 1098cdeaf1f1SFam Zheng m_data->l2_index = l2_index; 1099cdeaf1f1SFam Zheng m_data->offset = *cluster_offset; 1100cdeaf1f1SFam Zheng m_data->l2_offset = l2_offset; 1101cdeaf1f1SFam Zheng m_data->l2_cache_entry = &l2_table[l2_index]; 1102cdeaf1f1SFam Zheng } 110314ead646SFam Zheng if (extent->has_zero_grain && *cluster_offset == VMDK_GTE_ZEROED) { 110414ead646SFam Zheng zeroed = true; 110514ead646SFam Zheng } 110614ead646SFam Zheng 110714ead646SFam Zheng if (!*cluster_offset || zeroed) { 110891b85bd3SFam Zheng if (!allocate) { 110914ead646SFam Zheng return zeroed ? VMDK_ZEROED : VMDK_UNALLOC; 111091b85bd3SFam Zheng } 11119949f97eSKevin Wolf 1112ae261c86SFam Zheng /* Avoid the L2 tables update for the images that have snapshots. */ 111391b85bd3SFam Zheng *cluster_offset = bdrv_getlength(extent->file); 11142b2c8c5dSFam Zheng if (!extent->compressed) { 1115b3976d3cSFam Zheng bdrv_truncate( 1116b3976d3cSFam Zheng extent->file, 111791b85bd3SFam Zheng *cluster_offset + (extent->cluster_sectors << 9) 1118b3976d3cSFam Zheng ); 11192b2c8c5dSFam Zheng } 1120019d6b8fSAnthony Liguori 112191b85bd3SFam Zheng *cluster_offset >>= 9; 1122e304e8e5SFam Zheng l2_table[l2_index] = cpu_to_le32(*cluster_offset); 11239949f97eSKevin Wolf 1124019d6b8fSAnthony Liguori /* First of all we write grain itself, to avoid race condition 1125019d6b8fSAnthony Liguori * that may to corrupt the image. 1126019d6b8fSAnthony Liguori * This problem may occur because of insufficient space on host disk 1127019d6b8fSAnthony Liguori * or inappropriate VM shutdown. 1128019d6b8fSAnthony Liguori */ 1129b3976d3cSFam Zheng if (get_whole_cluster( 1130ae261c86SFam Zheng bs, extent, *cluster_offset, offset, allocate) == -1) { 113165f74725SFam Zheng return VMDK_ERROR; 1132ae261c86SFam Zheng } 1133019d6b8fSAnthony Liguori 1134019d6b8fSAnthony Liguori if (m_data) { 1135e304e8e5SFam Zheng m_data->offset = *cluster_offset; 1136019d6b8fSAnthony Liguori } 1137019d6b8fSAnthony Liguori } 113891b85bd3SFam Zheng *cluster_offset <<= 9; 113965f74725SFam Zheng return VMDK_OK; 1140019d6b8fSAnthony Liguori } 1141019d6b8fSAnthony Liguori 1142b3976d3cSFam Zheng static VmdkExtent *find_extent(BDRVVmdkState *s, 1143b3976d3cSFam Zheng int64_t sector_num, VmdkExtent *start_hint) 1144b3976d3cSFam Zheng { 1145b3976d3cSFam Zheng VmdkExtent *extent = start_hint; 1146b3976d3cSFam Zheng 1147b3976d3cSFam Zheng if (!extent) { 1148b3976d3cSFam Zheng extent = &s->extents[0]; 1149b3976d3cSFam Zheng } 1150b3976d3cSFam Zheng while (extent < &s->extents[s->num_extents]) { 1151b3976d3cSFam Zheng if (sector_num < extent->end_sector) { 1152b3976d3cSFam Zheng return extent; 1153b3976d3cSFam Zheng } 1154b3976d3cSFam Zheng extent++; 1155b3976d3cSFam Zheng } 1156b3976d3cSFam Zheng return NULL; 1157b3976d3cSFam Zheng } 1158b3976d3cSFam Zheng 1159b6b8a333SPaolo Bonzini static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs, 1160f8a2e5e3SStefan Hajnoczi int64_t sector_num, int nb_sectors, int *pnum) 1161019d6b8fSAnthony Liguori { 1162019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1163b3976d3cSFam Zheng int64_t index_in_cluster, n, ret; 1164b3976d3cSFam Zheng uint64_t offset; 1165b3976d3cSFam Zheng VmdkExtent *extent; 1166b3976d3cSFam Zheng 1167b3976d3cSFam Zheng extent = find_extent(s, sector_num, NULL); 1168b3976d3cSFam Zheng if (!extent) { 1169b3976d3cSFam Zheng return 0; 1170b3976d3cSFam Zheng } 1171f8a2e5e3SStefan Hajnoczi qemu_co_mutex_lock(&s->lock); 117291b85bd3SFam Zheng ret = get_cluster_offset(bs, extent, NULL, 117391b85bd3SFam Zheng sector_num * 512, 0, &offset); 1174f8a2e5e3SStefan Hajnoczi qemu_co_mutex_unlock(&s->lock); 117514ead646SFam Zheng 11764bc74be9SPaolo Bonzini switch (ret) { 11774bc74be9SPaolo Bonzini case VMDK_ERROR: 11784bc74be9SPaolo Bonzini ret = -EIO; 11794bc74be9SPaolo Bonzini break; 11804bc74be9SPaolo Bonzini case VMDK_UNALLOC: 11814bc74be9SPaolo Bonzini ret = 0; 11824bc74be9SPaolo Bonzini break; 11834bc74be9SPaolo Bonzini case VMDK_ZEROED: 11844bc74be9SPaolo Bonzini ret = BDRV_BLOCK_ZERO; 11854bc74be9SPaolo Bonzini break; 11864bc74be9SPaolo Bonzini case VMDK_OK: 11874bc74be9SPaolo Bonzini ret = BDRV_BLOCK_DATA; 11883eba13ecSPeter Lieven if (extent->file == bs->file && !extent->compressed) { 11894bc74be9SPaolo Bonzini ret |= BDRV_BLOCK_OFFSET_VALID | offset; 11904bc74be9SPaolo Bonzini } 11914bc74be9SPaolo Bonzini 11924bc74be9SPaolo Bonzini break; 11934bc74be9SPaolo Bonzini } 119491b85bd3SFam Zheng 1195b3976d3cSFam Zheng index_in_cluster = sector_num % extent->cluster_sectors; 1196b3976d3cSFam Zheng n = extent->cluster_sectors - index_in_cluster; 1197ae261c86SFam Zheng if (n > nb_sectors) { 1198019d6b8fSAnthony Liguori n = nb_sectors; 1199ae261c86SFam Zheng } 1200019d6b8fSAnthony Liguori *pnum = n; 1201b3976d3cSFam Zheng return ret; 1202019d6b8fSAnthony Liguori } 1203019d6b8fSAnthony Liguori 1204dd3f6ee2SFam Zheng static int vmdk_write_extent(VmdkExtent *extent, int64_t cluster_offset, 1205dd3f6ee2SFam Zheng int64_t offset_in_cluster, const uint8_t *buf, 1206dd3f6ee2SFam Zheng int nb_sectors, int64_t sector_num) 1207dd3f6ee2SFam Zheng { 1208dd3f6ee2SFam Zheng int ret; 12092b2c8c5dSFam Zheng VmdkGrainMarker *data = NULL; 12102b2c8c5dSFam Zheng uLongf buf_len; 1211dd3f6ee2SFam Zheng const uint8_t *write_buf = buf; 1212dd3f6ee2SFam Zheng int write_len = nb_sectors * 512; 1213dd3f6ee2SFam Zheng 12142b2c8c5dSFam Zheng if (extent->compressed) { 12152b2c8c5dSFam Zheng if (!extent->has_marker) { 12162b2c8c5dSFam Zheng ret = -EINVAL; 12172b2c8c5dSFam Zheng goto out; 12182b2c8c5dSFam Zheng } 12192b2c8c5dSFam Zheng buf_len = (extent->cluster_sectors << 9) * 2; 12202b2c8c5dSFam Zheng data = g_malloc(buf_len + sizeof(VmdkGrainMarker)); 12212b2c8c5dSFam Zheng if (compress(data->data, &buf_len, buf, nb_sectors << 9) != Z_OK || 12222b2c8c5dSFam Zheng buf_len == 0) { 12232b2c8c5dSFam Zheng ret = -EINVAL; 12242b2c8c5dSFam Zheng goto out; 12252b2c8c5dSFam Zheng } 12262b2c8c5dSFam Zheng data->lba = sector_num; 12272b2c8c5dSFam Zheng data->size = buf_len; 12282b2c8c5dSFam Zheng write_buf = (uint8_t *)data; 12292b2c8c5dSFam Zheng write_len = buf_len + sizeof(VmdkGrainMarker); 12302b2c8c5dSFam Zheng } 1231dd3f6ee2SFam Zheng ret = bdrv_pwrite(extent->file, 1232dd3f6ee2SFam Zheng cluster_offset + offset_in_cluster, 1233dd3f6ee2SFam Zheng write_buf, 1234dd3f6ee2SFam Zheng write_len); 1235dd3f6ee2SFam Zheng if (ret != write_len) { 1236dd3f6ee2SFam Zheng ret = ret < 0 ? ret : -EIO; 1237dd3f6ee2SFam Zheng goto out; 1238dd3f6ee2SFam Zheng } 1239dd3f6ee2SFam Zheng ret = 0; 1240dd3f6ee2SFam Zheng out: 12412b2c8c5dSFam Zheng g_free(data); 1242dd3f6ee2SFam Zheng return ret; 1243dd3f6ee2SFam Zheng } 1244dd3f6ee2SFam Zheng 1245dd3f6ee2SFam Zheng static int vmdk_read_extent(VmdkExtent *extent, int64_t cluster_offset, 1246dd3f6ee2SFam Zheng int64_t offset_in_cluster, uint8_t *buf, 1247dd3f6ee2SFam Zheng int nb_sectors) 1248dd3f6ee2SFam Zheng { 1249dd3f6ee2SFam Zheng int ret; 12502b2c8c5dSFam Zheng int cluster_bytes, buf_bytes; 12512b2c8c5dSFam Zheng uint8_t *cluster_buf, *compressed_data; 12522b2c8c5dSFam Zheng uint8_t *uncomp_buf; 12532b2c8c5dSFam Zheng uint32_t data_len; 12542b2c8c5dSFam Zheng VmdkGrainMarker *marker; 12552b2c8c5dSFam Zheng uLongf buf_len; 1256dd3f6ee2SFam Zheng 12572b2c8c5dSFam Zheng 12582b2c8c5dSFam Zheng if (!extent->compressed) { 1259dd3f6ee2SFam Zheng ret = bdrv_pread(extent->file, 1260dd3f6ee2SFam Zheng cluster_offset + offset_in_cluster, 1261dd3f6ee2SFam Zheng buf, nb_sectors * 512); 1262dd3f6ee2SFam Zheng if (ret == nb_sectors * 512) { 1263dd3f6ee2SFam Zheng return 0; 1264dd3f6ee2SFam Zheng } else { 1265dd3f6ee2SFam Zheng return -EIO; 1266dd3f6ee2SFam Zheng } 1267dd3f6ee2SFam Zheng } 12682b2c8c5dSFam Zheng cluster_bytes = extent->cluster_sectors * 512; 12692b2c8c5dSFam Zheng /* Read two clusters in case GrainMarker + compressed data > one cluster */ 12702b2c8c5dSFam Zheng buf_bytes = cluster_bytes * 2; 12712b2c8c5dSFam Zheng cluster_buf = g_malloc(buf_bytes); 12722b2c8c5dSFam Zheng uncomp_buf = g_malloc(cluster_bytes); 12732b2c8c5dSFam Zheng ret = bdrv_pread(extent->file, 12742b2c8c5dSFam Zheng cluster_offset, 12752b2c8c5dSFam Zheng cluster_buf, buf_bytes); 12762b2c8c5dSFam Zheng if (ret < 0) { 12772b2c8c5dSFam Zheng goto out; 12782b2c8c5dSFam Zheng } 12792b2c8c5dSFam Zheng compressed_data = cluster_buf; 12802b2c8c5dSFam Zheng buf_len = cluster_bytes; 12812b2c8c5dSFam Zheng data_len = cluster_bytes; 12822b2c8c5dSFam Zheng if (extent->has_marker) { 12832b2c8c5dSFam Zheng marker = (VmdkGrainMarker *)cluster_buf; 12842b2c8c5dSFam Zheng compressed_data = marker->data; 12852b2c8c5dSFam Zheng data_len = le32_to_cpu(marker->size); 12862b2c8c5dSFam Zheng } 12872b2c8c5dSFam Zheng if (!data_len || data_len > buf_bytes) { 12882b2c8c5dSFam Zheng ret = -EINVAL; 12892b2c8c5dSFam Zheng goto out; 12902b2c8c5dSFam Zheng } 12912b2c8c5dSFam Zheng ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len); 12922b2c8c5dSFam Zheng if (ret != Z_OK) { 12932b2c8c5dSFam Zheng ret = -EINVAL; 12942b2c8c5dSFam Zheng goto out; 12952b2c8c5dSFam Zheng 12962b2c8c5dSFam Zheng } 12972b2c8c5dSFam Zheng if (offset_in_cluster < 0 || 12982b2c8c5dSFam Zheng offset_in_cluster + nb_sectors * 512 > buf_len) { 12992b2c8c5dSFam Zheng ret = -EINVAL; 13002b2c8c5dSFam Zheng goto out; 13012b2c8c5dSFam Zheng } 13022b2c8c5dSFam Zheng memcpy(buf, uncomp_buf + offset_in_cluster, nb_sectors * 512); 13032b2c8c5dSFam Zheng ret = 0; 13042b2c8c5dSFam Zheng 13052b2c8c5dSFam Zheng out: 13062b2c8c5dSFam Zheng g_free(uncomp_buf); 13072b2c8c5dSFam Zheng g_free(cluster_buf); 13082b2c8c5dSFam Zheng return ret; 13092b2c8c5dSFam Zheng } 1310dd3f6ee2SFam Zheng 1311019d6b8fSAnthony Liguori static int vmdk_read(BlockDriverState *bs, int64_t sector_num, 1312019d6b8fSAnthony Liguori uint8_t *buf, int nb_sectors) 1313019d6b8fSAnthony Liguori { 1314019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1315b3976d3cSFam Zheng int ret; 1316b3976d3cSFam Zheng uint64_t n, index_in_cluster; 1317b1649faeSGerhard Wiesinger uint64_t extent_begin_sector, extent_relative_sector_num; 1318b3976d3cSFam Zheng VmdkExtent *extent = NULL; 1319019d6b8fSAnthony Liguori uint64_t cluster_offset; 1320019d6b8fSAnthony Liguori 1321019d6b8fSAnthony Liguori while (nb_sectors > 0) { 1322b3976d3cSFam Zheng extent = find_extent(s, sector_num, extent); 1323b3976d3cSFam Zheng if (!extent) { 1324b3976d3cSFam Zheng return -EIO; 1325b3976d3cSFam Zheng } 132691b85bd3SFam Zheng ret = get_cluster_offset( 132791b85bd3SFam Zheng bs, extent, NULL, 132891b85bd3SFam Zheng sector_num << 9, 0, &cluster_offset); 1329b1649faeSGerhard Wiesinger extent_begin_sector = extent->end_sector - extent->sectors; 1330b1649faeSGerhard Wiesinger extent_relative_sector_num = sector_num - extent_begin_sector; 1331b1649faeSGerhard Wiesinger index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; 1332b3976d3cSFam Zheng n = extent->cluster_sectors - index_in_cluster; 1333ae261c86SFam Zheng if (n > nb_sectors) { 1334019d6b8fSAnthony Liguori n = nb_sectors; 1335ae261c86SFam Zheng } 133614ead646SFam Zheng if (ret != VMDK_OK) { 133791b85bd3SFam Zheng /* if not allocated, try to read from parent image, if exist */ 133814ead646SFam Zheng if (bs->backing_hd && ret != VMDK_ZEROED) { 1339ae261c86SFam Zheng if (!vmdk_is_cid_valid(bs)) { 13407fa60fa3SFam Zheng return -EINVAL; 1341ae261c86SFam Zheng } 1342b171271aSKevin Wolf ret = bdrv_read(bs->backing_hd, sector_num, buf, n); 1343ae261c86SFam Zheng if (ret < 0) { 13447fa60fa3SFam Zheng return ret; 1345ae261c86SFam Zheng } 1346019d6b8fSAnthony Liguori } else { 1347019d6b8fSAnthony Liguori memset(buf, 0, 512 * n); 1348019d6b8fSAnthony Liguori } 1349019d6b8fSAnthony Liguori } else { 1350dd3f6ee2SFam Zheng ret = vmdk_read_extent(extent, 1351dd3f6ee2SFam Zheng cluster_offset, index_in_cluster * 512, 1352dd3f6ee2SFam Zheng buf, n); 1353dd3f6ee2SFam Zheng if (ret) { 13547fa60fa3SFam Zheng return ret; 13557fa60fa3SFam Zheng } 1356019d6b8fSAnthony Liguori } 1357019d6b8fSAnthony Liguori nb_sectors -= n; 1358019d6b8fSAnthony Liguori sector_num += n; 1359019d6b8fSAnthony Liguori buf += n * 512; 1360019d6b8fSAnthony Liguori } 1361019d6b8fSAnthony Liguori return 0; 1362019d6b8fSAnthony Liguori } 1363019d6b8fSAnthony Liguori 13642914caa0SPaolo Bonzini static coroutine_fn int vmdk_co_read(BlockDriverState *bs, int64_t sector_num, 13652914caa0SPaolo Bonzini uint8_t *buf, int nb_sectors) 13662914caa0SPaolo Bonzini { 13672914caa0SPaolo Bonzini int ret; 13682914caa0SPaolo Bonzini BDRVVmdkState *s = bs->opaque; 13692914caa0SPaolo Bonzini qemu_co_mutex_lock(&s->lock); 13702914caa0SPaolo Bonzini ret = vmdk_read(bs, sector_num, buf, nb_sectors); 13712914caa0SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 13722914caa0SPaolo Bonzini return ret; 13732914caa0SPaolo Bonzini } 13742914caa0SPaolo Bonzini 1375cdeaf1f1SFam Zheng /** 1376cdeaf1f1SFam Zheng * vmdk_write: 1377cdeaf1f1SFam Zheng * @zeroed: buf is ignored (data is zero), use zeroed_grain GTE feature 1378cdeaf1f1SFam Zheng * if possible, otherwise return -ENOTSUP. 13798e507243SFam Zheng * @zero_dry_run: used for zeroed == true only, don't update L2 table, just try 13808e507243SFam Zheng * with each cluster. By dry run we can find if the zero write 13818e507243SFam Zheng * is possible without modifying image data. 1382cdeaf1f1SFam Zheng * 1383cdeaf1f1SFam Zheng * Returns: error code with 0 for success. 1384cdeaf1f1SFam Zheng */ 1385019d6b8fSAnthony Liguori static int vmdk_write(BlockDriverState *bs, int64_t sector_num, 1386cdeaf1f1SFam Zheng const uint8_t *buf, int nb_sectors, 1387cdeaf1f1SFam Zheng bool zeroed, bool zero_dry_run) 1388019d6b8fSAnthony Liguori { 1389019d6b8fSAnthony Liguori BDRVVmdkState *s = bs->opaque; 1390b3976d3cSFam Zheng VmdkExtent *extent = NULL; 1391585ea0c8SFam Zheng int ret; 1392585ea0c8SFam Zheng int64_t index_in_cluster, n; 1393b1649faeSGerhard Wiesinger uint64_t extent_begin_sector, extent_relative_sector_num; 1394019d6b8fSAnthony Liguori uint64_t cluster_offset; 1395b3976d3cSFam Zheng VmdkMetaData m_data; 1396019d6b8fSAnthony Liguori 1397019d6b8fSAnthony Liguori if (sector_num > bs->total_sectors) { 13984823970bSFam Zheng error_report("Wrong offset: sector_num=0x%" PRIx64 1399019d6b8fSAnthony Liguori " total_sectors=0x%" PRIx64 "\n", 1400019d6b8fSAnthony Liguori sector_num, bs->total_sectors); 14017fa60fa3SFam Zheng return -EIO; 1402019d6b8fSAnthony Liguori } 1403019d6b8fSAnthony Liguori 1404019d6b8fSAnthony Liguori while (nb_sectors > 0) { 1405b3976d3cSFam Zheng extent = find_extent(s, sector_num, extent); 1406b3976d3cSFam Zheng if (!extent) { 1407b3976d3cSFam Zheng return -EIO; 1408b3976d3cSFam Zheng } 140991b85bd3SFam Zheng ret = get_cluster_offset( 1410b3976d3cSFam Zheng bs, 1411b3976d3cSFam Zheng extent, 1412b3976d3cSFam Zheng &m_data, 14132b2c8c5dSFam Zheng sector_num << 9, !extent->compressed, 14142b2c8c5dSFam Zheng &cluster_offset); 14152b2c8c5dSFam Zheng if (extent->compressed) { 141665f74725SFam Zheng if (ret == VMDK_OK) { 14172b2c8c5dSFam Zheng /* Refuse write to allocated cluster for streamOptimized */ 14184823970bSFam Zheng error_report("Could not write to allocated cluster" 14194823970bSFam Zheng " for streamOptimized"); 14202b2c8c5dSFam Zheng return -EIO; 14212b2c8c5dSFam Zheng } else { 14222b2c8c5dSFam Zheng /* allocate */ 14232b2c8c5dSFam Zheng ret = get_cluster_offset( 14242b2c8c5dSFam Zheng bs, 14252b2c8c5dSFam Zheng extent, 14262b2c8c5dSFam Zheng &m_data, 142791b85bd3SFam Zheng sector_num << 9, 1, 142891b85bd3SFam Zheng &cluster_offset); 14292b2c8c5dSFam Zheng } 14302b2c8c5dSFam Zheng } 1431cdeaf1f1SFam Zheng if (ret == VMDK_ERROR) { 143291b85bd3SFam Zheng return -EINVAL; 1433b3976d3cSFam Zheng } 1434b1649faeSGerhard Wiesinger extent_begin_sector = extent->end_sector - extent->sectors; 1435b1649faeSGerhard Wiesinger extent_relative_sector_num = sector_num - extent_begin_sector; 1436b1649faeSGerhard Wiesinger index_in_cluster = extent_relative_sector_num % extent->cluster_sectors; 1437b3976d3cSFam Zheng n = extent->cluster_sectors - index_in_cluster; 1438b3976d3cSFam Zheng if (n > nb_sectors) { 1439019d6b8fSAnthony Liguori n = nb_sectors; 1440b3976d3cSFam Zheng } 1441cdeaf1f1SFam Zheng if (zeroed) { 1442cdeaf1f1SFam Zheng /* Do zeroed write, buf is ignored */ 1443cdeaf1f1SFam Zheng if (extent->has_zero_grain && 1444cdeaf1f1SFam Zheng index_in_cluster == 0 && 1445cdeaf1f1SFam Zheng n >= extent->cluster_sectors) { 1446cdeaf1f1SFam Zheng n = extent->cluster_sectors; 1447cdeaf1f1SFam Zheng if (!zero_dry_run) { 1448cdeaf1f1SFam Zheng m_data.offset = VMDK_GTE_ZEROED; 1449cdeaf1f1SFam Zheng /* update L2 tables */ 1450cdeaf1f1SFam Zheng if (vmdk_L2update(extent, &m_data) != VMDK_OK) { 1451cdeaf1f1SFam Zheng return -EIO; 1452cdeaf1f1SFam Zheng } 1453cdeaf1f1SFam Zheng } 1454cdeaf1f1SFam Zheng } else { 1455cdeaf1f1SFam Zheng return -ENOTSUP; 1456cdeaf1f1SFam Zheng } 1457cdeaf1f1SFam Zheng } else { 1458dd3f6ee2SFam Zheng ret = vmdk_write_extent(extent, 1459dd3f6ee2SFam Zheng cluster_offset, index_in_cluster * 512, 1460dd3f6ee2SFam Zheng buf, n, sector_num); 1461dd3f6ee2SFam Zheng if (ret) { 14627fa60fa3SFam Zheng return ret; 1463b3976d3cSFam Zheng } 1464019d6b8fSAnthony Liguori if (m_data.valid) { 1465019d6b8fSAnthony Liguori /* update L2 tables */ 1466cdeaf1f1SFam Zheng if (vmdk_L2update(extent, &m_data) != VMDK_OK) { 14677fa60fa3SFam Zheng return -EIO; 1468019d6b8fSAnthony Liguori } 1469b3976d3cSFam Zheng } 1470cdeaf1f1SFam Zheng } 1471019d6b8fSAnthony Liguori nb_sectors -= n; 1472019d6b8fSAnthony Liguori sector_num += n; 1473019d6b8fSAnthony Liguori buf += n * 512; 1474019d6b8fSAnthony Liguori 1475ae261c86SFam Zheng /* update CID on the first write every time the virtual disk is 1476ae261c86SFam Zheng * opened */ 147769b4d86dSFam Zheng if (!s->cid_updated) { 147899f1835dSKevin Wolf ret = vmdk_write_cid(bs, time(NULL)); 147999f1835dSKevin Wolf if (ret < 0) { 148099f1835dSKevin Wolf return ret; 148199f1835dSKevin Wolf } 148269b4d86dSFam Zheng s->cid_updated = true; 1483019d6b8fSAnthony Liguori } 1484019d6b8fSAnthony Liguori } 1485019d6b8fSAnthony Liguori return 0; 1486019d6b8fSAnthony Liguori } 1487019d6b8fSAnthony Liguori 1488e183ef75SPaolo Bonzini static coroutine_fn int vmdk_co_write(BlockDriverState *bs, int64_t sector_num, 1489e183ef75SPaolo Bonzini const uint8_t *buf, int nb_sectors) 1490e183ef75SPaolo Bonzini { 1491e183ef75SPaolo Bonzini int ret; 1492e183ef75SPaolo Bonzini BDRVVmdkState *s = bs->opaque; 1493e183ef75SPaolo Bonzini qemu_co_mutex_lock(&s->lock); 1494cdeaf1f1SFam Zheng ret = vmdk_write(bs, sector_num, buf, nb_sectors, false, false); 1495cdeaf1f1SFam Zheng qemu_co_mutex_unlock(&s->lock); 1496cdeaf1f1SFam Zheng return ret; 1497cdeaf1f1SFam Zheng } 1498cdeaf1f1SFam Zheng 1499ba0ad89eSFam Zheng static int vmdk_write_compressed(BlockDriverState *bs, 1500ba0ad89eSFam Zheng int64_t sector_num, 1501ba0ad89eSFam Zheng const uint8_t *buf, 1502ba0ad89eSFam Zheng int nb_sectors) 1503ba0ad89eSFam Zheng { 1504ba0ad89eSFam Zheng BDRVVmdkState *s = bs->opaque; 1505ba0ad89eSFam Zheng if (s->num_extents == 1 && s->extents[0].compressed) { 1506ba0ad89eSFam Zheng return vmdk_write(bs, sector_num, buf, nb_sectors, false, false); 1507ba0ad89eSFam Zheng } else { 1508ba0ad89eSFam Zheng return -ENOTSUP; 1509ba0ad89eSFam Zheng } 1510ba0ad89eSFam Zheng } 1511ba0ad89eSFam Zheng 1512cdeaf1f1SFam Zheng static int coroutine_fn vmdk_co_write_zeroes(BlockDriverState *bs, 1513cdeaf1f1SFam Zheng int64_t sector_num, 1514aa7bfbffSPeter Lieven int nb_sectors, 1515aa7bfbffSPeter Lieven BdrvRequestFlags flags) 1516cdeaf1f1SFam Zheng { 1517cdeaf1f1SFam Zheng int ret; 1518cdeaf1f1SFam Zheng BDRVVmdkState *s = bs->opaque; 1519cdeaf1f1SFam Zheng qemu_co_mutex_lock(&s->lock); 15208e507243SFam Zheng /* write zeroes could fail if sectors not aligned to cluster, test it with 15218e507243SFam Zheng * dry_run == true before really updating image */ 1522cdeaf1f1SFam Zheng ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, true); 1523cdeaf1f1SFam Zheng if (!ret) { 1524cdeaf1f1SFam Zheng ret = vmdk_write(bs, sector_num, NULL, nb_sectors, true, false); 1525cdeaf1f1SFam Zheng } 1526e183ef75SPaolo Bonzini qemu_co_mutex_unlock(&s->lock); 1527e183ef75SPaolo Bonzini return ret; 1528e183ef75SPaolo Bonzini } 1529e183ef75SPaolo Bonzini 15306c031aacSFam Zheng static int vmdk_create_extent(const char *filename, int64_t filesize, 1531917703c1SFam Zheng bool flat, bool compress, bool zeroed_grain, 1532*4ab15590SChunyan Liu QemuOpts *opts, Error **errp) 1533019d6b8fSAnthony Liguori { 1534f66fd6c3SFam Zheng int ret, i; 1535917703c1SFam Zheng BlockDriverState *bs = NULL; 1536019d6b8fSAnthony Liguori VMDK4Header header; 1537c13959c7SFam Zheng Error *local_err = NULL; 1538917703c1SFam Zheng uint32_t tmp, magic, grains, gd_sectors, gt_size, gt_count; 1539917703c1SFam Zheng uint32_t *gd_buf = NULL; 1540917703c1SFam Zheng int gd_buf_size; 15410e7e1989SKevin Wolf 1542*4ab15590SChunyan Liu ret = bdrv_create_file(filename, opts, &local_err); 1543f66fd6c3SFam Zheng if (ret < 0) { 1544917703c1SFam Zheng error_propagate(errp, local_err); 1545917703c1SFam Zheng goto exit; 1546917703c1SFam Zheng } 1547917703c1SFam Zheng 15482e40134bSMax Reitz assert(bs == NULL); 15492e40134bSMax Reitz ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL, 15502e40134bSMax Reitz NULL, &local_err); 1551917703c1SFam Zheng if (ret < 0) { 1552917703c1SFam Zheng error_propagate(errp, local_err); 1553917703c1SFam Zheng goto exit; 1554917703c1SFam Zheng } 1555917703c1SFam Zheng 1556917703c1SFam Zheng if (flat) { 1557917703c1SFam Zheng ret = bdrv_truncate(bs, filesize); 1558917703c1SFam Zheng if (ret < 0) { 155939a611a3SJeff Cody error_setg_errno(errp, -ret, "Could not truncate file"); 1560f66fd6c3SFam Zheng } 1561f66fd6c3SFam Zheng goto exit; 1562f66fd6c3SFam Zheng } 1563019d6b8fSAnthony Liguori magic = cpu_to_be32(VMDK4_MAGIC); 1564019d6b8fSAnthony Liguori memset(&header, 0, sizeof(header)); 156569e0b6dfSFam Zheng header.version = zeroed_grain ? 2 : 1; 156695b0aa42SFam Zheng header.flags = VMDK4_FLAG_RGD | VMDK4_FLAG_NL_DETECT 156769e0b6dfSFam Zheng | (compress ? VMDK4_FLAG_COMPRESS | VMDK4_FLAG_MARKER : 0) 156869e0b6dfSFam Zheng | (zeroed_grain ? VMDK4_FLAG_ZERO_GRAIN : 0); 15696c031aacSFam Zheng header.compressAlgorithm = compress ? VMDK4_COMPRESSION_DEFLATE : 0; 1570917703c1SFam Zheng header.capacity = filesize / BDRV_SECTOR_SIZE; 157116372ff0SAlexander Graf header.granularity = 128; 1572917703c1SFam Zheng header.num_gtes_per_gt = BDRV_SECTOR_SIZE; 1573019d6b8fSAnthony Liguori 1574917703c1SFam Zheng grains = DIV_ROUND_UP(filesize / BDRV_SECTOR_SIZE, header.granularity); 1575917703c1SFam Zheng gt_size = DIV_ROUND_UP(header.num_gtes_per_gt * sizeof(uint32_t), 1576917703c1SFam Zheng BDRV_SECTOR_SIZE); 1577917703c1SFam Zheng gt_count = DIV_ROUND_UP(grains, header.num_gtes_per_gt); 1578917703c1SFam Zheng gd_sectors = DIV_ROUND_UP(gt_count * sizeof(uint32_t), BDRV_SECTOR_SIZE); 1579019d6b8fSAnthony Liguori 1580019d6b8fSAnthony Liguori header.desc_offset = 1; 1581019d6b8fSAnthony Liguori header.desc_size = 20; 1582019d6b8fSAnthony Liguori header.rgd_offset = header.desc_offset + header.desc_size; 1583917703c1SFam Zheng header.gd_offset = header.rgd_offset + gd_sectors + (gt_size * gt_count); 1584019d6b8fSAnthony Liguori header.grain_offset = 1585917703c1SFam Zheng ROUND_UP(header.gd_offset + gd_sectors + (gt_size * gt_count), 1586917703c1SFam Zheng header.granularity); 158716372ff0SAlexander Graf /* swap endianness for all header fields */ 158816372ff0SAlexander Graf header.version = cpu_to_le32(header.version); 158916372ff0SAlexander Graf header.flags = cpu_to_le32(header.flags); 159016372ff0SAlexander Graf header.capacity = cpu_to_le64(header.capacity); 159116372ff0SAlexander Graf header.granularity = cpu_to_le64(header.granularity); 1592ca8804ceSFam Zheng header.num_gtes_per_gt = cpu_to_le32(header.num_gtes_per_gt); 1593019d6b8fSAnthony Liguori header.desc_offset = cpu_to_le64(header.desc_offset); 1594019d6b8fSAnthony Liguori header.desc_size = cpu_to_le64(header.desc_size); 1595019d6b8fSAnthony Liguori header.rgd_offset = cpu_to_le64(header.rgd_offset); 1596019d6b8fSAnthony Liguori header.gd_offset = cpu_to_le64(header.gd_offset); 1597019d6b8fSAnthony Liguori header.grain_offset = cpu_to_le64(header.grain_offset); 15986c031aacSFam Zheng header.compressAlgorithm = cpu_to_le16(header.compressAlgorithm); 1599019d6b8fSAnthony Liguori 1600019d6b8fSAnthony Liguori header.check_bytes[0] = 0xa; 1601019d6b8fSAnthony Liguori header.check_bytes[1] = 0x20; 1602019d6b8fSAnthony Liguori header.check_bytes[2] = 0xd; 1603019d6b8fSAnthony Liguori header.check_bytes[3] = 0xa; 1604019d6b8fSAnthony Liguori 1605019d6b8fSAnthony Liguori /* write all the data */ 1606917703c1SFam Zheng ret = bdrv_pwrite(bs, 0, &magic, sizeof(magic)); 1607917703c1SFam Zheng if (ret < 0) { 1608917703c1SFam Zheng error_set(errp, QERR_IO_ERROR); 16091640366cSKirill A. Shutemov goto exit; 16101640366cSKirill A. Shutemov } 1611917703c1SFam Zheng ret = bdrv_pwrite(bs, sizeof(magic), &header, sizeof(header)); 1612917703c1SFam Zheng if (ret < 0) { 1613917703c1SFam Zheng error_set(errp, QERR_IO_ERROR); 16141640366cSKirill A. Shutemov goto exit; 16151640366cSKirill A. Shutemov } 1616019d6b8fSAnthony Liguori 1617917703c1SFam Zheng ret = bdrv_truncate(bs, le64_to_cpu(header.grain_offset) << 9); 16181640366cSKirill A. Shutemov if (ret < 0) { 161939a611a3SJeff Cody error_setg_errno(errp, -ret, "Could not truncate file"); 16201640366cSKirill A. Shutemov goto exit; 16211640366cSKirill A. Shutemov } 1622019d6b8fSAnthony Liguori 1623019d6b8fSAnthony Liguori /* write grain directory */ 1624917703c1SFam Zheng gd_buf_size = gd_sectors * BDRV_SECTOR_SIZE; 1625917703c1SFam Zheng gd_buf = g_malloc0(gd_buf_size); 1626917703c1SFam Zheng for (i = 0, tmp = le64_to_cpu(header.rgd_offset) + gd_sectors; 16271640366cSKirill A. Shutemov i < gt_count; i++, tmp += gt_size) { 1628917703c1SFam Zheng gd_buf[i] = cpu_to_le32(tmp); 16291640366cSKirill A. Shutemov } 1630917703c1SFam Zheng ret = bdrv_pwrite(bs, le64_to_cpu(header.rgd_offset) * BDRV_SECTOR_SIZE, 1631917703c1SFam Zheng gd_buf, gd_buf_size); 1632917703c1SFam Zheng if (ret < 0) { 1633917703c1SFam Zheng error_set(errp, QERR_IO_ERROR); 1634917703c1SFam Zheng goto exit; 16351640366cSKirill A. Shutemov } 1636019d6b8fSAnthony Liguori 1637019d6b8fSAnthony Liguori /* write backup grain directory */ 1638917703c1SFam Zheng for (i = 0, tmp = le64_to_cpu(header.gd_offset) + gd_sectors; 16391640366cSKirill A. Shutemov i < gt_count; i++, tmp += gt_size) { 1640917703c1SFam Zheng gd_buf[i] = cpu_to_le32(tmp); 16411640366cSKirill A. Shutemov } 1642917703c1SFam Zheng ret = bdrv_pwrite(bs, le64_to_cpu(header.gd_offset) * BDRV_SECTOR_SIZE, 1643917703c1SFam Zheng gd_buf, gd_buf_size); 1644917703c1SFam Zheng if (ret < 0) { 1645917703c1SFam Zheng error_set(errp, QERR_IO_ERROR); 1646917703c1SFam Zheng goto exit; 16471640366cSKirill A. Shutemov } 1648019d6b8fSAnthony Liguori 1649f66fd6c3SFam Zheng ret = 0; 1650f66fd6c3SFam Zheng exit: 1651917703c1SFam Zheng if (bs) { 1652917703c1SFam Zheng bdrv_unref(bs); 1653917703c1SFam Zheng } 1654917703c1SFam Zheng g_free(gd_buf); 1655f66fd6c3SFam Zheng return ret; 1656f66fd6c3SFam Zheng } 1657019d6b8fSAnthony Liguori 1658f66fd6c3SFam Zheng static int filename_decompose(const char *filename, char *path, char *prefix, 16594823970bSFam Zheng char *postfix, size_t buf_len, Error **errp) 1660f66fd6c3SFam Zheng { 1661f66fd6c3SFam Zheng const char *p, *q; 1662f66fd6c3SFam Zheng 1663f66fd6c3SFam Zheng if (filename == NULL || !strlen(filename)) { 16644823970bSFam Zheng error_setg(errp, "No filename provided"); 166565f74725SFam Zheng return VMDK_ERROR; 1666f66fd6c3SFam Zheng } 1667f66fd6c3SFam Zheng p = strrchr(filename, '/'); 1668f66fd6c3SFam Zheng if (p == NULL) { 1669f66fd6c3SFam Zheng p = strrchr(filename, '\\'); 1670f66fd6c3SFam Zheng } 1671f66fd6c3SFam Zheng if (p == NULL) { 1672f66fd6c3SFam Zheng p = strrchr(filename, ':'); 1673f66fd6c3SFam Zheng } 1674f66fd6c3SFam Zheng if (p != NULL) { 1675f66fd6c3SFam Zheng p++; 1676f66fd6c3SFam Zheng if (p - filename >= buf_len) { 167765f74725SFam Zheng return VMDK_ERROR; 1678f66fd6c3SFam Zheng } 1679f66fd6c3SFam Zheng pstrcpy(path, p - filename + 1, filename); 1680f66fd6c3SFam Zheng } else { 1681f66fd6c3SFam Zheng p = filename; 1682f66fd6c3SFam Zheng path[0] = '\0'; 1683f66fd6c3SFam Zheng } 1684f66fd6c3SFam Zheng q = strrchr(p, '.'); 1685f66fd6c3SFam Zheng if (q == NULL) { 1686f66fd6c3SFam Zheng pstrcpy(prefix, buf_len, p); 1687f66fd6c3SFam Zheng postfix[0] = '\0'; 1688f66fd6c3SFam Zheng } else { 1689f66fd6c3SFam Zheng if (q - p >= buf_len) { 169065f74725SFam Zheng return VMDK_ERROR; 1691f66fd6c3SFam Zheng } 1692f66fd6c3SFam Zheng pstrcpy(prefix, q - p + 1, p); 1693f66fd6c3SFam Zheng pstrcpy(postfix, buf_len, q); 1694f66fd6c3SFam Zheng } 169565f74725SFam Zheng return VMDK_OK; 1696f66fd6c3SFam Zheng } 1697f66fd6c3SFam Zheng 16985820f1daSChunyan Liu static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp) 1699f66fd6c3SFam Zheng { 1700917703c1SFam Zheng int idx = 0; 1701917703c1SFam Zheng BlockDriverState *new_bs = NULL; 1702c13959c7SFam Zheng Error *local_err = NULL; 1703af057fe7SFam Zheng char *desc = NULL; 1704f66fd6c3SFam Zheng int64_t total_size = 0, filesize; 17055820f1daSChunyan Liu char *adapter_type = NULL; 17065820f1daSChunyan Liu char *backing_file = NULL; 17075820f1daSChunyan Liu char *fmt = NULL; 1708f66fd6c3SFam Zheng int flags = 0; 1709f66fd6c3SFam Zheng int ret = 0; 17106c031aacSFam Zheng bool flat, split, compress; 1711af057fe7SFam Zheng GString *ext_desc_lines; 1712f66fd6c3SFam Zheng char path[PATH_MAX], prefix[PATH_MAX], postfix[PATH_MAX]; 1713f66fd6c3SFam Zheng const int64_t split_size = 0x80000000; /* VMDK has constant split size */ 1714f66fd6c3SFam Zheng const char *desc_extent_line; 1715f66fd6c3SFam Zheng char parent_desc_line[BUF_SIZE] = ""; 1716f66fd6c3SFam Zheng uint32_t parent_cid = 0xffffffff; 17177f2039f6SOthmar Pasteka uint32_t number_heads = 16; 171869e0b6dfSFam Zheng bool zeroed_grain = false; 1719917703c1SFam Zheng uint32_t desc_offset = 0, desc_len; 1720f66fd6c3SFam Zheng const char desc_template[] = 1721f66fd6c3SFam Zheng "# Disk DescriptorFile\n" 1722f66fd6c3SFam Zheng "version=1\n" 17239b17031aSFam Zheng "CID=%" PRIx32 "\n" 17249b17031aSFam Zheng "parentCID=%" PRIx32 "\n" 1725f66fd6c3SFam Zheng "createType=\"%s\"\n" 1726f66fd6c3SFam Zheng "%s" 1727f66fd6c3SFam Zheng "\n" 1728f66fd6c3SFam Zheng "# Extent description\n" 1729f66fd6c3SFam Zheng "%s" 1730f66fd6c3SFam Zheng "\n" 1731f66fd6c3SFam Zheng "# The Disk Data Base\n" 1732f66fd6c3SFam Zheng "#DDB\n" 1733f66fd6c3SFam Zheng "\n" 1734f66fd6c3SFam Zheng "ddb.virtualHWVersion = \"%d\"\n" 1735f66fd6c3SFam Zheng "ddb.geometry.cylinders = \"%" PRId64 "\"\n" 17364ab9dab5SFam Zheng "ddb.geometry.heads = \"%" PRIu32 "\"\n" 1737f66fd6c3SFam Zheng "ddb.geometry.sectors = \"63\"\n" 17387f2039f6SOthmar Pasteka "ddb.adapterType = \"%s\"\n"; 1739f66fd6c3SFam Zheng 1740af057fe7SFam Zheng ext_desc_lines = g_string_new(NULL); 1741af057fe7SFam Zheng 17424823970bSFam Zheng if (filename_decompose(filename, path, prefix, postfix, PATH_MAX, errp)) { 1743af057fe7SFam Zheng ret = -EINVAL; 1744af057fe7SFam Zheng goto exit; 1745f66fd6c3SFam Zheng } 1746f66fd6c3SFam Zheng /* Read out options */ 17475820f1daSChunyan Liu total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0); 17485820f1daSChunyan Liu adapter_type = qemu_opt_get_del(opts, BLOCK_OPT_ADAPTER_TYPE); 17495820f1daSChunyan Liu backing_file = qemu_opt_get_del(opts, BLOCK_OPT_BACKING_FILE); 17505820f1daSChunyan Liu if (qemu_opt_get_bool_del(opts, BLOCK_OPT_COMPAT6, false)) { 17515820f1daSChunyan Liu flags |= BLOCK_FLAG_COMPAT6; 1752f66fd6c3SFam Zheng } 17535820f1daSChunyan Liu fmt = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT); 17545820f1daSChunyan Liu if (qemu_opt_get_bool_del(opts, BLOCK_OPT_ZEROED_GRAIN, false)) { 17555820f1daSChunyan Liu zeroed_grain = true; 1756f66fd6c3SFam Zheng } 17575820f1daSChunyan Liu 17587f2039f6SOthmar Pasteka if (!adapter_type) { 17595820f1daSChunyan Liu adapter_type = g_strdup("ide"); 17607f2039f6SOthmar Pasteka } else if (strcmp(adapter_type, "ide") && 17617f2039f6SOthmar Pasteka strcmp(adapter_type, "buslogic") && 17627f2039f6SOthmar Pasteka strcmp(adapter_type, "lsilogic") && 17637f2039f6SOthmar Pasteka strcmp(adapter_type, "legacyESX")) { 17644823970bSFam Zheng error_setg(errp, "Unknown adapter type: '%s'", adapter_type); 1765af057fe7SFam Zheng ret = -EINVAL; 1766af057fe7SFam Zheng goto exit; 17677f2039f6SOthmar Pasteka } 17687f2039f6SOthmar Pasteka if (strcmp(adapter_type, "ide") != 0) { 17697f2039f6SOthmar Pasteka /* that's the number of heads with which vmware operates when 17707f2039f6SOthmar Pasteka creating, exporting, etc. vmdk files with a non-ide adapter type */ 17717f2039f6SOthmar Pasteka number_heads = 255; 17727f2039f6SOthmar Pasteka } 1773f66fd6c3SFam Zheng if (!fmt) { 1774f66fd6c3SFam Zheng /* Default format to monolithicSparse */ 17755820f1daSChunyan Liu fmt = g_strdup("monolithicSparse"); 1776f66fd6c3SFam Zheng } else if (strcmp(fmt, "monolithicFlat") && 1777f66fd6c3SFam Zheng strcmp(fmt, "monolithicSparse") && 1778f66fd6c3SFam Zheng strcmp(fmt, "twoGbMaxExtentSparse") && 17796c031aacSFam Zheng strcmp(fmt, "twoGbMaxExtentFlat") && 17806c031aacSFam Zheng strcmp(fmt, "streamOptimized")) { 17814823970bSFam Zheng error_setg(errp, "Unknown subformat: '%s'", fmt); 1782af057fe7SFam Zheng ret = -EINVAL; 1783af057fe7SFam Zheng goto exit; 1784f66fd6c3SFam Zheng } 1785f66fd6c3SFam Zheng split = !(strcmp(fmt, "twoGbMaxExtentFlat") && 1786f66fd6c3SFam Zheng strcmp(fmt, "twoGbMaxExtentSparse")); 1787f66fd6c3SFam Zheng flat = !(strcmp(fmt, "monolithicFlat") && 1788f66fd6c3SFam Zheng strcmp(fmt, "twoGbMaxExtentFlat")); 17896c031aacSFam Zheng compress = !strcmp(fmt, "streamOptimized"); 1790f66fd6c3SFam Zheng if (flat) { 17914ab9dab5SFam Zheng desc_extent_line = "RW %" PRId64 " FLAT \"%s\" 0\n"; 1792f66fd6c3SFam Zheng } else { 17934ab9dab5SFam Zheng desc_extent_line = "RW %" PRId64 " SPARSE \"%s\"\n"; 1794f66fd6c3SFam Zheng } 1795f66fd6c3SFam Zheng if (flat && backing_file) { 17964823970bSFam Zheng error_setg(errp, "Flat image can't have backing file"); 1797af057fe7SFam Zheng ret = -ENOTSUP; 1798af057fe7SFam Zheng goto exit; 1799f66fd6c3SFam Zheng } 180052c8d629SFam Zheng if (flat && zeroed_grain) { 180152c8d629SFam Zheng error_setg(errp, "Flat image can't enable zeroed grain"); 1802af057fe7SFam Zheng ret = -ENOTSUP; 1803af057fe7SFam Zheng goto exit; 180452c8d629SFam Zheng } 1805f66fd6c3SFam Zheng if (backing_file) { 1806f67503e5SMax Reitz BlockDriverState *bs = NULL; 1807ddf5636dSMax Reitz ret = bdrv_open(&bs, backing_file, NULL, NULL, BDRV_O_NO_BACKING, NULL, 1808ddf5636dSMax Reitz errp); 1809f66fd6c3SFam Zheng if (ret != 0) { 1810af057fe7SFam Zheng goto exit; 1811f66fd6c3SFam Zheng } 1812f66fd6c3SFam Zheng if (strcmp(bs->drv->format_name, "vmdk")) { 18134f6fd349SFam Zheng bdrv_unref(bs); 1814af057fe7SFam Zheng ret = -EINVAL; 1815af057fe7SFam Zheng goto exit; 1816f66fd6c3SFam Zheng } 1817f66fd6c3SFam Zheng parent_cid = vmdk_read_cid(bs, 0); 18184f6fd349SFam Zheng bdrv_unref(bs); 1819f66fd6c3SFam Zheng snprintf(parent_desc_line, sizeof(parent_desc_line), 18208ed610a1SFam Zheng "parentFileNameHint=\"%s\"", backing_file); 1821f66fd6c3SFam Zheng } 1822f66fd6c3SFam Zheng 1823f66fd6c3SFam Zheng /* Create extents */ 1824f66fd6c3SFam Zheng filesize = total_size; 1825f66fd6c3SFam Zheng while (filesize > 0) { 1826f66fd6c3SFam Zheng char desc_line[BUF_SIZE]; 1827f66fd6c3SFam Zheng char ext_filename[PATH_MAX]; 1828f66fd6c3SFam Zheng char desc_filename[PATH_MAX]; 1829f66fd6c3SFam Zheng int64_t size = filesize; 1830f66fd6c3SFam Zheng 1831f66fd6c3SFam Zheng if (split && size > split_size) { 1832f66fd6c3SFam Zheng size = split_size; 1833f66fd6c3SFam Zheng } 1834f66fd6c3SFam Zheng if (split) { 1835f66fd6c3SFam Zheng snprintf(desc_filename, sizeof(desc_filename), "%s-%c%03d%s", 1836f66fd6c3SFam Zheng prefix, flat ? 'f' : 's', ++idx, postfix); 1837f66fd6c3SFam Zheng } else if (flat) { 1838f66fd6c3SFam Zheng snprintf(desc_filename, sizeof(desc_filename), "%s-flat%s", 1839f66fd6c3SFam Zheng prefix, postfix); 1840f66fd6c3SFam Zheng } else { 1841f66fd6c3SFam Zheng snprintf(desc_filename, sizeof(desc_filename), "%s%s", 1842f66fd6c3SFam Zheng prefix, postfix); 1843f66fd6c3SFam Zheng } 1844f66fd6c3SFam Zheng snprintf(ext_filename, sizeof(ext_filename), "%s%s", 1845f66fd6c3SFam Zheng path, desc_filename); 1846f66fd6c3SFam Zheng 184769e0b6dfSFam Zheng if (vmdk_create_extent(ext_filename, size, 1848*4ab15590SChunyan Liu flat, compress, zeroed_grain, opts, errp)) { 1849af057fe7SFam Zheng ret = -EINVAL; 1850af057fe7SFam Zheng goto exit; 1851f66fd6c3SFam Zheng } 1852f66fd6c3SFam Zheng filesize -= size; 1853f66fd6c3SFam Zheng 1854f66fd6c3SFam Zheng /* Format description line */ 1855f66fd6c3SFam Zheng snprintf(desc_line, sizeof(desc_line), 1856917703c1SFam Zheng desc_extent_line, size / BDRV_SECTOR_SIZE, desc_filename); 1857af057fe7SFam Zheng g_string_append(ext_desc_lines, desc_line); 1858f66fd6c3SFam Zheng } 1859f66fd6c3SFam Zheng /* generate descriptor file */ 1860af057fe7SFam Zheng desc = g_strdup_printf(desc_template, 18619b17031aSFam Zheng (uint32_t)time(NULL), 1862f66fd6c3SFam Zheng parent_cid, 1863f66fd6c3SFam Zheng fmt, 1864f66fd6c3SFam Zheng parent_desc_line, 1865af057fe7SFam Zheng ext_desc_lines->str, 1866f66fd6c3SFam Zheng (flags & BLOCK_FLAG_COMPAT6 ? 6 : 4), 1867917703c1SFam Zheng total_size / 1868917703c1SFam Zheng (int64_t)(63 * number_heads * BDRV_SECTOR_SIZE), 1869af057fe7SFam Zheng number_heads, 18707f2039f6SOthmar Pasteka adapter_type); 1871917703c1SFam Zheng desc_len = strlen(desc); 1872917703c1SFam Zheng /* the descriptor offset = 0x200 */ 1873917703c1SFam Zheng if (!split && !flat) { 1874917703c1SFam Zheng desc_offset = 0x200; 1875f66fd6c3SFam Zheng } else { 1876c282e1fdSChunyan Liu ret = bdrv_create_file(filename, opts, &local_err); 1877917703c1SFam Zheng if (ret < 0) { 1878c13959c7SFam Zheng error_propagate(errp, local_err); 1879af057fe7SFam Zheng goto exit; 1880f66fd6c3SFam Zheng } 1881f66fd6c3SFam Zheng } 18822e40134bSMax Reitz assert(new_bs == NULL); 18832e40134bSMax Reitz ret = bdrv_open(&new_bs, filename, NULL, NULL, 18842e40134bSMax Reitz BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); 1885917703c1SFam Zheng if (ret < 0) { 1886c13959c7SFam Zheng error_propagate(errp, local_err); 1887917703c1SFam Zheng goto exit; 18881640366cSKirill A. Shutemov } 1889917703c1SFam Zheng ret = bdrv_pwrite(new_bs, desc_offset, desc, desc_len); 1890917703c1SFam Zheng if (ret < 0) { 1891917703c1SFam Zheng error_setg_errno(errp, -ret, "Could not write description"); 1892917703c1SFam Zheng goto exit; 1893917703c1SFam Zheng } 1894917703c1SFam Zheng /* bdrv_pwrite write padding zeros to align to sector, we don't need that 1895917703c1SFam Zheng * for description file */ 1896917703c1SFam Zheng if (desc_offset == 0) { 1897917703c1SFam Zheng ret = bdrv_truncate(new_bs, desc_len); 1898917703c1SFam Zheng if (ret < 0) { 189939a611a3SJeff Cody error_setg_errno(errp, -ret, "Could not truncate file"); 1900917703c1SFam Zheng } 1901917703c1SFam Zheng } 1902af057fe7SFam Zheng exit: 1903917703c1SFam Zheng if (new_bs) { 1904917703c1SFam Zheng bdrv_unref(new_bs); 1905917703c1SFam Zheng } 19065820f1daSChunyan Liu g_free(adapter_type); 19075820f1daSChunyan Liu g_free(backing_file); 19085820f1daSChunyan Liu g_free(fmt); 1909af057fe7SFam Zheng g_free(desc); 1910af057fe7SFam Zheng g_string_free(ext_desc_lines, true); 19111640366cSKirill A. Shutemov return ret; 1912019d6b8fSAnthony Liguori } 1913019d6b8fSAnthony Liguori 1914019d6b8fSAnthony Liguori static void vmdk_close(BlockDriverState *bs) 1915019d6b8fSAnthony Liguori { 19162bc3166cSKevin Wolf BDRVVmdkState *s = bs->opaque; 19172bc3166cSKevin Wolf 1918b3976d3cSFam Zheng vmdk_free_extents(bs); 1919f4c129a3SFam Zheng g_free(s->create_type); 19202bc3166cSKevin Wolf 19212bc3166cSKevin Wolf migrate_del_blocker(s->migration_blocker); 19222bc3166cSKevin Wolf error_free(s->migration_blocker); 1923019d6b8fSAnthony Liguori } 1924019d6b8fSAnthony Liguori 19258b94ff85SPaolo Bonzini static coroutine_fn int vmdk_co_flush(BlockDriverState *bs) 1926019d6b8fSAnthony Liguori { 1927333c574dSFam Zheng BDRVVmdkState *s = bs->opaque; 192829cdb251SPaolo Bonzini int i, err; 192929cdb251SPaolo Bonzini int ret = 0; 1930333c574dSFam Zheng 1931333c574dSFam Zheng for (i = 0; i < s->num_extents; i++) { 19328b94ff85SPaolo Bonzini err = bdrv_co_flush(s->extents[i].file); 1933333c574dSFam Zheng if (err < 0) { 1934333c574dSFam Zheng ret = err; 1935333c574dSFam Zheng } 1936333c574dSFam Zheng } 1937333c574dSFam Zheng return ret; 1938019d6b8fSAnthony Liguori } 1939019d6b8fSAnthony Liguori 19404a1d5e1fSFam Zheng static int64_t vmdk_get_allocated_file_size(BlockDriverState *bs) 19414a1d5e1fSFam Zheng { 19424a1d5e1fSFam Zheng int i; 19434a1d5e1fSFam Zheng int64_t ret = 0; 19444a1d5e1fSFam Zheng int64_t r; 19454a1d5e1fSFam Zheng BDRVVmdkState *s = bs->opaque; 19464a1d5e1fSFam Zheng 19474a1d5e1fSFam Zheng ret = bdrv_get_allocated_file_size(bs->file); 19484a1d5e1fSFam Zheng if (ret < 0) { 19494a1d5e1fSFam Zheng return ret; 19504a1d5e1fSFam Zheng } 19514a1d5e1fSFam Zheng for (i = 0; i < s->num_extents; i++) { 19524a1d5e1fSFam Zheng if (s->extents[i].file == bs->file) { 19534a1d5e1fSFam Zheng continue; 19544a1d5e1fSFam Zheng } 19554a1d5e1fSFam Zheng r = bdrv_get_allocated_file_size(s->extents[i].file); 19564a1d5e1fSFam Zheng if (r < 0) { 19574a1d5e1fSFam Zheng return r; 19584a1d5e1fSFam Zheng } 19594a1d5e1fSFam Zheng ret += r; 19604a1d5e1fSFam Zheng } 19614a1d5e1fSFam Zheng return ret; 19624a1d5e1fSFam Zheng } 19630e7e1989SKevin Wolf 1964da7a50f9SFam Zheng static int vmdk_has_zero_init(BlockDriverState *bs) 1965da7a50f9SFam Zheng { 1966da7a50f9SFam Zheng int i; 1967da7a50f9SFam Zheng BDRVVmdkState *s = bs->opaque; 1968da7a50f9SFam Zheng 1969da7a50f9SFam Zheng /* If has a flat extent and its underlying storage doesn't have zero init, 1970da7a50f9SFam Zheng * return 0. */ 1971da7a50f9SFam Zheng for (i = 0; i < s->num_extents; i++) { 1972da7a50f9SFam Zheng if (s->extents[i].flat) { 1973da7a50f9SFam Zheng if (!bdrv_has_zero_init(s->extents[i].file)) { 1974da7a50f9SFam Zheng return 0; 1975da7a50f9SFam Zheng } 1976da7a50f9SFam Zheng } 1977da7a50f9SFam Zheng } 1978da7a50f9SFam Zheng return 1; 1979da7a50f9SFam Zheng } 1980da7a50f9SFam Zheng 1981f4c129a3SFam Zheng static ImageInfo *vmdk_get_extent_info(VmdkExtent *extent) 1982f4c129a3SFam Zheng { 1983f4c129a3SFam Zheng ImageInfo *info = g_new0(ImageInfo, 1); 1984f4c129a3SFam Zheng 1985f4c129a3SFam Zheng *info = (ImageInfo){ 1986f4c129a3SFam Zheng .filename = g_strdup(extent->file->filename), 1987f4c129a3SFam Zheng .format = g_strdup(extent->type), 1988f4c129a3SFam Zheng .virtual_size = extent->sectors * BDRV_SECTOR_SIZE, 1989f4c129a3SFam Zheng .compressed = extent->compressed, 1990f4c129a3SFam Zheng .has_compressed = extent->compressed, 1991f4c129a3SFam Zheng .cluster_size = extent->cluster_sectors * BDRV_SECTOR_SIZE, 1992f4c129a3SFam Zheng .has_cluster_size = !extent->flat, 1993f4c129a3SFam Zheng }; 1994f4c129a3SFam Zheng 1995f4c129a3SFam Zheng return info; 1996f4c129a3SFam Zheng } 1997f4c129a3SFam Zheng 1998f43aa8e1SPeter Lieven static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result, 1999f43aa8e1SPeter Lieven BdrvCheckMode fix) 2000f43aa8e1SPeter Lieven { 2001f43aa8e1SPeter Lieven BDRVVmdkState *s = bs->opaque; 2002f43aa8e1SPeter Lieven VmdkExtent *extent = NULL; 2003f43aa8e1SPeter Lieven int64_t sector_num = 0; 2004f43aa8e1SPeter Lieven int64_t total_sectors = bdrv_getlength(bs) / BDRV_SECTOR_SIZE; 2005f43aa8e1SPeter Lieven int ret; 2006f43aa8e1SPeter Lieven uint64_t cluster_offset; 2007f43aa8e1SPeter Lieven 2008f43aa8e1SPeter Lieven if (fix) { 2009f43aa8e1SPeter Lieven return -ENOTSUP; 2010f43aa8e1SPeter Lieven } 2011f43aa8e1SPeter Lieven 2012f43aa8e1SPeter Lieven for (;;) { 2013f43aa8e1SPeter Lieven if (sector_num >= total_sectors) { 2014f43aa8e1SPeter Lieven return 0; 2015f43aa8e1SPeter Lieven } 2016f43aa8e1SPeter Lieven extent = find_extent(s, sector_num, extent); 2017f43aa8e1SPeter Lieven if (!extent) { 2018f43aa8e1SPeter Lieven fprintf(stderr, 2019f43aa8e1SPeter Lieven "ERROR: could not find extent for sector %" PRId64 "\n", 2020f43aa8e1SPeter Lieven sector_num); 2021f43aa8e1SPeter Lieven break; 2022f43aa8e1SPeter Lieven } 2023f43aa8e1SPeter Lieven ret = get_cluster_offset(bs, extent, NULL, 2024f43aa8e1SPeter Lieven sector_num << BDRV_SECTOR_BITS, 2025f43aa8e1SPeter Lieven 0, &cluster_offset); 2026f43aa8e1SPeter Lieven if (ret == VMDK_ERROR) { 2027f43aa8e1SPeter Lieven fprintf(stderr, 2028f43aa8e1SPeter Lieven "ERROR: could not get cluster_offset for sector %" 2029f43aa8e1SPeter Lieven PRId64 "\n", sector_num); 2030f43aa8e1SPeter Lieven break; 2031f43aa8e1SPeter Lieven } 2032f43aa8e1SPeter Lieven if (ret == VMDK_OK && cluster_offset >= bdrv_getlength(extent->file)) { 2033f43aa8e1SPeter Lieven fprintf(stderr, 2034f43aa8e1SPeter Lieven "ERROR: cluster offset for sector %" 2035f43aa8e1SPeter Lieven PRId64 " points after EOF\n", sector_num); 2036f43aa8e1SPeter Lieven break; 2037f43aa8e1SPeter Lieven } 2038f43aa8e1SPeter Lieven sector_num += extent->cluster_sectors; 2039f43aa8e1SPeter Lieven } 2040f43aa8e1SPeter Lieven 2041f43aa8e1SPeter Lieven result->corruptions++; 2042f43aa8e1SPeter Lieven return 0; 2043f43aa8e1SPeter Lieven } 2044f43aa8e1SPeter Lieven 2045f4c129a3SFam Zheng static ImageInfoSpecific *vmdk_get_specific_info(BlockDriverState *bs) 2046f4c129a3SFam Zheng { 2047f4c129a3SFam Zheng int i; 2048f4c129a3SFam Zheng BDRVVmdkState *s = bs->opaque; 2049f4c129a3SFam Zheng ImageInfoSpecific *spec_info = g_new0(ImageInfoSpecific, 1); 2050f4c129a3SFam Zheng ImageInfoList **next; 2051f4c129a3SFam Zheng 2052f4c129a3SFam Zheng *spec_info = (ImageInfoSpecific){ 2053f4c129a3SFam Zheng .kind = IMAGE_INFO_SPECIFIC_KIND_VMDK, 2054f4c129a3SFam Zheng { 2055f4c129a3SFam Zheng .vmdk = g_new0(ImageInfoSpecificVmdk, 1), 2056f4c129a3SFam Zheng }, 2057f4c129a3SFam Zheng }; 2058f4c129a3SFam Zheng 2059f4c129a3SFam Zheng *spec_info->vmdk = (ImageInfoSpecificVmdk) { 2060f4c129a3SFam Zheng .create_type = g_strdup(s->create_type), 2061f4c129a3SFam Zheng .cid = s->cid, 2062f4c129a3SFam Zheng .parent_cid = s->parent_cid, 2063f4c129a3SFam Zheng }; 2064f4c129a3SFam Zheng 2065f4c129a3SFam Zheng next = &spec_info->vmdk->extents; 2066f4c129a3SFam Zheng for (i = 0; i < s->num_extents; i++) { 2067f4c129a3SFam Zheng *next = g_new0(ImageInfoList, 1); 2068f4c129a3SFam Zheng (*next)->value = vmdk_get_extent_info(&s->extents[i]); 2069f4c129a3SFam Zheng (*next)->next = NULL; 2070f4c129a3SFam Zheng next = &(*next)->next; 2071f4c129a3SFam Zheng } 2072f4c129a3SFam Zheng 2073f4c129a3SFam Zheng return spec_info; 2074f4c129a3SFam Zheng } 2075f4c129a3SFam Zheng 207674fe188cSFam Zheng static int vmdk_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) 207774fe188cSFam Zheng { 207874fe188cSFam Zheng int i; 207974fe188cSFam Zheng BDRVVmdkState *s = bs->opaque; 208074fe188cSFam Zheng assert(s->num_extents); 208174fe188cSFam Zheng bdi->needs_compressed_writes = s->extents[0].compressed; 208274fe188cSFam Zheng if (!s->extents[0].flat) { 208374fe188cSFam Zheng bdi->cluster_size = s->extents[0].cluster_sectors << BDRV_SECTOR_BITS; 208474fe188cSFam Zheng } 208574fe188cSFam Zheng /* See if we have multiple extents but they have different cases */ 208674fe188cSFam Zheng for (i = 1; i < s->num_extents; i++) { 208774fe188cSFam Zheng if (bdi->needs_compressed_writes != s->extents[i].compressed || 208874fe188cSFam Zheng (bdi->cluster_size && bdi->cluster_size != 208974fe188cSFam Zheng s->extents[i].cluster_sectors << BDRV_SECTOR_BITS)) { 209074fe188cSFam Zheng return -ENOTSUP; 209174fe188cSFam Zheng } 209274fe188cSFam Zheng } 209374fe188cSFam Zheng return 0; 209474fe188cSFam Zheng } 209574fe188cSFam Zheng 2096c75f3bdfSStefan Hajnoczi static void vmdk_detach_aio_context(BlockDriverState *bs) 2097c75f3bdfSStefan Hajnoczi { 2098c75f3bdfSStefan Hajnoczi BDRVVmdkState *s = bs->opaque; 2099c75f3bdfSStefan Hajnoczi int i; 2100c75f3bdfSStefan Hajnoczi 2101c75f3bdfSStefan Hajnoczi for (i = 0; i < s->num_extents; i++) { 2102c75f3bdfSStefan Hajnoczi bdrv_detach_aio_context(s->extents[i].file); 2103c75f3bdfSStefan Hajnoczi } 2104c75f3bdfSStefan Hajnoczi } 2105c75f3bdfSStefan Hajnoczi 2106c75f3bdfSStefan Hajnoczi static void vmdk_attach_aio_context(BlockDriverState *bs, 2107c75f3bdfSStefan Hajnoczi AioContext *new_context) 2108c75f3bdfSStefan Hajnoczi { 2109c75f3bdfSStefan Hajnoczi BDRVVmdkState *s = bs->opaque; 2110c75f3bdfSStefan Hajnoczi int i; 2111c75f3bdfSStefan Hajnoczi 2112c75f3bdfSStefan Hajnoczi for (i = 0; i < s->num_extents; i++) { 2113c75f3bdfSStefan Hajnoczi bdrv_attach_aio_context(s->extents[i].file, new_context); 2114c75f3bdfSStefan Hajnoczi } 2115c75f3bdfSStefan Hajnoczi } 2116c75f3bdfSStefan Hajnoczi 21175820f1daSChunyan Liu static QemuOptsList vmdk_create_opts = { 21185820f1daSChunyan Liu .name = "vmdk-create-opts", 21195820f1daSChunyan Liu .head = QTAILQ_HEAD_INITIALIZER(vmdk_create_opts.head), 21205820f1daSChunyan Liu .desc = { 2121db08adf5SKevin Wolf { 2122db08adf5SKevin Wolf .name = BLOCK_OPT_SIZE, 21235820f1daSChunyan Liu .type = QEMU_OPT_SIZE, 2124db08adf5SKevin Wolf .help = "Virtual disk size" 2125db08adf5SKevin Wolf }, 2126db08adf5SKevin Wolf { 21277f2039f6SOthmar Pasteka .name = BLOCK_OPT_ADAPTER_TYPE, 21285820f1daSChunyan Liu .type = QEMU_OPT_STRING, 21297f2039f6SOthmar Pasteka .help = "Virtual adapter type, can be one of " 21307f2039f6SOthmar Pasteka "ide (default), lsilogic, buslogic or legacyESX" 21317f2039f6SOthmar Pasteka }, 21327f2039f6SOthmar Pasteka { 2133db08adf5SKevin Wolf .name = BLOCK_OPT_BACKING_FILE, 21345820f1daSChunyan Liu .type = QEMU_OPT_STRING, 2135db08adf5SKevin Wolf .help = "File name of a base image" 2136db08adf5SKevin Wolf }, 2137db08adf5SKevin Wolf { 2138db08adf5SKevin Wolf .name = BLOCK_OPT_COMPAT6, 21395820f1daSChunyan Liu .type = QEMU_OPT_BOOL, 21405820f1daSChunyan Liu .help = "VMDK version 6 image", 21415820f1daSChunyan Liu .def_value_str = "off" 2142db08adf5SKevin Wolf }, 2143f66fd6c3SFam Zheng { 2144f66fd6c3SFam Zheng .name = BLOCK_OPT_SUBFMT, 21455820f1daSChunyan Liu .type = QEMU_OPT_STRING, 2146f66fd6c3SFam Zheng .help = 2147f66fd6c3SFam Zheng "VMDK flat extent format, can be one of " 21486c031aacSFam Zheng "{monolithicSparse (default) | monolithicFlat | twoGbMaxExtentSparse | twoGbMaxExtentFlat | streamOptimized} " 2149f66fd6c3SFam Zheng }, 215069e0b6dfSFam Zheng { 215169e0b6dfSFam Zheng .name = BLOCK_OPT_ZEROED_GRAIN, 21525820f1daSChunyan Liu .type = QEMU_OPT_BOOL, 21535820f1daSChunyan Liu .help = "Enable efficient zero writes " 21545820f1daSChunyan Liu "using the zeroed-grain GTE feature" 215569e0b6dfSFam Zheng }, 21565820f1daSChunyan Liu { /* end of list */ } 21575820f1daSChunyan Liu } 21580e7e1989SKevin Wolf }; 21590e7e1989SKevin Wolf 2160019d6b8fSAnthony Liguori static BlockDriver bdrv_vmdk = { 2161019d6b8fSAnthony Liguori .format_name = "vmdk", 2162019d6b8fSAnthony Liguori .instance_size = sizeof(BDRVVmdkState), 2163019d6b8fSAnthony Liguori .bdrv_probe = vmdk_probe, 21646511ef77SKevin Wolf .bdrv_open = vmdk_open, 2165f43aa8e1SPeter Lieven .bdrv_check = vmdk_check, 21663897575fSJeff Cody .bdrv_reopen_prepare = vmdk_reopen_prepare, 21672914caa0SPaolo Bonzini .bdrv_read = vmdk_co_read, 2168e183ef75SPaolo Bonzini .bdrv_write = vmdk_co_write, 2169ba0ad89eSFam Zheng .bdrv_write_compressed = vmdk_write_compressed, 2170cdeaf1f1SFam Zheng .bdrv_co_write_zeroes = vmdk_co_write_zeroes, 2171019d6b8fSAnthony Liguori .bdrv_close = vmdk_close, 2172c282e1fdSChunyan Liu .bdrv_create = vmdk_create, 2173c68b89acSKevin Wolf .bdrv_co_flush_to_disk = vmdk_co_flush, 2174b6b8a333SPaolo Bonzini .bdrv_co_get_block_status = vmdk_co_get_block_status, 21754a1d5e1fSFam Zheng .bdrv_get_allocated_file_size = vmdk_get_allocated_file_size, 2176da7a50f9SFam Zheng .bdrv_has_zero_init = vmdk_has_zero_init, 2177f4c129a3SFam Zheng .bdrv_get_specific_info = vmdk_get_specific_info, 2178d34682cdSKevin Wolf .bdrv_refresh_limits = vmdk_refresh_limits, 217974fe188cSFam Zheng .bdrv_get_info = vmdk_get_info, 2180c75f3bdfSStefan Hajnoczi .bdrv_detach_aio_context = vmdk_detach_aio_context, 2181c75f3bdfSStefan Hajnoczi .bdrv_attach_aio_context = vmdk_attach_aio_context, 21820e7e1989SKevin Wolf 21838ee79e70SKevin Wolf .supports_backing = true, 21845820f1daSChunyan Liu .create_opts = &vmdk_create_opts, 2185019d6b8fSAnthony Liguori }; 2186019d6b8fSAnthony Liguori 2187019d6b8fSAnthony Liguori static void bdrv_vmdk_init(void) 2188019d6b8fSAnthony Liguori { 2189019d6b8fSAnthony Liguori bdrv_register(&bdrv_vmdk); 2190019d6b8fSAnthony Liguori } 2191019d6b8fSAnthony Liguori 2192019d6b8fSAnthony Liguori block_init(bdrv_vmdk_init); 2193