]> git.proxmox.com Git - qemu.git/blobdiff - block/vdi.c
qcow2/vdi: Change check to distinguish error cases
[qemu.git] / block / vdi.c
index 45aa81c7004f8a8107f685b5f8dd29f7c5bcbe30..f72633cf192a7b764939e717fd6ad87cd2e2ebb0 100644 (file)
@@ -291,11 +291,10 @@ static void vdi_header_print(VdiHeader *header)
 }
 #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;
@@ -315,11 +314,12 @@ static int vdi_check(BlockDriverState *bs)
                 } 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++;
             }
         }
     }
@@ -327,12 +327,12 @@ static int vdi_check(BlockDriverState *bs)
         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)
@@ -376,21 +376,15 @@ static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
     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;
     }
 
@@ -399,6 +393,15 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
     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);
@@ -417,9 +420,9 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
     } 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");
@@ -438,8 +441,10 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
 
     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;
     }
 
@@ -449,7 +454,6 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
     qemu_free(s->bmap);
 
  fail:
-    bdrv_delete(s->hd);
     return -1;
 }
 
@@ -473,7 +477,7 @@ static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
 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);
@@ -604,7 +608,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
         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;
@@ -667,7 +671,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
             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;
@@ -696,7 +700,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
             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;
@@ -745,7 +749,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
         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) {
@@ -758,7 +762,7 @@ static void vdi_aio_write_cb(void *opaque, int ret)
         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;
@@ -831,7 +835,10 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
         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));
 
@@ -861,7 +868,10 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
         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;
@@ -888,16 +898,12 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
 
 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);
 }