From patchwork Wed Oct 31 14:19:15 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Michael Roth X-Patchwork-Id: 991446 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=nongnu.org (client-ip=2001:4830:134:3::11; helo=lists.gnu.org; envelope-from=qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linux.vnet.ibm.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="i3JjbzbO"; dkim-atps=neutral Received: from lists.gnu.org (lists.gnu.org [IPv6:2001:4830:134:3::11]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42lVzf2k4Dz9s2P for ; Thu, 1 Nov 2018 01:27:41 +1100 (AEDT) Received: from localhost ([::1]:59909 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gHrT7-00079N-F5 for incoming@patchwork.ozlabs.org; Wed, 31 Oct 2018 10:27:37 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:33387) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1gHrMa-0000qB-EP for qemu-devel@nongnu.org; Wed, 31 Oct 2018 10:20:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1gHrMY-0007BI-Kd for qemu-devel@nongnu.org; Wed, 31 Oct 2018 10:20:52 -0400 Received: from mail-ot1-x330.google.com ([2607:f8b0:4864:20::330]:45632) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1gHrMY-00074C-9Q for qemu-devel@nongnu.org; Wed, 31 Oct 2018 10:20:50 -0400 Received: by mail-ot1-x330.google.com with SMTP id g10so3611733otl.12 for ; Wed, 31 Oct 2018 07:20:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=q4qvYUHQbKVfk7EWyk8ZHhYnBemb39mILFxX0uRYWYU=; b=i3JjbzbOe2zUd/6qYCMvqSgl5iTbGQApToI1l4XnZe3TtObADTcSzLNvKPzULKaAqk VtyaZdckYdhn/z+9uCGHtXnLJPKe3vhoMu4SSgfSeY4509FbY10iV4T76nXQgHmYsxBb FpuAC194cEtpu0TMmMAuV6nr0bjB8sG4RYnLyRyA89QAIu2iBx72l/M10ezcKxdWOHG+ yaKB5hohrBlxc+7iAnT04HM42bq/AV0Tp9rs+mPZCPsfK3yGkp54Dbrb0UyKNwGZ0mtn r/F4/niupYcOAQilR4VtxuoyvuPVYq9kLMejJ5fc6ad3xWlwPV43M38NgOUVq47PO6zJ C0eA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; bh=q4qvYUHQbKVfk7EWyk8ZHhYnBemb39mILFxX0uRYWYU=; b=rvNtdT/4joKbJebl2vea/tRYluga37WlCqZD46+dd5lE1JUa3r5LvwiEZYNUQ9nKm5 f1r8EkmPP1zDQMnUwmUON3uQ2nV3fCnV1XgMxGua0A3tLHpND3basRGdC5aeTpJ0eh/h gYvSCbLXCbXjjFTi1rzOQKEuIGqumnU73o5kdUowu9qwHaQ+oFw5nCVUoGaOsUZ7U3xV ymDeRVyMZFq7MUiuovLjAlugGOAeXGhfCeZfQCR4t7F0m0hUBc/aZWgScU8DgXSwOxLk 4tAEgwDOJPlqOR3Q8ITDNJk3Y+4VCGsJn8Lm1r3haw1jI0QcyQxKP04FProTOZS/Zrqb ABPA== X-Gm-Message-State: AGRZ1gJRhIb3sCXZukzvjSDQyR8O30T/o3q5KywCItO/zFTm1KcavYQ1 +1bi7L0Oy0/jdW3hQ4fwhn2VrGDa X-Google-Smtp-Source: AJdET5dDPtE8g0R2Om+RXILVI7f414U1RZEPY/GVCjUHo4ONBU8QwOJ2PhJLn4ImHj6NL8cWPe1UXw== X-Received: by 2002:a9d:388c:: with SMTP id p12mr2026351otc.158.1540995637530; Wed, 31 Oct 2018 07:20:37 -0700 (PDT) Received: from localhost (76-251-165-188.lightspeed.austtx.sbcglobal.net. [76.251.165.188]) by smtp.gmail.com with ESMTPSA id 111sm23000172otf.51.2018.10.31.07.20.36 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Wed, 31 Oct 2018 07:20:36 -0700 (PDT) From: Michael Roth To: qemu-devel@nongnu.org Date: Wed, 31 Oct 2018 09:19:15 -0500 Message-Id: <20181031141925.30026-15-mdroth@linux.vnet.ibm.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20181031141925.30026-1-mdroth@linux.vnet.ibm.com> References: <20181031141925.30026-1-mdroth@linux.vnet.ibm.com> MIME-Version: 1.0 X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2607:f8b0:4864:20::330 Subject: [Qemu-devel] [PULL v3 14/24] qga-win: handle multi-disk volumes 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: peter.maydell@linaro.org, =?utf-8?b?VG9tw6HFoSBHb2xlbWJpb3Zza8O9?= Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: "Qemu-devel" From: Tomáš Golembiovský 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ý Signed-off-by: Michael Roth --- 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 21a88d31e1..90432bbfce 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -491,9 +491,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) { @@ -517,7 +534,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"); @@ -672,20 +689,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; @@ -714,7 +731,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; @@ -725,8 +742,7 @@ static void get_single_disk_info(char *name, GuestDiskAddress *disk, } err_close: - CloseHandle(vol_h); -err: + CloseHandle(disk_h); return; } @@ -738,6 +754,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); @@ -745,20 +765,90 @@ 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: qapi_free_GuestDiskAddress(disk); + g_free(extents); g_free(name); return list;