]> Git Repo - qemu.git/blame - block/vpc.c
qcow2: Remove BDS parameter from qcow2_cache_get_table_addr()
[qemu.git] / block / vpc.c
CommitLineData
6a0f9e82 1/*
cc2040f8 2 * Block driver for Connectix / Microsoft Virtual PC images
5fafdf24 3 *
6a0f9e82 4 * Copyright (c) 2005 Alex Beregszaszi
15d35bc5 5 * Copyright (c) 2009 Kevin Wolf <[email protected]>
5fafdf24 6 *
6a0f9e82
FB
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
922a01a0 25
80c71a24 26#include "qemu/osdep.h"
da34e65c 27#include "qapi/error.h"
737e150e 28#include "block/block_int.h"
b8f45cdf 29#include "sysemu/block-backend.h"
1de7afc9 30#include "qemu/module.h"
922a01a0 31#include "qemu/option.h"
795c40b8 32#include "migration/blocker.h"
58369e22 33#include "qemu/bswap.h"
38440a21 34#include "qemu/uuid.h"
6a0f9e82
FB
35
36/**************************************************************/
37
38#define HEADER_SIZE 512
39
40//#define CACHE
41
2cfacb62
AL
42enum vhd_type {
43 VHD_FIXED = 2,
44 VHD_DYNAMIC = 3,
45 VHD_DIFFERENCING = 4,
46};
47
9c057d0b 48/* Seconds since Jan 1, 2000 0:00:00 (UTC) */
57c7d9e5
AL
49#define VHD_TIMESTAMP_BASE 946684800
50
fb9245c2
JC
51#define VHD_CHS_MAX_C 65535LL
52#define VHD_CHS_MAX_H 16
53#define VHD_CHS_MAX_S 255
54
c23fb11b 55#define VHD_MAX_SECTORS 0xff000000 /* 2040 GiB max image size */
fb9245c2
JC
56#define VHD_MAX_GEOMETRY (VHD_CHS_MAX_C * VHD_CHS_MAX_H * VHD_CHS_MAX_S)
57
58#define VPC_OPT_FORCE_SIZE "force_size"
97f1c45c 59
9c057d0b 60/* always big-endian */
e54835c0 61typedef struct vhd_footer {
9c057d0b 62 char creator[8]; /* "conectix" */
2cfacb62
AL
63 uint32_t features;
64 uint32_t version;
65
9c057d0b 66 /* Offset of next header structure, 0xFFFFFFFF if none */
2cfacb62
AL
67 uint64_t data_offset;
68
9c057d0b 69 /* Seconds since Jan 1, 2000 0:00:00 (UTC) */
2cfacb62
AL
70 uint32_t timestamp;
71
9c057d0b 72 char creator_app[4]; /* e.g., "vpc " */
2cfacb62
AL
73 uint16_t major;
74 uint16_t minor;
9c057d0b 75 char creator_os[4]; /* "Wi2k" */
2cfacb62
AL
76
77 uint64_t orig_size;
03671ded 78 uint64_t current_size;
2cfacb62
AL
79
80 uint16_t cyls;
81 uint8_t heads;
82 uint8_t secs_per_cyl;
83
84 uint32_t type;
85
9c057d0b
JC
86 /* Checksum of the Hard Disk Footer ("one's complement of the sum of all
87 the bytes in the footer without the checksum field") */
2cfacb62
AL
88 uint32_t checksum;
89
9c057d0b 90 /* UUID used to identify a parent hard disk (backing file) */
38440a21 91 QemuUUID uuid;
2cfacb62
AL
92
93 uint8_t in_saved_state;
e54835c0 94} QEMU_PACKED VHDFooter;
b9fa33a6 95
e54835c0 96typedef struct vhd_dyndisk_header {
9c057d0b 97 char magic[8]; /* "cxsparse" */
2cfacb62 98
9c057d0b 99 /* Offset of next header structure, 0xFFFFFFFF if none */
2cfacb62
AL
100 uint64_t data_offset;
101
9c057d0b 102 /* Offset of the Block Allocation Table (BAT) */
2cfacb62
AL
103 uint64_t table_offset;
104
105 uint32_t version;
9c057d0b 106 uint32_t max_table_entries; /* 32bit/entry */
2cfacb62 107
9c057d0b 108 /* 2 MB by default, must be a power of two */
2cfacb62
AL
109 uint32_t block_size;
110
111 uint32_t checksum;
112 uint8_t parent_uuid[16];
113 uint32_t parent_timestamp;
114 uint32_t reserved;
115
9c057d0b 116 /* Backing file name (in UTF-16) */
2cfacb62
AL
117 uint8_t parent_name[512];
118
119 struct {
120 uint32_t platform;
121 uint32_t data_space;
122 uint32_t data_length;
123 uint32_t reserved;
124 uint64_t data_offset;
125 } parent_locator[8];
e54835c0 126} QEMU_PACKED VHDDynDiskHeader;
6a0f9e82
FB
127
128typedef struct BDRVVPCState {
848c66e8 129 CoMutex lock;
15d35bc5
AL
130 uint8_t footer_buf[HEADER_SIZE];
131 uint64_t free_data_block_offset;
2cfacb62 132 int max_table_entries;
6a0f9e82 133 uint32_t *pagetable;
15d35bc5
AL
134 uint64_t bat_offset;
135 uint64_t last_bitmap_offset;
6a0f9e82 136
2cfacb62 137 uint32_t block_size;
15d35bc5 138 uint32_t bitmap_size;
c540d53a
JC
139 bool force_use_chs;
140 bool force_use_sz;
15d35bc5 141
6a0f9e82
FB
142#ifdef CACHE
143 uint8_t *pageentry_u8;
144 uint32_t *pageentry_u32;
145 uint16_t *pageentry_u16;
3b46e624 146
6a0f9e82
FB
147 uint64_t last_bitmap;
148#endif
612ff3d8
KW
149
150 Error *migration_blocker;
6a0f9e82
FB
151} BDRVVPCState;
152
c540d53a
JC
153#define VPC_OPT_SIZE_CALC "force_size_calc"
154static QemuOptsList vpc_runtime_opts = {
155 .name = "vpc-runtime-opts",
156 .head = QTAILQ_HEAD_INITIALIZER(vpc_runtime_opts.head),
157 .desc = {
158 {
159 .name = VPC_OPT_SIZE_CALC,
160 .type = QEMU_OPT_STRING,
161 .help = "Force disk size calculation to use either CHS geometry, "
162 "or use the disk current_size specified in the VHD footer. "
163 "{chs, current_size}"
164 },
165 { /* end of list */ }
166 }
167};
168
57c7d9e5
AL
169static uint32_t vpc_checksum(uint8_t* buf, size_t size)
170{
171 uint32_t res = 0;
172 int i;
173
174 for (i = 0; i < size; i++)
175 res += buf[i];
176
177 return ~res;
178}
179
180
6a0f9e82
FB
181static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
182{
ffe8ab83 183 if (buf_size >= 8 && !strncmp((char *)buf, "conectix", 8))
6a0f9e82 184 return 100;
6a0f9e82
FB
185 return 0;
186}
187
c540d53a
JC
188static void vpc_parse_options(BlockDriverState *bs, QemuOpts *opts,
189 Error **errp)
190{
191 BDRVVPCState *s = bs->opaque;
192 const char *size_calc;
193
194 size_calc = qemu_opt_get(opts, VPC_OPT_SIZE_CALC);
195
196 if (!size_calc) {
197 /* no override, use autodetect only */
198 } else if (!strcmp(size_calc, "current_size")) {
199 s->force_use_sz = true;
200 } else if (!strcmp(size_calc, "chs")) {
201 s->force_use_chs = true;
202 } else {
203 error_setg(errp, "Invalid size calculation mode: '%s'", size_calc);
204 }
205}
206
015a1036
HR
207static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
208 Error **errp)
6a0f9e82
FB
209{
210 BDRVVPCState *s = bs->opaque;
66f82cee 211 int i;
e54835c0
JC
212 VHDFooter *footer;
213 VHDDynDiskHeader *dyndisk_header;
c540d53a
JC
214 QemuOpts *opts = NULL;
215 Error *local_err = NULL;
216 bool use_chs;
b9fa33a6 217 uint8_t buf[HEADER_SIZE];
57c7d9e5 218 uint32_t checksum;
97f1c45c 219 uint64_t computed_size;
b15deac7 220 uint64_t pagetable_size;
24da78db 221 int disk_type = VHD_DYNAMIC;
59294e46 222 int ret;
81caa3cc 223 int64_t bs_size;
6a0f9e82 224
4e4bf5c4
KW
225 bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
226 false, errp);
227 if (!bs->file) {
228 return -EINVAL;
229 }
230
c540d53a
JC
231 opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
232 qemu_opts_absorb_qdict(opts, options, &local_err);
233 if (local_err) {
234 error_propagate(errp, local_err);
235 ret = -EINVAL;
236 goto fail;
237 }
238
239 vpc_parse_options(bs, opts, &local_err);
240 if (local_err) {
241 error_propagate(errp, local_err);
242 ret = -EINVAL;
243 goto fail;
244 }
245
cf2ab8fc 246 ret = bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE);
59294e46 247 if (ret < 0) {
32f6439c 248 error_setg(errp, "Unable to read VHD header");
6a0f9e82 249 goto fail;
59294e46 250 }
6a0f9e82 251
e54835c0 252 footer = (VHDFooter *) s->footer_buf;
24da78db 253 if (strncmp(footer->creator, "conectix", 8)) {
9a4f4c31 254 int64_t offset = bdrv_getlength(bs->file->bs);
59294e46
KW
255 if (offset < 0) {
256 ret = offset;
32f6439c 257 error_setg(errp, "Invalid file size");
59294e46
KW
258 goto fail;
259 } else if (offset < HEADER_SIZE) {
260 ret = -EINVAL;
32f6439c 261 error_setg(errp, "File too small for a VHD header");
24da78db
CA
262 goto fail;
263 }
59294e46 264
24da78db 265 /* If a fixed disk, the footer is found only at the end of the file */
cf2ab8fc 266 ret = bdrv_pread(bs->file, offset-HEADER_SIZE, s->footer_buf,
59294e46
KW
267 HEADER_SIZE);
268 if (ret < 0) {
24da78db
CA
269 goto fail;
270 }
271 if (strncmp(footer->creator, "conectix", 8)) {
76abe407
PB
272 error_setg(errp, "invalid VPC image");
273 ret = -EINVAL;
24da78db
CA
274 goto fail;
275 }
276 disk_type = VHD_FIXED;
277 }
6a0f9e82 278
57c7d9e5
AL
279 checksum = be32_to_cpu(footer->checksum);
280 footer->checksum = 0;
281 if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum)
282 fprintf(stderr, "block-vpc: The header checksum of '%s' is "
66f82cee 283 "incorrect.\n", bs->filename);
57c7d9e5 284
c088b691 285 /* Write 'checksum' back to footer, or else will leave it with zero. */
a4127c42 286 footer->checksum = cpu_to_be32(checksum);
c088b691 287
9c057d0b
JC
288 /* The visible size of a image in Virtual PC depends on the geometry
289 rather than on the size stored in the footer (the size in the footer
290 is too large usually) */
33ccf667
SH
291 bs->total_sectors = (int64_t)
292 be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
1fa79228 293
c540d53a
JC
294 /* Microsoft Virtual PC and Microsoft Hyper-V produce and read
295 * VHD image sizes differently. VPC will rely on CHS geometry,
296 * while Hyper-V and disk2vhd use the size specified in the footer.
297 *
298 * We use a couple of approaches to try and determine the correct method:
299 * look at the Creator App field, and look for images that have CHS
300 * geometry that is the maximum value.
301 *
302 * If the CHS geometry is the maximum CHS geometry, then we assume that
303 * the size is the footer->current_size to avoid truncation. Otherwise,
304 * we follow the table based on footer->creator_app:
305 *
306 * Known creator apps:
307 * 'vpc ' : CHS Virtual PC (uses disk geometry)
308 * 'qemu' : CHS QEMU (uses disk geometry)
fb9245c2 309 * 'qem2' : current_size QEMU (uses current_size)
c540d53a
JC
310 * 'win ' : current_size Hyper-V
311 * 'd2v ' : current_size Disk2vhd
9bdfb9e8 312 * 'tap\0' : current_size XenServer
bab246db 313 * 'CTXS' : current_size XenConverter
c540d53a
JC
314 *
315 * The user can override the table values via drive options, however
316 * even with an override we will still use current_size for images
317 * that have CHS geometry of the maximum size.
318 */
319 use_chs = (!!strncmp(footer->creator_app, "win ", 4) &&
fb9245c2 320 !!strncmp(footer->creator_app, "qem2", 4) &&
9bdfb9e8 321 !!strncmp(footer->creator_app, "d2v ", 4) &&
bab246db 322 !!strncmp(footer->creator_app, "CTXS", 4) &&
9bdfb9e8 323 !!memcmp(footer->creator_app, "tap", 4)) || s->force_use_chs;
c540d53a
JC
324
325 if (!use_chs || bs->total_sectors == VHD_MAX_GEOMETRY || s->force_use_sz) {
03671ded 326 bs->total_sectors = be64_to_cpu(footer->current_size) /
c540d53a 327 BDRV_SECTOR_SIZE;
0173e7bb
PL
328 }
329
c23fb11b
JC
330 /* Allow a maximum disk size of 2040 GiB */
331 if (bs->total_sectors > VHD_MAX_SECTORS) {
59294e46 332 ret = -EFBIG;
efc8243d
SH
333 goto fail;
334 }
335
24da78db 336 if (disk_type == VHD_DYNAMIC) {
cf2ab8fc 337 ret = bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf,
59294e46
KW
338 HEADER_SIZE);
339 if (ret < 0) {
32f6439c 340 error_setg(errp, "Error reading dynamic VHD header");
24da78db
CA
341 goto fail;
342 }
b9fa33a6 343
e54835c0 344 dyndisk_header = (VHDDynDiskHeader *) buf;
6a0f9e82 345
24da78db 346 if (strncmp(dyndisk_header->magic, "cxsparse", 8)) {
32f6439c 347 error_setg(errp, "Invalid header magic");
59294e46 348 ret = -EINVAL;
24da78db
CA
349 goto fail;
350 }
6a0f9e82 351
24da78db 352 s->block_size = be32_to_cpu(dyndisk_header->block_size);
5e71dfad
KW
353 if (!is_power_of_2(s->block_size) || s->block_size < BDRV_SECTOR_SIZE) {
354 error_setg(errp, "Invalid block size %" PRIu32, s->block_size);
355 ret = -EINVAL;
356 goto fail;
357 }
24da78db 358 s->bitmap_size = ((s->block_size / (8 * 512)) + 511) & ~511;
15d35bc5 359
24da78db 360 s->max_table_entries = be32_to_cpu(dyndisk_header->max_table_entries);
97f1c45c
JC
361
362 if ((bs->total_sectors * 512) / s->block_size > 0xffffffffU) {
32f6439c 363 error_setg(errp, "Too many blocks");
97f1c45c
JC
364 ret = -EINVAL;
365 goto fail;
366 }
97f1c45c
JC
367
368 computed_size = (uint64_t) s->max_table_entries * s->block_size;
369 if (computed_size < bs->total_sectors * 512) {
32f6439c 370 error_setg(errp, "Page table too small");
97f1c45c
JC
371 ret = -EINVAL;
372 goto fail;
373 }
374
b15deac7
JC
375 if (s->max_table_entries > SIZE_MAX / 4 ||
376 s->max_table_entries > (int) INT_MAX / 4) {
377 error_setg(errp, "Max Table Entries too large (%" PRId32 ")",
378 s->max_table_entries);
379 ret = -EINVAL;
380 goto fail;
381 }
382
383 pagetable_size = (uint64_t) s->max_table_entries * 4;
384
9a4f4c31 385 s->pagetable = qemu_try_blockalign(bs->file->bs, pagetable_size);
5fb09cd5 386 if (s->pagetable == NULL) {
32f6439c 387 error_setg(errp, "Unable to allocate memory for page table");
5fb09cd5
KW
388 ret = -ENOMEM;
389 goto fail;
390 }
b71d1c2e 391
24da78db 392 s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
59294e46 393
cf2ab8fc 394 ret = bdrv_pread(bs->file, s->bat_offset, s->pagetable,
9a4f4c31 395 pagetable_size);
59294e46 396 if (ret < 0) {
32f6439c 397 error_setg(errp, "Error reading pagetable");
24da78db
CA
398 goto fail;
399 }
b71d1c2e 400
24da78db 401 s->free_data_block_offset =
b15deac7 402 ROUND_UP(s->bat_offset + pagetable_size, 512);
15d35bc5 403
24da78db
CA
404 for (i = 0; i < s->max_table_entries; i++) {
405 be32_to_cpus(&s->pagetable[i]);
406 if (s->pagetable[i] != 0xFFFFFFFF) {
407 int64_t next = (512 * (int64_t) s->pagetable[i]) +
408 s->bitmap_size + s->block_size;
15d35bc5 409
24da78db
CA
410 if (next > s->free_data_block_offset) {
411 s->free_data_block_offset = next;
412 }
413 }
15d35bc5 414 }
15d35bc5 415
81caa3cc
EB
416 bs_size = bdrv_getlength(bs->file->bs);
417 if (bs_size < 0) {
418 error_setg_errno(errp, -bs_size, "Unable to learn image size");
419 ret = bs_size;
420 goto fail;
421 }
422 if (s->free_data_block_offset > bs_size) {
fb8fe35f
PL
423 error_setg(errp, "block-vpc: free_data_block_offset points after "
424 "the end of file. The image has been truncated.");
425 ret = -EINVAL;
426 goto fail;
427 }
428
24da78db 429 s->last_bitmap_offset = (int64_t) -1;
6a0f9e82 430
6a0f9e82 431#ifdef CACHE
24da78db
CA
432 s->pageentry_u8 = g_malloc(512);
433 s->pageentry_u32 = s->pageentry_u8;
434 s->pageentry_u16 = s->pageentry_u8;
435 s->last_pagetable = -1;
6a0f9e82 436#endif
24da78db 437 }
6a0f9e82 438
612ff3d8 439 /* Disable migration when VHD images are used */
81e5f78a
AG
440 error_setg(&s->migration_blocker, "The vpc format used by node '%s' "
441 "does not support live migration",
442 bdrv_get_device_or_node_name(bs));
fe44dc91
AA
443 ret = migrate_add_blocker(s->migration_blocker, &local_err);
444 if (local_err) {
445 error_propagate(errp, local_err);
446 error_free(s->migration_blocker);
447 goto fail;
448 }
449
450 qemu_co_mutex_init(&s->lock);
612ff3d8 451
6a0f9e82 452 return 0;
59294e46
KW
453
454fail:
97f1c45c 455 qemu_vfree(s->pagetable);
59294e46
KW
456#ifdef CACHE
457 g_free(s->pageentry_u8);
458#endif
459 return ret;
6a0f9e82
FB
460}
461
3fe4b700
JC
462static int vpc_reopen_prepare(BDRVReopenState *state,
463 BlockReopenQueue *queue, Error **errp)
464{
465 return 0;
466}
467
b71d1c2e
AL
468/*
469 * Returns the absolute byte offset of the given sector in the image file.
470 * If the sector is not allocated, -1 is returned instead.
cfc87e00
PM
471 * If an error occurred trying to write an updated block bitmap back to
472 * the file, -2 is returned, and the error value is written to *err.
473 * This can only happen for a write operation.
15d35bc5
AL
474 *
475 * The parameter write must be 1 if the offset will be used for a write
476 * operation (the block bitmaps is updated then), 0 otherwise.
cfc87e00 477 * If write is true then err must not be NULL.
b71d1c2e 478 */
d46b7cc6 479static inline int64_t get_image_offset(BlockDriverState *bs, uint64_t offset,
cfc87e00 480 bool write, int *err)
6a0f9e82
FB
481{
482 BDRVVPCState *s = bs->opaque;
6a0f9e82 483 uint64_t bitmap_offset, block_offset;
d46b7cc6 484 uint32_t pagetable_index, offset_in_block;
6a0f9e82 485
cfc87e00
PM
486 assert(!(write && err == NULL));
487
2cfacb62 488 pagetable_index = offset / s->block_size;
d46b7cc6 489 offset_in_block = offset % s->block_size;
3b46e624 490
15d35bc5 491 if (pagetable_index >= s->max_table_entries || s->pagetable[pagetable_index] == 0xffffffff)
9c057d0b 492 return -1; /* not allocated */
6a0f9e82 493
378e2aea 494 bitmap_offset = 512 * (uint64_t) s->pagetable[pagetable_index];
d46b7cc6 495 block_offset = bitmap_offset + s->bitmap_size + offset_in_block;
15d35bc5 496
9c057d0b
JC
497 /* We must ensure that we don't write to any sectors which are marked as
498 unused in the bitmap. We get away with setting all bits in the block
499 bitmap each time we write to a new block. This might cause Virtual PC to
500 miss sparse read optimization, but it's not a problem in terms of
501 correctness. */
15d35bc5
AL
502 if (write && (s->last_bitmap_offset != bitmap_offset)) {
503 uint8_t bitmap[s->bitmap_size];
cfc87e00 504 int r;
15d35bc5
AL
505
506 s->last_bitmap_offset = bitmap_offset;
507 memset(bitmap, 0xff, s->bitmap_size);
cfc87e00
PM
508 r = bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
509 if (r < 0) {
510 *err = r;
511 return -2;
512 }
15d35bc5 513 }
3b46e624 514
b71d1c2e 515 return block_offset;
6a0f9e82
FB
516}
517
15d35bc5
AL
518/*
519 * Writes the footer to the end of the image file. This is needed when the
520 * file grows as it overwrites the old footer
521 *
522 * Returns 0 on success and < 0 on error
523 */
524static int rewrite_footer(BlockDriverState* bs)
525{
526 int ret;
527 BDRVVPCState *s = bs->opaque;
528 int64_t offset = s->free_data_block_offset;
529
d9ca2ea2 530 ret = bdrv_pwrite_sync(bs->file, offset, s->footer_buf, HEADER_SIZE);
15d35bc5
AL
531 if (ret < 0)
532 return ret;
533
534 return 0;
535}
536
537/*
538 * Allocates a new block. This involves writing a new footer and updating
539 * the Block Allocation Table to use the space at the old end of the image
540 * file (overwriting the old footer)
541 *
542 * Returns the sectors' offset in the image file on success and < 0 on error
543 */
513b0f02 544static int64_t alloc_block(BlockDriverState* bs, int64_t offset)
15d35bc5
AL
545{
546 BDRVVPCState *s = bs->opaque;
547 int64_t bat_offset;
548 uint32_t index, bat_value;
549 int ret;
550 uint8_t bitmap[s->bitmap_size];
551
9c057d0b 552 /* Check if sector_num is valid */
513b0f02
KW
553 if ((offset < 0) || (offset > bs->total_sectors * BDRV_SECTOR_SIZE)) {
554 return -EINVAL;
555 }
15d35bc5 556
9c057d0b 557 /* Write entry into in-memory BAT */
513b0f02
KW
558 index = offset / s->block_size;
559 assert(s->pagetable[index] == 0xFFFFFFFF);
15d35bc5
AL
560 s->pagetable[index] = s->free_data_block_offset / 512;
561
9c057d0b 562 /* Initialize the block's bitmap */
15d35bc5 563 memset(bitmap, 0xff, s->bitmap_size);
d9ca2ea2 564 ret = bdrv_pwrite_sync(bs->file, s->free_data_block_offset, bitmap,
078a458e 565 s->bitmap_size);
5bb1cbac
KW
566 if (ret < 0) {
567 return ret;
568 }
15d35bc5 569
9c057d0b 570 /* Write new footer (the old one will be overwritten) */
15d35bc5
AL
571 s->free_data_block_offset += s->block_size + s->bitmap_size;
572 ret = rewrite_footer(bs);
573 if (ret < 0)
574 goto fail;
575
9c057d0b 576 /* Write BAT entry to disk */
15d35bc5 577 bat_offset = s->bat_offset + (4 * index);
a4127c42 578 bat_value = cpu_to_be32(s->pagetable[index]);
d9ca2ea2 579 ret = bdrv_pwrite_sync(bs->file, bat_offset, &bat_value, 4);
15d35bc5
AL
580 if (ret < 0)
581 goto fail;
582
cfc87e00 583 return get_image_offset(bs, offset, false, NULL);
15d35bc5
AL
584
585fail:
586 s->free_data_block_offset -= (s->block_size + s->bitmap_size);
513b0f02 587 return ret;
15d35bc5
AL
588}
589
97b00e28
PB
590static int vpc_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
591{
592 BDRVVPCState *s = (BDRVVPCState *)bs->opaque;
593 VHDFooter *footer = (VHDFooter *) s->footer_buf;
594
0d4cc3e7 595 if (be32_to_cpu(footer->type) != VHD_FIXED) {
97b00e28
PB
596 bdi->cluster_size = s->block_size;
597 }
598
95de6d70 599 bdi->unallocated_blocks_are_zero = true;
97b00e28
PB
600 return 0;
601}
602
d46b7cc6
KW
603static int coroutine_fn
604vpc_co_preadv(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
605 QEMUIOVector *qiov, int flags)
6a0f9e82 606{
6c6ea921 607 BDRVVPCState *s = bs->opaque;
6a0f9e82 608 int ret;
d46b7cc6
KW
609 int64_t image_offset;
610 int64_t n_bytes;
611 int64_t bytes_done = 0;
e54835c0 612 VHDFooter *footer = (VHDFooter *) s->footer_buf;
d46b7cc6 613 QEMUIOVector local_qiov;
6a0f9e82 614
0d4cc3e7 615 if (be32_to_cpu(footer->type) == VHD_FIXED) {
a03ef88f 616 return bdrv_co_preadv(bs->file, offset, bytes, qiov, 0);
24da78db 617 }
b71d1c2e 618
d46b7cc6
KW
619 qemu_co_mutex_lock(&s->lock);
620 qemu_iovec_init(&local_qiov, qiov->niov);
6c6ea921 621
d46b7cc6 622 while (bytes > 0) {
cfc87e00 623 image_offset = get_image_offset(bs, offset, false, NULL);
d46b7cc6
KW
624 n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
625
626 if (image_offset == -1) {
627 qemu_iovec_memset(qiov, bytes_done, 0, n_bytes);
b71d1c2e 628 } else {
d46b7cc6
KW
629 qemu_iovec_reset(&local_qiov);
630 qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
631
a03ef88f 632 ret = bdrv_co_preadv(bs->file, image_offset, n_bytes,
d46b7cc6
KW
633 &local_qiov, 0);
634 if (ret < 0) {
635 goto fail;
6c6ea921 636 }
b71d1c2e
AL
637 }
638
d46b7cc6
KW
639 bytes -= n_bytes;
640 offset += n_bytes;
641 bytes_done += n_bytes;
6a0f9e82 642 }
6a0f9e82 643
d46b7cc6
KW
644 ret = 0;
645fail:
646 qemu_iovec_destroy(&local_qiov);
2914caa0 647 qemu_co_mutex_unlock(&s->lock);
d46b7cc6 648
2914caa0
PB
649 return ret;
650}
651
513b0f02
KW
652static int coroutine_fn
653vpc_co_pwritev(BlockDriverState *bs, uint64_t offset, uint64_t bytes,
654 QEMUIOVector *qiov, int flags)
15d35bc5 655{
6c6ea921 656 BDRVVPCState *s = bs->opaque;
513b0f02
KW
657 int64_t image_offset;
658 int64_t n_bytes;
659 int64_t bytes_done = 0;
c8115f8e 660 int ret = 0;
e54835c0 661 VHDFooter *footer = (VHDFooter *) s->footer_buf;
513b0f02 662 QEMUIOVector local_qiov;
15d35bc5 663
0d4cc3e7 664 if (be32_to_cpu(footer->type) == VHD_FIXED) {
a03ef88f 665 return bdrv_co_pwritev(bs->file, offset, bytes, qiov, 0);
24da78db 666 }
15d35bc5 667
513b0f02
KW
668 qemu_co_mutex_lock(&s->lock);
669 qemu_iovec_init(&local_qiov, qiov->niov);
670
671 while (bytes > 0) {
cfc87e00
PM
672 image_offset = get_image_offset(bs, offset, true, &ret);
673 if (image_offset == -2) {
674 /* Failed to write block bitmap: can't proceed with write */
675 goto fail;
676 }
513b0f02 677 n_bytes = MIN(bytes, s->block_size - (offset % s->block_size));
6c6ea921 678
513b0f02
KW
679 if (image_offset == -1) {
680 image_offset = alloc_block(bs, offset);
681 if (image_offset < 0) {
682 ret = image_offset;
683 goto fail;
684 }
15d35bc5
AL
685 }
686
513b0f02
KW
687 qemu_iovec_reset(&local_qiov);
688 qemu_iovec_concat(&local_qiov, qiov, bytes_done, n_bytes);
689
a03ef88f 690 ret = bdrv_co_pwritev(bs->file, image_offset, n_bytes,
513b0f02
KW
691 &local_qiov, 0);
692 if (ret < 0) {
693 goto fail;
6c6ea921 694 }
15d35bc5 695
513b0f02
KW
696 bytes -= n_bytes;
697 offset += n_bytes;
698 bytes_done += n_bytes;
15d35bc5
AL
699 }
700
513b0f02
KW
701 ret = 0;
702fail:
703 qemu_iovec_destroy(&local_qiov);
e183ef75 704 qemu_co_mutex_unlock(&s->lock);
513b0f02 705
e183ef75
PB
706 return ret;
707}
708
0cc84887 709static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
67a0fd2a 710 int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
0cc84887
KW
711{
712 BDRVVPCState *s = bs->opaque;
713 VHDFooter *footer = (VHDFooter*) s->footer_buf;
2ec711dc 714 int64_t start, offset;
0cc84887 715 bool allocated;
778b087e 716 int64_t ret;
0cc84887
KW
717 int n;
718
719 if (be32_to_cpu(footer->type) == VHD_FIXED) {
720 *pnum = nb_sectors;
7429e207 721 *file = bs->file->bs;
d5254033 722 return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID |
0cc84887
KW
723 (sector_num << BDRV_SECTOR_BITS);
724 }
725
778b087e
PB
726 qemu_co_mutex_lock(&s->lock);
727
cfc87e00 728 offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false, NULL);
0cc84887
KW
729 start = offset;
730 allocated = (offset != -1);
731 *pnum = 0;
778b087e 732 ret = 0;
0cc84887
KW
733
734 do {
735 /* All sectors in a block are contiguous (without using the bitmap) */
736 n = ROUND_UP(sector_num + 1, s->block_size / BDRV_SECTOR_SIZE)
737 - sector_num;
738 n = MIN(n, nb_sectors);
739
740 *pnum += n;
741 sector_num += n;
742 nb_sectors -= n;
2ec711dc
PL
743 /* *pnum can't be greater than one block for allocated
744 * sectors since there is always a bitmap in between. */
745 if (allocated) {
7429e207 746 *file = bs->file->bs;
778b087e
PB
747 ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
748 break;
2ec711dc 749 }
0cc84887
KW
750 if (nb_sectors == 0) {
751 break;
752 }
cfc87e00
PM
753 offset = get_image_offset(bs, sector_num << BDRV_SECTOR_BITS, false,
754 NULL);
2ec711dc 755 } while (offset == -1);
0cc84887 756
778b087e
PB
757 qemu_co_mutex_unlock(&s->lock);
758 return ret;
0cc84887
KW
759}
760
57c7d9e5
AL
761/*
762 * Calculates the number of cylinders, heads and sectors per cylinder
763 * based on a given number of sectors. This is the algorithm described
764 * in the VHD specification.
765 *
766 * Note that the geometry doesn't always exactly match total_sectors but
767 * may round it down.
6e9ea0c0 768 *
c23fb11b 769 * Returns 0 on success, -EFBIG if the size is larger than 2040 GiB. Override
258d2edb
CA
770 * the hardware EIDE and ATA-2 limit of 16 heads (max disk size of 127 GB)
771 * and instead allow up to 255 heads.
57c7d9e5 772 */
6e9ea0c0 773static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
57c7d9e5
AL
774 uint8_t* heads, uint8_t* secs_per_cyl)
775{
776 uint32_t cyls_times_heads;
777
690cbb09 778 total_sectors = MIN(total_sectors, VHD_MAX_GEOMETRY);
57c7d9e5 779
690cbb09 780 if (total_sectors >= 65535LL * 16 * 63) {
57c7d9e5 781 *secs_per_cyl = 255;
690cbb09 782 *heads = 16;
57c7d9e5
AL
783 cyls_times_heads = total_sectors / *secs_per_cyl;
784 } else {
785 *secs_per_cyl = 17;
786 cyls_times_heads = total_sectors / *secs_per_cyl;
13f1493f 787 *heads = DIV_ROUND_UP(cyls_times_heads, 1024);
57c7d9e5 788
690cbb09 789 if (*heads < 4) {
57c7d9e5 790 *heads = 4;
690cbb09 791 }
57c7d9e5
AL
792
793 if (cyls_times_heads >= (*heads * 1024) || *heads > 16) {
794 *secs_per_cyl = 31;
795 *heads = 16;
796 cyls_times_heads = total_sectors / *secs_per_cyl;
797 }
798
799 if (cyls_times_heads >= (*heads * 1024)) {
800 *secs_per_cyl = 63;
801 *heads = 16;
802 cyls_times_heads = total_sectors / *secs_per_cyl;
803 }
804 }
805
dede4188 806 *cyls = cyls_times_heads / *heads;
6e9ea0c0
AJ
807
808 return 0;
57c7d9e5
AL
809}
810
b8f45cdf 811static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
fef6070e 812 int64_t total_sectors)
57c7d9e5 813{
e54835c0
JC
814 VHDDynDiskHeader *dyndisk_header =
815 (VHDDynDiskHeader *) buf;
57c7d9e5 816 size_t block_size, num_bat_entries;
24da78db 817 int i;
fef6070e
JC
818 int ret;
819 int64_t offset = 0;
57c7d9e5 820
9c057d0b 821 /* Write the footer (twice: at the beginning and at the end) */
57c7d9e5
AL
822 block_size = 0x200000;
823 num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
824
8341f00d 825 ret = blk_pwrite(blk, offset, buf, HEADER_SIZE, 0);
40a99aac 826 if (ret < 0) {
f0ff243a
BS
827 goto fail;
828 }
57c7d9e5 829
fef6070e 830 offset = 1536 + ((num_bat_entries * 4 + 511) & ~511);
8341f00d 831 ret = blk_pwrite(blk, offset, buf, HEADER_SIZE, 0);
fef6070e 832 if (ret < 0) {
f0ff243a
BS
833 goto fail;
834 }
57c7d9e5 835
9c057d0b 836 /* Write the initial BAT */
fef6070e 837 offset = 3 * 512;
57c7d9e5
AL
838
839 memset(buf, 0xFF, 512);
13f1493f 840 for (i = 0; i < DIV_ROUND_UP(num_bat_entries * 4, 512); i++) {
8341f00d 841 ret = blk_pwrite(blk, offset, buf, 512, 0);
fef6070e 842 if (ret < 0) {
f0ff243a
BS
843 goto fail;
844 }
fef6070e 845 offset += 512;
f0ff243a 846 }
57c7d9e5 847
9c057d0b 848 /* Prepare the Dynamic Disk Header */
57c7d9e5
AL
849 memset(buf, 0, 1024);
850
5ec4d682 851 memcpy(dyndisk_header->magic, "cxsparse", 8);
57c7d9e5 852
78439f6a
CA
853 /*
854 * Note: The spec is actually wrong here for data_offset, it says
855 * 0xFFFFFFFF, but MS tools expect all 64 bits to be set.
856 */
a4127c42
SH
857 dyndisk_header->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
858 dyndisk_header->table_offset = cpu_to_be64(3 * 512);
859 dyndisk_header->version = cpu_to_be32(0x00010000);
860 dyndisk_header->block_size = cpu_to_be32(block_size);
861 dyndisk_header->max_table_entries = cpu_to_be32(num_bat_entries);
57c7d9e5 862
a4127c42 863 dyndisk_header->checksum = cpu_to_be32(vpc_checksum(buf, 1024));
57c7d9e5 864
9c057d0b 865 /* Write the header */
fef6070e 866 offset = 512;
57c7d9e5 867
8341f00d 868 ret = blk_pwrite(blk, offset, buf, 1024, 0);
fef6070e 869 if (ret < 0) {
f0ff243a
BS
870 goto fail;
871 }
f0ff243a 872
24da78db
CA
873 fail:
874 return ret;
875}
876
b8f45cdf 877static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
ed3d2ec9 878 int64_t total_size, Error **errp)
24da78db 879{
fef6070e 880 int ret;
24da78db
CA
881
882 /* Add footer to total size */
fef6070e
JC
883 total_size += HEADER_SIZE;
884
3a691c50 885 ret = blk_truncate(blk, total_size, PREALLOC_MODE_OFF, errp);
fef6070e
JC
886 if (ret < 0) {
887 return ret;
24da78db
CA
888 }
889
8341f00d 890 ret = blk_pwrite(blk, total_size - HEADER_SIZE, buf, HEADER_SIZE, 0);
fef6070e 891 if (ret < 0) {
ed3d2ec9 892 error_setg_errno(errp, -ret, "Unable to write VHD header");
fef6070e
JC
893 return ret;
894 }
24da78db 895
24da78db
CA
896 return ret;
897}
898
fec9921f 899static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
24da78db
CA
900{
901 uint8_t buf[1024];
e54835c0 902 VHDFooter *footer = (VHDFooter *) buf;
fec9921f 903 char *disk_type_param;
fef6070e 904 int i;
24da78db
CA
905 uint16_t cyls = 0;
906 uint8_t heads = 0;
907 uint8_t secs_per_cyl = 0;
908 int64_t total_sectors;
909 int64_t total_size;
910 int disk_type;
911 int ret = -EIO;
fb9245c2 912 bool force_size;
fef6070e 913 Error *local_err = NULL;
b8f45cdf 914 BlockBackend *blk = NULL;
24da78db
CA
915
916 /* Read out options */
c2eb918e
HT
917 total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
918 BDRV_SECTOR_SIZE);
fec9921f
CL
919 disk_type_param = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
920 if (disk_type_param) {
921 if (!strcmp(disk_type_param, "dynamic")) {
24da78db 922 disk_type = VHD_DYNAMIC;
fec9921f 923 } else if (!strcmp(disk_type_param, "fixed")) {
24da78db
CA
924 disk_type = VHD_FIXED;
925 } else {
0211b9be 926 error_setg(errp, "Invalid disk type, %s", disk_type_param);
fec9921f
CL
927 ret = -EINVAL;
928 goto out;
24da78db
CA
929 }
930 } else {
931 disk_type = VHD_DYNAMIC;
932 }
933
fb9245c2
JC
934 force_size = qemu_opt_get_bool_del(opts, VPC_OPT_FORCE_SIZE, false);
935
fef6070e
JC
936 ret = bdrv_create_file(filename, opts, &local_err);
937 if (ret < 0) {
938 error_propagate(errp, local_err);
fec9921f 939 goto out;
24da78db 940 }
b8f45cdf 941
efaa7c4e 942 blk = blk_new_open(filename, NULL, NULL,
55880601
KW
943 BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
944 &local_err);
b8f45cdf 945 if (blk == NULL) {
fef6070e 946 error_propagate(errp, local_err);
b8f45cdf 947 ret = -EIO;
fef6070e 948 goto out;
4ab15590
CL
949 }
950
b8f45cdf
KW
951 blk_set_allow_write_beyond_eof(blk, true);
952
ecd880d9
KW
953 /*
954 * Calculate matching total_size and geometry. Increase the number of
955 * sectors requested until we get enough (or fail). This ensures that
956 * qemu-img convert doesn't truncate images, but rather rounds up.
690cbb09 957 *
fb9245c2 958 * If the image size can't be represented by a spec conformant CHS geometry,
690cbb09
PL
959 * we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use
960 * the image size from the VHD footer to calculate total_sectors.
ecd880d9 961 */
fb9245c2
JC
962 if (force_size) {
963 /* This will force the use of total_size for sector count, below */
964 cyls = VHD_CHS_MAX_C;
965 heads = VHD_CHS_MAX_H;
966 secs_per_cyl = VHD_CHS_MAX_S;
967 } else {
968 total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE);
969 for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
970 calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl);
971 }
690cbb09
PL
972 }
973
974 if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) {
975 total_sectors = total_size / BDRV_SECTOR_SIZE;
c23fb11b 976 /* Allow a maximum disk size of 2040 GiB */
690cbb09 977 if (total_sectors > VHD_MAX_SECTORS) {
0211b9be 978 error_setg(errp, "Disk size is too large, max size is 2040 GiB");
24da78db 979 ret = -EFBIG;
fef6070e 980 goto out;
24da78db 981 }
690cbb09
PL
982 } else {
983 total_sectors = (int64_t)cyls * heads * secs_per_cyl;
984 total_size = total_sectors * BDRV_SECTOR_SIZE;
24da78db 985 }
ecd880d9 986
24da78db
CA
987 /* Prepare the Hard Disk Footer */
988 memset(buf, 0, 1024);
989
990 memcpy(footer->creator, "conectix", 8);
fb9245c2
JC
991 if (force_size) {
992 memcpy(footer->creator_app, "qem2", 4);
993 } else {
994 memcpy(footer->creator_app, "qemu", 4);
995 }
24da78db
CA
996 memcpy(footer->creator_os, "Wi2k", 4);
997
a4127c42
SH
998 footer->features = cpu_to_be32(0x02);
999 footer->version = cpu_to_be32(0x00010000);
24da78db 1000 if (disk_type == VHD_DYNAMIC) {
a4127c42 1001 footer->data_offset = cpu_to_be64(HEADER_SIZE);
24da78db 1002 } else {
a4127c42 1003 footer->data_offset = cpu_to_be64(0xFFFFFFFFFFFFFFFFULL);
24da78db 1004 }
a4127c42 1005 footer->timestamp = cpu_to_be32(time(NULL) - VHD_TIMESTAMP_BASE);
24da78db
CA
1006
1007 /* Version of Virtual PC 2007 */
a4127c42
SH
1008 footer->major = cpu_to_be16(0x0005);
1009 footer->minor = cpu_to_be16(0x0003);
3f3f20dc 1010 footer->orig_size = cpu_to_be64(total_size);
03671ded 1011 footer->current_size = cpu_to_be64(total_size);
a4127c42 1012 footer->cyls = cpu_to_be16(cyls);
24da78db
CA
1013 footer->heads = heads;
1014 footer->secs_per_cyl = secs_per_cyl;
1015
a4127c42 1016 footer->type = cpu_to_be32(disk_type);
24da78db 1017
38440a21 1018 qemu_uuid_generate(&footer->uuid);
24da78db 1019
a4127c42 1020 footer->checksum = cpu_to_be32(vpc_checksum(buf, HEADER_SIZE));
24da78db
CA
1021
1022 if (disk_type == VHD_DYNAMIC) {
b8f45cdf 1023 ret = create_dynamic_disk(blk, buf, total_sectors);
ed3d2ec9
HR
1024 if (ret < 0) {
1025 error_setg(errp, "Unable to create or write VHD header");
1026 }
24da78db 1027 } else {
ed3d2ec9 1028 ret = create_fixed_disk(blk, buf, total_size, errp);
0211b9be 1029 }
24da78db 1030
fec9921f 1031out:
b8f45cdf 1032 blk_unref(blk);
fec9921f 1033 g_free(disk_type_param);
f0ff243a 1034 return ret;
57c7d9e5
AL
1035}
1036
72c6cc94
KW
1037static int vpc_has_zero_init(BlockDriverState *bs)
1038{
1039 BDRVVPCState *s = bs->opaque;
e54835c0 1040 VHDFooter *footer = (VHDFooter *) s->footer_buf;
72c6cc94 1041
0d4cc3e7 1042 if (be32_to_cpu(footer->type) == VHD_FIXED) {
9a4f4c31 1043 return bdrv_has_zero_init(bs->file->bs);
72c6cc94
KW
1044 } else {
1045 return 1;
1046 }
1047}
1048
6a0f9e82
FB
1049static void vpc_close(BlockDriverState *bs)
1050{
1051 BDRVVPCState *s = bs->opaque;
97f1c45c 1052 qemu_vfree(s->pagetable);
6a0f9e82 1053#ifdef CACHE
7267c094 1054 g_free(s->pageentry_u8);
6a0f9e82 1055#endif
612ff3d8
KW
1056
1057 migrate_del_blocker(s->migration_blocker);
1058 error_free(s->migration_blocker);
6a0f9e82
FB
1059}
1060
fec9921f
CL
1061static QemuOptsList vpc_create_opts = {
1062 .name = "vpc-create-opts",
1063 .head = QTAILQ_HEAD_INITIALIZER(vpc_create_opts.head),
1064 .desc = {
1065 {
1066 .name = BLOCK_OPT_SIZE,
1067 .type = QEMU_OPT_SIZE,
1068 .help = "Virtual disk size"
1069 },
1070 {
1071 .name = BLOCK_OPT_SUBFMT,
1072 .type = QEMU_OPT_STRING,
1073 .help =
1074 "Type of virtual hard disk format. Supported formats are "
1075 "{dynamic (default) | fixed} "
1076 },
fb9245c2
JC
1077 {
1078 .name = VPC_OPT_FORCE_SIZE,
1079 .type = QEMU_OPT_BOOL,
1080 .help = "Force disk size calculation to use the actual size "
1081 "specified, rather than using the nearest CHS-based "
1082 "calculation"
1083 },
fec9921f
CL
1084 { /* end of list */ }
1085 }
0e7e1989
KW
1086};
1087
5efa9d5a 1088static BlockDriver bdrv_vpc = {
4a411185
KW
1089 .format_name = "vpc",
1090 .instance_size = sizeof(BDRVVPCState),
c68b89ac 1091
72c6cc94
KW
1092 .bdrv_probe = vpc_probe,
1093 .bdrv_open = vpc_open,
1094 .bdrv_close = vpc_close,
1095 .bdrv_reopen_prepare = vpc_reopen_prepare,
862f215f 1096 .bdrv_child_perm = bdrv_format_default_perms,
c282e1fd 1097 .bdrv_create = vpc_create,
0e7e1989 1098
d46b7cc6 1099 .bdrv_co_preadv = vpc_co_preadv,
513b0f02 1100 .bdrv_co_pwritev = vpc_co_pwritev,
0cc84887 1101 .bdrv_co_get_block_status = vpc_co_get_block_status,
c68b89ac 1102
97b00e28
PB
1103 .bdrv_get_info = vpc_get_info,
1104
fec9921f 1105 .create_opts = &vpc_create_opts,
72c6cc94 1106 .bdrv_has_zero_init = vpc_has_zero_init,
6a0f9e82 1107};
5efa9d5a
AL
1108
1109static void bdrv_vpc_init(void)
1110{
1111 bdrv_register(&bdrv_vpc);
1112}
1113
1114block_init(bdrv_vpc_init);
This page took 0.854128 seconds and 4 git commands to generate.