[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH V3 1/2] hd-geometry.c: Integrate HDIO_GETGEO in
From: |
Markus Armbruster |
Subject: |
Re: [Qemu-devel] [PATCH V3 1/2] hd-geometry.c: Integrate HDIO_GETGEO in guessing for target-s390x |
Date: |
Mon, 18 Feb 2013 11:42:13 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux) |
Einar Lueck <address@hidden> writes:
> This patch extends the function hd_geometry_guess. It introduces a
> target specific hook. The default implementation for this target
> specific hook is empty, has therefore no effect and the existing logic
> works as before. For target-s390x, the behaviour is chosen as follows:
> If no geo could be guessed via guess_disk_lchs, a new function called
> guess_disk_pchs is called. The latter utilizes HDIO_GET_GEO ioctl to ask
> the underlying disk for geometry.
> If this is not successful (e.g. image files) geometry is derived
> from the size of the disk (as before).
> 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>
> Reviewed-by: Carsten Otte <address@hidden>
> Signed-off-by: Christian Borntraeger <address@hidden>
> ---
> hw/Makefile.objs | 6 ++++-
> hw/hd-geometry.c | 70
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 74 insertions(+), 2 deletions(-)
>
> diff --git a/hw/Makefile.objs b/hw/Makefile.objs
> index 447e32a..7832d2c 100644
> --- a/hw/Makefile.objs
> +++ b/hw/Makefile.objs
> @@ -178,7 +178,7 @@ common-obj-$(CONFIG_MAX111X) += max111x.o
> common-obj-$(CONFIG_DS1338) += ds1338.o
> common-obj-y += i2c.o smbus.o smbus_eeprom.o
> common-obj-y += eeprom93xx.o
> -common-obj-y += scsi-disk.o cdrom.o hd-geometry.o block-common.o
> +common-obj-y += scsi-disk.o cdrom.o block-common.o
> common-obj-y += scsi-generic.o scsi-bus.o
> common-obj-y += hid.o
> common-obj-$(CONFIG_SSI) += ssi.o
> @@ -209,6 +209,10 @@ obj-$(CONFIG_VGA) += vga.o
> obj-$(CONFIG_SOFTMMU) += device-hotplug.o
> obj-$(CONFIG_XEN) += xen_domainbuild.o xen_machine_pv.o
>
> +# geometry is target/architecture dependent and therefore needs to be built
> +# for every target platform
> +obj-y += hd-geometry.o
> +
> # Inter-VM PCI shared memory & VFIO PCI device assignment
> ifeq ($(CONFIG_PCI), y)
> obj-$(CONFIG_KVM) += ivshmem.o
> diff --git a/hw/hd-geometry.c b/hw/hd-geometry.c
> index c305143..98253d7 100644
> --- a/hw/hd-geometry.c
> +++ b/hw/hd-geometry.c
> @@ -33,6 +33,10 @@
> #include "block/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,6 +51,39 @@ 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);
> +
> +/* try to get geometry from disk via HDIO_GETGEO ioctl
> + Return 0 if OK, -1 if ioctl does not work (e.g. image file) */
> +inline static int guess_disk_pchs(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;
> + }
> +
> + /* HDIO_GETGEO may return success even though geo contains zeros
> + (e.g. certain multipath setups) */
> + if (!geo.heads || !geo.sectors || !geo.cylinders) {
> + return -1;
> + }
> +
> + *pheads = geo.heads;
> + *psectors = geo.sectors;
> + *pcylinders = geo.cylinders;
> + *ptranslation = BIOS_ATA_TRANSLATION_NONE;
> + 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,
> @@ -116,13 +153,43 @@ static void guess_chs_for_size(BlockDriverState *bs,
> *psecs = 63;
> }
>
> +/* target specific geometry guessing hooks:
> + * return 0 if guess available, != 0 in any other case */
> +#ifdef TARGET_S390X
> +static inline int target_geometry_guess(BlockDriverState *bs,
> + uint32_t *pcyls, uint32_t *pheads,
> + uint32_t *psecs, int *ptranslation)
> +{
> + int cyls, heads, secs;
> + if (!guess_disk_lchs(bs, &cyls, &heads, &secs)) {
Suggest to test < 0 for clarity, like the existing caller does.
> + *pcyls = cyls;
> + *pheads = heads;
> + *psecs = secs;
> + *ptranslation = BIOS_ATA_TRANSLATION_NONE;
> + return 0;
> + } else {
> + return guess_disk_pchs(bs, pcyls, pheads, psecs, ptranslation);
> + }
> +}
I'd prefer
if (guess_disk_lchs() < 0) {
...
return 0;
}
return guess_disk_lchs();
over your "return else". Matter of taste.
> +#else
> +static inline int target_geometry_guess(BlockDriverState *bs,
> + uint32_t *pcyls, uint32_t *pheads,
> + uint32_t *psecs, int *ptranslation)
> +{
> + return -1;
> +}
> +#endif
> +
> void hd_geometry_guess(BlockDriverState *bs,
> uint32_t *pcyls, uint32_t *pheads, uint32_t *psecs,
> int *ptrans)
> {
> int cylinders, heads, secs, translation;
>
> - if (guess_disk_lchs(bs, &cylinders, &heads, &secs) < 0) {
> + if (!target_geometry_guess(bs, pcyls, pheads, psecs, &translation)) {
Suggest to test < 0 for clarity.
> + /* a target specific guess has highest priority */
> + goto out;
Gratuitous goto: doing nothing here would take you to the exact same
place. So let's do that.
> + } else if (guess_disk_lchs(bs, &cylinders, &heads, &secs) < 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);
> @@ -143,6 +210,7 @@ void hd_geometry_guess(BlockDriverState *bs,
> the logical geometry */
> translation = BIOS_ATA_TRANSLATION_NONE;
> }
> +out:
> if (ptrans) {
> *ptrans = translation;
> }
Consider the following scenario on TARGET_S390X:
1. hd_geometry_guess() calls target_geometry_guess()
2. target_geometry_guess() calls guess_disk_lchs(), which fails
3. target_geometry_guess() calls guess_disk_pchs(), which fails
4. target_geometry_guess() fails.
5. hd_geometry_guess() calls guess_disk_lchs() again, and it fails
again.
Since your target_geometry_guess() for s390x wants to do the
guess_disk_lchs() itself, what moveing the call of guess_disk_lchs()
there for all targets?