From nobody Wed Jun 26 12:31:19 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) client-ip=209.51.188.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zoho.com: domain of gnu.org designates 209.51.188.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org Return-Path: Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mx.zohomail.com with SMTPS id 1547456695489323.12595155251904; Mon, 14 Jan 2019 01:04:55 -0800 (PST) Received: from localhost ([127.0.0.1]:45748 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1giyAw-0004Fl-BD for importer@patchew.org; Mon, 14 Jan 2019 04:04:54 -0500 Received: from eggs.gnu.org ([209.51.188.92]:59795) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1giy9q-0003nA-DF for qemu-devel@nongnu.org; Mon, 14 Jan 2019 04:03:50 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1giy9o-0001cR-Gc for qemu-devel@nongnu.org; Mon, 14 Jan 2019 04:03:46 -0500 Received: from mail-io1-xd43.google.com ([2607:f8b0:4864:20::d43]:40422) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1giy9o-0001b0-59 for qemu-devel@nongnu.org; Mon, 14 Jan 2019 04:03:44 -0500 Received: by mail-io1-xd43.google.com with SMTP id k2so17024126iog.7 for ; Mon, 14 Jan 2019 01:03:42 -0800 (PST) Received: from localhost.localdomain ([76.14.16.91]) by smtp.gmail.com with ESMTPSA id n129sm5344031itb.20.2019.01.14.01.03.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Mon, 14 Jan 2019 01:03:40 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=scalecomputing-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id; bh=c9i93nJRRJnR5YmaqPBLhDqRNDzUJXKXyTG6bBQ+L0o=; b=E+X87yUHDQDfG3KxDZgP0cBAGMf7fjnxBVCxDqk8G2vHDUOyxS5ginJnDlNQZhLIIz tKitJaTj3MExoKF+RhbiKILKdheSuA4q5HusuP6tAn7vK7YxN/A90sbfhIjvZnh+zsL5 4/HyfVRIuJ4rJ96Eym91Qb3y0+hAjGgzhqJkYEtLqDCvRhKtSlMrIx8CinpbLDPK8EYB axgc0y5AfWCTFLXF4e6zDM2T+y/3THaJNPsyScV2mWYo8hcbtukli0MvJ2743XcBd7EE JDlsQNH3zHeUIIUq+IDcDl+95raUEGjUYMArFOeLXxTheR0aDTDYhIDV3czRW1DaqmkY GM1w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=c9i93nJRRJnR5YmaqPBLhDqRNDzUJXKXyTG6bBQ+L0o=; b=o8Ob5Wxo1X0oCW1XJJ05Ds22t6YuazRLi3gnTkosen42tpFjHdcskkXuSTS5Rcu2Rw 5YDw8DoQaXnQtceyydl924fhEGHh1dNMKvG46R11mrJEfFDlNlbg+GzxfaELQtMkEnTL jKa/I6vSgfhMlFDmYesf4rshp3CIZs0PbaQ/ZFOe1ZM4Yasg3ScsFeUpzxUt3UsY3o8E m4xYx6hkNc6lvRc72G562OxYJ8EIl6WGdiZE5LwHSEOYi3QV2vHVfZFfURqhdOfAUhUn dLsUMfxXXcetyZz9As1VBLPCO/n+D83O6WilnSYN4SsU/zuhM9EXWflH7od/w/SkgcOg UfeQ== X-Gm-Message-State: AJcUukfgUvxeSE0Hy4e61E35w9PJ+Umr5H6rNBT/a1xB5swekNRAjGY+ AdFbAuvlWWWLyGF1s6j2hE8WRFhcv6CuJSls X-Google-Smtp-Source: ALg8bN4iTpQ89Ldlvm/v4SPv4snzx0PRwTeG7cdIre1Fn4+nBZrjhCkomZzZ48Qa1F0oq8TbbyIGPQ== X-Received: by 2002:a6b:5012:: with SMTP id e18mr16558785iob.73.1547456620891; Mon, 14 Jan 2019 01:03:40 -0800 (PST) From: mhines@scalecomputing.com To: qemu-devel@nongnu.org Date: Mon, 14 Jan 2019 01:03:23 -0800 Message-Id: <20190114090324.16176-1-mhines@scalecomputing.com> X-Mailer: git-send-email 2.11.0.windows.1 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::d43 Subject: [Qemu-devel] [PATCH] QGA: Fix guest-get-fsinfo PCI address collection in Windows X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matt Hines , Michael Roth Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail-DKIM: fail (Header signature does not verify) Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: Matt Hines Signed-off-by: Matt Hines --- configure | 2 +- qga/commands-win32.c | 295 +++++++++++++++++++++++++++++++++--------------= ---- qga/qapi-schema.json | 3 +- 3 files changed, 197 insertions(+), 103 deletions(-) diff --git a/configure b/configure index 5b1d83ea26..46f21c089f 100755 --- a/configure +++ b/configure @@ -4694,7 +4694,7 @@ int main(void) { EOF if compile_prog "" "" ; then guest_agent_ntddscsi=3Dyes - libs_qga=3D"-lsetupapi $libs_qga" + libs_qga=3D"-lsetupapi -lcfgmgr32 $libs_qga" fi fi =20 diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 62e1b51dfe..8c8f3a2c65 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #endif #include @@ -491,56 +492,29 @@ static GuestDiskBusType find_bus_type(STORAGE_BUS_TYP= E bus) return win2qemu[(int)bus]; } =20 -/* 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); +DEFINE_GUID(GUID_DEVINTERFACE_STORAGEPORT, + 0x2accfe60L, 0xc130, 0x11d2, 0xb0, 0x82, + 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b); =20 - -static GuestPCIAddress *get_pci_info(char *guid, Error **errp) +static GuestPCIAddress *get_pci_info(int number, Error **errp) { HDEVINFO dev_info; SP_DEVINFO_DATA dev_info_data; - DWORD size =3D 0; + SP_DEVICE_INTERFACE_DATA dev_iface_data; + HANDLE dev_file; int i; - char dev_name[MAX_PATH]; - char *buffer =3D NULL; GuestPCIAddress *pci =3D NULL; - char *name =3D NULL; bool partial_pci =3D false; + pci =3D g_malloc0(sizeof(*pci)); pci->domain =3D -1; pci->slot =3D -1; pci->function =3D -1; pci->bus =3D -1; =20 - if (g_str_has_prefix(guid, "\\\\.\\") || - g_str_has_prefix(guid, "\\\\?\\")) { - name =3D g_strdup(guid + 4); - } else { - name =3D g_strdup(guid); - } - - if (!QueryDosDevice(name, dev_name, ARRAY_SIZE(dev_name))) { - error_setg_win32(errp, GetLastError(), "failed to get dos device n= ame"); - goto out; - } - dev_info =3D SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (dev_info =3D=3D INVALID_HANDLE_VALUE) { @@ -550,90 +524,208 @@ static GuestPCIAddress *get_pci_info(char *guid, Err= or **errp) =20 g_debug("enumerating devices"); dev_info_data.cbSize =3D sizeof(SP_DEVINFO_DATA); + dev_iface_data.cbSize =3D sizeof(SP_DEVICE_INTERFACE_DATA); for (i =3D 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++)= { - DWORD addr, bus, slot, data, size2; - int func, dev; - while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, - SPDRP_PHYSICAL_DEVICE_OBJECT_N= AME, - &data, (PBYTE)buffer, size, - &size2)) { - size =3D MAX(size, size2); - if (GetLastError() =3D=3D ERROR_INSUFFICIENT_BUFFER) { - g_free(buffer); - /* Double the size to avoid problems on - * W2k MBCS systems per KB 888609. - * https://support.microsoft.com/en-us/kb/259695 */ - buffer =3D g_malloc(size * 2); - } else { + PSP_DEVICE_INTERFACE_DETAIL_DATA pdev_iface_detail_data =3D NULL; + STORAGE_DEVICE_NUMBER sdn; + char *parent_dev_id =3D NULL; + HDEVINFO parent_dev_info; + SP_DEVINFO_DATA parent_dev_info_data; + DWORD j; + DWORD size =3D 0; + + g_debug("getting device path"); + if (SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, + &GUID_DEVINTERFACE_DISK, 0, + &dev_iface_data)) { + while (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_iface_d= ata, + pdev_iface_detail_data, + size, &size, + &dev_info_data)) { + if (GetLastError() =3D=3D ERROR_INSUFFICIENT_BUFFER) { + pdev_iface_detail_data =3D g_malloc(size); + pdev_iface_detail_data->cbSize =3D + sizeof(*pdev_iface_detail_data); + } else { + error_setg_win32(errp, GetLastError(), + "failed to get device interfaces"); + goto free_dev_info; + } + } + + dev_file =3D CreateFile(pdev_iface_detail_data->DevicePath, 0, + FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, + NULL); + g_free(pdev_iface_detail_data); + + if (!DeviceIoControl(dev_file, IOCTL_STORAGE_GET_DEVICE_NUMBER, + NULL, 0, &sdn, sizeof(sdn), &size, NULL))= { + CloseHandle(dev_file); error_setg_win32(errp, GetLastError(), - "failed to get device name"); + "failed to get device slot number"); goto free_dev_info; } - } =20 - if (g_strcmp0(buffer, dev_name)) { - continue; + CloseHandle(dev_file); + if (sdn.DeviceNumber !=3D number) { + continue; + } + } else { + error_setg_win32(errp, GetLastError(), + "failed to get device interfaces"); + goto free_dev_info; } - g_debug("found device %s", dev_name); =20 - /* There is no need to allocate buffer in the next functions. The = size - * is known and ULONG according to - * https://support.microsoft.com/en-us/kb/253232 - * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543= 095(v=3Dvs.85).aspx - */ - if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, - SPDRP_BUSNUMBER, &data, (PBYTE)&bus, size, NULL)) { - debug_error("failed to get bus"); - bus =3D -1; - partial_pci =3D true; + g_debug("found device slot %d. Getting storage controller", number= ); + { + CONFIGRET cr; + DEVINST dev_inst, parent_dev_inst; + ULONG dev_id_size =3D 0; + + size =3D 0; + while (!SetupDiGetDeviceInstanceId(dev_info, &dev_info_data, + parent_dev_id, size, &size)= ) { + if (GetLastError() =3D=3D ERROR_INSUFFICIENT_BUFFER) { + parent_dev_id =3D g_malloc(size); + } else { + error_setg_win32(errp, GetLastError(), + "failed to get device instance ID"); + goto out; + } + } + + /* + * CM API used here as opposed to + * SetupDiGetDeviceProperty(..., DEVPKEY_Device_Parent, ...) + * which exports are only available in mingw-w64 6+ + */ + cr =3D CM_Locate_DevInst(&dev_inst, parent_dev_id, 0); + if (cr !=3D CR_SUCCESS) { + g_error("CM_Locate_DevInst failed with code %lx", cr); + error_setg_win32(errp, GetLastError(), + "failed to get device instance"); + goto out; + } + cr =3D CM_Get_Parent(&parent_dev_inst, dev_inst, 0); + if (cr !=3D CR_SUCCESS) { + g_error("CM_Get_Parent failed with code %lx", cr); + error_setg_win32(errp, GetLastError(), + "failed to get parent device instance"); + goto out; + } + + cr =3D CM_Get_Device_ID_Size(&dev_id_size, parent_dev_inst, 0); + if (cr !=3D CR_SUCCESS) { + g_error("CM_Get_Device_ID_Size failed with code %lx", cr); + error_setg_win32(errp, GetLastError(), + "failed to get parent device ID length"); + goto out; + } + + ++dev_id_size; + if (dev_id_size > size) { + g_free(parent_dev_id); + parent_dev_id =3D g_malloc(dev_id_size); + } + + cr =3D CM_Get_Device_ID(parent_dev_inst, parent_dev_id, dev_id= _size, + 0); + if (cr !=3D CR_SUCCESS) { + g_error("CM_Get_Device_ID failed with code %lx", cr); + error_setg_win32(errp, GetLastError(), + "failed to get parent device ID"); + goto out; + } } =20 - /* The function retrieves the device's address. This value will be - * transformed into device function and number */ - if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, - SPDRP_ADDRESS, &data, (PBYTE)&addr, size, NULL)) { - debug_error("failed to get address"); - addr =3D -1; - partial_pci =3D true; + g_debug("querying storage controller %s for PCI information", + parent_dev_id); + parent_dev_info =3D + SetupDiGetClassDevs(&GUID_DEVINTERFACE_STORAGEPORT, parent_dev= _id, + NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFAC= E); + g_free(parent_dev_id); + + if (parent_dev_info =3D=3D INVALID_HANDLE_VALUE) { + error_setg_win32(errp, GetLastError(), + "failed to get parent device"); + goto out; } =20 - /* This call returns UINumber of DEVICE_CAPABILITIES structure. - * This number is typically a user-perceived slot number. */ - if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, - SPDRP_UI_NUMBER, &data, (PBYTE)&slot, size, NULL)) { - debug_error("failed to get slot"); - slot =3D -1; - partial_pci =3D true; + parent_dev_info_data.cbSize =3D sizeof(SP_DEVINFO_DATA); + if (!SetupDiEnumDeviceInfo(parent_dev_info, 0, &parent_dev_info_da= ta)) { + error_setg_win32(errp, GetLastError(), + "failed to get parent device data"); + goto out; } =20 - /* SetupApi gives us the same information as driver with - * IoGetDeviceProperty. According to Microsoft - * https://support.microsoft.com/en-us/kb/253232 - * FunctionNumber =3D (USHORT)((propertyAddress) & 0x0000FFFF); - * DeviceNumber =3D (USHORT)(((propertyAddress) >> 16) & 0x0000FFF= F); - * SPDRP_ADDRESS is propertyAddress, so we do the same.*/ - - if (partial_pci) { - pci->domain =3D -1; - pci->slot =3D -1; - pci->function =3D -1; - pci->bus =3D -1; - } else { - func =3D ((int) addr =3D=3D -1) ? -1 : addr & 0x0000FFFF; - dev =3D ((int) addr =3D=3D -1) ? -1 : (addr >> 16) & 0x0000FFF= F; - pci->domain =3D dev; - pci->slot =3D (int) slot; - pci->function =3D func; - pci->bus =3D (int) bus; + for (j =3D 0; + SetupDiEnumDeviceInfo(parent_dev_info, j, &parent_dev_info_da= ta); + j++) { + DWORD addr, bus, slot, type; + int func, dev; + + /* There is no need to allocate buffer in the next functions. = The size + * is known and ULONG according to + * https://msdn.microsoft.com/en-us/library/windows/hardware/ff= 543095(v=3Dvs.85).aspx + */ + if (!SetupDiGetDeviceRegistryProperty( + parent_dev_info, &parent_dev_info_data, SPDRP_BUSNUMBER, + &type, (PBYTE)&bus, size, NULL)) { + debug_error("failed to get PCI bus"); + bus =3D -1; + partial_pci =3D true; + } + + /* The function retrieves the device's address. This value wil= l be + * transformed into device function and number */ + if (!SetupDiGetDeviceRegistryProperty( + parent_dev_info, &parent_dev_info_data, SPDRP_ADDRESS, + &type, (PBYTE)&addr, size, NULL)) { + debug_error("failed to get PCI address"); + addr =3D -1; + partial_pci =3D true; + } + + /* This call returns UINumber of DEVICE_CAPABILITIES structure. + * This number is typically a user-perceived slot number. */ + if (!SetupDiGetDeviceRegistryProperty( + parent_dev_info, &parent_dev_info_data, SPDRP_UI_NUMBE= R, + &type, (PBYTE)&slot, size, NULL)) { + debug_error("failed to get PCI slot"); + slot =3D -1; + partial_pci =3D true; + } + + /* SetupApi gives us the same information as driver with + * IoGetDeviceProperty. According to Microsoft + * https://docs.microsoft.com/en-us/windows/desktop/api/setupap= i/nf-setupapi-setupdigetdeviceregistrypropertya + * FunctionNumber =3D (USHORT)((propertyAddress) & 0x0000FFFF); + * DeviceNumber =3D (USHORT)(((propertyAddress) >> 16) & 0x0000= FFFF); + * SPDRP_ADDRESS is propertyAddress, so we do the same.*/ + + if (partial_pci) { + pci->domain =3D -1; + pci->slot =3D -1; + pci->function =3D -1; + pci->bus =3D -1; + continue; + } else { + func =3D ((int)addr =3D=3D -1) ? -1 : addr & 0x0000FFFF; + dev =3D ((int)addr =3D=3D -1) ? -1 : (addr >> 16) & 0x0000= FFFF; + pci->domain =3D dev; + pci->slot =3D (int)slot; + pci->function =3D func; + pci->bus =3D (int)bus; + break; + } } + SetupDiDestroyDeviceInfoList(parent_dev_info); break; } =20 free_dev_info: SetupDiDestroyDeviceInfoList(dev_info); out: - g_free(buffer); - g_free(name); return pci; } =20 @@ -720,7 +812,7 @@ static void get_single_disk_info(GuestDiskAddress *disk= , Error **errp) * if that doesn't hold since that suggests some other unexpected * breakage */ - disk->pci_controller =3D get_pci_info(disk->dev, &local_err); + disk->pci_controller =3D get_pci_info(disk->number, &local_err); if (local_err) { error_propagate(errp, local_err); goto err_close; @@ -736,7 +828,7 @@ static void get_single_disk_info(GuestDiskAddress *disk= , Error **errp) /* We are able to use the same ioctls for different bus types * according to Microsoft docs * https://technet.microsoft.com/en-us/library/ee851589(v=3Dws.10)= .aspx */ - g_debug("getting pci-controller info"); + g_debug("getting SCSI info"); if (DeviceIoControl(disk_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsi_= ad, sizeof(SCSI_ADDRESS), &len, NULL)) { disk->unit =3D addr.Lun; @@ -838,8 +930,9 @@ static GuestDiskAddressList *build_guest_disk_info(char= *guid, Error **errp) * https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-= a-file#win32-device-namespaces */ disk->has_dev =3D true; + disk->number =3D extents->Extents[i].DiskNumber; disk->dev =3D g_strdup_printf("\\\\.\\PhysicalDrive%lu", - extents->Extents[i].DiskNumber); + extents->Extents[i].DiskNumber); =20 get_single_disk_info(disk, &local_err); if (local_err) { diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index c6725b3ec8..0a78fb2e3a 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -836,6 +836,7 @@ # @unit: unit id # @serial: serial number (since: 3.1) # @dev: device node (POSIX) or device UNC (Windows) (since: 3.1) +# @number: device slot index (Windows) # # Since: 2.2 ## @@ -843,7 +844,7 @@ 'data': {'pci-controller': 'GuestPCIAddress', 'bus-type': 'GuestDiskBusType', 'bus': 'int', 'target': 'int', 'unit': 'int', - '*serial': 'str', '*dev': 'str'} } + '*serial': 'str', '*dev': 'str', 'number':'int'} } =20 ## # @GuestFilesystemInfo: --=20 2.11.0.windows.1