xref: /openbmc/qemu/block/parallels-ext.c (revision baefd977002e72402f2cc42b11f2cb11b96aae9e)
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