diff mbox

block/vpc: Fix conversion from size to disk geometry

Message ID 1273520786-10385-1-git-send-email-weil@mail.berlios.de
State New
Headers show

Commit Message

Stefan Weil May 10, 2010, 7:46 p.m. UTC
The VHD algorithm calculates a disk geometry
which is usually smaller than the requested size.

QEMU tried to round up but failed for certain sizes:

qemu-img create -f vpc disk.vpc 9437184
would create an image with 9435136 bytes
(which is too small for qemu-img convert).

Instead of hacking the geometry algorithm, the patch
increases the number of sectors until we get enough
sectors.

Cc: Kevin Wolf <kwolf@redhat.com>
Signed-off-by: Stefan Weil <weil@mail.berlios.de>
---
 block/vpc.c |   21 ++++++++++++---------
 1 files changed, 12 insertions(+), 9 deletions(-)

Comments

Kevin Wolf May 11, 2010, 9:46 a.m. UTC | #1
Am 10.05.2010 21:46, schrieb Stefan Weil:
> The VHD algorithm calculates a disk geometry
> which is usually smaller than the requested size.
> 
> QEMU tried to round up but failed for certain sizes:
> 
> qemu-img create -f vpc disk.vpc 9437184
> would create an image with 9435136 bytes
> (which is too small for qemu-img convert).
> 
> Instead of hacking the geometry algorithm, the patch
> increases the number of sectors until we get enough
> sectors.
> 
> Cc: Kevin Wolf <kwolf@redhat.com>
> Signed-off-by: Stefan Weil <weil@mail.berlios.de>

Thanks, applied to the block branch.

Kevin
diff mbox

Patch

diff --git a/block/vpc.c b/block/vpc.c
index f94e469..214e9d1 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -463,9 +463,7 @@  static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
         }
     }
 
-    // Note: Rounding up deviates from the Virtual PC behaviour
-    // However, we need this to avoid truncating images in qemu-img convert
-    *cyls = (cyls_times_heads + *heads - 1) / *heads;
+    *cyls = cyls_times_heads / *heads;
 
     return 0;
 }
@@ -477,9 +475,9 @@  static int vpc_create(const char *filename, QEMUOptionParameter *options)
     struct vhd_dyndisk_header* dyndisk_header =
         (struct vhd_dyndisk_header*) buf;
     int fd, i;
-    uint16_t cyls;
-    uint8_t heads;
-    uint8_t secs_per_cyl;
+    uint16_t cyls = 0;
+    uint8_t heads = 0;
+    uint8_t secs_per_cyl = 0;
     size_t block_size, num_bat_entries;
     int64_t total_sectors = 0;
 
@@ -496,9 +494,14 @@  static int vpc_create(const char *filename, QEMUOptionParameter *options)
     if (fd < 0)
         return -EIO;
 
-    // Calculate matching total_size and geometry
-    if (calculate_geometry(total_sectors, &cyls, &heads, &secs_per_cyl))
-        return -EFBIG;
+    /* Calculate matching total_size and geometry. Increase the number of
+       sectors requested until we get enough (or fail). */
+    for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
+        if (calculate_geometry(total_sectors + i,
+                               &cyls, &heads, &secs_per_cyl)) {
+            return -EFBIG;
+        }
+    }
     total_sectors = (int64_t) cyls * heads * secs_per_cyl;
 
     // Prepare the Hard Disk Footer