Patchwork [V18,21/25] block: add QemuOpts support for vpc.c

login
register
mail settings
Submitter Robert Wang
Date Aug. 13, 2013, 4:32 a.m.
Message ID <1376368326-7433-22-git-send-email-wdongxu@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/266717/
State New
Headers show

Comments

Robert Wang - Aug. 13, 2013, 4:32 a.m.
Signed-off-by: Dong Xu Wang <wdongxu@linux.vnet.ibm.com>
---
 block/vpc.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 125 insertions(+)

Patch

diff --git a/block/vpc.c b/block/vpc.c
index fe4f311..aa1263a 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -786,6 +786,109 @@  static int vpc_create(const char *filename, QEMUOptionParameter *options)
     return ret;
 }
 
+static int vpc_create_new(const char *filename, QemuOpts *opts)
+{
+    uint8_t buf[1024];
+    struct vhd_footer *footer = (struct vhd_footer *) buf;
+    char *disk_type_param = NULL;
+    int fd, i;
+    uint16_t cyls = 0;
+    uint8_t heads = 0;
+    uint8_t secs_per_cyl = 0;
+    int64_t total_sectors;
+    int64_t total_size = 0;
+    int disk_type = VHD_DYNAMIC;
+    int ret = -EIO;
+
+    /* Read out opts */
+    total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
+    disk_type_param = qemu_opt_get_del(opts, BLOCK_OPT_SUBFMT);
+    if (disk_type_param) {
+        if (!strcmp(disk_type_param, "dynamic")) {
+            disk_type = VHD_DYNAMIC;
+        } else if (!strcmp(disk_type_param, "fixed")) {
+            disk_type = VHD_FIXED;
+        } else {
+            ret = -EINVAL;
+            goto finish;
+        }
+    }
+
+    /* Create the file */
+    fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+    if (fd < 0) {
+        ret = -EIO;
+        goto finish;
+    }
+
+    /*
+     * Calculate matching total_size and geometry. Increase the number of
+     * sectors requested until we get enough (or fail). This ensures that
+     * qemu-img convert doesn't truncate images, but rather rounds up.
+     */
+    total_sectors = total_size / BDRV_SECTOR_SIZE;
+    for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
+        if (calculate_geometry(total_sectors + i, &cyls, &heads,
+                               &secs_per_cyl)) {
+            ret = -EFBIG;
+            goto fail;
+        }
+    }
+
+    total_sectors = (int64_t) cyls * heads * secs_per_cyl;
+
+    /* Prepare the Hard Disk Footer */
+    memset(buf, 0, 1024);
+
+    memcpy(footer->creator, "conectix", 8);
+    /* TODO Check if "qemu" creator_app is ok for VPC */
+    memcpy(footer->creator_app, "qemu", 4);
+    memcpy(footer->creator_os, "Wi2k", 4);
+
+    footer->features = be32_to_cpu(0x02);
+    footer->version = be32_to_cpu(0x00010000);
+    if (disk_type == VHD_DYNAMIC) {
+        footer->data_offset = be64_to_cpu(HEADER_SIZE);
+    } else {
+        footer->data_offset = be64_to_cpu(0xFFFFFFFFFFFFFFFFULL);
+    }
+    footer->timestamp = be32_to_cpu(time(NULL) - VHD_TIMESTAMP_BASE);
+
+    /* Version of Virtual PC 2007 */
+    footer->major = be16_to_cpu(0x0005);
+    footer->minor = be16_to_cpu(0x0003);
+    if (disk_type == VHD_DYNAMIC) {
+        footer->orig_size = be64_to_cpu(total_sectors * 512);
+        footer->size = be64_to_cpu(total_sectors * 512);
+    } else {
+        footer->orig_size = be64_to_cpu(total_size);
+        footer->size = be64_to_cpu(total_size);
+    }
+    footer->cyls = be16_to_cpu(cyls);
+    footer->heads = heads;
+    footer->secs_per_cyl = secs_per_cyl;
+
+    footer->type = be32_to_cpu(disk_type);
+
+#if defined(CONFIG_UUID)
+    uuid_generate(footer->uuid);
+#endif
+
+    footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
+
+    if (disk_type == VHD_DYNAMIC) {
+        ret = create_dynamic_disk(fd, buf, total_sectors);
+    } else {
+        ret = create_fixed_disk(fd, buf, total_size);
+    }
+
+ fail:
+    qemu_close(fd);
+finish:
+    g_free(disk_type_param);
+    return ret;
+}
+
 static int vpc_has_zero_init(BlockDriverState *bs)
 {
     BDRVVPCState *s = bs->opaque;
@@ -826,6 +929,26 @@  static QEMUOptionParameter vpc_create_options[] = {
     { NULL }
 };
 
+static QemuOptsList vpc_create_opts = {
+    .name = "vpc-create-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(vpc_create_opts.head),
+    .desc = {
+        {
+            .name = BLOCK_OPT_SIZE,
+            .type = QEMU_OPT_SIZE,
+            .help = "Virtual disk size"
+        },
+        {
+            .name = BLOCK_OPT_SUBFMT,
+            .type = QEMU_OPT_STRING,
+            .help =
+                "Type of virtual hard disk format. Supported formats are "
+                "{dynamic (default) | fixed} "
+        },
+        { /* end of list */ }
+    }
+};
+
 static BlockDriver bdrv_vpc = {
     .format_name    = "vpc",
     .instance_size  = sizeof(BDRVVPCState),
@@ -835,11 +958,13 @@  static BlockDriver bdrv_vpc = {
     .bdrv_close             = vpc_close,
     .bdrv_reopen_prepare    = vpc_reopen_prepare,
     .bdrv_create            = vpc_create,
+    .bdrv_create_new        = vpc_create_new,
 
     .bdrv_read              = vpc_co_read,
     .bdrv_write             = vpc_co_write,
 
     .create_options         = vpc_create_options,
+    .bdrv_create_opts       = &vpc_create_opts,
     .bdrv_has_zero_init     = vpc_has_zero_init,
 };