]> git.proxmox.com Git - qemu.git/blobdiff - block/vdi.c
target-sparc: Fix compiler errors (format strings)
[qemu.git] / block / vdi.c
index 4ca8dcb7dc6466cb3ced426ff4cc2c569d0cb58c..261cf9b98da5a6042054d2e1b2a9527c7eb6e4a4 100644 (file)
@@ -53,7 +53,7 @@
 #include "block_int.h"
 #include "module.h"
 
-#if defined(HAVE_UUID_H)
+#if defined(CONFIG_UUID)
 #include <uuid/uuid.h>
 #else
 /* TODO: move uuid emulation to some central place in QEMU. */
@@ -87,6 +87,7 @@ void uuid_unparse(const uuid_t uu, char *out);
 #define MiB     (KiB * KiB)
 
 #define SECTOR_SIZE 512
+#define DEFAULT_CLUSTER_SIZE (1 * MiB)
 
 #if defined(CONFIG_VDI_DEBUG)
 #define logout(fmt, ...) \
@@ -113,19 +114,19 @@ void uuid_unparse(const uuid_t uu, char *out);
  */
 #define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
 
-/* Unallocated blocks use this index (no need to convert endianess). */
+/* Unallocated blocks use this index (no need to convert endianness). */
 #define VDI_UNALLOCATED UINT32_MAX
 
-#if !defined(HAVE_UUID_H)
+#if !defined(CONFIG_UUID)
 void uuid_generate(uuid_t out)
 {
-    memset(out, 0, sizeof(out));
+    memset(out, 0, sizeof(uuid_t));
 }
 
 int uuid_is_null(const uuid_t uu)
 {
     uuid_t null_uuid = { 0 };
-    return memcmp(uu, null_uuid, sizeof(uu)) == 0;
+    return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0;
 }
 
 void uuid_unparse(const uuid_t uu, char *out)
@@ -151,6 +152,7 @@ typedef struct {
     /* Buffer for new allocated block. */
     void *block_buffer;
     void *orig_buf;
+    bool is_write;
     int header_modified;
     BlockDriverAIOCB *hd_aiocb;
     struct iovec hd_iov;
@@ -186,7 +188,6 @@ typedef struct {
 } VdiHeader;
 
 typedef struct {
-    BlockDriverState *hd;
     /* The block map entries are little endian (even in memory). */
     uint32_t *bmap;
     /* Size of block (bytes). */
@@ -195,7 +196,7 @@ typedef struct {
     uint32_t block_sectors;
     /* First sector of block map. */
     uint32_t bmap_sector;
-    /* VDI header (converted to host endianess). */
+    /* VDI header (converted to host endianness). */
     VdiHeader header;
 } BDRVVdiState;
 
@@ -291,11 +292,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 +315,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 +328,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 +377,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 +394,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 +421,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");
@@ -437,9 +441,11 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
     s->header = header;
 
     bmap_size = header.blocks_in_image * sizeof(uint32_t);
-    s->bmap = qemu_malloc(bmap_size);
-    if (bdrv_read(s->hd, s->bmap_sector,
-                  (uint8_t *)s->bmap, bmap_size / SECTOR_SIZE) < 0) {
+    bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
+    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 +455,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 +478,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);
@@ -500,6 +505,8 @@ static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
         acb->hd_aiocb = NULL;
         acb->sector_num = sector_num;
         acb->qiov = qiov;
+        acb->is_write = is_write;
+
         if (qiov->niov > 1) {
             acb->buf = qemu_blockalign(bs, qiov->size);
             acb->orig_buf = acb->buf;
@@ -538,14 +545,20 @@ static int vdi_schedule_bh(QEMUBHFunc *cb, VdiAIOCB *acb)
 }
 
 static void vdi_aio_read_cb(void *opaque, int ret);
+static void vdi_aio_write_cb(void *opaque, int ret);
 
-static void vdi_aio_read_bh(void *opaque)
+static void vdi_aio_rw_bh(void *opaque)
 {
     VdiAIOCB *acb = opaque;
     logout("\n");
     qemu_bh_delete(acb->bh);
     acb->bh = NULL;
-    vdi_aio_read_cb(opaque, 0);
+
+    if (acb->is_write) {
+        vdi_aio_write_cb(opaque, 0);
+    } else {
+        vdi_aio_read_cb(opaque, 0);
+    }
 }
 
 static void vdi_aio_read_cb(void *opaque, int ret)
@@ -593,7 +606,7 @@ static void vdi_aio_read_cb(void *opaque, int ret)
     if (bmap_entry == VDI_UNALLOCATED) {
         /* Block not allocated, return zeros, no need to wait. */
         memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
-        ret = vdi_schedule_bh(vdi_aio_read_bh, acb);
+        ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
         if (ret < 0) {
             goto done;
         }
@@ -604,9 +617,10 @@ 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) {
+            ret = -EIO;
             goto done;
         }
     }
@@ -625,12 +639,23 @@ static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
     VdiAIOCB *acb;
+    int ret;
+
     logout("\n");
     acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
     if (!acb) {
         return NULL;
     }
-    vdi_aio_read_cb(acb, 0);
+
+    ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+    if (ret < 0) {
+        if (acb->qiov->niov > 1) {
+            qemu_vfree(acb->orig_buf);
+        }
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
     return &acb->common;
 }
 
@@ -667,9 +692,10 @@ 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) {
+                ret = -EIO;
                 goto done;
             }
             return;
@@ -690,15 +716,16 @@ static void vdi_aio_write_cb(void *opaque, int ret)
             n_sectors = bmap_last - bmap_first + 1;
             offset = s->bmap_sector + bmap_first;
             acb->bmap_first = VDI_UNALLOCATED;
-            acb->hd_iov.iov_base = (uint8_t *)&s->bmap[0] +
-                                   bmap_first * SECTOR_SIZE;
+            acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
+                                            bmap_first * SECTOR_SIZE);
             acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
             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) {
+                ret = -EIO;
                 goto done;
             }
             return;
@@ -742,25 +769,27 @@ static void vdi_aio_write_cb(void *opaque, int ret)
         acb->bmap_last = block_index;
         memcpy(block + sector_in_block * SECTOR_SIZE,
                acb->buf, n_sectors * SECTOR_SIZE);
-        acb->hd_iov.iov_base = block;
+        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) {
+            ret = -EIO;
             goto done;
         }
     } else {
         uint64_t offset = s->header.offset_data / SECTOR_SIZE +
                           (uint64_t)bmap_entry * s->block_sectors +
                           sector_in_block;
-        acb->hd_iov.iov_base = acb->buf;
+        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) {
+            ret = -EIO;
             goto done;
         }
     }
@@ -780,12 +809,23 @@ static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
     VdiAIOCB *acb;
+    int ret;
+
     logout("\n");
     acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
     if (!acb) {
         return NULL;
     }
-    vdi_aio_write_cb(acb, 0);
+
+    ret = vdi_schedule_bh(vdi_aio_rw_bh, acb);
+    if (ret < 0) {
+        if (acb->qiov->niov > 1) {
+            qemu_vfree(acb->orig_buf);
+        }
+        qemu_aio_release(acb);
+        return NULL;
+    }
+
     return &acb->common;
 }
 
@@ -795,7 +835,7 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
     int result = 0;
     uint64_t bytes = 0;
     uint32_t blocks;
-    size_t block_size = 1 * MiB;
+    size_t block_size = DEFAULT_CLUSTER_SIZE;
     uint32_t image_type = VDI_TYPE_DYNAMIC;
     VdiHeader header;
     size_t i;
@@ -817,7 +857,9 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
 #endif
 #if defined(CONFIG_VDI_STATIC_IMAGE)
         } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
-            image_type = VDI_TYPE_STATIC;
+            if (options->value.n) {
+                image_type = VDI_TYPE_STATIC;
+            }
 #endif
         }
         options++;
@@ -829,7 +871,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));
 
@@ -845,6 +890,9 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
     header.disk_size = bytes;
     header.block_size = block_size;
     header.blocks_in_image = blocks;
+    if (image_type == VDI_TYPE_STATIC) {
+        header.blocks_allocated = blocks;
+    }
     uuid_generate(header.uuid_image);
     uuid_generate(header.uuid_last_snap);
     /* There is no need to set header.uuid_link or header.uuid_parent here. */
@@ -856,7 +904,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;
@@ -883,16 +934,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)
+static int vdi_flush(BlockDriverState *bs)
 {
-    BDRVVdiState *s = bs->opaque;
     logout("\n");
-    bdrv_flush(s->hd);
+    return bdrv_flush(bs->file);
 }
 
 
@@ -906,7 +953,8 @@ static QEMUOptionParameter vdi_create_options[] = {
     {
         .name = BLOCK_OPT_CLUSTER_SIZE,
         .type = OPT_SIZE,
-        .help = "VDI cluster (block) size"
+        .help = "VDI cluster (block) size",
+        .value = { .n = DEFAULT_CLUSTER_SIZE },
     },
 #endif
 #if defined(CONFIG_VDI_STATIC_IMAGE)