]> git.proxmox.com Git - mirror_qemu.git/blame - block/qcow2-bitmap.c
qcow2: add bitmaps extension
[mirror_qemu.git] / block / qcow2-bitmap.c
CommitLineData
88ddffae
VSO
1/*
2 * Bitmaps for the QCOW version 2 format
3 *
4 * Copyright (c) 2014-2017 Vladimir Sementsov-Ogievskiy
5 *
6 * This file is derived from qcow2-snapshot.c, original copyright:
7 * Copyright (c) 2004-2006 Fabrice Bellard
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in
17 * all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 * THE SOFTWARE.
26 */
27
28#include "qemu/osdep.h"
29#include "qapi/error.h"
30
31#include "block/block_int.h"
32#include "block/qcow2.h"
33
34/* NOTICE: BME here means Bitmaps Extension and used as a namespace for
35 * _internal_ constants. Please do not use this _internal_ abbreviation for
36 * other needs and/or outside of this file. */
37
38/* Bitmap directory entry constraints */
39#define BME_MAX_TABLE_SIZE 0x8000000
40#define BME_MAX_PHYS_SIZE 0x20000000 /* restrict BdrvDirtyBitmap size in RAM */
41#define BME_MAX_GRANULARITY_BITS 31
42#define BME_MIN_GRANULARITY_BITS 9
43#define BME_MAX_NAME_SIZE 1023
44
45/* Bitmap directory entry flags */
46#define BME_RESERVED_FLAGS 0xfffffffcU
47
48/* bits [1, 8] U [56, 63] are reserved */
49#define BME_TABLE_ENTRY_RESERVED_MASK 0xff000000000001feULL
50#define BME_TABLE_ENTRY_OFFSET_MASK 0x00fffffffffffe00ULL
51#define BME_TABLE_ENTRY_FLAG_ALL_ONES (1ULL << 0)
52
53typedef struct QEMU_PACKED Qcow2BitmapDirEntry {
54 /* header is 8 byte aligned */
55 uint64_t bitmap_table_offset;
56
57 uint32_t bitmap_table_size;
58 uint32_t flags;
59
60 uint8_t type;
61 uint8_t granularity_bits;
62 uint16_t name_size;
63 uint32_t extra_data_size;
64 /* extra data follows */
65 /* name follows */
66} Qcow2BitmapDirEntry;
67
68typedef struct Qcow2BitmapTable {
69 uint64_t offset;
70 uint32_t size; /* number of 64bit entries */
71 QSIMPLEQ_ENTRY(Qcow2BitmapTable) entry;
72} Qcow2BitmapTable;
73
74typedef struct Qcow2Bitmap {
75 Qcow2BitmapTable table;
76 uint32_t flags;
77 uint8_t granularity_bits;
78 char *name;
79
80 QSIMPLEQ_ENTRY(Qcow2Bitmap) entry;
81} Qcow2Bitmap;
82typedef QSIMPLEQ_HEAD(Qcow2BitmapList, Qcow2Bitmap) Qcow2BitmapList;
83
84typedef enum BitmapType {
85 BT_DIRTY_TRACKING_BITMAP = 1
86} BitmapType;
87
88static int check_table_entry(uint64_t entry, int cluster_size)
89{
90 uint64_t offset;
91
92 if (entry & BME_TABLE_ENTRY_RESERVED_MASK) {
93 return -EINVAL;
94 }
95
96 offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
97 if (offset != 0) {
98 /* if offset specified, bit 0 is reserved */
99 if (entry & BME_TABLE_ENTRY_FLAG_ALL_ONES) {
100 return -EINVAL;
101 }
102
103 if (offset % cluster_size != 0) {
104 return -EINVAL;
105 }
106 }
107
108 return 0;
109}
110
111static int bitmap_table_load(BlockDriverState *bs, Qcow2BitmapTable *tb,
112 uint64_t **bitmap_table)
113{
114 int ret;
115 BDRVQcow2State *s = bs->opaque;
116 uint32_t i;
117 uint64_t *table;
118
119 assert(tb->size != 0);
120 table = g_try_new(uint64_t, tb->size);
121 if (table == NULL) {
122 return -ENOMEM;
123 }
124
125 assert(tb->size <= BME_MAX_TABLE_SIZE);
126 ret = bdrv_pread(bs->file, tb->offset,
127 table, tb->size * sizeof(uint64_t));
128 if (ret < 0) {
129 goto fail;
130 }
131
132 for (i = 0; i < tb->size; ++i) {
133 be64_to_cpus(&table[i]);
134 ret = check_table_entry(table[i], s->cluster_size);
135 if (ret < 0) {
136 goto fail;
137 }
138 }
139
140 *bitmap_table = table;
141 return 0;
142
143fail:
144 g_free(table);
145
146 return ret;
147}
148
149/*
150 * Bitmap List
151 */
152
153/*
154 * Bitmap List private functions
155 * Only Bitmap List knows about bitmap directory structure in Qcow2.
156 */
157
158static inline void bitmap_dir_entry_to_cpu(Qcow2BitmapDirEntry *entry)
159{
160 be64_to_cpus(&entry->bitmap_table_offset);
161 be32_to_cpus(&entry->bitmap_table_size);
162 be32_to_cpus(&entry->flags);
163 be16_to_cpus(&entry->name_size);
164 be32_to_cpus(&entry->extra_data_size);
165}
166
167static inline int calc_dir_entry_size(size_t name_size, size_t extra_data_size)
168{
169 return align_offset(sizeof(Qcow2BitmapDirEntry) +
170 name_size + extra_data_size, 8);
171}
172
173static inline int dir_entry_size(Qcow2BitmapDirEntry *entry)
174{
175 return calc_dir_entry_size(entry->name_size, entry->extra_data_size);
176}
177
178static inline const char *dir_entry_name_field(Qcow2BitmapDirEntry *entry)
179{
180 return (const char *)(entry + 1) + entry->extra_data_size;
181}
182
183static inline char *dir_entry_copy_name(Qcow2BitmapDirEntry *entry)
184{
185 const char *name_field = dir_entry_name_field(entry);
186 return g_strndup(name_field, entry->name_size);
187}
188
189static inline Qcow2BitmapDirEntry *next_dir_entry(Qcow2BitmapDirEntry *entry)
190{
191 return (Qcow2BitmapDirEntry *)((uint8_t *)entry + dir_entry_size(entry));
192}
193
194static int check_dir_entry(BlockDriverState *bs, Qcow2BitmapDirEntry *entry)
195{
196 BDRVQcow2State *s = bs->opaque;
197 uint64_t phys_bitmap_bytes;
198 int64_t len;
199
200 bool fail = (entry->bitmap_table_size == 0) ||
201 (entry->bitmap_table_offset == 0) ||
202 (entry->bitmap_table_offset % s->cluster_size) ||
203 (entry->bitmap_table_size > BME_MAX_TABLE_SIZE) ||
204 (entry->granularity_bits > BME_MAX_GRANULARITY_BITS) ||
205 (entry->granularity_bits < BME_MIN_GRANULARITY_BITS) ||
206 (entry->flags & BME_RESERVED_FLAGS) ||
207 (entry->name_size > BME_MAX_NAME_SIZE) ||
208 (entry->type != BT_DIRTY_TRACKING_BITMAP);
209
210 if (fail) {
211 return -EINVAL;
212 }
213
214 phys_bitmap_bytes = (uint64_t)entry->bitmap_table_size * s->cluster_size;
215 len = bdrv_getlength(bs);
216
217 if (len < 0) {
218 return len;
219 }
220
221 fail = (phys_bitmap_bytes > BME_MAX_PHYS_SIZE) ||
222 (len > ((phys_bitmap_bytes * 8) << entry->granularity_bits));
223
224 return fail ? -EINVAL : 0;
225}
226
227/*
228 * Bitmap List public functions
229 */
230
231static void bitmap_free(Qcow2Bitmap *bm)
232{
233 g_free(bm->name);
234 g_free(bm);
235}
236
237static void bitmap_list_free(Qcow2BitmapList *bm_list)
238{
239 Qcow2Bitmap *bm;
240
241 if (bm_list == NULL) {
242 return;
243 }
244
245 while ((bm = QSIMPLEQ_FIRST(bm_list)) != NULL) {
246 QSIMPLEQ_REMOVE_HEAD(bm_list, entry);
247 bitmap_free(bm);
248 }
249
250 g_free(bm_list);
251}
252
253static Qcow2BitmapList *bitmap_list_new(void)
254{
255 Qcow2BitmapList *bm_list = g_new(Qcow2BitmapList, 1);
256 QSIMPLEQ_INIT(bm_list);
257
258 return bm_list;
259}
260
261/* bitmap_list_load
262 * Get bitmap list from qcow2 image. Actually reads bitmap directory,
263 * checks it and convert to bitmap list.
264 */
265static Qcow2BitmapList *bitmap_list_load(BlockDriverState *bs, uint64_t offset,
266 uint64_t size, Error **errp)
267{
268 int ret;
269 BDRVQcow2State *s = bs->opaque;
270 uint8_t *dir, *dir_end;
271 Qcow2BitmapDirEntry *e;
272 uint32_t nb_dir_entries = 0;
273 Qcow2BitmapList *bm_list = NULL;
274
275 if (size == 0) {
276 error_setg(errp, "Requested bitmap directory size is zero");
277 return NULL;
278 }
279
280 if (size > QCOW2_MAX_BITMAP_DIRECTORY_SIZE) {
281 error_setg(errp, "Requested bitmap directory size is too big");
282 return NULL;
283 }
284
285 dir = g_try_malloc(size);
286 if (dir == NULL) {
287 error_setg(errp, "Failed to allocate space for bitmap directory");
288 return NULL;
289 }
290 dir_end = dir + size;
291
292 ret = bdrv_pread(bs->file, offset, dir, size);
293 if (ret < 0) {
294 error_setg_errno(errp, -ret, "Failed to read bitmap directory");
295 goto fail;
296 }
297
298 bm_list = bitmap_list_new();
299 for (e = (Qcow2BitmapDirEntry *)dir;
300 e < (Qcow2BitmapDirEntry *)dir_end;
301 e = next_dir_entry(e))
302 {
303 Qcow2Bitmap *bm;
304
305 if ((uint8_t *)(e + 1) > dir_end) {
306 goto broken_dir;
307 }
308
309 if (++nb_dir_entries > s->nb_bitmaps) {
310 error_setg(errp, "More bitmaps found than specified in header"
311 " extension");
312 goto fail;
313 }
314 bitmap_dir_entry_to_cpu(e);
315
316 if ((uint8_t *)next_dir_entry(e) > dir_end) {
317 goto broken_dir;
318 }
319
320 if (e->extra_data_size != 0) {
321 error_setg(errp, "Bitmap extra data is not supported");
322 goto fail;
323 }
324
325 ret = check_dir_entry(bs, e);
326 if (ret < 0) {
327 error_setg(errp, "Bitmap '%.*s' doesn't satisfy the constraints",
328 e->name_size, dir_entry_name_field(e));
329 goto fail;
330 }
331
332 bm = g_new(Qcow2Bitmap, 1);
333 bm->table.offset = e->bitmap_table_offset;
334 bm->table.size = e->bitmap_table_size;
335 bm->flags = e->flags;
336 bm->granularity_bits = e->granularity_bits;
337 bm->name = dir_entry_copy_name(e);
338 QSIMPLEQ_INSERT_TAIL(bm_list, bm, entry);
339 }
340
341 if (nb_dir_entries != s->nb_bitmaps) {
342 error_setg(errp, "Less bitmaps found than specified in header"
343 " extension");
344 goto fail;
345 }
346
347 if ((uint8_t *)e != dir_end) {
348 goto broken_dir;
349 }
350
351 g_free(dir);
352 return bm_list;
353
354broken_dir:
355 ret = -EINVAL;
356 error_setg(errp, "Broken bitmap directory");
357
358fail:
359 g_free(dir);
360 bitmap_list_free(bm_list);
361
362 return NULL;
363}
364
365int qcow2_check_bitmaps_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
366 void **refcount_table,
367 int64_t *refcount_table_size)
368{
369 int ret;
370 BDRVQcow2State *s = bs->opaque;
371 Qcow2BitmapList *bm_list;
372 Qcow2Bitmap *bm;
373
374 if (s->nb_bitmaps == 0) {
375 return 0;
376 }
377
378 ret = qcow2_inc_refcounts_imrt(bs, res, refcount_table, refcount_table_size,
379 s->bitmap_directory_offset,
380 s->bitmap_directory_size);
381 if (ret < 0) {
382 return ret;
383 }
384
385 bm_list = bitmap_list_load(bs, s->bitmap_directory_offset,
386 s->bitmap_directory_size, NULL);
387 if (bm_list == NULL) {
388 res->corruptions++;
389 return -EINVAL;
390 }
391
392 QSIMPLEQ_FOREACH(bm, bm_list, entry) {
393 uint64_t *bitmap_table = NULL;
394 int i;
395
396 ret = qcow2_inc_refcounts_imrt(bs, res,
397 refcount_table, refcount_table_size,
398 bm->table.offset,
399 bm->table.size * sizeof(uint64_t));
400 if (ret < 0) {
401 goto out;
402 }
403
404 ret = bitmap_table_load(bs, &bm->table, &bitmap_table);
405 if (ret < 0) {
406 res->corruptions++;
407 goto out;
408 }
409
410 for (i = 0; i < bm->table.size; ++i) {
411 uint64_t entry = bitmap_table[i];
412 uint64_t offset = entry & BME_TABLE_ENTRY_OFFSET_MASK;
413
414 if (check_table_entry(entry, s->cluster_size) < 0) {
415 res->corruptions++;
416 continue;
417 }
418
419 if (offset == 0) {
420 continue;
421 }
422
423 ret = qcow2_inc_refcounts_imrt(bs, res,
424 refcount_table, refcount_table_size,
425 offset, s->cluster_size);
426 if (ret < 0) {
427 g_free(bitmap_table);
428 goto out;
429 }
430 }
431
432 g_free(bitmap_table);
433 }
434
435out:
436 bitmap_list_free(bm_list);
437
438 return ret;
439}