From nobody Sun Feb 8 16:30:48 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 207.211.31.120 as permitted sender) client-ip=207.211.31.120; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-1.mimecast.com; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 207.211.31.120 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=gmail.com ARC-Seal: i=1; a=rsa-sha256; t=1590009309; cv=none; d=zohomail.com; s=zohoarc; b=nUEVtSfsA+FagcNlbTeLYV0bbI/rxHS5onoipR5ME9sUXis99Wy//l+q9s5KOCU8krX43otBG/Y6ESzTuORkdQF/10Gc7deztSthTlQ2LRvDQtAjnjkRbj9wG2VxIgp7gmx4LTuF+EPOoUrPewYUdOG4XDbDjQZ4ISE80ifE/40= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1590009309; h=Content-Type:Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=SLNm4AzskS+jEoyCs0+WyFm2d/sN72XedfwEuvWJtiE=; b=UeNAZEd2nkU/g1GMWwk4BB7qhwRS6jpFhZMv73X/VhyvxTkzQR7W+08PNA+6xCYc8A/G3E1dUewAPJGS8KGjkfJqKFB9mc/HW40nig+QkQhKwxCKLA7oBymPzXGLEWDz6h76Y5yfQRB7ttCSDao9morleuFhkvHFfPeB6XKic+U= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of redhat.com designates 207.211.31.120 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail header.from= (p=none dis=none) header.from= Return-Path: Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [207.211.31.120]) by mx.zohomail.com with SMTPS id 1590009309583160.9841884924116; Wed, 20 May 2020 14:15:09 -0700 (PDT) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-293-6PprPDNDO2yVO5B9SpmPKA-1; Wed, 20 May 2020 17:15:04 -0400 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 18626474; Wed, 20 May 2020 21:14:59 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id EC6AC7959C; Wed, 20 May 2020 21:14:58 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id BF32C180CB39; Wed, 20 May 2020 21:14:58 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 04KLCgRh002255 for ; Wed, 20 May 2020 17:12:42 -0400 Received: by smtp.corp.redhat.com (Postfix) id 6AAB42166BA3; Wed, 20 May 2020 21:12:42 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast05.extmail.prod.ext.rdu2.redhat.com [10.11.55.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6681D2166BA2 for ; Wed, 20 May 2020 21:12:42 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 42C60800296 for ; Wed, 20 May 2020 21:12:42 +0000 (UTC) Received: from mail-qk1-f193.google.com (mail-qk1-f193.google.com [209.85.222.193]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-356-yqC7xuErN4y6lgqDiU0BoA-1; Wed, 20 May 2020 17:12:40 -0400 Received: by mail-qk1-f193.google.com with SMTP id m11so5186651qka.4 for ; Wed, 20 May 2020 14:12:39 -0700 (PDT) Received: from rekt.ibmuc.com ([2804:431:c7c7:fbf2:bc5e:c314:af31:7070]) by smtp.gmail.com with ESMTPSA id z14sm2992031qki.83.2020.05.20.14.12.36 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 May 2020 14:12:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1590009308; h=from:from:sender:sender: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:list-id:list-help: list-unsubscribe:list-subscribe:list-post; bh=SLNm4AzskS+jEoyCs0+WyFm2d/sN72XedfwEuvWJtiE=; b=aXvjSa42+5OHS4YTf3gUS1Wo2eAdeIRCiqvkqDGNp3Rp2ctH65kU8i/bLH7W0V3Wr2gARG jaMsLvEVT/UkdF/N8xDsqnFAjogXbbmu1IpzbIr4qErgacfBPP5L2/gkOUa4g3BGGb7zGP woXPTx2AVEPFGRodu+b17b4UcLlWrfM= X-MC-Unique: 6PprPDNDO2yVO5B9SpmPKA-1 X-MC-Unique: yqC7xuErN4y6lgqDiU0BoA-1 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=SLNm4AzskS+jEoyCs0+WyFm2d/sN72XedfwEuvWJtiE=; b=S26BaQAlkrAEGrrVjR6HDH4DCdjEeVtbfaApHVL0vvI/3y+61sNXfl06/VrjX/T68g 9/lHAFj25GgSZOsQPiN9eojeDRwvHkCsQHdn0+jjl7ctpcsLbKcVyyq9NFAZfDUd2D+M MguJ6MzuxoKsxRvNqf6pMiuhDq2NjL8zB5SiIOWp79xjYPgZ2RIcQD68TYdON2yqBFdl fojqNTVl5cx6h7lCBy58qzMk77VxBWuKAyQcgKwQS3oXAe0nYdIinWkGAv/VaLu3pnon xgawGnJTPI3qdvgX044i+TaLsuxyt0kVfG2VtNMxfkHUY/rIoWml577Hdv7pJb7Wn33x SCYw== X-Gm-Message-State: AOAM533oOnegqQTP5JmNG4eHvzYkypFMLQAPf1sIftbpIJ7T09bjBWTp kYvBCSkGorDCkT13JdLqqe0Iy8DQ X-Google-Smtp-Source: ABdhPJzyzTYP4WOMQGBb8dzAzWObvdbket7i1Sf216reyksKv2XyleSsiDsAOkypLJuScTwd216wJw== X-Received: by 2002:a37:9f44:: with SMTP id i65mr1067085qke.103.1590009158685; Wed, 20 May 2020 14:12:38 -0700 (PDT) From: Daniel Henrique Barboza To: libvir-list@redhat.com Subject: [PATCH v3 16/21] qemu: hotplug: Implement multifunction device hotplug Date: Wed, 20 May 2020 18:11:38 -0300 Message-Id: <20200520211143.2980117-17-danielhb413@gmail.com> In-Reply-To: <20200520211143.2980117-1-danielhb413@gmail.com> References: <20200520211143.2980117-1-danielhb413@gmail.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-loop: libvir-list@redhat.com Cc: Daniel Henrique Barboza , sbhat@linux.ibm.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @redhat.com) Content-Type: text/plain; charset="utf-8" From: Shivaprasad G Bhat The support to allow multifunction device hotplug consists of using virDomainDeviceDefListPtr lists instead of single virDomainDeviceDefPtr device definitions in both qemuDomainAttachDeviceConfig() and qemuDomainAttachDeviceLive(). In AttachDeviceConfig() the same existing single device code is ran for all devs in the list. AttachDeviceLive() will verify if the list has size =3D 1 (meaning it is a single device attach) and redirect the code to the regular single dev attach procedure. If list size > 1, we'll execute a new specialized function called qemuDomainAttachMultifunctionDevice(), which is prepared to handle the nuances of this type of hotplug. The changes in both AttachDeviceLive() and AttachDeviceConfig() implied in changes to be made in qemuDomainAttachDeviceLiveAndConfig(), which is now handling a device list instead of a single device. No changes in regular device hotplug mechanics were made. Signed-off-by: Shivaprasad G Bhat Signed-off-by: Daniel Henrique Barboza --- src/qemu/qemu_domain_address.c | 74 +++++++++++ src/qemu/qemu_domain_address.h | 4 + src/qemu/qemu_driver.c | 119 +++++++++++------- src/qemu/qemu_hotplug.c | 86 +++++++++++++ src/qemu/qemu_hotplug.h | 4 + tests/qemuhotplugtest.c | 39 ++++-- ...emuhotplug-multifunction-hostdev-pci-2.xml | 14 +++ .../qemuhotplug-multifunction-hostdev-pci.xml | 26 ++++ ...ug-base-live+multifunction-hostdev-pci.xml | 82 ++++++++++++ ...-base-live+multifunction-hostdev-pci-2.xml | 59 +++++++++ ...es-base-live+multifunction-hostdev-pci.xml | 69 ++++++++++ 11 files changed, 524 insertions(+), 52 deletions(-) create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-multifunction-= hostdev-pci-2.xml create mode 100644 tests/qemuhotplugtestdevices/qemuhotplug-multifunction-= hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-base-live+mult= ifunction-hostdev-pci.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-l= ive+multifunction-hostdev-pci-2.xml create mode 100644 tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-l= ive+multifunction-hostdev-pci.xml diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c index 05ef4de100..94d91a5daf 100644 --- a/src/qemu/qemu_domain_address.c +++ b/src/qemu/qemu_domain_address.c @@ -23,6 +23,7 @@ =20 #include "qemu_domain_address.h" #include "qemu_domain.h" +#include "domain_conf.h" #include "viralloc.h" #include "virhostdev.h" #include "virerror.h" @@ -3439,6 +3440,79 @@ qemuDomainEnsurePCIAddress(virDomainObjPtr obj, info->pciConnectFlags); } =20 + +int +qemuDomainPCIMultifunctionHostdevEnsurePCIAddresses(virDomainObjPtr vm, + virDomainDeviceDefList= Ptr devlist, + virQEMUDriverPtr drive= r) +{ + int ret =3D -1, aggrslotidx =3D 0; + virBitmapPtr slotmap =3D NULL; + size_t i; + qemuDomainObjPrivatePtr priv =3D vm->privateData; + virDomainPCIMultifunctionAddressInfoPtr devinfos =3D NULL; + + if (devlist->count > VIR_PCI_MAX_FUNCTIONS) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("More devices per slot found")); + return -1; + } + + for (i =3D 0; i < devlist->count; i++) + qemuDomainFillDevicePCIConnectFlags(vm->def, devlist->devs[i], + priv->qemuCaps, driver); + + if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + devlist->cou= nt) < 0) + return -1; + + /* Temporarily add the devices to the domain def to get the + * next aggregateIdx */ + for (i =3D 0; i < devlist->count; i++) + vm->def->hostdevs[vm->def->nhostdevs++] =3D devlist->devs[i]->data= .hostdev; + + for (i =3D 0; i < devlist->count; i++) { + virDomainHostdevDefPtr hostdev =3D devlist->devs[i]->data.hostdev; + + if (qemuDomainIsPSeries(vm->def)) + /* Isolation groups are only relevant for pSeries guests */ + qemuDomainFillDeviceIsolationGroup(vm->def, devlist->devs[i]); + + qemuDomainSetDeviceSlotAggregateIdx(vm->def, devlist->devs[i]); + aggrslotidx =3D aggrslotidx ? aggrslotidx : hostdev->info->aggrega= teSlotIdx; + + if (aggrslotidx !=3D hostdev->info->aggregateSlotIdx) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Devices belong to different PCI slots")); + return -1; + } + } + + for (i =3D 0; i < devlist->count; i++) + vm->def->hostdevs[--(vm->def->nhostdevs)] =3D NULL; + + slotmap =3D virDomainDefHostdevGetPCIOnlineFunctionMap(vm->def, aggrsl= otidx); + if (!virBitmapIsAllClear(slotmap)) { + virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s", + _("Device already assigned to guest")); + return -1; + } + + if (VIR_ALLOC(devinfos) < 0) + return -1; + + for (i =3D 0; i < devlist->count; i++) { + virDomainHostdevDefPtr hostdev =3D devlist->devs[i]->data.hostdev; + virPCIDeviceAddress addr =3D hostdev->source.subsys.u.pci.addr; + + devinfos->infos[addr.function] =3D hostdev->info; + } + + ret =3D virDomainPCIAddressEnsureMultifunctionAddress(priv->pciaddrs, = devinfos); + VIR_FREE(devinfos); + return ret; +} + + void qemuDomainReleaseDeviceAddress(virDomainObjPtr vm, virDomainDeviceInfoPtr info) diff --git a/src/qemu/qemu_domain_address.h b/src/qemu/qemu_domain_address.h index 8d51456f5b..b9ba577001 100644 --- a/src/qemu/qemu_domain_address.h +++ b/src/qemu/qemu_domain_address.h @@ -50,6 +50,10 @@ int qemuDomainEnsurePCIAddress(virDomainObjPtr obj, virQEMUDriverPtr driver) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3); =20 +int qemuDomainPCIMultifunctionHostdevEnsurePCIAddresses(virDomainObjPtr ob= j, + virDomainDeviceDef= ListPtr devlist, + virQEMUDriverPtr d= river); + void qemuDomainFillDeviceIsolationGroup(virDomainDefPtr def, virDomainDeviceDefPtr dev) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index f880a5d6cf..3217d93a73 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7977,17 +7977,28 @@ qemuDomainAttachDeviceLiveInternal(virDomainObjPtr = vm, =20 static int qemuDomainAttachDeviceLive(virDomainObjPtr vm, - virDomainDeviceDefPtr dev, + virDomainDeviceDefListPtr devlist, virQEMUDriverPtr driver) { int ret =3D -1; + size_t i; =20 - if (virDomainDefCompatibleDevice(vm->def, dev, NULL, - VIR_DOMAIN_DEVICE_ACTION_ATTACH, - false) < 0) - return -1; + for (i =3D 0; i < devlist->count; i++) + if (virDomainDefCompatibleDevice(vm->def, devlist->devs[i], NULL, + VIR_DOMAIN_DEVICE_ACTION_ATTACH, + false) < 0) + return ret; + + if (devlist->count > 1) { + ret =3D qemuDomainAttachMultifunctionDevice(vm, devlist, driver); + if (ret =3D=3D 0) { + for (i =3D 0; i < devlist->count; i++) + devlist->devs[i]->data.hostdev =3D NULL; + } + } else if (devlist->count =3D=3D 1) { + ret =3D qemuDomainAttachDeviceLiveInternal(vm, devlist->devs[0], d= river); + } =20 - ret =3D qemuDomainAttachDeviceLiveInternal(vm, dev, driver); if (ret =3D=3D 0) ret =3D qemuDomainUpdateDeviceList(driver, vm, QEMU_ASYNC_JOB_NONE= ); =20 @@ -8334,18 +8345,24 @@ qemuDomainAttachDeviceConfigInternal(virDomainDefPt= r vmdef, =20 static int qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef, - virDomainDeviceDefPtr dev, + virDomainDeviceDefListPtr devlist, virQEMUCapsPtr qemuCaps, unsigned int parse_flags, virDomainXMLOptionPtr xmlopt) { - if (virDomainDefCompatibleDevice(vmdef, dev, NULL, - VIR_DOMAIN_DEVICE_ACTION_ATTACH, - false) < 0) - return -1; + size_t i; =20 - if (qemuDomainAttachDeviceConfigInternal(vmdef, dev)) - return -1; + for (i =3D 0; i < devlist->count; i++) { + if (virDomainDefCompatibleDevice(vmdef, devlist->devs[i], NULL, + VIR_DOMAIN_DEVICE_ACTION_ATTACH, + false) < 0) + return -1; + } + + for (i =3D 0; i < devlist->count; i++) { + if (qemuDomainAttachDeviceConfigInternal(vmdef, devlist->devs[i])) + return -1; + } =20 if (virDomainDefPostParse(vmdef, parse_flags, xmlopt, qemuCaps) < 0) return -1; @@ -8711,9 +8728,14 @@ qemuDomainAttachDeviceLiveAndConfig(virDomainObjPtr = vm, qemuDomainObjPrivatePtr priv =3D vm->privateData; virDomainDefPtr vmdef =3D NULL; g_autoptr(virQEMUDriverConfig) cfg =3D NULL; - virDomainDeviceDefPtr devConf =3D NULL; - virDomainDeviceDef devConfSave =3D { 0 }; + virDomainDeviceDefPtr devConfSave =3D NULL; virDomainDeviceDefPtr devLive =3D NULL; + virDomainDeviceDefListPtr devListConf =3D NULL; + virDomainDeviceDefListPtr devListConfSave =3D NULL; + virDomainDeviceDefListPtr devListLive =3D NULL; + virDomainDeviceDefListData data =3D {.def =3D vm->def, + .xmlopt =3D driver->xmlopt}; + size_t i; int ret =3D -1; unsigned int parse_flags =3D VIR_DOMAIN_DEF_PARSE_INACTIVE | VIR_DOMAIN_DEF_PARSE_ABI_UPDATE; @@ -8732,52 +8754,58 @@ qemuDomainAttachDeviceLiveAndConfig(virDomainObjPtr= vm, if (!vmdef) goto cleanup; =20 - if (!(devConf =3D virDomainDeviceDefParse(xml, vmdef, - driver->xmlopt, priv->qemu= Caps, - parse_flags))) + devListConf =3D qemuDomainDeviceParseXMLMany(xml, &data, priv->qem= uCaps, + parse_flags); + if (!devListConf) goto cleanup; =20 /* - * devConf will be NULLed out by + * devListConf will be NULLed out by * qemuDomainAttachDeviceConfig(), so save it for later use by * qemuDomainAttachDeviceLiveAndConfigHomogenize() */ - devConfSave =3D *devConf; - - if (virDomainDeviceValidateAliasForHotplug(vm, devConf, - VIR_DOMAIN_AFFECT_CONFI= G) < 0) - goto cleanup; + if (flags & VIR_DOMAIN_AFFECT_LIVE) { + devListConfSave =3D virDomainDeviceDefListCopy(devListConf, + &data, + priv->qemuCaps); + if (!devListConfSave) + goto cleanup; + } =20 - if (virDomainDefCompatibleDevice(vmdef, devConf, NULL, - VIR_DOMAIN_DEVICE_ACTION_ATTACH, - false) < 0) - goto cleanup; + for (i =3D 0; i < devListConf->count; i++) { + if (virDomainDeviceValidateAliasForHotplug(vm, + devListConf->devs[i= ], + flags) < 0) + goto cleanup; + } =20 - if (qemuDomainAttachDeviceConfig(vmdef, devConf, priv->qemuCaps, + if (qemuDomainAttachDeviceConfig(vmdef, devListConf, priv->qemuCap= s, parse_flags, driver->xmlopt) < 0) goto cleanup; } =20 if (flags & VIR_DOMAIN_AFFECT_LIVE) { - if (!(devLive =3D virDomainDeviceDefParse(xml, vm->def, - driver->xmlopt, priv->qemu= Caps, - parse_flags))) + devListLive =3D qemuDomainDeviceParseXMLMany(xml, &data, priv->qem= uCaps, + parse_flags); + if (!devListLive) goto cleanup; =20 - if (flags & VIR_DOMAIN_AFFECT_CONFIG) - qemuDomainAttachDeviceLiveAndConfigHomogenize(&devConfSave, de= vLive); + for (i =3D 0; i < devListLive->count; i++) { + devLive =3D devListLive->devs[i]; =20 - if (virDomainDeviceValidateAliasForHotplug(vm, devLive, - VIR_DOMAIN_AFFECT_LIVE)= < 0) - goto cleanup; + if (flags & VIR_DOMAIN_AFFECT_CONFIG) { + devConfSave =3D devListConfSave->devs[i]; + qemuDomainAttachDeviceLiveAndConfigHomogenize(devConfSave, + devLive); + } =20 - if (virDomainDefCompatibleDevice(vm->def, devLive, NULL, - VIR_DOMAIN_DEVICE_ACTION_ATTACH, - true) < 0) - goto cleanup; + if (virDomainDeviceValidateAliasForHotplug(vm, devLive, + VIR_DOMAIN_AFFECT_L= IVE) < 0) + goto cleanup; + } =20 - if (qemuDomainAttachDeviceLive(vm, devLive, driver) < 0) + if (qemuDomainAttachDeviceLive(vm, devListLive, driver) < 0) goto cleanup; /* * update domain status forcibly because the domain status may be @@ -8800,8 +8828,11 @@ qemuDomainAttachDeviceLiveAndConfig(virDomainObjPtr = vm, ret =3D 0; cleanup: virDomainDefFree(vmdef); - virDomainDeviceDefFree(devConf); - virDomainDeviceDefFree(devLive); + devConfSave =3D NULL; + devLive =3D NULL; + virDomainDeviceDefListFree(devListConf); + virDomainDeviceDefListFree(devListConfSave); + virDomainDeviceDefListFree(devListLive); =20 return ret; } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index b9946e8b8e..a6c520ec1b 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1685,6 +1685,92 @@ qemuDomainAttachHostPCIDevice(virQEMUDriverPtr drive= r, } =20 =20 +static int +qemuiHostdevPCIMultifunctionDevicesListSort(const void *p1, + const void *p2) +{ + virDomainDeviceDefPtr a =3D *(virDomainDeviceDefPtr *) p1; + virDomainDeviceDefPtr b =3D *(virDomainDeviceDefPtr *) p2; + virPCIDeviceAddressPtr addr1 =3D &a->data.hostdev->source.subsys.u.pci= .addr; + virPCIDeviceAddressPtr addr2 =3D &b->data.hostdev->source.subsys.u.pci= .addr; + + return addr1->function - addr2->function; +} + + +int +qemuDomainAttachMultifunctionDevice(virDomainObjPtr vm, + virDomainDeviceDefListPtr devlist, + virQEMUDriverPtr driver) +{ + qemuDomainObjPrivatePtr priv =3D vm->privateData; + size_t i, d, h =3D devlist->count; + int ret =3D -1; + char *alias; + virObjectEventPtr event; + virDomainHostdevDefPtr hostdev; + + qsort(devlist->devs, devlist->count, sizeof(*devlist->devs), + qemuiHostdevPCIMultifunctionDevicesListSort); + + if (qemuDomainPCIMultifunctionHostdevEnsurePCIAddresses(vm, devlist, + driver) < 0) + return -1; + + for (d =3D 0; d < devlist->count; d++) { + hostdev =3D devlist->devs[d]->data.hostdev; + + if (qemuDomainAttachPCIHostDevicePrepare(driver, vm->def, hostdev, + priv->qemuCaps) < 0) + goto cleanup; + } + + /* Hotplug all functions, and Primary at last */ + for (h =3D devlist->count; h > 0; h--) { + /* The functions need not be contiguous, as a card may be sold with + * minimal functionality and then install the additional functions= on + * purchase into any of the daughter-card connectors. + */ + hostdev =3D devlist->devs[h-1]->data.hostdev; + + ret =3D qemuDomainAttachHostPCIDevice(driver, vm, hostdev); + if (ret) + goto release; + + alias =3D hostdev->info->alias; + hostdev =3D NULL; + + event =3D virDomainEventDeviceAddedNewFromObj(vm, alias); + virObjectEventStateQueue(driver->domainEventState, event); + } + + release: + /* Release addresses for the device which are not hotplugged. + */ + for (i =3D 0; i < h; i++) + qemuDomainReleaseDeviceAddress(vm, devlist->devs[i]->data.hostdev-= >info); + + cleanup: + /* If none are actually hotplugged and just detached from the + * host driver reattach the devices to host driver. + * + * If one of the hotplug failed, those which are already hotplugged ca= nnot + * be unplugged as they are released by qemu only on guest reboot even + * if we issue device_del on them. + * So, dont attempt to reattach any of them. + * NB: Let them be in the guest as they are not used anyway without + * function-zero? + */ + if (d > 0 && h =3D=3D devlist->count) { + for (i =3D 0; i < d; i++) + qemuHostdevReAttachPCIDevices(driver, vm->def->name, + &devlist->devs[i]->data.hostdev,= 1); + } + + return ret; +} + + void qemuDomainDelTLSObjects(virQEMUDriverPtr driver, virDomainObjPtr vm, diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 9df4a4e5f7..b62528a6d9 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -126,6 +126,10 @@ int qemuDomainAttachPCIHostDevicePrepare(virQEMUDriver= Ptr driver, virDomainDefPtr def, virDomainHostdevDefPtr dev, virQEMUCapsPtr qemuCaps); +int +qemuDomainAttachMultifunctionDevice(virDomainObjPtr vm, + virDomainDeviceDefListPtr devlist, + virQEMUDriverPtr driver); =20 int qemuDomainChrInsert(virDomainDefPtr vmdef, diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index 57f64d191c..32d186ef73 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -90,6 +90,7 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt, virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_PR_MANAGER_HELPER); virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_SCSI_BLOCK); virQEMUCapsSet(priv->qemuCaps, QEMU_CAPS_VIRTIO_PCI_DISABLE_LEGACY); + virQEMUCapsSet(priv->qemuCaps, X_QEMU_CAPS_PCI_MULTIFUNCTION); =20 if (qemuTestCapsCacheInsert(driver.qemuCapsCache, priv->qemuCaps) < 0) return -1; @@ -118,9 +119,14 @@ qemuHotplugCreateObjects(virDomainXMLOptionPtr xmlopt, =20 static int testQemuHotplugAttach(virDomainObjPtr vm, - virDomainDeviceDefPtr dev) + virDomainDeviceDefListPtr devlist) { int ret =3D -1; + virDomainDeviceDefPtr dev; + + if (devlist->count > 1) + return qemuDomainAttachMultifunctionDevice(vm, devlist, &driver); + dev =3D devlist->devs[0]; =20 switch (dev->type) { case VIR_DOMAIN_DEVICE_DISK: @@ -245,7 +251,9 @@ testQemuHotplug(const void *data) bool keep =3D test->keep; unsigned int device_parse_flags =3D 0; virDomainObjPtr vm =3D NULL; - virDomainDeviceDefPtr dev =3D NULL; + virDomainDeviceDefPtr dev =3D NULL; /* temporary */ + virDomainDeviceDefListPtr devlist =3D NULL; + virDomainDeviceDefListData listdata; virCapsPtr caps =3D NULL; qemuMonitorTestPtr test_mon =3D NULL; qemuDomainObjPrivatePtr priv =3D NULL; @@ -283,11 +291,15 @@ testQemuHotplug(const void *data) if (test->action =3D=3D ATTACH) device_parse_flags =3D VIR_DOMAIN_DEF_PARSE_INACTIVE; =20 - if (!(dev =3D virDomainDeviceDefParse(device_xml, vm->def, - driver.xmlopt, NULL, - device_parse_flags))) + listdata.def =3D vm->def; + listdata.xmlopt =3D driver.xmlopt; + devlist =3D qemuDomainDeviceParseXMLMany(device_xml, &listdata, NULL, + device_parse_flags); + if (!devlist) goto cleanup; =20 + dev =3D devlist->devs[0]; /* temporary */ + /* Now is the best time to feed the spoofed monitor with predefined * replies. */ if (!(test_mon =3D qemuMonitorTestNew(driver.xmlopt, vm, &driver, @@ -316,11 +328,11 @@ testQemuHotplug(const void *data) =20 switch (test->action) { case ATTACH: - ret =3D testQemuHotplugAttach(vm, dev); + ret =3D testQemuHotplugAttach(vm, devlist); if (ret =3D=3D 0) { /* vm->def stolen dev->data.* so we just need to free the dev * envelope */ - VIR_FREE(dev); + virDomainDeviceDefListFreeShallow(devlist); } if (ret =3D=3D 0 || fail) ret =3D testQemuHotplugCheckResult(vm, result_xml, @@ -356,7 +368,7 @@ testQemuHotplug(const void *data) virObjectUnref(vm); test->vm =3D NULL; } - virDomainDeviceDefFree(dev); + virDomainDeviceDefListFree(devlist); virObjectUnref(caps); qemuMonitorTestFree(test_mon); return ((ret < 0 && fail) || (!ret && !fail)) ? 0 : -1; @@ -840,6 +852,17 @@ mymain(void) "device_add", QMP_OK); DO_TEST_DETACH("pseries-base-live", "hostdev-pci", false, false, "device_del", QMP_DEVICE_DELETED("hostdev0") QMP_OK); + DO_TEST_ATTACH("base-live", "multifunction-hostdev-pci", false, false, + "device_add", QMP_OK, + "device_add", QMP_OK, + "device_add", QMP_OK, + "device_add", QMP_OK); + + qemuTestSetHostArch(&driver, VIR_ARCH_PPC64); + DO_TEST_ATTACH("pseries-base-live", "multifunction-hostdev-pci-2", fal= se, false, + "device_add", QMP_OK, + "device_add", QMP_OK); + qemuTestSetHostArch(&driver, VIR_ARCH_X86_64); =20 DO_TEST_ATTACH("base-live", "watchdog", false, true, "watchdog-set-action", QMP_OK, diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev= -pci-2.xml b/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev= -pci-2.xml new file mode 100644 index 0000000000..02e2236e5d --- /dev/null +++ b/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci-2.= xml @@ -0,0 +1,14 @@ + + + + +
+ + + + + +
+ + + diff --git a/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev= -pci.xml b/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-p= ci.xml new file mode 100644 index 0000000000..bef4be219f --- /dev/null +++ b/tests/qemuhotplugtestdevices/qemuhotplug-multifunction-hostdev-pci.xml @@ -0,0 +1,26 @@ + + + + +
+ + + + + +
+ + + + + +
+ + + + + +
+ + + diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-base-live+multifuncti= on-hostdev-pci.xml b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+mul= tifunction-hostdev-pci.xml new file mode 100644 index 0000000000..9dd04d3350 --- /dev/null +++ b/tests/qemuhotplugtestdomains/qemuhotplug-base-live+multifunction-host= dev-pci.xml @@ -0,0 +1,82 @@ + + hotplug + d091ea82-29e6-2e34-3005-f02617b36e87 + 4194304 + 4194304 + 4 + + hvm + + + + + + + + + destroy + restart + restart + + /usr/bin/qemu-system-x86_64 + + +
+ + + +
+ + + +
+ + + + + + +
+ + + + + + + + + + +
+ + +
+ + + + +
+ + +
+ + + + +
+ + +
+ + + + +
+ + +
+ + + + + diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+mul= tifunction-hostdev-pci-2.xml b/tests/qemuhotplugtestdomains/qemuhotplug-pse= ries-base-live+multifunction-hostdev-pci-2.xml new file mode 100644 index 0000000000..f99c1b3741 --- /dev/null +++ b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunct= ion-hostdev-pci-2.xml @@ -0,0 +1,59 @@ + + hotplug + d091ea82-29e6-2e34-3005-f02617b36e87 + 4194304 + 4194304 + 4 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu-system-ppc64 + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + +
+ + + + +
+ + +
+ + + + + + diff --git a/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+mul= tifunction-hostdev-pci.xml b/tests/qemuhotplugtestdomains/qemuhotplug-pseri= es-base-live+multifunction-hostdev-pci.xml new file mode 100644 index 0000000000..9338d42e2e --- /dev/null +++ b/tests/qemuhotplugtestdomains/qemuhotplug-pseries-base-live+multifunct= ion-hostdev-pci.xml @@ -0,0 +1,69 @@ + + hotplug + d091ea82-29e6-2e34-3005-f02617b36e87 + 4194304 + 4194304 + 4 + + hvm + + + + destroy + restart + destroy + + /usr/bin/qemu-system-ppc64 + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + + +
+ + +
+ + + + +
+ + +
+ + + + +
+ + +
+ + + + + + + + --=20 2.26.2