qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/2] hd-geometry.c: Integrate HDIO_GETGEO in gue


From: Paolo Bonzini
Subject: Re: [Qemu-devel] [PATCH 2/2] hd-geometry.c: Integrate HDIO_GETGEO in guessing
Date: Mon, 20 Aug 2012 10:50:42 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:14.0) Gecko/20120717 Thunderbird/14.0

Il 15/08/2012 09:44, Jens Freimann ha scritto:
> From: Einar Lueck <address@hidden>
> 
> This patch extends the function guess_disk_lchs. If no geo could
> be derived from reading disk content, HDIO_GETGEO ioctl is issued.
> If this is not successful (e.g. image files) geometry is derived
> from the size of the disk (as before). To achieve this, the MSDOS
> partition table reading logic and the translation computation logic
> have been moved into a separate function guess_disk_msdosgeo. The
> HDIO_GETGEO logic is captured in a new function guess_disk_ioctlgeo.
> guess_disk_lchs then encapsulates both (the overall guessing logic).
> The new HDIO_GETGEO logic is required for two use cases:
> a) Support for geometries of Direct Attached Storage Disks (DASD)
> on s390x configured as backing of virtio block devices.
> b) Support for FCP attached SCSI disks that do not yet have a
> partition table. Without this patch, fdisk -l on the host would
> return different results then fdisk -l in the guest.
> 
> Signed-off-by: Einar Lueck <address@hidden>
> Signed-off-by: Jens Freimann <address@hidden>
> ---
>  hw/hd-geometry.c | 118 
> ++++++++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 81 insertions(+), 37 deletions(-)
> 
> diff --git a/hw/hd-geometry.c b/hw/hd-geometry.c
> index 1cdb9fb..fc29075 100644
> --- a/hw/hd-geometry.c
> +++ b/hw/hd-geometry.c
> @@ -33,6 +33,10 @@
>  #include "block.h"
>  #include "hw/block-common.h"
>  #include "trace.h"
> +#ifdef __linux__
> +#include <linux/fs.h>
> +#include <linux/hdreg.h>
> +#endif
>  
>  struct partition {
>          uint8_t boot_ind;           /* 0x80 - active */
> @@ -47,13 +51,59 @@ struct partition {
>          uint32_t nr_sects;          /* nr of sectors in partition */
>  } QEMU_PACKED;
>  
> +static void guess_chs_for_size(BlockDriverState *bs,
> +                uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
> +{
> +    uint64_t nb_sectors;
> +    int cylinders;
> +
> +    bdrv_get_geometry(bs, &nb_sectors);
> +
> +    cylinders = nb_sectors / (16 * 63);
> +    if (cylinders > 16383) {
> +        cylinders = 16383;
> +    } else if (cylinders < 2) {
> +        cylinders = 2;
> +    }
> +    *pcyls = cylinders;
> +    *pheads = 16;
> +    *psecs = 63;
> +}
> +
> +/* try to get geometry from disk via HDIO_GETGEO ioctl
> +   Return 0 if OK, -1 if ioctl does not work (e.g. image file) */
> +static inline int guess_disk_ioctlgeo(BlockDriverState *bs,
> +                                     uint32_t *pcylinders, uint32_t *pheads,
> +                                     uint32_t *psectors, int *ptranslation)
> +{
> +#ifdef __linux__
> +    struct hd_geometry geo;
> +
> +    if (bdrv_ioctl(bs, HDIO_GETGEO, &geo)) {
> +        return -1;
> +    }
> +
> +    *pheads = geo.heads;
> +    *psectors = geo.sectors;
> +    *pcylinders = geo.cylinders;
> +    *ptranslation = BIOS_ATA_TRANSLATION_NONE;
> +    trace_hd_geometry_lchs_guess(bs, *pcylinders, *pheads, *psectors);
> +    return 0;
> +#else
> +    return -1;
> +#endif
> +}
> +
> +
>  /* try to guess the disk logical geometry from the MSDOS partition table.
>     Return 0 if OK, -1 if could not guess */
> -static int guess_disk_lchs(BlockDriverState *bs,
> -                           int *pcylinders, int *pheads, int *psectors)
> +static int guess_disk_msdosgeo(BlockDriverState *bs,
> +                               uint32_t *pcylinders, uint32_t *pheads,
> +                               uint32_t *psectors, int *ptranslation)
>  {
>      uint8_t buf[BDRV_SECTOR_SIZE];
> -    int i, heads, sectors, cylinders;
> +    int i, translation;
> +    uint32_t heads, sectors, cylinders;
>      struct partition *p;
>      uint32_t nr_sects;
>      uint64_t nb_sectors;
> @@ -87,9 +137,26 @@ static int guess_disk_lchs(BlockDriverState *bs,
>              if (cylinders < 1 || cylinders > 16383) {
>                  continue;
>              }
> +
> +            if (heads > 16) {
> +                /* LCHS guess with heads > 16 means that a BIOS LBA
> +                   translation was active, so a standard physical disk
> +                   geometry is OK */
> +                guess_chs_for_size(bs, &cylinders, &heads, &sectors);
> +                translation = cylinders * heads <= 131072
> +                    ? BIOS_ATA_TRANSLATION_LARGE
> +                    : BIOS_ATA_TRANSLATION_LBA;
> +            } else {
> +                /* LCHS guess with heads <= 16: use as physical geometry */
> +                /* disable any translation to be in sync with
> +                   the logical geometry */
> +                translation = BIOS_ATA_TRANSLATION_NONE;
> +            }
>              *pheads = heads;
>              *psectors = sectors;
>              *pcylinders = cylinders;
> +            *ptranslation = translation;
> +
>              trace_hd_geometry_lchs_guess(bs, cylinders, heads, sectors);
>              return 0;
>          }
> @@ -97,51 +164,28 @@ static int guess_disk_lchs(BlockDriverState *bs,
>      return -1;
>  }
>  
> -static void guess_chs_for_size(BlockDriverState *bs,
> -                uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs)
> -{
> -    uint64_t nb_sectors;
> -    int cylinders;
> -
> -    bdrv_get_geometry(bs, &nb_sectors);
> -
> -    cylinders = nb_sectors / (16 * 63);
> -    if (cylinders > 16383) {
> -        cylinders = 16383;
> -    } else if (cylinders < 2) {
> -        cylinders = 2;
> +/* try to guess the disk logical geometry
> +   Return 0 if OK, -1 if could not guess */
> +static int guess_disk_lchs(BlockDriverState *bs,
> +                           uint32_t *pcylinders, uint32_t *pheads, 
> +                           uint32_t *psectors, int *ptranslation) {
> +    if (!guess_disk_msdosgeo(bs, pcylinders, pheads, psectors, 
> ptranslation)) {
> +        return 0;
>      }
> -    *pcyls = cylinders;
> -    *pheads = 16;
> -    *psecs = 63;
> +
> +    return guess_disk_ioctlgeo(bs, pcylinders, pheads, psectors, 
> ptranslation);
>  }
>  
>  void hd_geometry_guess(BlockDriverState *bs,
>                         uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
>                         int *ptrans)
>  {
> -    int cylinders, heads, secs, translation;
> +    int translation;
>  
> -    if (guess_disk_lchs(bs, &cylinders, &heads, &secs) < 0) {
> +    if (guess_disk_lchs(bs, pcyls, pheads, psecs, &translation) < 0) {
>          /* no LCHS guess: use a standard physical disk geometry  */
>          guess_chs_for_size(bs, pcyls, pheads, psecs);
>          translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
> -    } else if (heads > 16) {
> -        /* LCHS guess with heads > 16 means that a BIOS LBA
> -           translation was active, so a standard physical disk
> -           geometry is OK */
> -        guess_chs_for_size(bs, pcyls, pheads, psecs);
> -        translation = *pcyls * *pheads <= 131072
> -            ? BIOS_ATA_TRANSLATION_LARGE
> -            : BIOS_ATA_TRANSLATION_LBA;
> -    } else {
> -        /* LCHS guess with heads <= 16: use as physical geometry */
> -        *pcyls = cylinders;
> -        *pheads = heads;
> -        *psecs = secs;
> -        /* disable any translation to be in sync with
> -           the logical geometry */
> -        translation = BIOS_ATA_TRANSLATION_NONE;
>      }
>      if (ptrans) {
>          *ptrans = translation;
> 

Looks good.

Paolo



reply via email to

[Prev in Thread] Current Thread [Next in Thread]