qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: "Tomáš Golembiovský" <tgolembi@redhat.com>
To: Sameeh Jubran <sameeh@daynix.com>
Cc: QEMU Developers <qemu-devel@nongnu.org>,
	Michael Roth <mdroth@linux.vnet.ibm.com>,
	okrishtal@virtuozzo.com, Sameeh Jubran <sjubran@redhat.com>,
	marcandre.lureau@redhat.com
Subject: Re: [Qemu-devel] [PATCH v4 09/11] qga-win: handle multi-disk volumes
Date: Wed, 10 Oct 2018 16:57:49 +0200	[thread overview]
Message-ID: <20181010165749.3621ab7e@fiorina> (raw)
In-Reply-To: <CAKPgXcF4S9V=nVCxknjK9-SB6As9Qb4nNQJCajTg+cc0V3NR1Q@mail.gmail.com>

On Sun, 7 Oct 2018 15:13:26 +0300
Sameeh Jubran <sameeh@daynix.com> wrote:

> I did a quick scan for the documentation and the code and it seems that the
> name format that you're looking for is provided by the "QueryDosDeviceW"
> function. The function returns multiple names and in the current code we
> only check the first one. I believe that one of these names provided should
> be the win32 device name (dos name).
> 
> Plus I did some googling and found out this similar question:
> https://stackoverflow.com/questions/36199097/list-the-content-of-the-win32-device-namespace

Unfortunately the function QueryDosDevice does not help much with our
situation. Yes, it can tell you that "HarddiskVolume2" is symbolic link
to "\Device\HarddiskVolume2" or that "PhysicalDrive1" is symbolic link
to "\Device\Harddisk1\DR1".

What it does not tell you is that "\Device\Harddisk1\DR1" and
"\Device\0000001c" are two different names for one device.

> Which suggested using the following tool:
> https://docs.microsoft.com/en-us/sysinternals/downloads/winobj

Yes, this is a nice tool for listing the devices.

    Tomas
> 
> 
> On Thu, Oct 4, 2018 at 2:43 PM Tomáš Golembiovský <tgolembi@redhat.com>
> wrote:
> 
> > Probe the volume for disk extents and return list of all disks.
> > Originally only first disk of composite volume was returned.
> >
> > Note that the patch changes get_pci_info() from one state of brokenness
> > into a different state of brokenness. In other words it still does not do
> > what it's supposed to do (see comment in code). If anyone knows how to
> > fix it, please step in.
> >
> > Signed-off-by: Tomáš Golembiovský <tgolembi@redhat.com>
> > ---
> >  qga/commands-win32.c | 126 ++++++++++++++++++++++++++++++++++++-------
> >  1 file changed, 108 insertions(+), 18 deletions(-)
> >
> > diff --git a/qga/commands-win32.c b/qga/commands-win32.c
> > index 1e64642b8a..a591d8221d 100644
> > --- a/qga/commands-win32.c
> > +++ b/qga/commands-win32.c
> > @@ -477,9 +477,26 @@ static GuestDiskBusType
> > find_bus_type(STORAGE_BUS_TYPE bus)
> >      return win2qemu[(int)bus];
> >  }
> >
> > +/* XXX: The following function is BROKEN!
> > + *
> > + * It does not work and probably has never worked. When we query for list
> > of
> > + * disks we get cryptic names like "\Device\0000001d" instead of
> > + * "\PhysicalDriveX" or "\HarddiskX". Whether the names can be translated
> > one
> > + * way or the other for comparison is an open question.
> > + *
> > + * When we query volume names (the original version) we are able to match
> > those
> > + * but then the property queries report error "Invalid function". (duh!)
> > + */
> > +
> > +/*
> >  DEFINE_GUID(GUID_DEVINTERFACE_VOLUME,
> >          0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2,
> >          0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
> > +*/
> > +DEFINE_GUID(GUID_DEVINTERFACE_DISK,
> > +        0x53f56307L, 0xb6bf, 0x11d0, 0x94, 0xf2,
> > +        0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
> > +
> >
> >  static GuestPCIAddress *get_pci_info(char *guid, Error **errp)
> >  {
> > @@ -497,7 +514,7 @@ static GuestPCIAddress *get_pci_info(char *guid, Error
> > **errp)
> >          goto out;
> >      }
> >
> > -    dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, 0, 0,
> > +    dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0,
> >                                     DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
> >      if (dev_info == INVALID_HANDLE_VALUE) {
> >          error_setg_win32(errp, GetLastError(), "failed to get devices
> > tree");
> > @@ -637,20 +654,20 @@ static void get_single_disk_info(char *name,
> > GuestDiskAddress *disk,
> >  {
> >      SCSI_ADDRESS addr, *scsi_ad;
> >      DWORD len;
> > -    HANDLE vol_h;
> > +    HANDLE disk_h;
> >      Error *local_err = NULL;
> >
> >      scsi_ad = &addr;
> >
> >      g_debug("getting disk info for: %s", name);
> > -    vol_h = CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
> > +    disk_h = CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
> >                         0, NULL);
> > -    if (vol_h == INVALID_HANDLE_VALUE) {
> > -        error_setg_win32(errp, GetLastError(), "failed to open volume");
> > -        goto err;
> > +    if (disk_h == INVALID_HANDLE_VALUE) {
> > +        error_setg_win32(errp, GetLastError(), "failed to open disk");
> > +        return;
> >      }
> >
> > -    get_disk_properties(vol_h, disk, &local_err);
> > +    get_disk_properties(disk_h, disk, &local_err);
> >      if (local_err) {
> >          error_propagate(errp, local_err);
> >          goto err_close;
> > @@ -668,7 +685,7 @@ static void get_single_disk_info(char *name,
> > GuestDiskAddress *disk,
> >           * according to Microsoft docs
> >           *
> > https://technet.microsoft.com/en-us/library/ee851589(v=ws.10).aspx */
> >          g_debug("getting pci-controller info");
> > -        if (DeviceIoControl(vol_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0,
> > scsi_ad,
> > +        if (DeviceIoControl(disk_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0,
> > scsi_ad,
> >                              sizeof(SCSI_ADDRESS), &len, NULL)) {
> >              disk->unit = addr.Lun;
> >              disk->target = addr.TargetId;
> > @@ -699,8 +716,7 @@ static void get_single_disk_info(char *name,
> > GuestDiskAddress *disk,
> >      }
> >
> >  err_close:
> > -    CloseHandle(vol_h);
> > -err:
> > +    CloseHandle(disk_h);
> >      return;
> >  }
> >
> > @@ -712,6 +728,10 @@ static GuestDiskAddressList
> > *build_guest_disk_info(char *guid, Error **errp)
> >      Error *local_err = NULL;
> >      GuestDiskAddressList *list = NULL, *cur_item = NULL;
> >      GuestDiskAddress *disk = NULL;
> > +    int i;
> > +    HANDLE vol_h;
> > +    DWORD size;
> > +    PVOLUME_DISK_EXTENTS extents = NULL;
> >
> >      /* strip final backslash */
> >      char *name = g_strdup(guid);
> > @@ -719,19 +739,89 @@ static GuestDiskAddressList
> > *build_guest_disk_info(char *guid, Error **errp)
> >          name[strlen(name) - 1] = 0;
> >      }
> >
> > -    disk = g_malloc0(sizeof(GuestDiskAddress));
> > -    get_single_disk_info(name, disk, &local_err);
> > -    if (local_err) {
> > -        error_propagate(errp, local_err);
> > +    g_debug("opening %s", name);
> > +    vol_h = CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
> > +                       0, NULL);
> > +    if (vol_h == INVALID_HANDLE_VALUE) {
> > +        error_setg_win32(errp, GetLastError(), "failed to open volume");
> >          goto out;
> >      }
> >
> > -    cur_item = g_malloc0(sizeof(*list));
> > -    cur_item->value = disk;
> > -    disk = NULL;
> > -    list = cur_item;
> > +    /* Get list of extents */
> > +    g_debug("getting disk extents");
> > +    size = sizeof(VOLUME_DISK_EXTENTS);
> > +    extents = g_malloc0(size);
> > +    if (!DeviceIoControl(vol_h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
> > NULL,
> > +                         0, extents, size, NULL, NULL)) {
> > +        DWORD last_err = GetLastError();
> > +        if (last_err == ERROR_MORE_DATA) {
> > +            /* Try once more with big enough buffer */
> > +            size = sizeof(VOLUME_DISK_EXTENTS)
> > +                + extents->NumberOfDiskExtents*sizeof(DISK_EXTENT);
> > +            g_free(extents);
> > +            extents = g_malloc0(size);
> > +            if (!DeviceIoControl(
> > +                    vol_h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL,
> > +                    0, extents, size, NULL, NULL)) {
> > +                error_setg_win32(errp, GetLastError(),
> > +                    "failed to get disk extents");
> > +                return NULL;
> > +            }
> > +        } else if (last_err == ERROR_INVALID_FUNCTION) {
> > +            /* Possibly CD-ROM or a shared drive. Try to pass the volume
> > */
> > +            g_debug("volume not on disk");
> > +            disk = g_malloc0(sizeof(GuestDiskAddress));
> > +            get_single_disk_info(name, disk, &local_err);
> > +            if (local_err) {
> > +                g_debug("failed to get disk info, ignoring error: %s",
> > +                    error_get_pretty(local_err));
> > +                error_free(local_err);
> > +                goto out;
> > +            }
> > +            list = g_malloc0(sizeof(*list));
> > +            list->value = disk;
> > +            disk = NULL;
> > +            list->next = NULL;
> > +            goto out;
> > +        } else {
> > +            error_setg_win32(errp, GetLastError(),
> > +                "failed to get disk extents");
> > +            goto out;
> > +        }
> > +    }
> > +    g_debug("Number of extents: %lu", extents->NumberOfDiskExtents);
> > +
> > +    /* Go through each extent */
> > +    for (i = 0; i < extents->NumberOfDiskExtents; i++) {
> > +        char *disk_name = NULL;
> > +        disk = g_malloc0(sizeof(GuestDiskAddress));
> > +
> > +        /* Disk numbers directly correspond to numbers used in UNCs
> > +         *
> > +         * See documentation for DISK_EXTENT:
> > +         *
> > https://docs.microsoft.com/en-us/windows/desktop/api/winioctl/ns-winioctl-_disk_extent
> > +         *
> > +         * See also Naming Files, Paths and Namespaces:
> > +         *
> > https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#win32-device-namespaces
> > +         */
> > +        disk_name = g_strdup_printf("\\\\.\\PhysicalDrive%lu",
> > +            extents->Extents[i].DiskNumber);
> > +        get_single_disk_info(disk_name, disk, &local_err);
> > +        g_free(disk_name);
> > +        if (local_err) {
> > +            error_propagate(errp, local_err);
> > +            goto out;
> > +        }
> > +        cur_item = g_malloc0(sizeof(*list));
> > +        cur_item->value = disk;
> > +        disk = NULL;
> > +        cur_item->next = list;
> > +        list = cur_item;
> > +    }
> > +
> >
> >  out:
> > +    g_free(extents);
> >      g_free(disk);
> >      g_free(name);
> >
> > --
> > 2.19.0
> >
> >
> >  
> 
> -- 
> Respectfully,
> *Sameeh Jubran*
> *Linkedin <https://il.linkedin.com/pub/sameeh-jubran/87/747/a8a>*
> *Software Engineer @ Daynix <http://www.daynix.com>.*


-- 
Tomáš Golembiovský <tgolembi@redhat.com>

  reply	other threads:[~2018-10-10 14:58 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-04 11:22 [Qemu-devel] [PATCH v4 00/11] qga: report serial number and disk node Tomáš Golembiovský
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 01/11] qga-win: fix crashes when PCI info cannot be retrived Tomáš Golembiovský
2018-10-04 13:21   ` Marc-André Lureau
2018-10-09 11:07     ` Tomáš Golembiovský
2018-10-10 23:35   ` Michael Roth
2018-10-11  1:04   ` Eric Blake
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 02/11] qga-win: handle NULL values Tomáš Golembiovský
2018-10-04 13:21   ` Marc-André Lureau
2018-10-10 23:08   ` Michael Roth
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 03/11] build: rename CONFIG_QGA_NTDDDISK to CONFIG_QGA_NTDDSCSI Tomáš Golembiovský
2018-10-04 13:21   ` Marc-André Lureau
2018-10-07  9:29     ` Sameeh Jubran
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 04/11] qga-win: add debugging information Tomáš Golembiovský
2018-10-04 13:21   ` Marc-André Lureau
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 05/11] qga-win: refactor disk properties (bus) Tomáš Golembiovský
2018-10-04 13:21   ` Marc-André Lureau
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 06/11] configure: add test for libudev Tomáš Golembiovský
2018-10-04 13:21   ` Marc-André Lureau
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 07/11] qga: report disk serial number Tomáš Golembiovský
2018-10-04 13:21   ` Marc-André Lureau
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 08/11] qga-win: refactor disk info Tomáš Golembiovský
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 09/11] qga-win: handle multi-disk volumes Tomáš Golembiovský
2018-10-07 12:13   ` Sameeh Jubran
2018-10-10 14:57     ` Tomáš Golembiovský [this message]
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 10/11] qga: return disk device in guest-get-fsinfo Tomáš Golembiovský
2018-10-04 13:20   ` Marc-André Lureau
2018-10-04 11:22 ` [Qemu-devel] [PATCH v4 11/11] qga-win: demystify namespace striping Tomáš Golembiovský
2018-10-04 13:20   ` Marc-André Lureau
2018-10-07 11:03     ` Sameeh Jubran
2018-10-09 12:38     ` Tomáš Golembiovský
2018-10-10 17:19     ` Eric Blake

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=20181010165749.3621ab7e@fiorina \
    --to=tgolembi@redhat.com \
    --cc=marcandre.lureau@redhat.com \
    --cc=mdroth@linux.vnet.ibm.com \
    --cc=okrishtal@virtuozzo.com \
    --cc=qemu-devel@nongnu.org \
    --cc=sameeh@daynix.com \
    --cc=sjubran@redhat.com \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).