All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kevin Wolf <kwolf@redhat.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, qemu-devel@nongnu.org
Subject: [Qemu-devel] [PULL 05/40] block/vpc: choose size calculation method based on creator_app field
Date: Mon, 14 Mar 2016 18:37:06 +0100	[thread overview]
Message-ID: <1457977061-28087-6-git-send-email-kwolf@redhat.com> (raw)
In-Reply-To: <1457977061-28087-1-git-send-email-kwolf@redhat.com>

From: Jeff Cody <jcody@redhat.com>

The VHD file format is used by both Virtual PC, and Hyper-V.  However,
how the virtual disk size is calculated varies between the two.

Virtual PC uses the CHS drive parameters to determine the drive size.
Hyper-V, on the other hand, uses the current_size field in the footer
when determining image size.

This is problematic for a few reasons:

* VHD images from Hyper-V, using CHS calculations, will likely be
  trunctated.

* If we just rely always on current_size, then QEMU may have data
  compatibility issues with Virtual PC (we may write too much data
  into a VHD file to be used by Virtual PC, for instance).

* Existing VHD images created by QEMU have used the CHS calculations,
  except for images exceeding the 127GB limit.  We want to remain
  compatible with our own generated images.

Luckily, the VHD specification defines a 'Creator App' field, that is
used to indicate what software created the VHD file.

This patch does two things:

    1. Uses the 'Creator App' field to help determine how to calculate
       size, and

    2. Adds a VPC format option 'force_size_calc', so that the user can
       override the 'Creator App' auto-detection, in case there exist
       VHD images with unknown or contradictory 'Creator App' entries.

N.B.: We currently use the maximum CHS value as an indication to use the
current_size field.  This patch does not change that, even with the
'force_size_calc' option.

Signed-off-by: Jeff Cody <jcody@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
---
 block/vpc.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 82 insertions(+), 5 deletions(-)

diff --git a/block/vpc.c b/block/vpc.c
index f504536..54a38a7 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -128,6 +128,8 @@ typedef struct BDRVVPCState {
 
     uint32_t block_size;
     uint32_t bitmap_size;
+    bool force_use_chs;
+    bool force_use_sz;
 
 #ifdef CACHE
     uint8_t *pageentry_u8;
@@ -140,6 +142,22 @@ typedef struct BDRVVPCState {
     Error *migration_blocker;
 } BDRVVPCState;
 
+#define VPC_OPT_SIZE_CALC "force_size_calc"
+static QemuOptsList vpc_runtime_opts = {
+    .name = "vpc-runtime-opts",
+    .head = QTAILQ_HEAD_INITIALIZER(vpc_runtime_opts.head),
+    .desc = {
+        {
+            .name = VPC_OPT_SIZE_CALC,
+            .type = QEMU_OPT_STRING,
+            .help = "Force disk size calculation to use either CHS geometry, "
+                    "or use the disk current_size specified in the VHD footer. "
+                    "{chs, current_size}"
+        },
+        { /* end of list */ }
+    }
+};
+
 static uint32_t vpc_checksum(uint8_t* buf, size_t size)
 {
     uint32_t res = 0;
@@ -159,6 +177,25 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename)
     return 0;
 }
 
+static void vpc_parse_options(BlockDriverState *bs, QemuOpts *opts,
+                              Error **errp)
+{
+    BDRVVPCState *s = bs->opaque;
+    const char *size_calc;
+
+    size_calc = qemu_opt_get(opts, VPC_OPT_SIZE_CALC);
+
+    if (!size_calc) {
+       /* no override, use autodetect only */
+    } else if (!strcmp(size_calc, "current_size")) {
+        s->force_use_sz = true;
+    } else if (!strcmp(size_calc, "chs")) {
+        s->force_use_chs = true;
+    } else {
+        error_setg(errp, "Invalid size calculation mode: '%s'", size_calc);
+    }
+}
+
 static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
                     Error **errp)
 {
@@ -166,6 +203,9 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
     int i;
     VHDFooter *footer;
     VHDDynDiskHeader *dyndisk_header;
+    QemuOpts *opts = NULL;
+    Error *local_err = NULL;
+    bool use_chs;
     uint8_t buf[HEADER_SIZE];
     uint32_t checksum;
     uint64_t computed_size;
@@ -173,6 +213,21 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
     int disk_type = VHD_DYNAMIC;
     int ret;
 
+    opts = qemu_opts_create(&vpc_runtime_opts, NULL, 0, &error_abort);
+    qemu_opts_absorb_qdict(opts, options, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail;
+    }
+
+    vpc_parse_options(bs, opts, &local_err);
+    if (local_err) {
+        error_propagate(errp, local_err);
+        ret = -EINVAL;
+        goto fail;
+    }
+
     ret = bdrv_pread(bs->file->bs, 0, s->footer_buf, HEADER_SIZE);
     if (ret < 0) {
         goto fail;
@@ -218,12 +273,34 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
     bs->total_sectors = (int64_t)
         be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
 
-    /* Images that have exactly the maximum geometry are probably bigger and
-     * would be truncated if we adhered to the geometry for them. Rely on
-     * footer->current_size for them. */
-    if (bs->total_sectors == VHD_MAX_GEOMETRY) {
+    /* Microsoft Virtual PC and Microsoft Hyper-V produce and read
+     * VHD image sizes differently.  VPC will rely on CHS geometry,
+     * while Hyper-V and disk2vhd use the size specified in the footer.
+     *
+     * We use a couple of approaches to try and determine the correct method:
+     * look at the Creator App field, and look for images that have CHS
+     * geometry that is the maximum value.
+     *
+     * If the CHS geometry is the maximum CHS geometry, then we assume that
+     * the size is the footer->current_size to avoid truncation.  Otherwise,
+     * we follow the table based on footer->creator_app:
+     *
+     *  Known creator apps:
+     *      'vpc '  :  CHS              Virtual PC (uses disk geometry)
+     *      'qemu'  :  CHS              QEMU (uses disk geometry)
+     *      'win '  :  current_size     Hyper-V
+     *      'd2v '  :  current_size     Disk2vhd
+     *
+     *  The user can override the table values via drive options, however
+     *  even with an override we will still use current_size for images
+     *  that have CHS geometry of the maximum size.
+     */
+    use_chs = (!!strncmp(footer->creator_app, "win ", 4) &&
+               !!strncmp(footer->creator_app, "d2v ", 4)) || s->force_use_chs;
+
+    if (!use_chs || bs->total_sectors == VHD_MAX_GEOMETRY || s->force_use_sz) {
         bs->total_sectors = be64_to_cpu(footer->current_size) /
-                            BDRV_SECTOR_SIZE;
+                                        BDRV_SECTOR_SIZE;
     }
 
     /* Allow a maximum disk size of approximately 2 TB */
-- 
1.8.3.1

  parent reply	other threads:[~2016-03-14 17:37 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-03-14 17:37 [Qemu-devel] [PULL 00/40] Block patches Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 01/40] qemu-img: eliminate memory leak Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 02/40] block/qapi: Factor out bdrv_query_blk_stats() Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 03/40] block/qapi: Factor out bdrv_query_bds_stats() Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 04/40] block/qapi: Include empty drives in query-blockstats Kevin Wolf
2016-03-14 17:37 ` Kevin Wolf [this message]
2016-03-14 17:37 ` [Qemu-devel] [PULL 06/40] block/vpc: tests for auto-detecting VPC and Hyper-V VHD images Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 07/40] block/vpc: give option to force the current_size field in .bdrv_create Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 08/40] block/vpc: add tests for image creation force_size parameter Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 09/40] docs: fix invalid node name in qmp event Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 10/40] qmp event: Refactor QUORUM_REPORT_BAD Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 11/40] quorum: modify vote rules for flush operation Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 12/40] blockdev: Snapshotting must not open second instance of old top Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 13/40] block: Fix snapshot=on cache modes Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 14/40] block: Fix cache mode defaults in bds_tree_init() Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 15/40] vmdk: Switch to heap arrays for vmdk_write_cid Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 16/40] vmdk: Switch to heap arrays for vmdk_read_cid Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 17/40] vmdk: Switch to heap arrays for vmdk_parent_open Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 18/40] hmp: 'drive_add -n' for creating a node without BB Kevin Wolf
2016-03-16 10:41   ` Paolo Bonzini
2016-03-16 10:47     ` Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 19/40] hmp: Extend drive_del to delete nodes " Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 20/40] block: Use writeback in .bdrv_create() implementations Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 21/40] block: Introduce blk_set_allow_write_beyond_eof() Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 22/40] parallels: Use BB functions in .bdrv_create() Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 23/40] qcow: " Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 24/40] qcow2: " Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 25/40] qed: " Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 26/40] sheepdog: " Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 27/40] vdi: " Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 28/40] vhdx: " Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 29/40] vmdk: " Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 30/40] vpc: " Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 31/40] backup: Use Bitmap to replace "s->bitmap" Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 32/40] block: Include hbitmap.h in block.h Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 33/40] typedefs: Add BdrvDirtyBitmap Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 34/40] block: Move block dirty bitmap code to separate files Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 35/40] block: Remove unused typedef of BlockDriverDirtyHandler Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 36/40] iotests: Correct 081's reference output Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 37/40] quorum: Fix crash in quorum_aio_cb() Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 38/40] monitor: Separate QUORUM_REPORT_BAD events according to the node name Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 39/40] monitor: Use QEMU_CLOCK_VIRTUAL for the event queue in qtest mode Kevin Wolf
2016-03-14 17:37 ` [Qemu-devel] [PULL 40/40] iotests: Add test for QMP event rates Kevin Wolf
2016-03-15 10:07 ` [Qemu-devel] [PULL 00/40] Block patches Peter Maydell

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1457977061-28087-6-git-send-email-kwolf@redhat.com \
    --to=kwolf@redhat.com \
    --cc=qemu-block@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.