From patchwork Thu Nov 18 13:32:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12627063 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3BC55C433F5 for ; Thu, 18 Nov 2021 13:58:07 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BDDF361A88 for ; Thu, 18 Nov 2021 13:58:06 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org BDDF361A88 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=nongnu.org Received: from localhost ([::1]:40348 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mnhvR-0003ad-VA for qemu-devel@archiver.kernel.org; Thu, 18 Nov 2021 08:58:05 -0500 Received: from eggs.gnu.org ([209.51.188.92]:56248) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhYH-0006pz-Pc for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:34:09 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:43203) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhYC-0002W6-Ez for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:34:07 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1637242442; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7lCIBCzyW1VprGHqSSOJCGP/x8FvLGwEVaBdWdWlK9M=; b=ch7bc/9NCqnHkhTssL5Uo70QftVosmGznaRf/OXHttyLotvl/R7I3f86f65dscDOlaNatZ IfzHqVnjcjtRzjCniblb2HEIkMr+1PRL9nQo3823fb+H41BzOArLfWnWDa6OoBjpnizL6H VMkg9D+lrcAgXjIhS4SCLMU7zPq/NS8= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-489-UAUm5lniPHG13bHzkzFzEw-1; Thu, 18 Nov 2021 08:33:59 -0500 X-MC-Unique: UAUm5lniPHG13bHzkzFzEw-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 4216A1006AA6; Thu, 18 Nov 2021 13:33:58 +0000 (UTC) Received: from thinkpad.redhat.com (unknown [10.39.194.176]) by smtp.corp.redhat.com (Postfix) with ESMTP id 715103AEF; Thu, 18 Nov 2021 13:33:23 +0000 (UTC) From: Laurent Vivier To: qemu-devel@nongnu.org Subject: [PATCH v3 1/5] qtest/libqos: add a function to initialize secondary PCI buses Date: Thu, 18 Nov 2021 14:32:21 +0100 Message-Id: <20211118133225.324937-2-lvivier@redhat.com> In-Reply-To: <20211118133225.324937-1-lvivier@redhat.com> References: <20211118133225.324937-1-lvivier@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lvivier@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -34 X-Spam_score: -3.5 X-Spam_bar: --- X-Spam_report: (-3.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.698, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , "Michael S. Tsirkin" , Michael Roth , Juan Quintela , Gerd Hoffmann , Paolo Bonzini , Ani Sinha , Igor Mammedov , Jens Freimann Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Scan the PCI devices to find bridge and set PCI_SECONDARY_BUS and PCI_SUBORDINATE_BUS (algorithm from seabios) Signed-off-by: Laurent Vivier --- include/hw/pci/pci_bridge.h | 8 +++ tests/qtest/libqos/pci.c | 118 ++++++++++++++++++++++++++++++++++++ tests/qtest/libqos/pci.h | 1 + 3 files changed, 127 insertions(+) diff --git a/include/hw/pci/pci_bridge.h b/include/hw/pci/pci_bridge.h index a94d350034bf..30691a6e5728 100644 --- a/include/hw/pci/pci_bridge.h +++ b/include/hw/pci/pci_bridge.h @@ -138,6 +138,7 @@ typedef struct PCIBridgeQemuCap { uint64_t mem_pref_64; /* Prefetchable memory to reserve (64-bit MMIO) */ } PCIBridgeQemuCap; +#define REDHAT_PCI_CAP_TYPE_OFFSET 3 #define REDHAT_PCI_CAP_RESOURCE_RESERVE 1 /* @@ -152,6 +153,13 @@ typedef struct PCIResReserve { uint64_t mem_pref_64; } PCIResReserve; +#define REDHAT_PCI_CAP_RES_RESERVE_BUS_RES 4 +#define REDHAT_PCI_CAP_RES_RESERVE_IO 8 +#define REDHAT_PCI_CAP_RES_RESERVE_MEM 16 +#define REDHAT_PCI_CAP_RES_RESERVE_PREF_MEM_32 20 +#define REDHAT_PCI_CAP_RES_RESERVE_PREF_MEM_64 24 +#define REDHAT_PCI_CAP_RES_RESERVE_CAP_SIZE 32 + int pci_bridge_qemu_reserve_cap_init(PCIDevice *dev, int cap_offset, PCIResReserve res_reserve, Error **errp); diff --git a/tests/qtest/libqos/pci.c b/tests/qtest/libqos/pci.c index e1e96189c821..3f0b18f4750b 100644 --- a/tests/qtest/libqos/pci.c +++ b/tests/qtest/libqos/pci.c @@ -13,6 +13,8 @@ #include "qemu/osdep.h" #include "pci.h" +#include "hw/pci/pci.h" +#include "hw/pci/pci_bridge.h" #include "hw/pci/pci_regs.h" #include "qemu/host-utils.h" #include "qgraph.h" @@ -99,6 +101,122 @@ void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr) g_assert(!addr->device_id || device_id == addr->device_id); } +static uint8_t qpci_find_resource_reserve_capability(QPCIDevice *dev) +{ + uint16_t device_id; + uint8_t cap = 0; + + if (qpci_config_readw(dev, PCI_VENDOR_ID) != PCI_VENDOR_ID_REDHAT) { + return 0; + } + + device_id = qpci_config_readw(dev, PCI_DEVICE_ID); + + if (device_id != PCI_DEVICE_ID_REDHAT_PCIE_RP && + device_id != PCI_DEVICE_ID_REDHAT_BRIDGE) { + return 0; + } + + do { + cap = qpci_find_capability(dev, PCI_CAP_ID_VNDR, cap); + } while (cap && + qpci_config_readb(dev, cap + REDHAT_PCI_CAP_TYPE_OFFSET) != + REDHAT_PCI_CAP_RESOURCE_RESERVE); + if (cap) { + uint8_t cap_len = qpci_config_readb(dev, cap + PCI_CAP_FLAGS); + if (cap_len < REDHAT_PCI_CAP_RES_RESERVE_CAP_SIZE) { + return 0; + } + } + return cap; +} + +static void qpci_secondary_buses_rec(QPCIBus *qbus, int bus, int *pci_bus) +{ + QPCIDevice *dev; + uint16_t class; + uint8_t pribus, secbus, subbus; + int i; + + for (i = 0; i < 32; i++) { + dev = qpci_device_find(qbus, QPCI_DEVFN(bus + i, 0)); + if (dev == NULL) { + continue; + } + class = qpci_config_readw(dev, PCI_CLASS_DEVICE); + if (class == PCI_CLASS_BRIDGE_PCI) { + qpci_config_writeb(dev, PCI_SECONDARY_BUS, 255); + qpci_config_writeb(dev, PCI_SUBORDINATE_BUS, 0); + } + g_free(dev); + } + + for (i = 0; i < 32; i++) { + dev = qpci_device_find(qbus, QPCI_DEVFN(bus + i, 0)); + if (dev == NULL) { + continue; + } + class = qpci_config_readw(dev, PCI_CLASS_DEVICE); + if (class != PCI_CLASS_BRIDGE_PCI) { + continue; + } + + pribus = qpci_config_readb(dev, PCI_PRIMARY_BUS); + if (pribus != bus) { + qpci_config_writeb(dev, PCI_PRIMARY_BUS, bus); + } + + secbus = qpci_config_readb(dev, PCI_SECONDARY_BUS); + (*pci_bus)++; + if (*pci_bus != secbus) { + secbus = *pci_bus; + qpci_config_writeb(dev, PCI_SECONDARY_BUS, secbus); + } + + subbus = qpci_config_readb(dev, PCI_SUBORDINATE_BUS); + qpci_config_writeb(dev, PCI_SUBORDINATE_BUS, 255); + + qpci_secondary_buses_rec(qbus, secbus << 5, pci_bus); + + if (subbus != *pci_bus) { + uint8_t res_bus = *pci_bus; + uint8_t cap = qpci_find_resource_reserve_capability(dev); + + if (cap) { + uint32_t tmp_res_bus; + + tmp_res_bus = qpci_config_readl(dev, cap + + REDHAT_PCI_CAP_RES_RESERVE_BUS_RES); + if (tmp_res_bus != (uint32_t)-1) { + res_bus = tmp_res_bus & 0xFF; + if ((uint8_t)(res_bus + secbus) < secbus || + (uint8_t)(res_bus + secbus) < res_bus) { + res_bus = 0; + } + if (secbus + res_bus > *pci_bus) { + res_bus = secbus + res_bus; + } + } + } + subbus = res_bus; + *pci_bus = res_bus; + } + + qpci_config_writeb(dev, PCI_SUBORDINATE_BUS, subbus); + g_free(dev); + } +} + +int qpci_secondary_buses_init(QPCIBus *bus) +{ + int last_bus = 0; + + qpci_secondary_buses_rec(bus, 0, &last_bus); + + return last_bus; +} + + void qpci_device_enable(QPCIDevice *dev) { uint16_t cmd; diff --git a/tests/qtest/libqos/pci.h b/tests/qtest/libqos/pci.h index ee64fdecbda8..becb800f9e6a 100644 --- a/tests/qtest/libqos/pci.h +++ b/tests/qtest/libqos/pci.h @@ -81,6 +81,7 @@ void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id, void *data); QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn); void qpci_device_init(QPCIDevice *dev, QPCIBus *bus, QPCIAddress *addr); +int qpci_secondary_buses_init(QPCIBus *bus); bool qpci_has_buggy_msi(QPCIDevice *dev); bool qpci_check_buggy_msi(QPCIDevice *dev); From patchwork Thu Nov 18 13:32:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12627053 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7FA10C433F5 for ; Thu, 18 Nov 2021 13:51:16 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0272B61A64 for ; Thu, 18 Nov 2021 13:51:15 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 0272B61A64 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=nongnu.org Received: from localhost ([::1]:50806 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mnhop-00081t-6U for qemu-devel@archiver.kernel.org; Thu, 18 Nov 2021 08:51:15 -0500 Received: from eggs.gnu.org ([209.51.188.92]:56354) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhYr-0007HZ-U7 for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:34:45 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:54305) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhYp-0002Y0-Gx for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:34:45 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1637242476; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=rEiuKmGLt95QF4YviXOb5k/yIarRQJYC/W03G1/cqds=; b=TXXd+Nhqi16iDACc9cXgXM9i1j8acEu12+CU7fL4jvoiJ+0nfEl+2Ds737o7kKb1b+uxyf hq2C0eXKQTNsLnLwuqXwDQTxalKqKijCaBbrQ/vI5QwwwFANqdbCcA1UKyBVjMYUM0ZjTD QmPE5UB9lVZX9iUWNI/rqfoNG16eoHU= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-251--8hgsXwvNWulkMgr7I4flA-1; Thu, 18 Nov 2021 08:34:33 -0500 X-MC-Unique: -8hgsXwvNWulkMgr7I4flA-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id CBC751B18BC5; Thu, 18 Nov 2021 13:34:31 +0000 (UTC) Received: from thinkpad.redhat.com (unknown [10.39.194.176]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9875A19D9B; Thu, 18 Nov 2021 13:33:58 +0000 (UTC) From: Laurent Vivier To: qemu-devel@nongnu.org Subject: [PATCH v3 2/5] tests/qtest: add some tests for virtio-net failover Date: Thu, 18 Nov 2021 14:32:22 +0100 Message-Id: <20211118133225.324937-3-lvivier@redhat.com> In-Reply-To: <20211118133225.324937-1-lvivier@redhat.com> References: <20211118133225.324937-1-lvivier@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lvivier@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -34 X-Spam_score: -3.5 X-Spam_bar: --- X-Spam_report: (-3.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.698, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , "Michael S. Tsirkin" , Michael Roth , Juan Quintela , Gerd Hoffmann , Paolo Bonzini , Ani Sinha , Igor Mammedov , Jens Freimann Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Add test cases to test several error cases that must be generated by invalid failover configuration. Add a combination of coldplug and hotplug test cases to be sure the primary is correctly managed according the presence or not of the STANDBY feature. Signed-off-by: Laurent Vivier --- tests/qtest/meson.build | 3 + tests/qtest/virtio-net-failover.c | 635 ++++++++++++++++++++++++++++++ 2 files changed, 638 insertions(+) create mode 100644 tests/qtest/virtio-net-failover.c diff --git a/tests/qtest/meson.build b/tests/qtest/meson.build index c9d8458062ff..6d66bf522156 100644 --- a/tests/qtest/meson.build +++ b/tests/qtest/meson.build @@ -22,6 +22,9 @@ qtests_generic = \ (config_all_devices.has_key('CONFIG_VIRTIO_SCSI') ? ['fuzz-virtio-scsi-test'] : []) + \ (config_all_devices.has_key('CONFIG_SB16') ? ['fuzz-sb16-test'] : []) + \ (config_all_devices.has_key('CONFIG_SDHCI_PCI') ? ['fuzz-sdcard-test'] : []) + \ + (config_all_devices.has_key('CONFIG_VIRTIO_NET') and \ + config_all_devices.has_key('CONFIG_Q35') and \ + config_all_devices.has_key('CONFIG_VIRTIO_PCI') ? ['virtio-net-failover'] : []) + \ [ 'cdrom-test', 'device-introspect-test', diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c new file mode 100644 index 000000000000..576d4454c3c3 --- /dev/null +++ b/tests/qtest/virtio-net-failover.c @@ -0,0 +1,635 @@ +#include "qemu/osdep.h" +#include "libqos/libqtest.h" +#include "libqos/pci.h" +#include "libqos/pci-pc.h" +#include "qapi/qmp/qdict.h" +#include "qapi/qmp/qlist.h" +#include "qapi/qmp/qjson.h" +#include "libqos/malloc-pc.h" +#include "libqos/virtio-pci.h" +#include "hw/pci/pci.h" + +#define ACPI_PCIHP_ADDR_ICH9 0x0cc0 +#define PCI_EJ_BASE 0x0008 + +#define BASE_MACHINE "-M q35 -nodefaults " \ + "-device pcie-root-port,id=root0,addr=0x1,bus=pcie.0,chassis=1 " \ + "-device pcie-root-port,id=root1,addr=0x2,bus=pcie.0,chassis=2 " + +#define MAC_PRIMARY "52:54:00:11:11:11" +#define MAC_STANDBY "52:54:00:22:22:22" + +static QGuestAllocator guest_malloc; +static QPCIBus *pcibus; + +static QTestState *machine_start(const char *args) +{ + QTestState *qts; + QPCIDevice *dev; + + qts = qtest_init(args); + + pc_alloc_init(&guest_malloc, qts, 0); + pcibus = qpci_new_pc(qts, &guest_malloc); + g_assert(qpci_secondary_buses_init(pcibus) == 2); + + dev = qpci_device_find(pcibus, QPCI_DEVFN(1, 0)); /* root0 */ + g_assert_nonnull(dev); + + qpci_device_enable(dev); + qpci_iomap(dev, 4, NULL); + + g_free(dev); + + dev = qpci_device_find(pcibus, QPCI_DEVFN(2, 0)); /* root1 */ + g_assert_nonnull(dev); + + qpci_device_enable(dev); + qpci_iomap(dev, 4, NULL); + + g_free(dev); + + return qts; +} + +static void machine_stop(QTestState *qts) +{ + qpci_free_pc(pcibus); + alloc_destroy(&guest_malloc); + qtest_quit(qts); +} + +static void test_error_id(void) +{ + QTestState *qts; + QDict *resp; + QDict *err; + + qts = machine_start(BASE_MACHINE + "-device virtio-net,bus=root0,id=standby0,failover=on"); + + resp = qtest_qmp(qts, "{'execute': 'device_add'," + "'arguments': {" + "'driver': 'virtio-net'," + "'bus': 'root1'," + "'failover_pair_id': 'standby0'" + "} }"); + g_assert(qdict_haskey(resp, "error")); + + err = qdict_get_qdict(resp, "error"); + g_assert(qdict_haskey(err, "desc")); + + g_assert_cmpstr(qdict_get_str(err, "desc"), ==, + "Device with failover_pair_id needs to have id"); + + qobject_unref(resp); + + machine_stop(qts); +} + +static void test_error_pcie(void) +{ + QTestState *qts; + QDict *resp; + QDict *err; + + qts = machine_start(BASE_MACHINE + "-device virtio-net,bus=root0,id=standby0,failover=on"); + + resp = qtest_qmp(qts, "{'execute': 'device_add'," + "'arguments': {" + "'driver': 'virtio-net'," + "'id': 'primary0'," + "'bus': 'pcie.0'," + "'failover_pair_id': 'standby0'" + "} }"); + g_assert(qdict_haskey(resp, "error")); + + err = qdict_get_qdict(resp, "error"); + g_assert(qdict_haskey(err, "desc")); + + g_assert_cmpstr(qdict_get_str(err, "desc"), ==, + "Bus 'pcie.0' does not support hotplugging"); + + qobject_unref(resp); + + machine_stop(qts); +} + +static QDict *find_device(QDict *bus, const char *name) +{ + const QObject *obj; + QList *devices; + QList *list; + + devices = qdict_get_qlist(bus, "devices"); + if (devices == NULL) { + return NULL; + } + + list = qlist_copy(devices); + while ((obj = qlist_pop(list))) { + QDict *device; + + device = qobject_to(QDict, obj); + + if (qdict_haskey(device, "pci_bridge")) { + QDict *bridge; + QDict *bridge_device; + + bridge = qdict_get_qdict(device, "pci_bridge"); + + if (qdict_haskey(bridge, "devices")) { + bridge_device = find_device(bridge, name); + if (bridge_device) { + qobject_unref(list); + return bridge_device; + } + } + } + + if (!qdict_haskey(device, "qdev_id")) { + continue; + } + + if (strcmp(qdict_get_str(device, "qdev_id"), name) == 0) { + qobject_ref(device); + qobject_unref(list); + return device; + } + } + qobject_unref(list); + + return NULL; +} + +static QDict *get_bus(QTestState *qts, int num) +{ + QObject *obj; + QDict *resp; + QList *ret; + + resp = qtest_qmp(qts, "{ 'execute': 'query-pci' }"); + g_assert(qdict_haskey(resp, "return")); + + ret = qdict_get_qlist(resp, "return"); + g_assert_nonnull(ret); + + while ((obj = qlist_pop(ret))) { + QDict *bus; + + bus = qobject_to(QDict, obj); + if (!qdict_haskey(bus, "bus")) { + continue; + } + if (qdict_get_int(bus, "bus") == num) { + qobject_ref(bus); + qobject_unref(resp); + return bus; + } + } + qobject_unref(resp); + + return NULL; +} + +static char *get_mac(QTestState *qts, const char *name) +{ + QDict *resp; + char *mac; + + resp = qtest_qmp(qts, "{ 'execute': 'qom-get', " + "'arguments': { " + "'path': %s, " + "'property': 'mac' } }", name); + + g_assert(qdict_haskey(resp, "return")); + + mac = g_strdup( qdict_get_str(resp, "return")); + + qobject_unref(resp); + + return mac; +} + +static void check_cards(QTestState *qts, bool standby, bool primary) +{ + QDict *device; + QDict *bus; + char *mac; + + bus = get_bus(qts, 0); + device = find_device(bus, "standby0"); + if (standby) { + g_assert_nonnull(device); + qobject_unref(device); + + mac = get_mac(qts, "/machine/peripheral/standby0"); + g_assert_cmpstr(mac, ==, MAC_STANDBY); + g_free(mac); + } else { + g_assert_null(device); + } + + device = find_device(bus, "primary0"); + if (primary) { + g_assert_nonnull(device); + qobject_unref(device); + + mac = get_mac(qts, "/machine/peripheral/primary0"); + g_assert_cmpstr(mac, ==, MAC_PRIMARY); + g_free(mac); + } else { + g_assert_null(device); + } + qobject_unref(bus); +} + +static void test_on(void) +{ + QTestState *qts; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-device virtio-net,bus=root0,id=standby0," + "failover=on,netdev=hs0,mac="MAC_STANDBY" " + "-device virtio-net,bus=root1,id=primary0," + "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY); + + check_cards(qts, true, false); /* standby, no primary */ + + machine_stop(qts); +} + +static void test_on_mismatch(void) +{ + QTestState *qts; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-device virtio-net,bus=root0,id=standby0," + "failover=on,netdev=hs0,mac="MAC_STANDBY" " + "-netdev user,id=hs1 " + "-device virtio-net,bus=root1,id=primary0," + "failover_pair_id=standby1,netdev=hs1,mac="MAC_PRIMARY); + + check_cards(qts, true, true); /* standby, primary (but no failover) */ + + machine_stop(qts); +} + +static void test_off(void) +{ + QTestState *qts; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-device virtio-net,bus=root0,id=standby0," + "failover=off,netdev=hs0,mac="MAC_STANDBY" " + "-netdev user,id=hs1 " + "-device virtio-net,bus=root1,id=primary0," + "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY); + + check_cards(qts, true, true); /* standby, primary (but no failover) */ + + machine_stop(qts); +} + +static void start_virtio_net(QTestState *qts, int bus, int slot) +{ + QVirtioPCIDevice *dev; + uint64_t features; + QPCIAddress addr; + QDict *resp; + QDict *data; + + addr.devfn = QPCI_DEVFN((bus << 5) + slot, 0); + dev = virtio_pci_new(pcibus, &addr); + g_assert_nonnull(dev); + qvirtio_pci_device_enable(dev); + qvirtio_start_device(&dev->vdev); + features = qvirtio_get_features(&dev->vdev); + features = features & ~(QVIRTIO_F_BAD_FEATURE | + (1ull << VIRTIO_RING_F_INDIRECT_DESC) | + (1ull << VIRTIO_RING_F_EVENT_IDX)); + qvirtio_set_features(&dev->vdev, features); + qvirtio_set_driver_ok(&dev->vdev); + + resp = qtest_qmp_eventwait_ref(qts, "FAILOVER_NEGOTIATED"); + g_assert(qdict_haskey(resp, "data")); + + data = qdict_get_qdict(resp, "data"); + g_assert(qdict_haskey(data, "device-id")); + g_assert_cmpstr(qdict_get_str(data, "device-id"), ==, "standby0"); + + qobject_unref(resp); +} + +static void test_enabled(void) +{ + QTestState *qts; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-device virtio-net,bus=root0,id=standby0," + "failover=on,netdev=hs0,mac="MAC_STANDBY" " + "-netdev user,id=hs1 " + "-device virtio-net,bus=root1,id=primary0," + "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY" " + ); + + check_cards(qts, true, false); /* standby, no primary */ + + start_virtio_net(qts, 1, 0); + + check_cards(qts, true, true); /* standby, primary with failover */ + + machine_stop(qts); +} + +static void test_hotplug_1(void) +{ + QTestState *qts; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-device virtio-net,bus=root0,id=standby0," + "failover=on,netdev=hs0,mac="MAC_STANDBY" " + "-netdev user,id=hs1 " + ); + + check_cards(qts, true, false); /* no standby, no primary */ + + start_virtio_net(qts, 1, 0); + + check_cards(qts, true, false); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'mac': '"MAC_PRIMARY"'}"); + + check_cards(qts, true, true); + + machine_stop(qts); +} + +static void test_hotplug_1_reverse(void) +{ + QTestState *qts; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 " + "-device virtio-net,bus=root1,id=primary0," + "failover_pair_id=standby0,netdev=hs1,mac="MAC_PRIMARY" " + ); + + check_cards(qts, false, true); + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'on'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY"'}"); + + check_cards(qts, true, true); /* XXX: sounds like a bug */ + + start_virtio_net(qts, 1, 0); + + check_cards(qts, true, true); + + machine_stop(qts); +} + +static void test_hotplug_2(void) +{ + QTestState *qts; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 " + ); + + check_cards(qts, false, false); /* no standby, no primary */ + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'on'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY"'}"); + + check_cards(qts, true, false); + + start_virtio_net(qts, 1, 0); + + check_cards(qts, true, false); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'mac': '"MAC_PRIMARY"'}"); + + check_cards(qts, true, true); + + machine_stop(qts); +} + +static void test_hotplug_2_reverse(void) +{ + QTestState *qts; + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 " + ); + + check_cards(qts, false, false); /* no standby, no primary */ + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'mac': '"MAC_PRIMARY"'}"); + + check_cards(qts, false, true); + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'on'," + "'netdev': 'hs0'," + "'rombar': 0," + "'romfile': ''," + "'mac': '"MAC_STANDBY"'}"); + + check_cards(qts, true, true); /* XXX: sounds like a bug */ + + start_virtio_net(qts, 1, 0); + + check_cards(qts, true, true); + + machine_stop(qts); +} + +static void test_outmigrate(gconstpointer opaque) +{ + QTestState *qts; + QDict *resp, *args, *data; + g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 " + ); + + check_cards(qts, false, false); /* no standby, no primary */ + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'on'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY"'}"); + + check_cards(qts, true, false); + + start_virtio_net(qts, 1, 0); + + check_cards(qts, true, false); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'rombar': 0," + "'romfile': ''," + "'mac': '"MAC_PRIMARY"'}"); + + check_cards(qts, true, true); + + args = qdict_from_jsonf_nofail("{}"); + g_assert_nonnull(args); + qdict_put_str(args, "uri", uri); + + resp = qtest_qmp(qts, "{ 'execute': 'migrate', 'arguments': %p}", args); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + resp = qtest_qmp_eventwait_ref(qts, "UNPLUG_PRIMARY"); + g_assert(qdict_haskey(resp, "data")); + + data = qdict_get_qdict(resp, "data"); + g_assert(qdict_haskey(data, "device-id")); + g_assert_cmpstr(qdict_get_str(data, "device-id"), ==, "primary0"); + + qobject_unref(resp); + + qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); + + resp = qtest_qmp_eventwait_ref(qts, "STOP"); + qobject_unref(resp); + + /* + * in fact, the card is ejected from the point of view of kernel + * but not really from QEMU to be able to hotplug it back if + * migration fails. So we can't check that: + * check_cards(qts, true, false); + */ + + machine_stop(qts); +} + +static void test_inmigrate(gconstpointer opaque) +{ + QTestState *qts; + QDict *resp, *args; + g_autofree gchar *uri = g_strdup_printf("exec: cat %s", (gchar *)opaque); + + qts = machine_start(BASE_MACHINE + "-netdev user,id=hs0 " + "-netdev user,id=hs1 " + "-incoming defer " + ); + + check_cards(qts, false, false); /* no standby, no primary */ + + qtest_qmp_device_add(qts, "virtio-net", "standby0", + "{'bus': 'root0'," + "'failover': 'on'," + "'netdev': 'hs0'," + "'mac': '"MAC_STANDBY"'}"); + + check_cards(qts, true, false); + + qtest_qmp_device_add(qts, "virtio-net", "primary0", + "{'bus': 'root1'," + "'failover_pair_id': 'standby0'," + "'netdev': 'hs1'," + "'rombar': 0," + "'romfile': ''," + "'mac': '"MAC_PRIMARY"'}"); + + check_cards(qts, true, false); + + args = qdict_from_jsonf_nofail("{}"); + g_assert_nonnull(args); + qdict_put_str(args, "uri", uri); + + resp = qtest_qmp(qts, "{ 'execute': 'migrate-incoming', 'arguments': %p}", + args); + g_assert(qdict_haskey(resp, "return")); + qobject_unref(resp); + + qtest_qmp_eventwait(qts, "MIGRATION"); + qtest_qmp_eventwait(qts, "FAILOVER_NEGOTIATED"); + + check_cards(qts, true, true); + + qtest_qmp_eventwait(qts, "RESUME"); + + machine_stop(qts); +} + +int main(int argc, char **argv) +{ + gchar *tmpfile = g_strdup_printf("/tmp/failover_test_migrate-%u-%u", + getpid(), g_test_rand_int()); + const char *arch; + int ret; + + g_test_init(&argc, &argv, NULL); + + arch = qtest_get_arch(); + if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) { + g_test_message("Skipping test for non-x86"); + return g_test_run(); + } + + qtest_add_func("failover-virtio-net/params/error/id", test_error_id); + qtest_add_func("failover-virtio-net/params/error/pcie", test_error_pcie); + qtest_add_func("failover-virtio-net/params/error/on", test_on); + qtest_add_func("failover-virtio-net/params/error/on_mismatch", + test_on_mismatch); + qtest_add_func("failover-virtio-net/params/error/off", test_off); + qtest_add_func("failover-virtio-net/params/error/enabled", test_enabled); + qtest_add_func("failover-virtio-net/params/error/hotplug_1", + test_hotplug_1); + qtest_add_func("failover-virtio-net/params/error/hotplug_1_reverse", + test_hotplug_1_reverse); + qtest_add_func("failover-virtio-net/params/error/hotplug_2", + test_hotplug_2); + qtest_add_func("failover-virtio-net/params/error/hotplug_2_reverse", + test_hotplug_2_reverse); + qtest_add_data_func("failover-virtio-net/params/error/outmigrate", + tmpfile, test_outmigrate); + qtest_add_data_func("failover-virtio-net/params/error/inmigrate", + tmpfile, test_inmigrate); + + ret = g_test_run(); + + unlink(tmpfile); + g_free(tmpfile); + + return ret; +} From patchwork Thu Nov 18 13:32:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12627069 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5E746C433EF for ; Thu, 18 Nov 2021 14:00:35 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 10F24610CA for ; Thu, 18 Nov 2021 14:00:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 10F24610CA Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=nongnu.org Received: from localhost ([::1]:45434 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mnhxq-000737-5H for qemu-devel@archiver.kernel.org; Thu, 18 Nov 2021 09:00:34 -0500 Received: from eggs.gnu.org ([209.51.188.92]:56510) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhZK-0007VP-Qy for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:35:15 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:54611) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhZJ-0002cC-0i for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:35:14 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1637242511; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=UPYKx9uhzqpV56MxW183OXn607XHAZablOEesagsGDs=; b=YGLSYiT6dyfac9ZMtuiwZoKPt9/tWu5gnuRWwqbu34zLL6Sa/aBXpfEFXCCDn7JdJNNS56 CQ3HZgPE/Oxa+nII0I5fbzhqrgVklaJlvMoh9XTud6hsFJSj247cmHbk0XfHNkU2A3RsyU HvFJWDU9vPfBNq0T0lLCr0tX4QnWVU4= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-177-9zHduQgxNOK5h3xDzPNi0Q-1; Thu, 18 Nov 2021 08:35:10 -0500 X-MC-Unique: 9zHduQgxNOK5h3xDzPNi0Q-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 559238799E0; Thu, 18 Nov 2021 13:35:09 +0000 (UTC) Received: from thinkpad.redhat.com (unknown [10.39.194.176]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2E5B83AEA; Thu, 18 Nov 2021 13:34:32 +0000 (UTC) From: Laurent Vivier To: qemu-devel@nongnu.org Subject: [PATCH v3 3/5] failover: fix unplug pending detection Date: Thu, 18 Nov 2021 14:32:23 +0100 Message-Id: <20211118133225.324937-4-lvivier@redhat.com> In-Reply-To: <20211118133225.324937-1-lvivier@redhat.com> References: <20211118133225.324937-1-lvivier@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lvivier@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -34 X-Spam_score: -3.5 X-Spam_bar: --- X-Spam_report: (-3.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.698, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , "Michael S. Tsirkin" , Michael Roth , Juan Quintela , Gerd Hoffmann , Paolo Bonzini , Ani Sinha , Igor Mammedov , Jens Freimann Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Failover needs to detect the end of the PCI unplug to start migration after the VFIO card has been unplugged. To do that, a flag is set in pcie_cap_slot_unplug_request_cb() and reset in pcie_unplug_device(). But since 17858a169508 ("hw/acpi/ich9: Set ACPI PCI hot-plug as default on Q35") we have switched to ACPI unplug and these functions are not called anymore and the flag not set. So failover migration is not able to detect if card is really unplugged and acts as it's done as soon as it's started. So it doesn't wait the end of the unplug to start the migration. We don't see any problem when we test that because ACPI unplug is faster than PCIe native hotplug and when the migration really starts the unplug operation is already done. See c000a9bd06ea ("pci: mark device having guest unplug request pending") a99c4da9fc2a ("pci: mark devices partially unplugged") Signed-off-by: Laurent Vivier Reviewed-by: Ani Sinha --- hw/acpi/pcihp.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c index f610a25d2ef9..30405b5113d7 100644 --- a/hw/acpi/pcihp.c +++ b/hw/acpi/pcihp.c @@ -222,9 +222,27 @@ static void acpi_pcihp_eject_slot(AcpiPciHpState *s, unsigned bsel, unsigned slo PCIDevice *dev = PCI_DEVICE(qdev); if (PCI_SLOT(dev->devfn) == slot) { if (!acpi_pcihp_pc_no_hotplug(s, dev)) { - hotplug_ctrl = qdev_get_hotplug_handler(qdev); - hotplug_handler_unplug(hotplug_ctrl, qdev, &error_abort); - object_unparent(OBJECT(qdev)); + /* + * partially_hotplugged is used by virtio-net failover: + * failover has asked the guest OS to unplug the device + * but we need to keep some references to the device + * to be able to plug it back in case of failure so + * we don't execute hotplug_handler_unplug(). + */ + if (dev->partially_hotplugged) { + /* + * pending_deleted_event is set to true when + * virtio-net failover asks to unplug the device, + * and set to false here when the operation is done + * This is used by the migration loop to detect the + * end of the operation and really start the migration. + */ + qdev->pending_deleted_event = false; + } else { + hotplug_ctrl = qdev_get_hotplug_handler(qdev); + hotplug_handler_unplug(hotplug_ctrl, qdev, &error_abort); + object_unparent(OBJECT(qdev)); + } } } } @@ -396,6 +414,12 @@ void acpi_pcihp_device_unplug_request_cb(HotplugHandler *hotplug_dev, return; } + /* + * pending_deleted_event is used by virtio-net failover to detect the + * end of the unplug operation, the flag is set to false in + * acpi_pcihp_eject_slot() when the operation is completed. + */ + pdev->qdev.pending_deleted_event = true; s->acpi_pcihp_pci_status[bsel].down |= (1U << slot); acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS); } From patchwork Thu Nov 18 13:32:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12627071 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 42345C433EF for ; Thu, 18 Nov 2021 14:03:05 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8EBF761ACE for ; Thu, 18 Nov 2021 14:03:04 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 8EBF761ACE Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=nongnu.org Received: from localhost ([::1]:50228 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mni0F-00026L-Ih for qemu-devel@archiver.kernel.org; Thu, 18 Nov 2021 09:03:03 -0500 Received: from eggs.gnu.org ([209.51.188.92]:56750) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhaI-0008I0-Cu for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:36:14 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.129.124]:22664) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhaG-0002nb-9F for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:36:14 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1637242571; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=7B2/7pto1JIgqLKbEslmOH4VFn6TU80oluTorY46zv0=; b=eA4adHdZ2nt4wJ9CHbLN9lo2Tl+egLf4nZ4G+o1ISZ/EGL0gRHYgo2K41TrsCO7uC8K/yd DVxH9EdZ3kirxLFk/mX/dlsHDHWXVMi5Ddo0rZi9xDWmPvrKGKGjlNueOjAX8c4r2lOdvX HQ8dqo0AUOcO1JUwTGOFITnFm9uk7mg= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-389-2-K_2WdmOru8xEcE_ZJzKw-1; Thu, 18 Nov 2021 08:36:10 -0500 X-MC-Unique: 2-K_2WdmOru8xEcE_ZJzKw-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 73FE9100E326; Thu, 18 Nov 2021 13:36:09 +0000 (UTC) Received: from thinkpad.redhat.com (unknown [10.39.194.176]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2522726DE2; Thu, 18 Nov 2021 13:35:09 +0000 (UTC) From: Laurent Vivier To: qemu-devel@nongnu.org Subject: [PATCH v3 4/5] libqtest: add a function to use a timeout when waiting for an event Date: Thu, 18 Nov 2021 14:32:24 +0100 Message-Id: <20211118133225.324937-5-lvivier@redhat.com> In-Reply-To: <20211118133225.324937-1-lvivier@redhat.com> References: <20211118133225.324937-1-lvivier@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lvivier@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=170.10.129.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -34 X-Spam_score: -3.5 X-Spam_bar: --- X-Spam_report: (-3.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.698, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H4=0.001, RCVD_IN_MSPIKE_WL=0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , "Michael S. Tsirkin" , Michael Roth , Juan Quintela , Gerd Hoffmann , Paolo Bonzini , Ani Sinha , Igor Mammedov , Jens Freimann Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" To be able to check we _don't_ receive a given event, we need to be able to stop to wait for it after a given amount of time. To do that, introduce a timeout value in qtest_qmp_eventwait(). The new version of the function is qtest_qmp_eventwait_timeout(), that uses the new function qtest_qmp_receive_dict_timeout(). Signed-off-by: Laurent Vivier --- tests/qtest/libqos/libqtest.h | 26 +++++++++++++++++++++++- tests/qtest/libqtest.c | 37 ++++++++++++++++++++++++++++++----- tests/unit/test-qga.c | 2 +- 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/tests/qtest/libqos/libqtest.h b/tests/qtest/libqos/libqtest.h index 59e927119563..3f96afa5f431 100644 --- a/tests/qtest/libqos/libqtest.h +++ b/tests/qtest/libqos/libqtest.h @@ -209,6 +209,17 @@ void qtest_qmp_vsend_fds(QTestState *s, int *fds, size_t fds_num, void qtest_qmp_vsend(QTestState *s, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0); +/** + * qtest_qmp_receive_dict_timeout: + * @s: #QTestState instance to operate on. + * @timeout: time to wait before aborting read + * + * Reads a QMP message from QEMU and returns the response. + * If a timeout is provided, return NULL if message is + * not received during the given amount of time + */ +QDict *qtest_qmp_receive_dict_timeout(QTestState *s, struct timeval *timeout); + /** * qtest_qmp_receive_dict: * @s: #QTestState instance to operate on. @@ -236,6 +247,19 @@ QDict *qtest_qmp_receive(QTestState *s); */ void qtest_qmp_eventwait(QTestState *s, const char *event); +/** + * qtest_qmp_eventwait_timeout: + * @s: #QTestState instance to operate on. + * @timeout: time to wait before aborting wait + * @event: event to wait for. + * + * Continuously polls for QMP responses until it receives the desired event + * or the timeout exausts. + * Returns a copy of the event for further investigation or NULL on timeout + */ +QDict *qtest_qmp_eventwait_timeout(QTestState *s, struct timeval *timeout, + const char *event); + /** * qtest_qmp_eventwait_ref: * @s: #QTestState instance to operate on. @@ -690,7 +714,7 @@ void qtest_remove_abrt_handler(void *data); void qtest_qmp_assert_success(QTestState *qts, const char *fmt, ...) GCC_FMT_ATTR(2, 3); -QDict *qmp_fd_receive(int fd); +QDict *qmp_fd_receive(int fd, struct timeval *timeout); void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num, const char *fmt, va_list ap) GCC_FMT_ATTR(4, 0); void qmp_fd_vsend(int fd, const char *fmt, va_list ap) GCC_FMT_ATTR(2, 0); diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c index 25aeea385bfa..10e05d0c7aa8 100644 --- a/tests/qtest/libqtest.c +++ b/tests/qtest/libqtest.c @@ -599,7 +599,7 @@ static void qmp_response(void *opaque, QObject *obj, Error *err) g_assert(qmp->response); } -QDict *qmp_fd_receive(int fd) +QDict *qmp_fd_receive(int fd, struct timeval *timeout) { QMPResponseParser qmp; bool log = getenv("QTEST_LOG") != NULL; @@ -610,6 +610,18 @@ QDict *qmp_fd_receive(int fd) ssize_t len; char c; + if (timeout) { + fd_set set; + int ret; + + FD_ZERO(&set); + FD_SET(fd, &set); + ret = select(fd + 1, &set, NULL, NULL, timeout); + if (ret == 0) { + /* timeout */ + return NULL; + } + } len = read(fd, &c, 1); if (len == -1 && errno == EINTR) { continue; @@ -643,9 +655,14 @@ QDict *qtest_qmp_receive(QTestState *s) } } +QDict *qtest_qmp_receive_dict_timeout(QTestState *s, struct timeval *timeout) +{ + return qmp_fd_receive(s->qmp_fd, timeout); +} + QDict *qtest_qmp_receive_dict(QTestState *s) { - return qmp_fd_receive(s->qmp_fd); + return qtest_qmp_receive_dict_timeout(s, NULL); } int qtest_socket_server(const char *socket_path) @@ -729,7 +746,7 @@ QDict *qmp_fdv(int fd, const char *fmt, va_list ap) { qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap); - return qmp_fd_receive(fd); + return qmp_fd_receive(fd, NULL); } QDict *qtest_vqmp_fds(QTestState *s, int *fds, size_t fds_num, @@ -848,7 +865,8 @@ QDict *qtest_qmp_event_ref(QTestState *s, const char *event) return NULL; } -QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event) +QDict *qtest_qmp_eventwait_timeout(QTestState *s, struct timeval *timeout, + const char *event) { QDict *response = qtest_qmp_event_ref(s, event); @@ -857,7 +875,11 @@ QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event) } for (;;) { - response = qtest_qmp_receive_dict(s); + response = qtest_qmp_receive_dict_timeout(s, timeout); + if (timeout != NULL && response == NULL) { + /* exit on timeout */ + return NULL; + } if ((qdict_haskey(response, "event")) && (strcmp(qdict_get_str(response, "event"), event) == 0)) { return response; @@ -866,6 +888,11 @@ QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event) } } +QDict *qtest_qmp_eventwait_ref(QTestState *s, const char *event) +{ + return qtest_qmp_eventwait_timeout(s, NULL, event); +} + void qtest_qmp_eventwait(QTestState *s, const char *event) { QDict *response; diff --git a/tests/unit/test-qga.c b/tests/unit/test-qga.c index 5cb140d1b53d..22aa6405aaec 100644 --- a/tests/unit/test-qga.c +++ b/tests/unit/test-qga.c @@ -174,7 +174,7 @@ static void test_qga_sync_delimited(gconstpointer fix) g_assert_cmpint(v, ==, 1); } while (c != 0xff); - ret = qmp_fd_receive(fixture->fd); + ret = qmp_fd_receive(fixture->fd, NULL); g_assert_nonnull(ret); qmp_assert_no_error(ret); From patchwork Thu Nov 18 13:32:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Laurent Vivier X-Patchwork-Id: 12627085 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EC0E0C433F5 for ; Thu, 18 Nov 2021 14:07:38 +0000 (UTC) Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AF39460EFD for ; Thu, 18 Nov 2021 14:07:38 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org AF39460EFD Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=nongnu.org Received: from localhost ([::1]:60288 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mni4f-0000kt-PM for qemu-devel@archiver.kernel.org; Thu, 18 Nov 2021 09:07:37 -0500 Received: from eggs.gnu.org ([209.51.188.92]:56932) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhan-0000Mm-R4 for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:36:45 -0500 Received: from us-smtp-delivery-124.mimecast.com ([170.10.133.124]:57692) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mnhal-0002xI-41 for qemu-devel@nongnu.org; Thu, 18 Nov 2021 08:36:44 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1637242601; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=X/eVZJnBVIUvyH3r5un5vIjp7TpJsxQpMLa8nQ9v+LA=; b=IJXsMZeuEIQgQNB5iS+PEU/uW9k0ModUSj1NVDsMHAeWor+lsJnRiVc2kkI0U7iaRJ1IHw bKrNsho9BHXSwP3o4sWElVyBx1yHTbS1QzPjRfyzx402sVwr7UIjhOkjoKUW00wB4KiXHP AriToIYi9BVfBHmg8cImjzoR0jDJ6wY= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-318-NmH__Cp2PhyyWQQFqzh3Uw-1; Thu, 18 Nov 2021 08:36:40 -0500 X-MC-Unique: NmH__Cp2PhyyWQQFqzh3Uw-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 74ACC1B18BCB; Thu, 18 Nov 2021 13:36:39 +0000 (UTC) Received: from thinkpad.redhat.com (unknown [10.39.194.176]) by smtp.corp.redhat.com (Postfix) with ESMTP id A85CB3AEA; Thu, 18 Nov 2021 13:36:09 +0000 (UTC) From: Laurent Vivier To: qemu-devel@nongnu.org Subject: [PATCH v3 5/5] tests/libqtest: update virtio-net failover test Date: Thu, 18 Nov 2021 14:32:25 +0100 Message-Id: <20211118133225.324937-6-lvivier@redhat.com> In-Reply-To: <20211118133225.324937-1-lvivier@redhat.com> References: <20211118133225.324937-1-lvivier@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=lvivier@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Received-SPF: pass client-ip=170.10.133.124; envelope-from=lvivier@redhat.com; helo=us-smtp-delivery-124.mimecast.com X-Spam_score_int: -34 X-Spam_score: -3.5 X-Spam_bar: --- X-Spam_report: (-3.5 / 5.0 requ) BAYES_00=-1.9, DKIMWL_WL_HIGH=-0.698, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_LOW=-0.7, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Laurent Vivier , Thomas Huth , =?utf-8?q?Daniel_P_=2E_Berrang=C3=A9?= , "Michael S. Tsirkin" , Michael Roth , Juan Quintela , Gerd Hoffmann , Paolo Bonzini , Ani Sinha , Igor Mammedov , Jens Freimann Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: "Qemu-devel" Update the migration test to check we correctly wait the end of the card unplug before doing the migration. Signed-off-by: Laurent Vivier --- tests/qtest/virtio-net-failover.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/qtest/virtio-net-failover.c b/tests/qtest/virtio-net-failover.c index 576d4454c3c3..7cc276e6ffc1 100644 --- a/tests/qtest/virtio-net-failover.c +++ b/tests/qtest/virtio-net-failover.c @@ -478,6 +478,7 @@ static void test_outmigrate(gconstpointer opaque) QTestState *qts; QDict *resp, *args, *data; g_autofree gchar *uri = g_strdup_printf("exec: cat > %s", (gchar *)opaque); + struct timeval timeout; qts = machine_start(BASE_MACHINE "-netdev user,id=hs0 " @@ -525,11 +526,19 @@ static void test_outmigrate(gconstpointer opaque) qobject_unref(resp); - qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); + /* + * The migration cannot start if the card is not ejected, + * so we check it cannot end ("STOP") before the card is ejected + */ + /* 10s is enough for ACPI, PCIe native would need at least 30s */ + timeout.tv_sec = 10; + timeout.tv_usec = 0; + resp = qtest_qmp_eventwait_timeout(qts, &timeout, "STOP"); + g_assert_null(resp); - resp = qtest_qmp_eventwait_ref(qts, "STOP"); - qobject_unref(resp); + qtest_outl(qts, ACPI_PCIHP_ADDR_ICH9 + PCI_EJ_BASE, 1); + qtest_qmp_eventwait(qts, "STOP"); /* * in fact, the card is ejected from the point of view of kernel * but not really from QEMU to be able to hotplug it back if