]> git.proxmox.com Git - mirror_qemu.git/blob - block/parallels.c
block/parallels: implement parallels_check method of block driver
[mirror_qemu.git] / block / parallels.c
1 /*
2 * Block driver for Parallels disk image format
3 *
4 * Copyright (c) 2007 Alex Beregszaszi
5 * Copyright (c) 2015 Denis V. Lunev <den@openvz.org>
6 *
7 * This code was originally based on comparing different disk images created
8 * by Parallels. Currently it is based on opened OpenVZ sources
9 * available at
10 * http://git.openvz.org/?p=ploop;a=summary
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this software and associated documentation files (the "Software"), to deal
14 * in the Software without restriction, including without limitation the rights
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the Software is
17 * furnished to do so, subject to the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 * THE SOFTWARE.
29 */
30 #include "qemu-common.h"
31 #include "block/block_int.h"
32 #include "qemu/module.h"
33
34 /**************************************************************/
35
36 #define HEADER_MAGIC "WithoutFreeSpace"
37 #define HEADER_MAGIC2 "WithouFreSpacExt"
38 #define HEADER_VERSION 2
39
40 #define DEFAULT_CLUSTER_SIZE 1048576 /* 1 MiB */
41
42
43 // always little-endian
44 typedef struct ParallelsHeader {
45 char magic[16]; // "WithoutFreeSpace"
46 uint32_t version;
47 uint32_t heads;
48 uint32_t cylinders;
49 uint32_t tracks;
50 uint32_t bat_entries;
51 uint64_t nb_sectors;
52 uint32_t inuse;
53 uint32_t data_off;
54 char padding[12];
55 } QEMU_PACKED ParallelsHeader;
56
57 typedef struct BDRVParallelsState {
58 /** Locking is conservative, the lock protects
59 * - image file extending (truncate, fallocate)
60 * - any access to block allocation table
61 */
62 CoMutex lock;
63
64 ParallelsHeader *header;
65 uint32_t header_size;
66 uint32_t *bat_bitmap;
67 unsigned int bat_size;
68
69 unsigned int tracks;
70
71 unsigned int off_multiplier;
72
73 bool has_truncate;
74 } BDRVParallelsState;
75
76
77 static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx)
78 {
79 return (uint64_t)le32_to_cpu(s->bat_bitmap[idx]) * s->off_multiplier;
80 }
81
82 static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
83 {
84 uint32_t index, offset;
85
86 index = sector_num / s->tracks;
87 offset = sector_num % s->tracks;
88
89 /* not allocated */
90 if ((index >= s->bat_size) || (s->bat_bitmap[index] == 0)) {
91 return -1;
92 }
93 return bat2sect(s, index) + offset;
94 }
95
96 static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
97 int nb_sectors)
98 {
99 int ret = s->tracks - sector_num % s->tracks;
100 return MIN(nb_sectors, ret);
101 }
102
103 static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num)
104 {
105 BDRVParallelsState *s = bs->opaque;
106 uint32_t idx, offset;
107 int64_t pos;
108 int ret;
109
110 idx = sector_num / s->tracks;
111 offset = sector_num % s->tracks;
112
113 if (idx >= s->bat_size) {
114 return -EINVAL;
115 }
116 if (s->bat_bitmap[idx] != 0) {
117 return bat2sect(s, idx) + offset;
118 }
119
120 pos = bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS;
121 if (s->has_truncate) {
122 ret = bdrv_truncate(bs->file, (pos + s->tracks) << BDRV_SECTOR_BITS);
123 } else {
124 ret = bdrv_write_zeroes(bs->file, pos, s->tracks, 0);
125 }
126 if (ret < 0) {
127 return ret;
128 }
129
130 s->bat_bitmap[idx] = cpu_to_le32(pos / s->off_multiplier);
131 ret = bdrv_pwrite(bs->file,
132 sizeof(ParallelsHeader) + idx * sizeof(s->bat_bitmap[idx]),
133 s->bat_bitmap + idx, sizeof(s->bat_bitmap[idx]));
134 if (ret < 0) {
135 s->bat_bitmap[idx] = 0;
136 return ret;
137 }
138 return bat2sect(s, idx) + offset;
139 }
140
141 static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
142 int64_t sector_num, int nb_sectors, int *pnum)
143 {
144 BDRVParallelsState *s = bs->opaque;
145 int64_t offset;
146
147 qemu_co_mutex_lock(&s->lock);
148 offset = seek_to_sector(s, sector_num);
149 qemu_co_mutex_unlock(&s->lock);
150
151 *pnum = cluster_remainder(s, sector_num, nb_sectors);
152
153 if (offset < 0) {
154 return 0;
155 }
156
157 return (offset << BDRV_SECTOR_BITS) |
158 BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
159 }
160
161 static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
162 int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
163 {
164 BDRVParallelsState *s = bs->opaque;
165 uint64_t bytes_done = 0;
166 QEMUIOVector hd_qiov;
167 int ret = 0;
168
169 qemu_iovec_init(&hd_qiov, qiov->niov);
170
171 while (nb_sectors > 0) {
172 int64_t position;
173 int n, nbytes;
174
175 qemu_co_mutex_lock(&s->lock);
176 position = allocate_cluster(bs, sector_num);
177 qemu_co_mutex_unlock(&s->lock);
178 if (position < 0) {
179 ret = (int)position;
180 break;
181 }
182
183 n = cluster_remainder(s, sector_num, nb_sectors);
184 nbytes = n << BDRV_SECTOR_BITS;
185
186 qemu_iovec_reset(&hd_qiov);
187 qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
188
189 ret = bdrv_co_writev(bs->file, position, n, &hd_qiov);
190 if (ret < 0) {
191 break;
192 }
193
194 nb_sectors -= n;
195 sector_num += n;
196 bytes_done += nbytes;
197 }
198
199 qemu_iovec_destroy(&hd_qiov);
200 return ret;
201 }
202
203 static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
204 int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
205 {
206 BDRVParallelsState *s = bs->opaque;
207 uint64_t bytes_done = 0;
208 QEMUIOVector hd_qiov;
209 int ret = 0;
210
211 qemu_iovec_init(&hd_qiov, qiov->niov);
212
213 while (nb_sectors > 0) {
214 int64_t position;
215 int n, nbytes;
216
217 qemu_co_mutex_lock(&s->lock);
218 position = seek_to_sector(s, sector_num);
219 qemu_co_mutex_unlock(&s->lock);
220
221 n = cluster_remainder(s, sector_num, nb_sectors);
222 nbytes = n << BDRV_SECTOR_BITS;
223
224 if (position < 0) {
225 qemu_iovec_memset(qiov, bytes_done, 0, nbytes);
226 } else {
227 qemu_iovec_reset(&hd_qiov);
228 qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
229
230 ret = bdrv_co_readv(bs->file, position, n, &hd_qiov);
231 if (ret < 0) {
232 break;
233 }
234 }
235
236 nb_sectors -= n;
237 sector_num += n;
238 bytes_done += nbytes;
239 }
240
241 qemu_iovec_destroy(&hd_qiov);
242 return ret;
243 }
244
245
246 static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
247 BdrvCheckMode fix)
248 {
249 BDRVParallelsState *s = bs->opaque;
250 int64_t size, prev_off, high_off;
251 int ret;
252 uint32_t i;
253 bool flush_bat = false;
254 int cluster_size = s->tracks << BDRV_SECTOR_BITS;
255
256 size = bdrv_getlength(bs->file);
257 if (size < 0) {
258 res->check_errors++;
259 return size;
260 }
261
262 res->bfi.total_clusters = s->bat_size;
263 res->bfi.compressed_clusters = 0; /* compression is not supported */
264
265 high_off = 0;
266 prev_off = 0;
267 for (i = 0; i < s->bat_size; i++) {
268 int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
269 if (off == 0) {
270 prev_off = 0;
271 continue;
272 }
273
274 /* cluster outside the image */
275 if (off > size) {
276 fprintf(stderr, "%s cluster %u is outside image\n",
277 fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
278 res->corruptions++;
279 if (fix & BDRV_FIX_ERRORS) {
280 prev_off = 0;
281 s->bat_bitmap[i] = 0;
282 res->corruptions_fixed++;
283 flush_bat = true;
284 continue;
285 }
286 }
287
288 res->bfi.allocated_clusters++;
289 if (off > high_off) {
290 high_off = off;
291 }
292
293 if (prev_off != 0 && (prev_off + cluster_size) != off) {
294 res->bfi.fragmented_clusters++;
295 }
296 prev_off = off;
297 }
298
299 if (flush_bat) {
300 ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
301 if (ret < 0) {
302 res->check_errors++;
303 return ret;
304 }
305 }
306
307 res->image_end_offset = high_off + cluster_size;
308 if (size > res->image_end_offset) {
309 int64_t count;
310 count = DIV_ROUND_UP(size - res->image_end_offset, cluster_size);
311 fprintf(stderr, "%s space leaked at the end of the image %" PRId64 "\n",
312 fix & BDRV_FIX_LEAKS ? "Repairing" : "ERROR",
313 size - res->image_end_offset);
314 res->leaks += count;
315 if (fix & BDRV_FIX_LEAKS) {
316 ret = bdrv_truncate(bs->file, res->image_end_offset);
317 if (ret < 0) {
318 res->check_errors++;
319 return ret;
320 }
321 res->leaks_fixed += count;
322 }
323 }
324
325 return 0;
326 }
327
328
329 static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
330 {
331 int64_t total_size, cl_size;
332 uint8_t tmp[BDRV_SECTOR_SIZE];
333 Error *local_err = NULL;
334 BlockDriverState *file;
335 uint32_t bat_entries, bat_sectors;
336 ParallelsHeader header;
337 int ret;
338
339 total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
340 BDRV_SECTOR_SIZE);
341 cl_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
342 DEFAULT_CLUSTER_SIZE), BDRV_SECTOR_SIZE);
343
344 ret = bdrv_create_file(filename, opts, &local_err);
345 if (ret < 0) {
346 error_propagate(errp, local_err);
347 return ret;
348 }
349
350 file = NULL;
351 ret = bdrv_open(&file, filename, NULL, NULL,
352 BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
353 if (ret < 0) {
354 error_propagate(errp, local_err);
355 return ret;
356 }
357 ret = bdrv_truncate(file, 0);
358 if (ret < 0) {
359 goto exit;
360 }
361
362 bat_entries = DIV_ROUND_UP(total_size, cl_size);
363 bat_sectors = DIV_ROUND_UP(bat_entries * sizeof(uint32_t) +
364 sizeof(ParallelsHeader), cl_size);
365 bat_sectors = (bat_sectors * cl_size) >> BDRV_SECTOR_BITS;
366
367 memset(&header, 0, sizeof(header));
368 memcpy(header.magic, HEADER_MAGIC2, sizeof(header.magic));
369 header.version = cpu_to_le32(HEADER_VERSION);
370 /* don't care much about geometry, it is not used on image level */
371 header.heads = cpu_to_le32(16);
372 header.cylinders = cpu_to_le32(total_size / BDRV_SECTOR_SIZE / 16 / 32);
373 header.tracks = cpu_to_le32(cl_size >> BDRV_SECTOR_BITS);
374 header.bat_entries = cpu_to_le32(bat_entries);
375 header.nb_sectors = cpu_to_le64(DIV_ROUND_UP(total_size, BDRV_SECTOR_SIZE));
376 header.data_off = cpu_to_le32(bat_sectors);
377
378 /* write all the data */
379 memset(tmp, 0, sizeof(tmp));
380 memcpy(tmp, &header, sizeof(header));
381
382 ret = bdrv_pwrite(file, 0, tmp, BDRV_SECTOR_SIZE);
383 if (ret < 0) {
384 goto exit;
385 }
386 ret = bdrv_write_zeroes(file, 1, bat_sectors - 1, 0);
387 if (ret < 0) {
388 goto exit;
389 }
390 ret = 0;
391
392 done:
393 bdrv_unref(file);
394 return ret;
395
396 exit:
397 error_setg_errno(errp, -ret, "Failed to create Parallels image");
398 goto done;
399 }
400
401
402 static int parallels_probe(const uint8_t *buf, int buf_size,
403 const char *filename)
404 {
405 const ParallelsHeader *ph = (const void *)buf;
406
407 if (buf_size < sizeof(ParallelsHeader)) {
408 return 0;
409 }
410
411 if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
412 !memcmp(ph->magic, HEADER_MAGIC2, 16)) &&
413 (le32_to_cpu(ph->version) == HEADER_VERSION)) {
414 return 100;
415 }
416
417 return 0;
418 }
419
420 static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
421 Error **errp)
422 {
423 BDRVParallelsState *s = bs->opaque;
424 ParallelsHeader ph;
425 int ret, size;
426
427 ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
428 if (ret < 0) {
429 goto fail;
430 }
431
432 bs->total_sectors = le64_to_cpu(ph.nb_sectors);
433
434 if (le32_to_cpu(ph.version) != HEADER_VERSION) {
435 goto fail_format;
436 }
437 if (!memcmp(ph.magic, HEADER_MAGIC, 16)) {
438 s->off_multiplier = 1;
439 bs->total_sectors = 0xffffffff & bs->total_sectors;
440 } else if (!memcmp(ph.magic, HEADER_MAGIC2, 16)) {
441 s->off_multiplier = le32_to_cpu(ph.tracks);
442 } else {
443 goto fail_format;
444 }
445
446 s->tracks = le32_to_cpu(ph.tracks);
447 if (s->tracks == 0) {
448 error_setg(errp, "Invalid image: Zero sectors per track");
449 ret = -EINVAL;
450 goto fail;
451 }
452 if (s->tracks > INT32_MAX/513) {
453 error_setg(errp, "Invalid image: Too big cluster");
454 ret = -EFBIG;
455 goto fail;
456 }
457
458 s->bat_size = le32_to_cpu(ph.bat_entries);
459 if (s->bat_size > INT_MAX / sizeof(uint32_t)) {
460 error_setg(errp, "Catalog too large");
461 ret = -EFBIG;
462 goto fail;
463 }
464
465 size = sizeof(ParallelsHeader) + sizeof(uint32_t) * s->bat_size;
466 s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file));
467 s->header = qemu_try_blockalign(bs->file, s->header_size);
468 if (s->header == NULL) {
469 ret = -ENOMEM;
470 goto fail;
471 }
472 if (le32_to_cpu(ph.data_off) < s->header_size) {
473 /* there is not enough unused space to fit to block align between BAT
474 and actual data. We can't avoid read-modify-write... */
475 s->header_size = size;
476 }
477
478 ret = bdrv_pread(bs->file, 0, s->header, s->header_size);
479 if (ret < 0) {
480 goto fail;
481 }
482 s->bat_bitmap = (uint32_t *)(s->header + 1);
483
484 s->has_truncate = bdrv_has_zero_init(bs->file) &&
485 bdrv_truncate(bs->file, bdrv_getlength(bs->file)) == 0;
486
487 qemu_co_mutex_init(&s->lock);
488 return 0;
489
490 fail_format:
491 error_setg(errp, "Image not in Parallels format");
492 ret = -EINVAL;
493 fail:
494 qemu_vfree(s->header);
495 return ret;
496 }
497
498
499 static void parallels_close(BlockDriverState *bs)
500 {
501 BDRVParallelsState *s = bs->opaque;
502 qemu_vfree(s->header);
503 }
504
505 static QemuOptsList parallels_create_opts = {
506 .name = "parallels-create-opts",
507 .head = QTAILQ_HEAD_INITIALIZER(parallels_create_opts.head),
508 .desc = {
509 {
510 .name = BLOCK_OPT_SIZE,
511 .type = QEMU_OPT_SIZE,
512 .help = "Virtual disk size",
513 },
514 {
515 .name = BLOCK_OPT_CLUSTER_SIZE,
516 .type = QEMU_OPT_SIZE,
517 .help = "Parallels image cluster size",
518 .def_value_str = stringify(DEFAULT_CLUSTER_SIZE),
519 },
520 { /* end of list */ }
521 }
522 };
523
524 static BlockDriver bdrv_parallels = {
525 .format_name = "parallels",
526 .instance_size = sizeof(BDRVParallelsState),
527 .bdrv_probe = parallels_probe,
528 .bdrv_open = parallels_open,
529 .bdrv_close = parallels_close,
530 .bdrv_co_get_block_status = parallels_co_get_block_status,
531 .bdrv_has_zero_init = bdrv_has_zero_init_1,
532 .bdrv_co_readv = parallels_co_readv,
533 .bdrv_co_writev = parallels_co_writev,
534
535 .bdrv_create = parallels_create,
536 .bdrv_check = parallels_check,
537 .create_opts = &parallels_create_opts,
538 };
539
540 static void bdrv_parallels_init(void)
541 {
542 bdrv_register(&bdrv_parallels);
543 }
544
545 block_init(bdrv_parallels_init);