1*baefd977SVladimir Sementsov-Ogievskiy /* 2*baefd977SVladimir Sementsov-Ogievskiy * Support of Parallels Format Extension. It's a part of Parallels format 3*baefd977SVladimir Sementsov-Ogievskiy * driver. 4*baefd977SVladimir Sementsov-Ogievskiy * 5*baefd977SVladimir Sementsov-Ogievskiy * Copyright (c) 2021 Virtuozzo International GmbH 6*baefd977SVladimir Sementsov-Ogievskiy * 7*baefd977SVladimir Sementsov-Ogievskiy * Permission is hereby granted, free of charge, to any person obtaining a copy 8*baefd977SVladimir Sementsov-Ogievskiy * of this software and associated documentation files (the "Software"), to deal 9*baefd977SVladimir Sementsov-Ogievskiy * in the Software without restriction, including without limitation the rights 10*baefd977SVladimir Sementsov-Ogievskiy * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11*baefd977SVladimir Sementsov-Ogievskiy * copies of the Software, and to permit persons to whom the Software is 12*baefd977SVladimir Sementsov-Ogievskiy * furnished to do so, subject to the following conditions: 13*baefd977SVladimir Sementsov-Ogievskiy * 14*baefd977SVladimir Sementsov-Ogievskiy * The above copyright notice and this permission notice shall be included in 15*baefd977SVladimir Sementsov-Ogievskiy * all copies or substantial portions of the Software. 16*baefd977SVladimir Sementsov-Ogievskiy * 17*baefd977SVladimir Sementsov-Ogievskiy * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18*baefd977SVladimir Sementsov-Ogievskiy * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19*baefd977SVladimir Sementsov-Ogievskiy * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20*baefd977SVladimir Sementsov-Ogievskiy * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21*baefd977SVladimir Sementsov-Ogievskiy * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22*baefd977SVladimir Sementsov-Ogievskiy * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23*baefd977SVladimir Sementsov-Ogievskiy * THE SOFTWARE. 24*baefd977SVladimir Sementsov-Ogievskiy */ 25*baefd977SVladimir Sementsov-Ogievskiy 26*baefd977SVladimir Sementsov-Ogievskiy #include "qemu/osdep.h" 27*baefd977SVladimir Sementsov-Ogievskiy #include "qapi/error.h" 28*baefd977SVladimir Sementsov-Ogievskiy #include "block/block_int.h" 29*baefd977SVladimir Sementsov-Ogievskiy #include "parallels.h" 30*baefd977SVladimir Sementsov-Ogievskiy #include "crypto/hash.h" 31*baefd977SVladimir Sementsov-Ogievskiy #include "qemu/uuid.h" 32*baefd977SVladimir Sementsov-Ogievskiy 33*baefd977SVladimir Sementsov-Ogievskiy #define PARALLELS_FORMAT_EXTENSION_MAGIC 0xAB234CEF23DCEA87ULL 34*baefd977SVladimir Sementsov-Ogievskiy 35*baefd977SVladimir Sementsov-Ogievskiy #define PARALLELS_END_OF_FEATURES_MAGIC 0x0ULL 36*baefd977SVladimir Sementsov-Ogievskiy #define PARALLELS_DIRTY_BITMAP_FEATURE_MAGIC 0x20385FAE252CB34AULL 37*baefd977SVladimir Sementsov-Ogievskiy 38*baefd977SVladimir Sementsov-Ogievskiy typedef struct ParallelsFormatExtensionHeader { 39*baefd977SVladimir Sementsov-Ogievskiy uint64_t magic; /* PARALLELS_FORMAT_EXTENSION_MAGIC */ 40*baefd977SVladimir Sementsov-Ogievskiy uint8_t check_sum[16]; 41*baefd977SVladimir Sementsov-Ogievskiy } QEMU_PACKED ParallelsFormatExtensionHeader; 42*baefd977SVladimir Sementsov-Ogievskiy 43*baefd977SVladimir Sementsov-Ogievskiy typedef struct ParallelsFeatureHeader { 44*baefd977SVladimir Sementsov-Ogievskiy uint64_t magic; 45*baefd977SVladimir Sementsov-Ogievskiy uint64_t flags; 46*baefd977SVladimir Sementsov-Ogievskiy uint32_t data_size; 47*baefd977SVladimir Sementsov-Ogievskiy uint32_t _unused; 48*baefd977SVladimir Sementsov-Ogievskiy } QEMU_PACKED ParallelsFeatureHeader; 49*baefd977SVladimir Sementsov-Ogievskiy 50*baefd977SVladimir Sementsov-Ogievskiy typedef struct ParallelsDirtyBitmapFeature { 51*baefd977SVladimir Sementsov-Ogievskiy uint64_t size; 52*baefd977SVladimir Sementsov-Ogievskiy uint8_t id[16]; 53*baefd977SVladimir Sementsov-Ogievskiy uint32_t granularity; 54*baefd977SVladimir Sementsov-Ogievskiy uint32_t l1_size; 55*baefd977SVladimir Sementsov-Ogievskiy /* L1 table follows */ 56*baefd977SVladimir Sementsov-Ogievskiy } QEMU_PACKED ParallelsDirtyBitmapFeature; 57*baefd977SVladimir Sementsov-Ogievskiy 58*baefd977SVladimir Sementsov-Ogievskiy /* Given L1 table read bitmap data from the image and populate @bitmap */ 59*baefd977SVladimir Sementsov-Ogievskiy static int parallels_load_bitmap_data(BlockDriverState *bs, 60*baefd977SVladimir Sementsov-Ogievskiy const uint64_t *l1_table, 61*baefd977SVladimir Sementsov-Ogievskiy uint32_t l1_size, 62*baefd977SVladimir Sementsov-Ogievskiy BdrvDirtyBitmap *bitmap, 63*baefd977SVladimir Sementsov-Ogievskiy Error **errp) 64*baefd977SVladimir Sementsov-Ogievskiy { 65*baefd977SVladimir Sementsov-Ogievskiy BDRVParallelsState *s = bs->opaque; 66*baefd977SVladimir Sementsov-Ogievskiy int ret = 0; 67*baefd977SVladimir Sementsov-Ogievskiy uint64_t offset, limit; 68*baefd977SVladimir Sementsov-Ogievskiy uint64_t bm_size = bdrv_dirty_bitmap_size(bitmap); 69*baefd977SVladimir Sementsov-Ogievskiy uint8_t *buf = NULL; 70*baefd977SVladimir Sementsov-Ogievskiy uint64_t i, tab_size = 71*baefd977SVladimir Sementsov-Ogievskiy DIV_ROUND_UP(bdrv_dirty_bitmap_serialization_size(bitmap, 0, bm_size), 72*baefd977SVladimir Sementsov-Ogievskiy s->cluster_size); 73*baefd977SVladimir Sementsov-Ogievskiy 74*baefd977SVladimir Sementsov-Ogievskiy if (tab_size != l1_size) { 75*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Bitmap table size %" PRIu32 " does not correspond " 76*baefd977SVladimir Sementsov-Ogievskiy "to bitmap size and cluster size. Expected %" PRIu64, 77*baefd977SVladimir Sementsov-Ogievskiy l1_size, tab_size); 78*baefd977SVladimir Sementsov-Ogievskiy return -EINVAL; 79*baefd977SVladimir Sementsov-Ogievskiy } 80*baefd977SVladimir Sementsov-Ogievskiy 81*baefd977SVladimir Sementsov-Ogievskiy buf = qemu_blockalign(bs, s->cluster_size); 82*baefd977SVladimir Sementsov-Ogievskiy limit = bdrv_dirty_bitmap_serialization_coverage(s->cluster_size, bitmap); 83*baefd977SVladimir Sementsov-Ogievskiy for (i = 0, offset = 0; i < tab_size; ++i, offset += limit) { 84*baefd977SVladimir Sementsov-Ogievskiy uint64_t count = MIN(bm_size - offset, limit); 85*baefd977SVladimir Sementsov-Ogievskiy uint64_t entry = l1_table[i]; 86*baefd977SVladimir Sementsov-Ogievskiy 87*baefd977SVladimir Sementsov-Ogievskiy if (entry == 0) { 88*baefd977SVladimir Sementsov-Ogievskiy /* No need to deserialize zeros because @bitmap is cleared. */ 89*baefd977SVladimir Sementsov-Ogievskiy continue; 90*baefd977SVladimir Sementsov-Ogievskiy } 91*baefd977SVladimir Sementsov-Ogievskiy 92*baefd977SVladimir Sementsov-Ogievskiy if (entry == 1) { 93*baefd977SVladimir Sementsov-Ogievskiy bdrv_dirty_bitmap_deserialize_ones(bitmap, offset, count, false); 94*baefd977SVladimir Sementsov-Ogievskiy } else { 95*baefd977SVladimir Sementsov-Ogievskiy ret = bdrv_pread(bs->file, entry << BDRV_SECTOR_BITS, buf, 96*baefd977SVladimir Sementsov-Ogievskiy s->cluster_size); 97*baefd977SVladimir Sementsov-Ogievskiy if (ret < 0) { 98*baefd977SVladimir Sementsov-Ogievskiy error_setg_errno(errp, -ret, 99*baefd977SVladimir Sementsov-Ogievskiy "Failed to read bitmap data cluster"); 100*baefd977SVladimir Sementsov-Ogievskiy goto finish; 101*baefd977SVladimir Sementsov-Ogievskiy } 102*baefd977SVladimir Sementsov-Ogievskiy bdrv_dirty_bitmap_deserialize_part(bitmap, buf, offset, count, 103*baefd977SVladimir Sementsov-Ogievskiy false); 104*baefd977SVladimir Sementsov-Ogievskiy } 105*baefd977SVladimir Sementsov-Ogievskiy } 106*baefd977SVladimir Sementsov-Ogievskiy ret = 0; 107*baefd977SVladimir Sementsov-Ogievskiy 108*baefd977SVladimir Sementsov-Ogievskiy bdrv_dirty_bitmap_deserialize_finish(bitmap); 109*baefd977SVladimir Sementsov-Ogievskiy 110*baefd977SVladimir Sementsov-Ogievskiy finish: 111*baefd977SVladimir Sementsov-Ogievskiy qemu_vfree(buf); 112*baefd977SVladimir Sementsov-Ogievskiy 113*baefd977SVladimir Sementsov-Ogievskiy return ret; 114*baefd977SVladimir Sementsov-Ogievskiy } 115*baefd977SVladimir Sementsov-Ogievskiy 116*baefd977SVladimir Sementsov-Ogievskiy /* 117*baefd977SVladimir Sementsov-Ogievskiy * @data buffer (of @data_size size) is the Dirty bitmaps feature which 118*baefd977SVladimir Sementsov-Ogievskiy * consists of ParallelsDirtyBitmapFeature followed by L1 table. 119*baefd977SVladimir Sementsov-Ogievskiy */ 120*baefd977SVladimir Sementsov-Ogievskiy static BdrvDirtyBitmap *parallels_load_bitmap(BlockDriverState *bs, 121*baefd977SVladimir Sementsov-Ogievskiy uint8_t *data, 122*baefd977SVladimir Sementsov-Ogievskiy size_t data_size, 123*baefd977SVladimir Sementsov-Ogievskiy Error **errp) 124*baefd977SVladimir Sementsov-Ogievskiy { 125*baefd977SVladimir Sementsov-Ogievskiy int ret; 126*baefd977SVladimir Sementsov-Ogievskiy ParallelsDirtyBitmapFeature bf; 127*baefd977SVladimir Sementsov-Ogievskiy g_autofree uint64_t *l1_table = NULL; 128*baefd977SVladimir Sementsov-Ogievskiy BdrvDirtyBitmap *bitmap; 129*baefd977SVladimir Sementsov-Ogievskiy QemuUUID uuid; 130*baefd977SVladimir Sementsov-Ogievskiy char uuidstr[UUID_FMT_LEN + 1]; 131*baefd977SVladimir Sementsov-Ogievskiy int i; 132*baefd977SVladimir Sementsov-Ogievskiy 133*baefd977SVladimir Sementsov-Ogievskiy if (data_size < sizeof(bf)) { 134*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Too small Bitmap Feature area in Parallels Format " 135*baefd977SVladimir Sementsov-Ogievskiy "Extension: %zu bytes, expected at least %zu bytes", 136*baefd977SVladimir Sementsov-Ogievskiy data_size, sizeof(bf)); 137*baefd977SVladimir Sementsov-Ogievskiy return NULL; 138*baefd977SVladimir Sementsov-Ogievskiy } 139*baefd977SVladimir Sementsov-Ogievskiy memcpy(&bf, data, sizeof(bf)); 140*baefd977SVladimir Sementsov-Ogievskiy bf.size = le64_to_cpu(bf.size); 141*baefd977SVladimir Sementsov-Ogievskiy bf.granularity = le32_to_cpu(bf.granularity) << BDRV_SECTOR_BITS; 142*baefd977SVladimir Sementsov-Ogievskiy bf.l1_size = le32_to_cpu(bf.l1_size); 143*baefd977SVladimir Sementsov-Ogievskiy data += sizeof(bf); 144*baefd977SVladimir Sementsov-Ogievskiy data_size -= sizeof(bf); 145*baefd977SVladimir Sementsov-Ogievskiy 146*baefd977SVladimir Sementsov-Ogievskiy if (bf.size != bs->total_sectors) { 147*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Bitmap size (in sectors) %" PRId64 " differs from " 148*baefd977SVladimir Sementsov-Ogievskiy "disk size in sectors %" PRId64, bf.size, bs->total_sectors); 149*baefd977SVladimir Sementsov-Ogievskiy return NULL; 150*baefd977SVladimir Sementsov-Ogievskiy } 151*baefd977SVladimir Sementsov-Ogievskiy 152*baefd977SVladimir Sementsov-Ogievskiy if (bf.l1_size * sizeof(uint64_t) > data_size) { 153*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Bitmaps feature corrupted: l1 table exceeds " 154*baefd977SVladimir Sementsov-Ogievskiy "extension data_size"); 155*baefd977SVladimir Sementsov-Ogievskiy return NULL; 156*baefd977SVladimir Sementsov-Ogievskiy } 157*baefd977SVladimir Sementsov-Ogievskiy 158*baefd977SVladimir Sementsov-Ogievskiy memcpy(&uuid, bf.id, sizeof(uuid)); 159*baefd977SVladimir Sementsov-Ogievskiy qemu_uuid_unparse(&uuid, uuidstr); 160*baefd977SVladimir Sementsov-Ogievskiy bitmap = bdrv_create_dirty_bitmap(bs, bf.granularity, uuidstr, errp); 161*baefd977SVladimir Sementsov-Ogievskiy if (!bitmap) { 162*baefd977SVladimir Sementsov-Ogievskiy return NULL; 163*baefd977SVladimir Sementsov-Ogievskiy } 164*baefd977SVladimir Sementsov-Ogievskiy 165*baefd977SVladimir Sementsov-Ogievskiy l1_table = g_new(uint64_t, bf.l1_size); 166*baefd977SVladimir Sementsov-Ogievskiy for (i = 0; i < bf.l1_size; i++, data += sizeof(uint64_t)) { 167*baefd977SVladimir Sementsov-Ogievskiy l1_table[i] = ldq_le_p(data); 168*baefd977SVladimir Sementsov-Ogievskiy } 169*baefd977SVladimir Sementsov-Ogievskiy 170*baefd977SVladimir Sementsov-Ogievskiy ret = parallels_load_bitmap_data(bs, l1_table, bf.l1_size, bitmap, errp); 171*baefd977SVladimir Sementsov-Ogievskiy if (ret < 0) { 172*baefd977SVladimir Sementsov-Ogievskiy bdrv_release_dirty_bitmap(bitmap); 173*baefd977SVladimir Sementsov-Ogievskiy return NULL; 174*baefd977SVladimir Sementsov-Ogievskiy } 175*baefd977SVladimir Sementsov-Ogievskiy 176*baefd977SVladimir Sementsov-Ogievskiy /* We support format extension only for RO parallels images. */ 177*baefd977SVladimir Sementsov-Ogievskiy assert(!(bs->open_flags & BDRV_O_RDWR)); 178*baefd977SVladimir Sementsov-Ogievskiy bdrv_dirty_bitmap_set_readonly(bitmap, true); 179*baefd977SVladimir Sementsov-Ogievskiy 180*baefd977SVladimir Sementsov-Ogievskiy return bitmap; 181*baefd977SVladimir Sementsov-Ogievskiy } 182*baefd977SVladimir Sementsov-Ogievskiy 183*baefd977SVladimir Sementsov-Ogievskiy static int parallels_parse_format_extension(BlockDriverState *bs, 184*baefd977SVladimir Sementsov-Ogievskiy uint8_t *ext_cluster, Error **errp) 185*baefd977SVladimir Sementsov-Ogievskiy { 186*baefd977SVladimir Sementsov-Ogievskiy BDRVParallelsState *s = bs->opaque; 187*baefd977SVladimir Sementsov-Ogievskiy int ret; 188*baefd977SVladimir Sementsov-Ogievskiy int remaining = s->cluster_size; 189*baefd977SVladimir Sementsov-Ogievskiy uint8_t *pos = ext_cluster; 190*baefd977SVladimir Sementsov-Ogievskiy ParallelsFormatExtensionHeader eh; 191*baefd977SVladimir Sementsov-Ogievskiy g_autofree uint8_t *hash = NULL; 192*baefd977SVladimir Sementsov-Ogievskiy size_t hash_len = 0; 193*baefd977SVladimir Sementsov-Ogievskiy GSList *bitmaps = NULL, *el; 194*baefd977SVladimir Sementsov-Ogievskiy 195*baefd977SVladimir Sementsov-Ogievskiy memcpy(&eh, pos, sizeof(eh)); 196*baefd977SVladimir Sementsov-Ogievskiy eh.magic = le64_to_cpu(eh.magic); 197*baefd977SVladimir Sementsov-Ogievskiy pos += sizeof(eh); 198*baefd977SVladimir Sementsov-Ogievskiy remaining -= sizeof(eh); 199*baefd977SVladimir Sementsov-Ogievskiy 200*baefd977SVladimir Sementsov-Ogievskiy if (eh.magic != PARALLELS_FORMAT_EXTENSION_MAGIC) { 201*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Wrong parallels Format Extension magic: 0x%" PRIx64 202*baefd977SVladimir Sementsov-Ogievskiy ", expected: 0x%llx", eh.magic, 203*baefd977SVladimir Sementsov-Ogievskiy PARALLELS_FORMAT_EXTENSION_MAGIC); 204*baefd977SVladimir Sementsov-Ogievskiy goto fail; 205*baefd977SVladimir Sementsov-Ogievskiy } 206*baefd977SVladimir Sementsov-Ogievskiy 207*baefd977SVladimir Sementsov-Ogievskiy ret = qcrypto_hash_bytes(QCRYPTO_HASH_ALG_MD5, (char *)pos, remaining, 208*baefd977SVladimir Sementsov-Ogievskiy &hash, &hash_len, errp); 209*baefd977SVladimir Sementsov-Ogievskiy if (ret < 0) { 210*baefd977SVladimir Sementsov-Ogievskiy goto fail; 211*baefd977SVladimir Sementsov-Ogievskiy } 212*baefd977SVladimir Sementsov-Ogievskiy 213*baefd977SVladimir Sementsov-Ogievskiy if (hash_len != sizeof(eh.check_sum) || 214*baefd977SVladimir Sementsov-Ogievskiy memcmp(hash, eh.check_sum, sizeof(eh.check_sum)) != 0) { 215*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Wrong checksum in Format Extension header. Format " 216*baefd977SVladimir Sementsov-Ogievskiy "extension is corrupted."); 217*baefd977SVladimir Sementsov-Ogievskiy goto fail; 218*baefd977SVladimir Sementsov-Ogievskiy } 219*baefd977SVladimir Sementsov-Ogievskiy 220*baefd977SVladimir Sementsov-Ogievskiy while (true) { 221*baefd977SVladimir Sementsov-Ogievskiy ParallelsFeatureHeader fh; 222*baefd977SVladimir Sementsov-Ogievskiy BdrvDirtyBitmap *bitmap; 223*baefd977SVladimir Sementsov-Ogievskiy 224*baefd977SVladimir Sementsov-Ogievskiy if (remaining < sizeof(fh)) { 225*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Can not read feature header, as remaining bytes " 226*baefd977SVladimir Sementsov-Ogievskiy "(%d) in Format Extension is less than Feature header " 227*baefd977SVladimir Sementsov-Ogievskiy "size (%zu)", remaining, sizeof(fh)); 228*baefd977SVladimir Sementsov-Ogievskiy goto fail; 229*baefd977SVladimir Sementsov-Ogievskiy } 230*baefd977SVladimir Sementsov-Ogievskiy 231*baefd977SVladimir Sementsov-Ogievskiy memcpy(&fh, pos, sizeof(fh)); 232*baefd977SVladimir Sementsov-Ogievskiy pos += sizeof(fh); 233*baefd977SVladimir Sementsov-Ogievskiy remaining -= sizeof(fh); 234*baefd977SVladimir Sementsov-Ogievskiy 235*baefd977SVladimir Sementsov-Ogievskiy fh.magic = le64_to_cpu(fh.magic); 236*baefd977SVladimir Sementsov-Ogievskiy fh.flags = le64_to_cpu(fh.flags); 237*baefd977SVladimir Sementsov-Ogievskiy fh.data_size = le32_to_cpu(fh.data_size); 238*baefd977SVladimir Sementsov-Ogievskiy 239*baefd977SVladimir Sementsov-Ogievskiy if (fh.flags) { 240*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Flags for extension feature are unsupported"); 241*baefd977SVladimir Sementsov-Ogievskiy goto fail; 242*baefd977SVladimir Sementsov-Ogievskiy } 243*baefd977SVladimir Sementsov-Ogievskiy 244*baefd977SVladimir Sementsov-Ogievskiy if (fh.data_size > remaining) { 245*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Feature data_size exceedes Format Extension " 246*baefd977SVladimir Sementsov-Ogievskiy "cluster"); 247*baefd977SVladimir Sementsov-Ogievskiy goto fail; 248*baefd977SVladimir Sementsov-Ogievskiy } 249*baefd977SVladimir Sementsov-Ogievskiy 250*baefd977SVladimir Sementsov-Ogievskiy switch (fh.magic) { 251*baefd977SVladimir Sementsov-Ogievskiy case PARALLELS_END_OF_FEATURES_MAGIC: 252*baefd977SVladimir Sementsov-Ogievskiy return 0; 253*baefd977SVladimir Sementsov-Ogievskiy 254*baefd977SVladimir Sementsov-Ogievskiy case PARALLELS_DIRTY_BITMAP_FEATURE_MAGIC: 255*baefd977SVladimir Sementsov-Ogievskiy bitmap = parallels_load_bitmap(bs, pos, fh.data_size, errp); 256*baefd977SVladimir Sementsov-Ogievskiy if (!bitmap) { 257*baefd977SVladimir Sementsov-Ogievskiy goto fail; 258*baefd977SVladimir Sementsov-Ogievskiy } 259*baefd977SVladimir Sementsov-Ogievskiy bitmaps = g_slist_append(bitmaps, bitmap); 260*baefd977SVladimir Sementsov-Ogievskiy break; 261*baefd977SVladimir Sementsov-Ogievskiy 262*baefd977SVladimir Sementsov-Ogievskiy default: 263*baefd977SVladimir Sementsov-Ogievskiy error_setg(errp, "Unknown feature: 0x%" PRIu64, fh.magic); 264*baefd977SVladimir Sementsov-Ogievskiy goto fail; 265*baefd977SVladimir Sementsov-Ogievskiy } 266*baefd977SVladimir Sementsov-Ogievskiy 267*baefd977SVladimir Sementsov-Ogievskiy pos = ext_cluster + QEMU_ALIGN_UP(pos + fh.data_size - ext_cluster, 8); 268*baefd977SVladimir Sementsov-Ogievskiy } 269*baefd977SVladimir Sementsov-Ogievskiy 270*baefd977SVladimir Sementsov-Ogievskiy fail: 271*baefd977SVladimir Sementsov-Ogievskiy for (el = bitmaps; el; el = el->next) { 272*baefd977SVladimir Sementsov-Ogievskiy bdrv_release_dirty_bitmap(el->data); 273*baefd977SVladimir Sementsov-Ogievskiy } 274*baefd977SVladimir Sementsov-Ogievskiy g_slist_free(bitmaps); 275*baefd977SVladimir Sementsov-Ogievskiy 276*baefd977SVladimir Sementsov-Ogievskiy return -EINVAL; 277*baefd977SVladimir Sementsov-Ogievskiy } 278*baefd977SVladimir Sementsov-Ogievskiy 279*baefd977SVladimir Sementsov-Ogievskiy int parallels_read_format_extension(BlockDriverState *bs, 280*baefd977SVladimir Sementsov-Ogievskiy int64_t ext_off, Error **errp) 281*baefd977SVladimir Sementsov-Ogievskiy { 282*baefd977SVladimir Sementsov-Ogievskiy BDRVParallelsState *s = bs->opaque; 283*baefd977SVladimir Sementsov-Ogievskiy int ret; 284*baefd977SVladimir Sementsov-Ogievskiy uint8_t *ext_cluster = qemu_blockalign(bs, s->cluster_size); 285*baefd977SVladimir Sementsov-Ogievskiy 286*baefd977SVladimir Sementsov-Ogievskiy assert(ext_off > 0); 287*baefd977SVladimir Sementsov-Ogievskiy 288*baefd977SVladimir Sementsov-Ogievskiy ret = bdrv_pread(bs->file, ext_off, ext_cluster, s->cluster_size); 289*baefd977SVladimir Sementsov-Ogievskiy if (ret < 0) { 290*baefd977SVladimir Sementsov-Ogievskiy error_setg_errno(errp, -ret, "Failed to read Format Extension cluster"); 291*baefd977SVladimir Sementsov-Ogievskiy goto out; 292*baefd977SVladimir Sementsov-Ogievskiy } 293*baefd977SVladimir Sementsov-Ogievskiy 294*baefd977SVladimir Sementsov-Ogievskiy ret = parallels_parse_format_extension(bs, ext_cluster, errp); 295*baefd977SVladimir Sementsov-Ogievskiy 296*baefd977SVladimir Sementsov-Ogievskiy out: 297*baefd977SVladimir Sementsov-Ogievskiy qemu_vfree(ext_cluster); 298*baefd977SVladimir Sementsov-Ogievskiy 299*baefd977SVladimir Sementsov-Ogievskiy return ret; 300*baefd977SVladimir Sementsov-Ogievskiy } 301