}
#endif
-static int vdi_check(BlockDriverState *bs)
+static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
{
/* TODO: additional checks possible. */
BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
- int n_errors = 0;
uint32_t blocks_allocated = 0;
uint32_t block;
uint32_t *bmap;
} else {
fprintf(stderr, "ERROR: block index %" PRIu32
" also used by %" PRIu32 "\n", bmap[bmap_entry], bmap_entry);
+ res->corruptions++;
}
} else {
fprintf(stderr, "ERROR: block index %" PRIu32
" too large, is %" PRIu32 "\n", block, bmap_entry);
- n_errors++;
+ res->corruptions++;
}
}
}
fprintf(stderr, "ERROR: allocated blocks mismatch, is %" PRIu32
", should be %" PRIu32 "\n",
blocks_allocated, s->header.blocks_allocated);
- n_errors++;
+ res->corruptions++;
}
qemu_free(bmap);
- return n_errors;
+ return 0;
}
static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return result;
}
-static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
+static int vdi_open(BlockDriverState *bs, int flags)
{
BDRVVdiState *s = bs->opaque;
VdiHeader header;
size_t bmap_size;
- int ret;
logout("\n");
- ret = bdrv_file_open(&s->hd, filename, flags);
- if (ret < 0) {
- return ret;
- }
-
- if (bdrv_read(s->hd, 0, (uint8_t *)&header, 1) < 0) {
+ if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) {
goto fail;
}
vdi_header_print(&header);
#endif
+ if (header.disk_size % SECTOR_SIZE != 0) {
+ /* 'VBoxManage convertfromraw' can create images with odd disk sizes.
+ We accept them but round the disk size to the next multiple of
+ SECTOR_SIZE. */
+ logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size);
+ header.disk_size += SECTOR_SIZE - 1;
+ header.disk_size &= ~(SECTOR_SIZE - 1);
+ }
+
if (header.version != VDI_VERSION_1_1) {
logout("unsupported version %u.%u\n",
header.version >> 16, header.version & 0xffff);
} else if (header.block_size != 1 * MiB) {
logout("unsupported block size %u B\n", header.block_size);
goto fail;
- } else if (header.disk_size !=
+ } else if (header.disk_size >
(uint64_t)header.blocks_in_image * header.block_size) {
- logout("unexpected block number %u B\n", header.blocks_in_image);
+ logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
goto fail;
} else if (!uuid_is_null(header.uuid_link)) {
logout("link uuid != 0, unsupported\n");
bmap_size = header.blocks_in_image * sizeof(uint32_t);
bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
- s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
- if (bdrv_read(s->hd, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
+ if (bmap_size > 0) {
+ s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
+ }
+ if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
goto fail_free_bmap;
}
qemu_free(s->bmap);
fail:
- bdrv_delete(s->hd);
return -1;
}
static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
{
/* TODO: This code is untested. How can I get it executed? */
- VdiAIOCB *acb = (VdiAIOCB *)blockacb;
+ VdiAIOCB *acb = container_of(blockacb, VdiAIOCB, common);
logout("\n");
if (acb->hd_aiocb) {
bdrv_aio_cancel(acb->hd_aiocb);
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- acb->hd_aiocb = bdrv_aio_readv(s->hd, offset, &acb->hd_qiov,
+ acb->hd_aiocb = bdrv_aio_readv(bs->file, offset, &acb->hd_qiov,
n_sectors, vdi_aio_read_cb, acb);
if (acb->hd_aiocb == NULL) {
goto done;
acb->hd_iov.iov_base = acb->block_buffer;
acb->hd_iov.iov_len = SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- acb->hd_aiocb = bdrv_aio_writev(s->hd, 0, &acb->hd_qiov, 1,
+ acb->hd_aiocb = bdrv_aio_writev(bs->file, 0, &acb->hd_qiov, 1,
vdi_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
goto done;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
logout("will write %u block map sectors starting from entry %u\n",
n_sectors, bmap_first);
- acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
+ acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
n_sectors, vdi_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
goto done;
acb->hd_iov.iov_base = (void *)block;
acb->hd_iov.iov_len = s->block_size;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- acb->hd_aiocb = bdrv_aio_writev(s->hd, offset,
+ acb->hd_aiocb = bdrv_aio_writev(bs->file, offset,
&acb->hd_qiov, s->block_sectors,
vdi_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
acb->hd_iov.iov_base = (void *)acb->buf;
acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
- acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
+ acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
n_sectors, vdi_aio_write_cb, acb);
if (acb->hd_aiocb == NULL) {
goto done;
return -errno;
}
- blocks = bytes / block_size;
+ /* We need enough blocks to store the given disk size,
+ so always round up. */
+ blocks = (bytes + block_size - 1) / block_size;
+
bmap_size = blocks * sizeof(uint32_t);
bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
result = -errno;
}
- bmap = (uint32_t *)qemu_mallocz(bmap_size);
+ bmap = NULL;
+ if (bmap_size > 0) {
+ bmap = (uint32_t *)qemu_mallocz(bmap_size);
+ }
for (i = 0; i < blocks; i++) {
if (image_type == VDI_TYPE_STATIC) {
bmap[i] = i;
static void vdi_close(BlockDriverState *bs)
{
- BDRVVdiState *s = bs->opaque;
- logout("\n");
- bdrv_delete(s->hd);
}
static void vdi_flush(BlockDriverState *bs)
{
- BDRVVdiState *s = bs->opaque;
logout("\n");
- bdrv_flush(s->hd);
+ bdrv_flush(bs->file);
}