From nobody Wed Nov 5 18:23:07 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1536320818612174.9042148730399; Fri, 7 Sep 2018 04:46:58 -0700 (PDT) Received: from localhost ([::1]:38036 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fyFE1-0004uN-Hl for importer@patchew.org; Fri, 07 Sep 2018 07:46:57 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:36717) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fyF9g-0000vS-19 for qemu-devel@nongnu.org; Fri, 07 Sep 2018 07:42:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fyF9b-0004BU-QE for qemu-devel@nongnu.org; Fri, 07 Sep 2018 07:42:27 -0400 Received: from mail-wm0-f67.google.com ([74.125.82.67]:50803) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1fyF9b-0004Ap-JC for qemu-devel@nongnu.org; Fri, 07 Sep 2018 07:42:23 -0400 Received: by mail-wm0-f67.google.com with SMTP id s12-v6so14473712wmc.0 for ; Fri, 07 Sep 2018 04:42:23 -0700 (PDT) Received: from fiorina.redhat.com (ip-94-112-73-67.net.upcbroadband.cz. [94.112.73.67]) by smtp.gmail.com with ESMTPSA id z184-v6sm25239813wmz.0.2018.09.07.04.42.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 07 Sep 2018 04:42:21 -0700 (PDT) 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:in-reply-to :references:mime-version:content-transfer-encoding; bh=RftnKltFhwuP6R629aoH79l3ckMGlV3RUfjayNzzB4Y=; b=izavvCgwfy1aKxUdZyVfhXgVFN6tSe+sJxDfoB2JFCF03rjVqO/mMcWYgd65eocZMd 9b52/6cyioLdHSalD59tjBKAQ9rtJp8LHyhBuzYzYombQKYbxTYzKil+ftpiqRn9LQPP +baCmUPC2JPsf/+s1IyYU2ZFVe6e5vxiNxf+cbrXw/heLeEVPwFTnGOPJn6D28aAisPj +99IH4vllvti+9f6P95UMKqGE1fe5SRe1T6foNzgp79GX1EzziJioTyQkvrFp6Kvx5fn 9KduhZZH17yP/vr2w9YUEo0c8AZFA3PxcBynkGQWXlWMQn4fa2GnWJJEdp7qi7rRJAj0 FvzA== X-Gm-Message-State: APzg51Duf8/xUi7KN1GV7bdTb+dlx1vvFdKG9UpDPgvpEiT7uiT/H0U9 QHd35goyAi96ssXjVrqjN06FYSyWIKQ= X-Google-Smtp-Source: ANB0VdZB2/7shPB7pIHkiTBg7v257GnrYeRAg9muEson4VNmhnIVYq8rmcfMedy6B2v/3AdNiC3UAg== X-Received: by 2002:a1c:4c0c:: with SMTP id z12-v6mr5365208wmf.57.1536320541938; Fri, 07 Sep 2018 04:42:21 -0700 (PDT) From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= To: qemu-devel@nongnu.org Date: Fri, 7 Sep 2018 13:42:13 +0200 Message-Id: <88c65dd59a7bbf55ad055447cccf4be39fcb824b.1536320522.git.tgolembi@redhat.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 74.125.82.67 Subject: [Qemu-devel] [PATCH v3 5/5] qga: return disk device in guest-get-fsinfo 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: Olga Krishtal , =?UTF-8?q?Tom=C3=A1=C5=A1=20Golembiovsk=C3=BD?= , Michael Roth , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RDMRC_1 RSF_0 Z_629925259 SPT_0 Report device node of the disk. It is implemented for Linux (needs udev) and Windows. The node is reported e.g. as "/dev/sda2" on Linux and as "\\?\PhysicalDriveX" on Windows. As part of this effort the Windows code was changed to probe 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=C3=A1=C5=A1 Golembiovsk=C3=BD --- qga/commands-posix.c | 7 +- qga/commands-win32.c | 163 +++++++++++++++++++++++++++++++++++-------- qga/qapi-schema.json | 3 +- 3 files changed, 142 insertions(+), 31 deletions(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 37fedd123b..d0d6ba49cb 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -947,7 +947,12 @@ static void build_guest_fsinfo_for_real_device(char co= nst *syspath, if (udev =3D=3D NULL || udevice =3D=3D NULL) { g_debug("failed to query udev"); } else { - const char *serial; + const char *devnode, *serial; + devnode =3D udev_device_get_devnode(udevice); + if (devnode !=3D NULL) { + disk->dev =3D g_strdup(devnode); + disk->has_dev =3D true; + } serial =3D udev_device_get_property_value(udevice, "ID_SERIAL"); if (serial !=3D NULL && *serial !=3D 0) { disk->serial =3D g_strdup(serial); diff --git a/qga/commands-win32.c b/qga/commands-win32.c index fa186154a8..2cde6bd0af 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]; } =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); + =20 static GuestPCIAddress *get_pci_info(char *guid, Error **errp) { @@ -497,7 +514,7 @@ static GuestPCIAddress *get_pci_info(char *guid, Error = **errp) goto out; } =20 - dev_info =3D SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, 0, 0, + dev_info =3D SetupDiGetClassDevs(&GUID_DEVINTERFACE_DISK, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); if (dev_info =3D=3D INVALID_HANDLE_VALUE) { error_setg_win32(errp, GetLastError(), "failed to get devices tree= "); @@ -632,31 +649,24 @@ out_free: return; } =20 -/* VSS provider works with volumes, thus there is no difference if - * the volume consist of spanned disks. Info about the first disk in the - * volume is returned for the spanned disk group (LVM) */ -static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **err= p) +static void get_single_disk_info(GuestDiskAddress *disk, Error **errp) { - GuestDiskAddressList *list =3D NULL; - GuestDiskAddress *disk; SCSI_ADDRESS addr, *scsi_ad; DWORD len; - HANDLE vol_h; + HANDLE disk_h; Error *local_err =3D NULL; =20 scsi_ad =3D &addr; - char *name =3D g_strndup(guid, strlen(guid)-1); =20 - g_debug("getting disk info for: %s", name); - vol_h =3D CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, + g_debug("getting disk info for: %s", disk->dev); + disk_h =3D CreateFile(disk->dev, 0, FILE_SHARE_READ, NULL, OPEN_EXISTI= NG, 0, NULL); - if (vol_h =3D=3D INVALID_HANDLE_VALUE) { - error_setg_win32(errp, GetLastError(), "failed to open volume"); - goto err; + if (disk_h =3D=3D INVALID_HANDLE_VALUE) { + error_setg_win32(errp, GetLastError(), "failed to open disk"); + return; } =20 - disk =3D g_malloc0(sizeof(*disk)); - 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; @@ -674,20 +684,20 @@ static GuestDiskAddressList *build_guest_disk_info(ch= ar *guid, Error **errp) * according to Microsoft docs * https://technet.microsoft.com/en-us/library/ee851589(v=3Dws.10)= .aspx */ g_debug("getting pci-controller info"); - if (DeviceIoControl(vol_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsi_a= d, + if (DeviceIoControl(disk_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsi_= ad, sizeof(SCSI_ADDRESS), &len, NULL)) { - Error *local_err =3D NULL; disk->unit =3D addr.Lun; disk->target =3D addr.TargetId; disk->bus =3D addr.PathId; g_debug("unit=3D%lld target=3D%lld bus=3D%lld", disk->unit, disk->target, disk->bus); - disk->pci_controller =3D get_pci_info(name, &local_err); + disk->pci_controller =3D get_pci_info(disk->dev, &local_err); =20 if (local_err) { g_debug("failed to get PCI controller info: %s", error_get_pretty(local_err)); error_free(local_err); + local_err =3D NULL; } else if (disk->pci_controller !=3D NULL) { g_debug("pci: domain=3D%lld bus=3D%lld slot=3D%lld functio= n=3D%lld", disk->pci_controller->domain, @@ -704,19 +714,107 @@ static GuestDiskAddressList *build_guest_disk_info(c= har *guid, Error **errp) disk->pci_controller =3D g_malloc0(sizeof(GuestPCIAddress)); } =20 - list =3D g_malloc0(sizeof(*list)); - list->value =3D disk; - list->next =3D NULL; - CloseHandle(vol_h); - return list; - err_close: + CloseHandle(disk_h); + return; +} + +static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **err= p) +{ + Error *local_err =3D NULL; + GuestDiskAddressList *list =3D NULL, *cur_item =3D NULL; + GuestDiskAddress *disk =3D NULL; + int i; + HANDLE vol_h; + DWORD size; + PVOLUME_DISK_EXTENTS extents =3D NULL; + + /* strip final backslash */ + char *name =3D g_strndup(guid, strlen(guid)-1); + + g_debug("opening %s", name); + vol_h =3D CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, + 0, NULL); + if (vol_h =3D=3D INVALID_HANDLE_VALUE) { + error_setg_win32(errp, GetLastError(), "failed to open volume"); + goto out; + } + + /* Get list of extents */ + g_debug("getting disk extents"); + size =3D sizeof(VOLUME_DISK_EXTENTS); + extents =3D g_malloc0(size); + if (!DeviceIoControl(vol_h, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS, NULL, + 0, extents, size, NULL, NULL)) { + DWORD last_err =3D GetLastError(); + if (last_err =3D=3D ERROR_MORE_DATA) { + /* Try once more with big enough buffer */ + size =3D sizeof(VOLUME_DISK_EXTENTS) + + extents->NumberOfDiskExtents * sizeof(DISK_EXTENT); + g_free(extents); + extents =3D 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 =3D=3D ERROR_INVALID_FUNCTION) { + /* Possibly CD-ROM or a shared drive. Try to pass the volume */ + g_debug("volume not on disk"); + disk =3D g_malloc0(sizeof(GuestDiskAddress)); + disk->has_dev =3D true; + disk->dev =3D g_strdup(name); + get_single_disk_info(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 =3D g_malloc0(sizeof(*list)); + list->value =3D disk; + disk =3D NULL; + list->next =3D NULL; + goto out; + } else { + error_setg_win32(errp, GetLastError(), "failed to get disk ext= ents"); + goto out; + } + } + g_debug("Number of extents: %lu", extents->NumberOfDiskExtents); + + /* Go through each extent */ + for (i =3D 0; i < extents->NumberOfDiskExtents; i++) { + disk =3D 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/n= s-winioctl-_disk_extent + */ + disk->has_dev =3D true; + disk->dev =3D g_strdup_printf("\\\\?\\PhysicalDrive%lu", + extents->Extents[i].DiskNumber); + + get_single_disk_info(disk, &local_err); + if (local_err) { + error_propagate(errp, local_err); + goto out; + } + cur_item =3D g_malloc0(sizeof(*list)); + cur_item->value =3D disk; + disk =3D NULL; + cur_item->next =3D list; + list =3D cur_item; + } + + +out: + g_free(extents); g_free(disk); - CloseHandle(vol_h); -err: g_free(name); =20 - return NULL; + return list; } =20 #else @@ -783,6 +881,12 @@ static GuestFilesystemInfo *build_guest_fsinfo(char *g= uid, Error **errp) } fs->type =3D g_strdup(fs_name); fs->disk =3D build_guest_disk_info(guid, errp); + if (fs->disk =3D=3D NULL) { + g_free(fs); + fs =3D NULL; + goto free; + } + free: g_free(mnt_point); return fs; @@ -803,7 +907,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **e= rrp) do { GuestFilesystemInfo *info =3D build_guest_fsinfo(guid, errp); if (info =3D=3D NULL) { - continue; + goto out; } new =3D g_malloc(sizeof(*ret)); new->value =3D info; @@ -815,6 +919,7 @@ GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **e= rrp) error_setg_win32(errp, GetLastError(), "failed to find next volume= "); } =20 +out: FindVolumeClose(vol_h); return ret; } diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index 3bcda6257e..c6725b3ec8 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -835,6 +835,7 @@ # @target: target id # @unit: unit id # @serial: serial number (since: 3.1) +# @dev: device node (POSIX) or device UNC (Windows) (since: 3.1) # # Since: 2.2 ## @@ -842,7 +843,7 @@ 'data': {'pci-controller': 'GuestPCIAddress', 'bus-type': 'GuestDiskBusType', 'bus': 'int', 'target': 'int', 'unit': 'int', - '*serial': 'str'} } + '*serial': 'str', '*dev': 'str'} } =20 ## # @GuestFilesystemInfo: --=20 2.18.0