1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include "qemu/osdep.h"
27#include "qapi/error.h"
28#include "block/block_int.h"
29#include "block/qdict.h"
30#include "sysemu/block-backend.h"
31#include "qemu/module.h"
32#include "qemu/option.h"
33#include "migration/blocker.h"
34#include "qemu/bswap.h"
35#include "qemu/uuid.h"
36#include "qapi/qmp/qdict.h"
37#include "qapi/qobject-input-visitor.h"
38#include "qapi/qapi-visit-block-core.h"
39
40
41
42#define HEADER_SIZE 512
43
44
45
46enum vhd_type {
47 VHD_FIXED = 2,
48 VHD_DYNAMIC = 3,
49 VHD_DIFFERENCING = 4,
50};
51
52
53#define VHD_TIMESTAMP_BASE 946684800
54
55#define VHD_CHS_MAX_C 65535LL
56#define VHD_CHS_MAX_H 16
57#define VHD_CHS_MAX_S 255
58
59#define VHD_MAX_SECTORS 0xff000000
60#define VHD_MAX_GEOMETRY (VHD_CHS_MAX_C * VHD_CHS_MAX_H * VHD_CHS_MAX_S)
61
62#define VPC_OPT_FORCE_SIZE "force_size"
63
64
65typedef struct vhd_footer {
66 char creator[8];
67 uint32_t features;
68 uint32_t version;
69
70
71 uint64_t data_offset;
72
73
74 uint32_t timestamp;
75
76 char creator_app[4];
77 uint16_t major;
78 uint16_t minor;
79 char creator_os[4];
80
81 uint64_t orig_size;
82 uint64_t current_size;
83
84 uint16_t cyls;
85 uint8_t heads;
86 uint8_t secs_per_cyl;
87
88 uint32_t type;
89
90
91
92 uint32_t checksum;
93
94
95 QemuUUID uuid;
96
97 uint8_t in_saved_state;
98} QEMU_PACKED VHDFooter;
99
100typedef struct vhd_dyndisk_header {
101 char magic[8];
102
103
104 uint64_t data_offset;
105
106
107 uint64_t table_offset;
108
109 uint32_t version;
110 uint32_t max_table_entries;
111
112
113 uint32_t block_size;
114
115 uint32_t checksum;
116 uint8_t parent_uuid[16];
117 uint32_t parent_timestamp;
118 uint32_t reserved;
119
120
121 uint8_t parent_name[512];
122
123 struct {
124 uint32_t platform;
125 uint32_t data_space;
126 uint32_t data_length;
127 uint32_t reserved;
128 uint64_t data_offset;
129 } parent_locator[8];
130} QEMU_PACKED VHDDynDiskHeader;
131
132typedef struct BDRVVPCState {
133 CoMutex lock;
134 uint8_t footer_buf[HEADER_SIZE];
135 uint64_t free_data_block_offset;
136 int max_table_entries;
137 uint32_t *pagetable;
138 uint64_t bat_offset;
139 uint64_t last_bitmap_offset;
140
141 uint32_t block_size;
142 uint32_t bitmap_size;
143 bool force_use_chs;
144 bool force_use_sz;
145
146#ifdef CACHE
147 uint8_t *pageentry_u8;
148 uint32_t *pageentry_u32;
149 uint16_t *pageentry_u16;
150
151 uint64_t last_bitmap;
152#endif
153
154 Error *migration_blocker;
155} BDRVVPCState;
156
157#define VPC_OPT_SIZE_CALC "force_size_calc"
158static QemuOptsList vpc_runtime_opts = {
159 .name = "vpc-runtime-opts",
160 .head = QTAILQ_HEAD_INITIALIZER(vpc_runtime_opts.head),
161 .desc = {
162 {
163 .name = VPC_OPT_SIZE_CALC,
164 .type = QEMU_OPT_STRING,
165 .help = "Force disk size calculation to use either CHS geometry, "
166 "or use the disk current_size specified in the VHD footer. "
167 "{chs, current_size}"
168 },
169 { }
170 }
171};
172
173static QemuOptsList vpc_create_opts;
174
175static uint32_t vpc_checksum(uint8_t* buf, size_t size)
176{
177 uint32_t res = 0;
178 int i;
179
180 for (i = 0; i < size; i++)
181 res += buf[i];
182
183 return ~res;
184}
185
186
187static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
188{
189 if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
190 return 100;
191 return 0;
192}
193
194static void vpc_parse_options(BlockDriverState *bs, QemuOpts *opts,
195 Error **errp)
196{
197 BDRVVPCState *s = bs->opaque;
198 const char *size_calc;
199
200 size_calc = qemu_opt_get(opts, VPC_OPT_SIZE_CALC);
201
202 if (!size_calc) {
203
204 } else if (!strcmp(size_calc, "current_size")) {
205 s->force_use_sz = true;
206 } else if (!strcmp(size_calc, "chs")) {
207 s->force_use_chs = true;
208 } else {
209 error_setg(errp, "Invalid size calculation mode: '%s'", size_calc);
210 }
211}
212
213static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
214 Error **errp)
215{
216 BDRVVPCState *s = bs->opaque;
217 int i;
218 VHDFooter *footer;
219 VHDDynDiskHeader *dyndisk_header;
220 QemuOpts *opts = NULL;
221 Error *local_err = NULL;
222 bool use_chs;
223 uint8_t buf[HEADER_SIZE];
224 uint32_t checksum;
225 uint64_t computed_size;
226 uint64_t pagetable_size;
227 int disk_type = VHD_DYNAMIC;
228 int ret;
229 int64_t bs_size;
230
231 bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
232 false, errp);
233 if (!bs->file) {
234 return -EINVAL;
235 }
236
237 opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
238 qemu_opts_absorb_qdict(opts, options, &local_err);
239 if (local_err) {
240 error_propagate(errp, local_err);
241 ret = -EINVAL;
242 goto fail;
243 }
244
245 vpc_parse_options(bs, opts, &local_err);
246 if (local_err) {
247 error_propagate(errp, local_err);
248 ret = -EINVAL;
249 goto fail;
250 }
251
252 ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
253 if (ret < 0) {
254 error_setg(errp, "Unable to read VHD header");
255 goto fail;
256 }
257
258 footer = (VHDFooter *) s->footer_buf;
259 if (strncmp(footer->creator, "conectix", 8)) {
260 int64_t offset = bdrv_getlength(bs->file->bs);
261 if (offset < 0) {
262 ret = offset;
263 error_setg(errp, "Invalid file size");
264 goto fail;
265 } else if (offset < HEADER_SIZE) {
266 ret = -EINVAL;
267 error_setg(errp, "File too small for a VHD header");
268 goto fail;
269 }
270
271
272 ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf,
273 HEADER_SIZE);
274 if (ret < 0) {
275 goto fail;
276 }
277 if (strncmp(footer->creator, "conectix", 8)) {
278 error_setg(errp, "invalid VPC image");
279 ret = -EINVAL;
280 goto fail;
281 }
282 disk_type = VHD_FIXED;
283 }
284
285 checksum = be32_to_cpu(footer->checksum);
286 footer->checksum = 0;
287 if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum) {
288 error_setg(errp, "Incorrect header checksum");
289 ret = -EINVAL;
290 goto fail;
291 }
292
293
294 footer->checksum = cpu_to_be32(checksum);
295
296
297
298
299 bs->total_sectors = (int64_t)
300 be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327 use_chs = (!!strncmp(footer->creator_app, "win ", 4) &&
328 !!strncmp(footer->creator_app, "qem2", 4) &&
329 !!strncmp(footer->creator_app, "d2v ", 4) &&
330 !!strncmp(footer->creator_app, "CTXS", 4) &&
331 !!memcmp(footer->creator_app, "tap", 4)) || s->force_use_chs;
332
333 if (!use_chs || bs->total_sectors == VHD_MAX_GEOMETRY || s->force_use_sz) {
334 bs->total_sectors = be64_to_cpu(footer->current_size) /
335 BDRV_SECTOR_SIZE;
336 }
337
338
339 if (bs->total_sectors > VHD_MAX_SECTORS) {
340 ret = -EFBIG;
341 goto fail;
342 }
343
344 if (disk_type == VHD_DYNAMIC) {
345 ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
346 HEADER_SIZE);
347 if (ret < 0) {
348 error_setg(errp, "Error reading dynamic VHD header");
349 goto fail;
350 }
351
352 dyndisk_header = (VHDDynDiskHeader *) buf;
353
354 if (strncmp(dyndisk_header->magic, "cxsparse", 8)) {
355 error_setg(errp, "Invalid header magic");
356 ret = -EINVAL;
357 goto fail;
358 }
359
360 s->block_size = be32_to_cpu(dyndisk_header->block_size);
361 if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) {
362 error_setg(errp, "Invalid block size %" PRIu32, s->block_size);
363 ret = -EINVAL;
364 goto fail;
365 }
366 s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
367
368 s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
369
370 if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) {
371 error_setg(errp, "Too many blocks");
372 ret = -EINVAL;
373 goto fail;
374 }
375
376 computed_size = (uint64_t) s->max_table_entries * s->block_size;
377 if (computed_size < bs->total_sectors * 512) {
378 error_setg(errp, "Page table too small");
379 ret = -EINVAL;
380 goto fail;
381 }
382
383 if (s->max_table_entries > SIZE_MAX / 4 ||
384 s->max_table_entries > (int) INT_MAX / 4) {
385 error_setg(errp, "Max Table Entries too large (%" PRId32 ")",
386 s->max_table_entries);
387 ret = -EINVAL;
388 goto fail;
389 }
390
391 pagetable_size = (uint64_t) s->max_table_entries * 4;
392
393 s->pagetable = qemu_try_blockalign(bs->file->bs, pagetable_size);
394 if (s->pagetable == NULL) {
395 error_setg(errp, "Unable to allocate memory for page table");
396 ret = -ENOMEM;
397 goto fail;
398 }
399
400 s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
401
402 ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
403 pagetable_size);
404 if (ret < 0) {
405 error_setg(errp, "Error reading pagetable");
406 goto fail;
407 }
408
409 s->free_data_block_offset =
410 ROUND_UP(s->bat_offset + pagetable_size, 512);
411
412 for (i = 0; i < s->max_table_entries; i++) {
413 be32_to_cpus(&s->pagetable[i]);
414 if (s->pagetable[i] != 0xFFFFFFFF) {
415 int64_t next = (512 * (int64_t) s->pagetable[i]) +
416 s->bitmap_size + s->block_size;
417
418 if (next > s->free_data_block_offset) {
419 s->free_data_block_offset = next;
420 }
421 }
422 }
423
424 bs_size = bdrv_getlength(bs->file->bs);
425 if (bs_size < 0) {
426 error_setg_errno(errp, -bs_size, "Unable to learn image size");
427 ret = bs_size;
428 goto fail;
429 }
430 if (s->free_data_block_offset > bs_size) {
431 error_setg(errp, "block-vpc: free_data_block_offset points after "
432 "the end of file. The image has been truncated.");
433 ret = -EINVAL;
434 goto fail;
435 }
436
437 s->last_bitmap_offset = (int64_t) -1;
438
439#ifdef CACHE
440 s->pageentry_u8 = g_malloc(512);
441 s->pageentry_u32 = s->pageentry_u8;
442 s->pageentry_u16 = s->pageentry_u8;
443 s->last_pagetable = -1;
444#endif
445 }
446
447
448 error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
449 "does not support live migration",
450 bdrv_get_device_or_node_name(bs));
451 ret = migrate_add_blocker(s->migration_blocker, &local_err);
452 if (local_err) {
453 error_propagate(errp, local_err);
454 error_free(s->migration_blocker);
455 goto fail;
456 }
457
458 qemu_co_mutex_init(&s->lock);
459 qemu_opts_del(opts);
460
461 return 0;
462
463fail:
464 qemu_opts_del(opts);
465 qemu_vfree(s->pagetable);
466#ifdef CACHE
467 g_free(s->pageentry_u8);
468#endif
469 return ret;
470}
471
472static int vpc_reopen_prepare(BDRVReopenState *state,
473 BlockReopenQueue *queue, Error **errp)
474{
475 return 0;
476}
477
478
479
480
481
482
483
484
485
486
487
488
489static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
490 bool write, int *err)
491{
492 BDRVVPCState *s = bs->opaque;
493 uint64_t bitmap_offset, block_offset;
494 uint32_t pagetable_index, offset_in_block;
495
496 assert(!(write && err == NULL));
497
498 pagetable_index = offset / s->block_size;
499 offset_in_block = offset % s->block_size;
500
501 if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
502 return -1;
503
504 bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
505 block_offset = bitmap_offset + s->bitmap_size + offset_in_block;
506
507
508
509
510
511
512 if (write && (s->last_bitmap_offset != bitmap_offset)) {
513 uint8_t bitmap[s->bitmap_size];
514 int r;
515
516 s->last_bitmap_offset = bitmap_offset;
517 memset(bitmap, 0xff, s->bitmap_size);
518 r = bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
519 if (r < 0) {
520 *err = r;
521 return -2;
522 }
523 }
524
525 return block_offset;
526}
527
528
529
530
531
532
533
534static int rewrite_footer(BlockDriverState* bs)
535{
536 int ret;
537 BDRVVPCState *s = bs->opaque;
538 int64_t offset = s->free_data_block_offset;
539
540 ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
541 if (ret < 0)
542 return ret;
543
544 return 0;
545}
546
547
548
549
550
551
552
553
554static int64_t alloc_block(BlockDriverState* bs, int64_t offset)
555{
556 BDRVVPCState *s = bs->opaque;
557 int64_t bat_offset;
558 uint32_t index, bat_value;
559 int ret;
560 uint8_t bitmap[s->bitmap_size];
561
562
563 if ((offset < 0) || (offset > bs->total_sectors * BDRV_SECTOR_SIZE)) {
564 return -EINVAL;
565 }
566
567
568 index = offset / s->block_size;
569 assert(s->pagetable[index] == 0xFFFFFFFF);
570 s->pagetable[index] = s->free_data_block_offset / 512;
571
572
573 memset(bitmap, 0xff, s->bitmap_size);
574 ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
575 s->bitmap_size);
576 if (ret < 0) {
577 return ret;
578 }
579
580
581 s->free_data_block_offset += s->block_size + s->bitmap_size;
582 ret = rewrite_footer(bs);
583 if (ret < 0)
584 goto fail;
585
586
587 bat_offset = s->bat_offset + (4 * index);
588 bat_value = cpu_to_be32(s->pagetable[index]);
589 ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
590 if (ret < 0)
591 goto fail;
592
593 return get_image_offset(bs, offset, false, NULL);
594
595fail:
596 s->free_data_block_offset -= (s->block_size + s->bitmap_size);
597 return ret;
598}
599
600static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
601{
602 BDRVVPCState *s = (BDRVVPCState *)bs->opaque;
603 VHDFooter *footer = (VHDFooter *) s->footer_buf;
604
605 if (be32_to_cpu(footer->type) != VHD_FIXED) {
606 bdi->cluster_size = s->block_size;
607 }
608
609 bdi->unallocated_blocks_are_zero = true;
610 return 0;
611}
612
613static int coroutine_fn
614vpc_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
615 QEMUIOVector *qiov, int flags)
616{
617 BDRVVPCState *s = bs->opaque;
618 int ret;
619 int64_t image_offset;
620 int64_t n_bytes;
621 int64_t bytes_done = 0;
622 VHDFooter *footer = (VHDFooter *) s->footer_buf;
623 QEMUIOVector local_qiov;
624
625 if (be32_to_cpu(footer->type) == VHD_FIXED) {
626 return bdrv_co_preadv(bs->file, offset, bytes, qiov, 0);
627 }
628
629 qemu_co_mutex_lock(&s->lock);
630 qemu_iovec_init(&local_qiov, qiov->niov);
631
632 while (bytes > 0) {
633 image_offset = get_image_offset(bs, offset, false, NULL);
634 n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
635
636 if (image_offset == -1) {
637 qemu_iovec_memset(qiov, bytes_done, 0, n_bytes);
638 } else {
639 qemu_iovec_reset(&local_qiov);
640 qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
641
642 ret = bdrv_co_preadv(bs->file, image_offset, n_bytes,
643 &local_qiov, 0);
644 if (ret < 0) {
645 goto fail;
646 }
647 }
648
649 bytes -= n_bytes;
650 offset += n_bytes;
651 bytes_done += n_bytes;
652 }
653
654 ret = 0;
655fail:
656 qemu_iovec_destroy(&local_qiov);
657 qemu_co_mutex_unlock(&s->lock);
658
659 return ret;
660}
661
662static int coroutine_fn
663vpc_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
664 QEMUIOVector *qiov, int flags)
665{
666 BDRVVPCState *s = bs->opaque;
667 int64_t image_offset;
668 int64_t n_bytes;
669 int64_t bytes_done = 0;
670 int ret = 0;
671 VHDFooter *footer = (VHDFooter *) s->footer_buf;
672 QEMUIOVector local_qiov;
673
674 if (be32_to_cpu(footer->type) == VHD_FIXED) {
675 return bdrv_co_pwritev(bs->file, offset, bytes, qiov, 0);
676 }
677
678 qemu_co_mutex_lock(&s->lock);
679 qemu_iovec_init(&local_qiov, qiov->niov);
680
681 while (bytes > 0) {
682 image_offset = get_image_offset(bs, offset, true, &ret);
683 if (image_offset == -2) {
684
685 goto fail;
686 }
687 n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
688
689 if (image_offset == -1) {
690 image_offset = alloc_block(bs, offset);
691 if (image_offset < 0) {
692 ret = image_offset;
693 goto fail;
694 }
695 }
696
697 qemu_iovec_reset(&local_qiov);
698 qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
699
700 ret = bdrv_co_pwritev(bs->file, image_offset, n_bytes,
701 &local_qiov, 0);
702 if (ret < 0) {
703 goto fail;
704 }
705
706 bytes -= n_bytes;
707 offset += n_bytes;
708 bytes_done += n_bytes;
709 }
710
711 ret = 0;
712fail:
713 qemu_iovec_destroy(&local_qiov);
714 qemu_co_mutex_unlock(&s->lock);
715
716 return ret;
717}
718
719static int coroutine_fn vpc_co_block_status(BlockDriverState *bs,
720 bool want_zero,
721 int64_t offset, int64_t bytes,
722 int64_t *pnum, int64_t *map,
723 BlockDriverState **file)
724{
725 BDRVVPCState *s = bs->opaque;
726 VHDFooter *footer = (VHDFooter*) s->footer_buf;
727 int64_t image_offset;
728 bool allocated;
729 int ret;
730 int64_t n;
731
732 if (be32_to_cpu(footer->type) == VHD_FIXED) {
733 *pnum = bytes;
734 *map = offset;
735 *file = bs->file->bs;
736 return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID;
737 }
738
739 qemu_co_mutex_lock(&s->lock);
740
741 image_offset = get_image_offset(bs, offset, false, NULL);
742 allocated = (image_offset != -1);
743 *pnum = 0;
744 ret = 0;
745
746 do {
747
748 n = ROUND_UP(offset + 1, s->block_size) - offset;
749 n = MIN(n, bytes);
750
751 *pnum += n;
752 offset += n;
753 bytes -= n;
754
755
756 if (allocated) {
757 *file = bs->file->bs;
758 *map = image_offset;
759 ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
760 break;
761 }
762 if (bytes == 0) {
763 break;
764 }
765 image_offset = get_image_offset(bs, offset, false, NULL);
766 } while (image_offset == -1);
767
768 qemu_co_mutex_unlock(&s->lock);
769 return ret;
770}
771
772
773
774
775
776
777
778
779
780
781
782
783
784static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
785 uint8_t* heads, uint8_t* secs_per_cyl)
786{
787 uint32_t cyls_times_heads;
788
789 total_sectors = MIN(total_sectors, VHD_MAX_GEOMETRY);
790
791 if (total_sectors >= 65535LL * 16 * 63) {
792 *secs_per_cyl = 255;
793 *heads = 16;
794 cyls_times_heads = total_sectors / *secs_per_cyl;
795 } else {
796 *secs_per_cyl = 17;
797 cyls_times_heads = total_sectors / *secs_per_cyl;
798 *heads = DIV_ROUND_UP(cyls_times_heads, 1024);
799
800 if (*heads < 4) {
801 *heads = 4;
802 }
803
804 if (cyls_times_heads >= (*heads * 1024) || *heads > 16) {
805 *secs_per_cyl = 31;
806 *heads = 16;
807 cyls_times_heads = total_sectors / *secs_per_cyl;
808 }
809
810 if (cyls_times_heads >= (*heads * 1024)) {
811 *secs_per_cyl = 63;
812 *heads = 16;
813 cyls_times_heads = total_sectors / *secs_per_cyl;
814 }
815 }
816
817 *cyls = cyls_times_heads / *heads;
818
819 return 0;
820}
821
822static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
823 int64_t total_sectors)
824{
825 VHDDynDiskHeader *dyndisk_header =
826 (VHDDynDiskHeader *) buf;
827 size_t block_size, num_bat_entries;
828 int i;
829 int ret;
830 int64_t offset = 0;
831
832
833 block_size = 0x200000;
834 num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
835
836 ret = blk_pwrite(blk, offset, buf, HEADER_SIZE, 0);
837 if (ret < 0) {
838 goto fail;
839 }
840
841 offset = 1536 + ((num_bat_entries * 4 + 511) & ~511);
842 ret = blk_pwrite(blk, offset, buf, HEADER_SIZE, 0);
843 if (ret < 0) {
844 goto fail;
845 }
846
847
848 offset = 3 * 512;
849
850 memset(buf, 0xFF, 512);
851 for (i = 0; i < DIV_ROUND_UP(num_bat_entries * 4, 512); i++) {
852 ret = blk_pwrite(blk, offset, buf, 512, 0);
853 if (ret < 0) {
854 goto fail;
855 }
856 offset += 512;
857 }
858
859
860 memset(buf, 0, 1024);
861
862 memcpy(dyndisk_header->magic, "cxsparse", 8);
863
864
865
866
867
868 dyndisk_header->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
869 dyndisk_header->table_offset = cpu_to_be64(3 * 512);
870 dyndisk_header->version = cpu_to_be32(0x00010000);
871 dyndisk_header->block_size = cpu_to_be32(block_size);
872 dyndisk_header->max_table_entries = cpu_to_be32(num_bat_entries);
873
874 dyndisk_header->checksum = cpu_to_be32(vpc_checksum(buf, 1024));
875
876
877 offset = 512;
878
879 ret = blk_pwrite(blk, offset, buf, 1024, 0);
880 if (ret < 0) {
881 goto fail;
882 }
883
884 ret = 0;
885 fail:
886 return ret;
887}
888
889static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
890 int64_t total_size, Error **errp)
891{
892 int ret;
893
894
895 total_size += HEADER_SIZE;
896
897 ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp);
898 if (ret < 0) {
899 return ret;
900 }
901
902 ret = blk_pwrite(blk, total_size - HEADER_SIZE, buf, HEADER_SIZE, 0);
903 if (ret < 0) {
904 error_setg_errno(errp, -ret, "Unable to write VHD header");
905 return ret;
906 }
907
908 return 0;
909}
910
911static int calculate_rounded_image_size(BlockdevCreateOptionsVpc *vpc_opts,
912 uint16_t *out_cyls,
913 uint8_t *out_heads,
914 uint8_t *out_secs_per_cyl,
915 int64_t *out_total_sectors,
916 Error **errp)
917{
918 int64_t total_size = vpc_opts->size;
919 uint16_t cyls = 0;
920 uint8_t heads = 0;
921 uint8_t secs_per_cyl = 0;
922 int64_t total_sectors;
923 int i;
924
925
926
927
928
929
930
931
932
933
934 if (vpc_opts->force_size) {
935
936 cyls = VHD_CHS_MAX_C;
937 heads = VHD_CHS_MAX_H;
938 secs_per_cyl = VHD_CHS_MAX_S;
939 } else {
940 total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE);
941 for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
942 calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl);
943 }
944 }
945
946 if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) {
947 total_sectors = total_size / BDRV_SECTOR_SIZE;
948
949 if (total_sectors > VHD_MAX_SECTORS) {
950 error_setg(errp, "Disk size is too large, max size is 2040 GiB");
951 return -EFBIG;
952 }
953 } else {
954 total_sectors = (int64_t) cyls * heads * secs_per_cyl;
955 }
956
957 *out_total_sectors = total_sectors;
958 if (out_cyls) {
959 *out_cyls = cyls;
960 *out_heads = heads;
961 *out_secs_per_cyl = secs_per_cyl;
962 }
963
964 return 0;
965}
966
967static int coroutine_fn vpc_co_create(BlockdevCreateOptions *opts,
968 Error **errp)
969{
970 BlockdevCreateOptionsVpc *vpc_opts;
971 BlockBackend *blk = NULL;
972 BlockDriverState *bs = NULL;
973
974 uint8_t buf[1024];
975 VHDFooter *footer = (VHDFooter *) buf;
976 uint16_t cyls = 0;
977 uint8_t heads = 0;
978 uint8_t secs_per_cyl = 0;
979 int64_t total_sectors;
980 int64_t total_size;
981 int disk_type;
982 int ret = -EIO;
983 QemuUUID uuid;
984
985 assert(opts->driver == BLOCKDEV_DRIVER_VPC);
986 vpc_opts = &opts->u.vpc;
987
988
989 total_size = vpc_opts->size;
990
991 if (!vpc_opts->has_subformat) {
992 vpc_opts->subformat = BLOCKDEV_VPC_SUBFORMAT_DYNAMIC;
993 }
994 switch (vpc_opts->subformat) {
995 case BLOCKDEV_VPC_SUBFORMAT_DYNAMIC:
996 disk_type = VHD_DYNAMIC;
997 break;
998 case BLOCKDEV_VPC_SUBFORMAT_FIXED:
999 disk_type = VHD_FIXED;
1000 break;
1001 default:
1002 g_assert_not_reached();
1003 }
1004
1005
1006 bs = bdrv_open_blockdev_ref(vpc_opts->file, errp);
1007 if (bs == NULL) {
1008 return -EIO;
1009 }
1010
1011 blk = blk_new(BLK_PERM_WRITE | BLK_PERM_RESIZE, BLK_PERM_ALL);
1012 ret = blk_insert_bs(blk, bs, errp);
1013 if (ret < 0) {
1014 goto out;
1015 }
1016 blk_set_allow_write_beyond_eof(blk, true);
1017
1018
1019 ret = calculate_rounded_image_size(vpc_opts, &cyls, &heads, &secs_per_cyl,
1020 &total_sectors, errp);
1021 if (ret < 0) {
1022 goto out;
1023 }
1024
1025 if (total_size != total_sectors * BDRV_SECTOR_SIZE) {
1026 error_setg(errp, "The requested image size cannot be represented in "
1027 "CHS geometry");
1028 error_append_hint(errp, "Try size=%llu or force-size=on (the "
1029 "latter makes the image incompatible with "
1030 "Virtual PC)",
1031 total_sectors * BDRV_SECTOR_SIZE);
1032 ret = -EINVAL;
1033 goto out;
1034 }
1035
1036
1037 memset(buf, 0, 1024);
1038
1039 memcpy(footer->creator, "conectix", 8);
1040 if (vpc_opts->force_size) {
1041 memcpy(footer->creator_app, "qem2", 4);
1042 } else {
1043 memcpy(footer->creator_app, "qemu", 4);
1044 }
1045 memcpy(footer->creator_os, "Wi2k", 4);
1046
1047 footer->features = cpu_to_be32(0x02);
1048 footer->version = cpu_to_be32(0x00010000);
1049 if (disk_type == VHD_DYNAMIC) {
1050 footer->data_offset = cpu_to_be64(HEADER_SIZE);
1051 } else {
1052 footer->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
1053 }
1054 footer->timestamp = cpu_to_be32(time(NULL) - VHD_TIMESTAMP_BASE);
1055
1056
1057 footer->major = cpu_to_be16(0x0005);
1058 footer->minor = cpu_to_be16(0x0003);
1059 footer->orig_size = cpu_to_be64(total_size);
1060 footer->current_size = cpu_to_be64(total_size);
1061 footer->cyls = cpu_to_be16(cyls);
1062 footer->heads = heads;
1063 footer->secs_per_cyl = secs_per_cyl;
1064
1065 footer->type = cpu_to_be32(disk_type);
1066
1067 qemu_uuid_generate(&uuid);
1068 footer->uuid = uuid;
1069
1070 footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE));
1071
1072 if (disk_type == VHD_DYNAMIC) {
1073 ret = create_dynamic_disk(blk, buf, total_sectors);
1074 if (ret < 0) {
1075 error_setg(errp, "Unable to create or write VHD header");
1076 }
1077 } else {
1078 ret = create_fixed_disk(blk, buf, total_size, errp);
1079 }
1080
1081out:
1082 blk_unref(blk);
1083 bdrv_unref(bs);
1084 return ret;
1085}
1086
1087static int coroutine_fn vpc_co_create_opts(const char *filename,
1088 QemuOpts *opts, Error **errp)
1089{
1090 BlockdevCreateOptions *create_options = NULL;
1091 QDict *qdict;
1092 Visitor *v;
1093 BlockDriverState *bs = NULL;
1094 Error *local_err = NULL;
1095 int ret;
1096
1097 static const QDictRenames opt_renames[] = {
1098 { VPC_OPT_FORCE_SIZE, "force-size" },
1099 { NULL, NULL },
1100 };
1101
1102
1103 qdict = qemu_opts_to_qdict_filtered(opts, NULL, &vpc_create_opts, true);
1104
1105 if (!qdict_rename_keys(qdict, opt_renames, errp)) {
1106 ret = -EINVAL;
1107 goto fail;
1108 }
1109
1110
1111 ret = bdrv_create_file(filename, opts, &local_err);
1112 if (ret < 0) {
1113 error_propagate(errp, local_err);
1114 goto fail;
1115 }
1116
1117 bs = bdrv_open(filename, NULL, NULL,
1118 BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL, errp);
1119 if (bs == NULL) {
1120 ret = -EIO;
1121 goto fail;
1122 }
1123
1124
1125 qdict_put_str(qdict, "driver", "vpc");
1126 qdict_put_str(qdict, "file", bs->node_name);
1127
1128 v = qobject_input_visitor_new_flat_confused(qdict, errp);
1129 if (!v) {
1130 ret = -EINVAL;
1131 goto fail;
1132 }
1133
1134 visit_type_BlockdevCreateOptions(v, NULL, &create_options, &local_err);
1135 visit_free(v);
1136
1137 if (local_err) {
1138 error_propagate(errp, local_err);
1139 ret = -EINVAL;
1140 goto fail;
1141 }
1142
1143
1144 assert(create_options->driver == BLOCKDEV_DRIVER_VPC);
1145 create_options->u.vpc.size =
1146 ROUND_UP(create_options->u.vpc.size, BDRV_SECTOR_SIZE);
1147
1148 if (!create_options->u.vpc.force_size) {
1149 int64_t total_sectors;
1150 ret = calculate_rounded_image_size(&create_options->u.vpc, NULL, NULL,
1151 NULL, &total_sectors, errp);
1152 if (ret < 0) {
1153 goto fail;
1154 }
1155
1156 create_options->u.vpc.size = total_sectors * BDRV_SECTOR_SIZE;
1157 }
1158
1159
1160
1161 ret = vpc_co_create(create_options, errp);
1162
1163fail:
1164 qobject_unref(qdict);
1165 bdrv_unref(bs);
1166 qapi_free_BlockdevCreateOptions(create_options);
1167 return ret;
1168}
1169
1170
1171static int vpc_has_zero_init(BlockDriverState *bs)
1172{
1173 BDRVVPCState *s = bs->opaque;
1174 VHDFooter *footer = (VHDFooter *) s->footer_buf;
1175
1176 if (be32_to_cpu(footer->type) == VHD_FIXED) {
1177 return bdrv_has_zero_init(bs->file->bs);
1178 } else {
1179 return 1;
1180 }
1181}
1182
1183static void vpc_close(BlockDriverState *bs)
1184{
1185 BDRVVPCState *s = bs->opaque;
1186 qemu_vfree(s->pagetable);
1187#ifdef CACHE
1188 g_free(s->pageentry_u8);
1189#endif
1190
1191 migrate_del_blocker(s->migration_blocker);
1192 error_free(s->migration_blocker);
1193}
1194
1195static QemuOptsList vpc_create_opts = {
1196 .name = "vpc-create-opts",
1197 .head = QTAILQ_HEAD_INITIALIZER(vpc_create_opts.head),
1198 .desc = {
1199 {
1200 .name = BLOCK_OPT_SIZE,
1201 .type = QEMU_OPT_SIZE,
1202 .help = "Virtual disk size"
1203 },
1204 {
1205 .name = BLOCK_OPT_SUBFMT,
1206 .type = QEMU_OPT_STRING,
1207 .help =
1208 "Type of virtual hard disk format. Supported formats are "
1209 "{dynamic (default) | fixed} "
1210 },
1211 {
1212 .name = VPC_OPT_FORCE_SIZE,
1213 .type = QEMU_OPT_BOOL,
1214 .help = "Force disk size calculation to use the actual size "
1215 "specified, rather than using the nearest CHS-based "
1216 "calculation"
1217 },
1218 { }
1219 }
1220};
1221
1222static const char *const vpc_strong_runtime_opts[] = {
1223 VPC_OPT_SIZE_CALC,
1224
1225 NULL
1226};
1227
1228static BlockDriver bdrv_vpc = {
1229 .format_name = "vpc",
1230 .instance_size = sizeof(BDRVVPCState),
1231
1232 .bdrv_probe = vpc_probe,
1233 .bdrv_open = vpc_open,
1234 .bdrv_close = vpc_close,
1235 .bdrv_reopen_prepare = vpc_reopen_prepare,
1236 .bdrv_child_perm = bdrv_format_default_perms,
1237 .bdrv_co_create = vpc_co_create,
1238 .bdrv_co_create_opts = vpc_co_create_opts,
1239
1240 .bdrv_co_preadv = vpc_co_preadv,
1241 .bdrv_co_pwritev = vpc_co_pwritev,
1242 .bdrv_co_block_status = vpc_co_block_status,
1243
1244 .bdrv_get_info = vpc_get_info,
1245
1246 .create_opts = &vpc_create_opts,
1247 .bdrv_has_zero_init = vpc_has_zero_init,
1248 .strong_runtime_opts = vpc_strong_runtime_opts,
1249};
1250
1251static void bdrv_vpc_init(void)
1252{
1253 bdrv_register(&bdrv_vpc);
1254}
1255
1256block_init(bdrv_vpc_init);
1257