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