From nobody Sun Feb 8 14:53:22 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=1590009278; cv=none; d=zohomail.com; s=zohoarc; b=L8jthF5Kligd9FoHIwOmzflXL3VcxVnfL65I/5TQimDkqNHzpPX4dVOzX7oCqmhyu0gR4L8FwPbYZioRcOeTQbJzZwL80N+xgI3kZcVDz6zV/oVEr1MrlVoz4Yq3AmUlWK/N+OhvT663i5SN//uGkry/XtAwIapp8Tlk2IRQnX4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1590009278; 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=Ke4etmALym6Wo5GkDtFOywwZemXQZzn1hU5m0XPVi0k=; b=XyUu2aBRglRiu2phuQdK0QH28PH/bG9Ugs6puHg3O3Q/gF0RJDaVp1difXDV6bB2fM0m3WQB7esfEuivUAKi4dRNGd4s+32jacO7ixjTg2B9BvYE3OCJDRP5Vh0OIl4IgLbs4W0Wjcfecfd4sQgotxNDtQl/2zUAfuWz31DgiG4= 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 1590009278432214.24982849632568; Wed, 20 May 2020 14:14:38 -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-471-mtMSRRFNMyKaRuIoWLOq6A-1; Wed, 20 May 2020 17:14:34 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 7B2F08018A6; Wed, 20 May 2020 21:14:29 +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 5C0FA6E9EA; Wed, 20 May 2020 21:14:29 +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 2C49C180954D; Wed, 20 May 2020 21:14:29 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 04KLCoOM002368 for ; Wed, 20 May 2020 17:12:50 -0400 Received: by smtp.corp.redhat.com (Postfix) id 8EBDC1007A45; Wed, 20 May 2020 21:12:50 +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 7177810D14F9 for ; Wed, 20 May 2020 21:12:46 +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 3E59C800294 for ; Wed, 20 May 2020 21:12:46 +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-400-aoI4Da79ON6Gq3Bm68XYTw-1; Wed, 20 May 2020 17:12:43 -0400 Received: by mail-qk1-f193.google.com with SMTP id b6so5111461qkh.11 for ; Wed, 20 May 2020 14:12:43 -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.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 20 May 2020 14:12:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1590009277; 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=Ke4etmALym6Wo5GkDtFOywwZemXQZzn1hU5m0XPVi0k=; b=Rvk4IGZGbz4t2itMhxjyNgl5EW7h0iIykYz7/+9GCM/X0QybdMdac2lvni2ywf7HkQ8tHV psW1vjZ3cX+1RmozJKztf7mtM4p7r9m6ehbPJQGhdPkGe8VqSSVdmzh0rRMDUbjVfuxeKS aayfaS9ammRFusSJZZhTxbIFL3rFA1U= X-MC-Unique: mtMSRRFNMyKaRuIoWLOq6A-1 X-MC-Unique: aoI4Da79ON6Gq3Bm68XYTw-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=Ke4etmALym6Wo5GkDtFOywwZemXQZzn1hU5m0XPVi0k=; b=BxGwzLZYLHR3fhM+LaiXQP4FSuIe4DBQS/3w37dOvCrwpRA6baPcp3nOhryYwL+qLa mUtNw1q+Rv+cl/BSqPdggF/9UqwSKVEsnHAwj1IbSTtzo/HMC2fkmwgBt2e8Hr2XN3nv F+masTZn0a43BWE0G1MVwRhv8CUx6L8QSi1U5JRGE5D0dKGtAcX3UwfzE4YIH9XJDzlh KKIyMUcqXAFPx12Wmzyq7OylDfT4SpS0gTs2vms7tpGMcAU9GyWwWgtGZfKOJOyJoZfI yhjYh98CJuoGmVscVP69v+5J9GGm4ePsEJ3N0eRcJKfpH6GSSF0/QYPMPxWupPuI8QXG HGeg== X-Gm-Message-State: AOAM532dBsfrdH52StAMEZZKxJMEo/nkTp+jHFgeG1SuoIpcZq17/HMh kZftwd6GgM6E87ISCqe7liiHscU3 X-Google-Smtp-Source: ABdhPJweejTLn71xwbs/GuNqjYbuJxcow5AfCID/5R/dO393gbdiUoOcoI4CV5HxgRUuqjk44OiFwA== X-Received: by 2002:a37:7904:: with SMTP id u4mr6787632qkc.297.1590009162845; Wed, 20 May 2020 14:12:42 -0700 (PDT) From: Daniel Henrique Barboza To: libvir-list@redhat.com Subject: [PATCH v3 18/21] qemu: hotplug: Implement multifunction device unplug Date: Wed, 20 May 2020 18:11:40 -0300 Message-Id: <20200520211143.2980117-19-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.3 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.15 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 same design ideas used in multifunction hotplug were used here as well. qemuDomainDetachDeviceConfig() was changed to accept a list of devices instead of a single device definition. qemuDomainDetachDeviceLiveAndConfig() was changed to handle device lists as well. For VIR_DOMAIN_AFFECT_LIVE, check if we're handling a single device unplug (devlist size =3D 1) and forward it to the regular qemuDomainDetachDeviceLive() function. Otherwise, a new qemuDomainDetachMultifunctionDevice() was added to handle the hot-unplug of multifunction devices. DetachMultifunctionDevice() is not considering the new multifunction unplug mechanics for the Pseries guest, present in QEMU 4.2 (the newest release ATM), to not break compatibility with older QEMU versions. This will be done properly in a later patch. Signed-off-by: Shivaprasad G Bhat Signed-off-by: Daniel Henrique Barboza --- src/qemu/qemu_driver.c | 66 +++++++++++++++------- src/qemu/qemu_hotplug.c | 116 +++++++++++++++++++++++++++++++++++++++ src/qemu/qemu_hotplug.h | 5 ++ src/qemu/qemu_validate.c | 2 +- src/qemu/qemu_validate.h | 1 + tests/qemuhotplugtest.c | 27 ++++++--- 6 files changed, 189 insertions(+), 28 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index ce44a1455a..e7119fda8c 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -50,6 +50,7 @@ #include "qemu_security.h" #include "qemu_checkpoint.h" #include "qemu_backup.h" +#include "qemu_validate.h" =20 #include "virerror.h" #include "virlog.h" @@ -8569,17 +8570,27 @@ qemuDomainDetachDeviceConfigInternal(virDomainDefPt= r vmdef, =20 static int qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef, - virDomainDeviceDefPtr dev, + virDomainDeviceDefListPtr devlist, virQEMUCapsPtr qemuCaps, unsigned int parse_flags, virDomainXMLOptionPtr xmlopt) { - if (qemuDomainDetachDeviceConfigInternal(vmdef, dev)) - return -1; + size_t i; + + for (i =3D 0; i < devlist->count; i++) { + if (qemuDomainDetachDeviceConfigInternal(vmdef, devlist->devs[i])) + return -1; + } =20 if (virDomainDefPostParse(vmdef, parse_flags, xmlopt, qemuCaps) < 0) return -1; =20 + /* Don't allow removing the primary function alone for a + * multifunction device (devlist->count greater than 1) + * leading to guest start failure later. */ + if (devlist->count > 1 && qemuValidateDomainDefPCIHostdevs(vmdef) < 0) + return -1; + return 0; } =20 @@ -9012,7 +9023,9 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr = driver, { qemuDomainObjPrivatePtr priv =3D vm->privateData; g_autoptr(virQEMUDriverConfig) cfg =3D NULL; - virDomainDeviceDefPtr dev =3D NULL, dev_copy =3D NULL; + virDomainDeviceDefListPtr devlist =3D NULL, devcopylist =3D NULL; + virDomainDeviceDefListData data =3D {.def =3D vm->def, + .xmlopt =3D driver->xmlopt}; unsigned int parse_flags =3D VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE; virDomainDefPtr vmdef =3D NULL; int ret =3D -1; @@ -9026,11 +9039,11 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPt= r driver, !(flags & VIR_DOMAIN_AFFECT_LIVE)) parse_flags |=3D VIR_DOMAIN_DEF_PARSE_INACTIVE; =20 - dev =3D dev_copy =3D virDomainDeviceDefParse(xml, vm->def, - driver->xmlopt, priv->qemuCap= s, - parse_flags); - if (dev =3D=3D NULL) + devlist =3D qemuDomainDeviceParseXMLMany(xml, &data, + priv->qemuCaps, parse_flags); + if (!devlist) goto cleanup; + devcopylist =3D devlist; =20 if (flags & VIR_DOMAIN_AFFECT_CONFIG && flags & VIR_DOMAIN_AFFECT_LIVE) { @@ -9038,9 +9051,9 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr = driver, * create a deep copy of device as adding * to CONFIG takes one instance. */ - dev_copy =3D virDomainDeviceDefCopy(dev, vm->def, - driver->xmlopt, priv->qemuCaps); - if (!dev_copy) + devcopylist =3D virDomainDeviceDefListCopy(devlist, &data, + priv->qemuCaps); + if (!devcopylist) goto cleanup; } =20 @@ -9050,7 +9063,7 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr = driver, if (!vmdef) goto cleanup; =20 - if (qemuDomainDetachDeviceConfig(vmdef, dev, priv->qemuCaps, + if (qemuDomainDetachDeviceConfig(vmdef, devlist, priv->qemuCaps, parse_flags, driver->xmlopt) < 0) goto cleanup; @@ -9059,7 +9072,13 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr= driver, if (flags & VIR_DOMAIN_AFFECT_LIVE) { int rc; =20 - if ((rc =3D qemuDomainDetachDeviceLive(vm, dev_copy, driver, false= )) < 0) + if (devlist->count > 1) { + if ((rc =3D qemuDomainDetachMultifunctionDevice(vm, devlist, d= river)) < 0) + goto cleanup; + } else if ((rc =3D qemuDomainDetachDeviceLive(vm, + devcopylist->devs[0], + driver, + false)) < 0) goto cleanup; =20 if (rc =3D=3D 0 && qemuDomainUpdateDeviceList(driver, vm, QEMU_ASY= NC_JOB_NONE) < 0) @@ -9086,9 +9105,9 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr = driver, ret =3D 0; =20 cleanup: - if (dev !=3D dev_copy) - virDomainDeviceDefFree(dev_copy); - virDomainDeviceDefFree(dev); + if (devlist !=3D devcopylist) + virDomainDeviceDefListFree(devcopylist); + virDomainDeviceDefListFree(devlist); virDomainDefFree(vmdef); return ret; } @@ -9106,6 +9125,7 @@ qemuDomainDetachDeviceAliasLiveAndConfig(virQEMUDrive= rPtr driver, virDomainDefPtr persistentDef =3D NULL; virDomainDefPtr vmdef =3D NULL; unsigned int parse_flags =3D VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE; + virDomainDeviceDefListPtr devlist =3D NULL; int ret =3D -1; =20 virCheckFlags(VIR_DOMAIN_AFFECT_LIVE | @@ -9121,16 +9141,22 @@ qemuDomainDetachDeviceAliasLiveAndConfig(virQEMUDri= verPtr driver, goto cleanup; =20 if (persistentDef) { - virDomainDeviceDef dev; + virDomainDeviceDefPtr dev; =20 if (!(vmdef =3D virDomainObjCopyPersistentDef(vm, driver->xmlopt, priv->qemuCaps))) goto cleanup; =20 - if (virDomainDefFindDevice(vmdef, alias, &dev, true) < 0) + if (virDomainDefFindDevice(vmdef, alias, dev, true) < 0) + goto cleanup; + + if (VIR_ALLOC(devlist) < 0) goto cleanup; =20 - if (qemuDomainDetachDeviceConfig(vmdef, &dev, priv->qemuCaps, + if (VIR_APPEND_ELEMENT(devlist->devs, devlist->count, dev) < 0) + goto cleanup; + + if (qemuDomainDetachDeviceConfig(vmdef, devlist, priv->qemuCaps, parse_flags, driver->xmlopt) < 0) goto cleanup; } @@ -9159,6 +9185,8 @@ qemuDomainDetachDeviceAliasLiveAndConfig(virQEMUDrive= rPtr driver, ret =3D 0; cleanup: virDomainDefFree(vmdef); + virDomainDeviceDefListFree(devlist); + return ret; } =20 diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index a6c520ec1b..9d6671f4f6 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -6086,6 +6086,122 @@ qemuDomainDetachDeviceLive(virDomainObjPtr vm, } =20 =20 +int +qemuDomainDetachMultifunctionDevice(virDomainObjPtr vm, + virDomainDeviceDefListPtr devlist, + virQEMUDriverPtr driver) +{ + size_t i; + int ret =3D -1; + g_autoptr(virBitmap) onlinemap =3D NULL; + virDomainHostdevDefPtr hostdev, detach =3D NULL; + virDomainHostdevSubsysPtr subsys =3D NULL; + int slotaggridx =3D 0; + virDomainHostdevSubsysPCIPtr pcisrc =3D NULL; + qemuDomainObjPrivatePtr priv =3D vm->privateData; + + qsort(devlist->devs, devlist->count, sizeof(*devlist->devs), + qemuiHostdevPCIMultifunctionDevicesListSort); + +#define FOR_EACH_DEV_IN_DEVLIST() \ + for (i =3D 0; i < devlist->count; i++) { \ + hostdev =3D devlist->devs[i]->data.hostdev; \ + subsys =3D &hostdev->source.subsys; \ + pcisrc =3D &subsys->u.pci; \ + virDomainHostdevFind(vm->def, hostdev, &detach); + + FOR_EACH_DEV_IN_DEVLIST() + if (hostdev->mode !=3D VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("hot unplug is not supported for hostdev mode= '%s'"), + virDomainHostdevModeTypeToString(hostdev->mode)= ); + return -1; + } + } + + FOR_EACH_DEV_IN_DEVLIST() + if (!detach) { + virReportError(VIR_ERR_DEVICE_MISSING, + _("host pci device %.4x:%.2x:%.2x.%.1x not foun= d"), + pcisrc->addr.domain, pcisrc->addr.bus, + pcisrc->addr.slot, pcisrc->addr.function); + return -1; + } + } + + /* Check if the devices belong to same guest slot.*/ + FOR_EACH_DEV_IN_DEVLIST() + /* Pick one aggregateSlotIdx and compare against rest of them */ + slotaggridx =3D slotaggridx ? slotaggridx : detach->info->aggregat= eSlotIdx; + if (slotaggridx !=3D detach->info->aggregateSlotIdx) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("host pci device %.4x:%.2x:%.2x.%.1x does " + "not belong to same slot"), + pcisrc->addr.domain, + pcisrc->addr.bus, + pcisrc->addr.slot, + pcisrc->addr.function); + return -1; + } + } + + /* Check if the whole slot is being removed or not */ + onlinemap =3D virDomainDefHostdevGetPCIOnlineFunctionMap(vm->def, slot= aggridx); + FOR_EACH_DEV_IN_DEVLIST() + ignore_value(virBitmapClearBit(onlinemap, pcisrc->addr.function)); + } + + if (!virBitmapIsAllClear(onlinemap)) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s", + _("hot unplug of partial PCI slot not allowed")); + return -1; + } + + /* Mark all aliases for removal */ + memset(&priv->unplug, 0, sizeof(priv->unplug)); + FOR_EACH_DEV_IN_DEVLIST() + if (qemuAssignDeviceHostdevAlias(vm->def, &detach->info->alias, -1= ) < 0) + goto reset; + + qemuDomainMarkDeviceAliasForRemoval(vm, detach->info->alias, false= ); + } + + qemuDomainObjEnterMonitor(driver, vm); + + /* must plug non-zero first, zero at last */ + for (i =3D devlist->count; i > 0; i--) { + hostdev =3D devlist->devs[i -1]->data.hostdev; + subsys =3D &hostdev->source.subsys; + pcisrc =3D &subsys->u.pci; + virDomainHostdevFind(vm->def, hostdev, &detach); + + if (qemuMonitorDelDevice(priv->mon, detach->info->alias) < 0) { + ignore_value(qemuDomainObjExitMonitor(driver, vm)); + if (virDomainObjIsActive(vm)) + virDomainAuditHostdev(vm, detach, "detach", false); + goto reset; + } + if (ARCH_IS_X86(vm->def->os.arch)) + break; /* deleting any one is enough! */ + } + + if (qemuDomainObjExitMonitor(driver, vm) < 0) + ret =3D -1; + + if ((ret =3D qemuDomainWaitForDeviceRemoval(vm)) =3D=3D 1) { + FOR_EACH_DEV_IN_DEVLIST() + ret =3D qemuDomainRemoveHostDevice(driver, vm, detach); + } + } + reset: + qemuDomainResetDeviceRemoval(vm); + +#undef FOR_EACH_DEV_IN_DEVLIST + + return ret; +} + + static int qemuDomainRemoveVcpu(virQEMUDriverPtr driver, virDomainObjPtr vm, diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index b62528a6d9..6e74473936 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -131,6 +131,11 @@ qemuDomainAttachMultifunctionDevice(virDomainObjPtr vm, virDomainDeviceDefListPtr devlist, virQEMUDriverPtr driver); =20 +int +qemuDomainDetachMultifunctionDevice(virDomainObjPtr vm, + virDomainDeviceDefListPtr devlist, + virQEMUDriverPtr driver); + int qemuDomainChrInsert(virDomainDefPtr vmdef, virDomainChrDefPtr chr); diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c index 956e3daf7d..b913ce2c5b 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -802,7 +802,7 @@ static int qemuValidateDomainDefPCIMultifunctionHostdev= (qemuDomainPCIHostdevData } =20 =20 -static int qemuValidateDomainDefPCIHostdevs(const virDomainDef *def) +int qemuValidateDomainDefPCIHostdevs(const virDomainDef *def) { qemuDomainPCIHostdevdata hostdevdata =3D {def, NULL, NULL}; =20 diff --git a/src/qemu/qemu_validate.h b/src/qemu/qemu_validate.h index acf7d26ce0..c6782066eb 100644 --- a/src/qemu/qemu_validate.h +++ b/src/qemu/qemu_validate.h @@ -33,3 +33,4 @@ int qemuValidateDomainDeviceDefDisk(const virDomainDiskDe= f *disk, int qemuValidateDomainDeviceDef(const virDomainDeviceDef *dev, const virDomainDef *def, void *opaque); +int qemuValidateDomainDefPCIHostdevs(const virDomainDef *def); diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index 32d186ef73..175f3ffed8 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -158,10 +158,15 @@ testQemuHotplugAttach(virDomainObjPtr vm, =20 static int testQemuHotplugDetach(virDomainObjPtr vm, - virDomainDeviceDefPtr dev, + virDomainDeviceDefListPtr devlist, bool async) { int ret =3D -1; + virDomainDeviceDefPtr dev; + + if (devlist->count > 1) + return qemuDomainDetachMultifunctionDevice(vm, devlist, &driver); + dev =3D devlist->devs[0]; =20 switch (dev->type) { case VIR_DOMAIN_DEVICE_DISK: @@ -251,7 +256,6 @@ testQemuHotplug(const void *data) bool keep =3D test->keep; unsigned int device_parse_flags =3D 0; virDomainObjPtr vm =3D NULL; - virDomainDeviceDefPtr dev =3D NULL; /* temporary */ virDomainDeviceDefListPtr devlist =3D NULL; virDomainDeviceDefListData listdata; virCapsPtr caps =3D NULL; @@ -298,8 +302,6 @@ testQemuHotplug(const void *data) 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, @@ -340,14 +342,14 @@ testQemuHotplug(const void *data) break; =20 case DETACH: - ret =3D testQemuHotplugDetach(vm, dev, false); + ret =3D testQemuHotplugDetach(vm, devlist, false); if (ret =3D=3D 0 || fail) ret =3D testQemuHotplugCheckResult(vm, domain_xml, domain_filename, fail); break; =20 case UPDATE: - ret =3D testQemuHotplugUpdate(vm, dev); + ret =3D testQemuHotplugUpdate(vm, devlist->devs[0]); } =20 virObjectLock(priv->mon); @@ -852,16 +854,25 @@ 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, + DO_TEST_ATTACH("base-live", "multifunction-hostdev-pci", false, true, "device_add", QMP_OK, "device_add", QMP_OK, "device_add", QMP_OK, "device_add", QMP_OK); + DO_TEST_DETACH("base-live", "multifunction-hostdev-pci", false, false, + "device_del", QMP_DEVICE_DELETED("hostdev3") + QMP_DEVICE_DELETED("hostdev2") + QMP_DEVICE_DELETED("hostdev1") + QMP_DEVICE_DELETED("hostdev0") QMP_OK); =20 qemuTestSetHostArch(&driver, VIR_ARCH_PPC64); - DO_TEST_ATTACH("pseries-base-live", "multifunction-hostdev-pci-2", fal= se, false, + DO_TEST_ATTACH("pseries-base-live", "multifunction-hostdev-pci-2", fal= se, true, "device_add", QMP_OK, "device_add", QMP_OK); + DO_TEST_DETACH("pseries-base-live", "multifunction-hostdev-pci-2", fal= se, false, + "device_del", QMP_OK, + "device_del", QMP_DEVICE_DELETED("hostdev1") + QMP_DEVICE_DELETED("hostdev0") QMP_OK); qemuTestSetHostArch(&driver, VIR_ARCH_X86_64); =20 DO_TEST_ATTACH("base-live", "watchdog", false, true, --=20 2.26.2