From nobody Thu Nov 28 16:40:08 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1521099126680462.2970735536817; Thu, 15 Mar 2018 00:32:06 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3E9217FDE2; Thu, 15 Mar 2018 07:32:05 +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 F251A63123; Thu, 15 Mar 2018 07:32:04 +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 B1004180BADB; Thu, 15 Mar 2018 07:32:04 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w2EHOTtS025659 for ; Wed, 14 Mar 2018 13:24:42 -0400 Received: by smtp.corp.redhat.com (Postfix) id E8DAA17503; Wed, 14 Mar 2018 17:24:29 +0000 (UTC) Received: from mx1.redhat.com (ext-mx09.extmail.prod.ext.phx2.redhat.com [10.5.110.38]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DD9FC5C542 for ; Wed, 14 Mar 2018 17:24:27 +0000 (UTC) Received: from mx0a-001b2d01.pphosted.com (mx0b-001b2d01.pphosted.com [148.163.158.5]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CEC973AD89 for ; Wed, 14 Mar 2018 17:24:25 +0000 (UTC) Received: from pps.filterd (m0098413.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.22/8.16.0.22) with SMTP id w2EHLe5t105953 for ; Wed, 14 Mar 2018 13:24:25 -0400 Received: from e06smtp10.uk.ibm.com (e06smtp10.uk.ibm.com [195.75.94.106]) by mx0b-001b2d01.pphosted.com with ESMTP id 2gq5fk7se2-1 (version=TLSv1.2 cipher=AES256-SHA256 bits=256 verify=NOT) for ; Wed, 14 Mar 2018 13:24:24 -0400 Received: from localhost by e06smtp10.uk.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 14 Mar 2018 17:24:22 -0000 Received: from b06cxnps3075.portsmouth.uk.ibm.com (9.149.109.195) by e06smtp10.uk.ibm.com (192.168.101.140) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Wed, 14 Mar 2018 17:24:21 -0000 Received: from d06av22.portsmouth.uk.ibm.com (d06av22.portsmouth.uk.ibm.com [9.149.105.58]) by b06cxnps3075.portsmouth.uk.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id w2EHOLdf65994842 for ; Wed, 14 Mar 2018 17:24:21 GMT Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 8FC8D4C04E for ; Wed, 14 Mar 2018 17:17:35 +0000 (GMT) Received: from d06av22.portsmouth.uk.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id CC0B44C044 for ; Wed, 14 Mar 2018 17:17:34 +0000 (GMT) Received: from localhost.localdomain (unknown [9.79.182.166]) by d06av22.portsmouth.uk.ibm.com (Postfix) with ESMTP for ; Wed, 14 Mar 2018 17:17:34 +0000 (GMT) From: Shivaprasad G Bhat To: libvir-list@redhat.com Date: Wed, 14 Mar 2018 22:54:18 +0530 In-Reply-To: <152104711186.10112.1077788328340024644.stgit@localhost.localdomain> References: <152104711186.10112.1077788328340024644.stgit@localhost.localdomain> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-TM-AS-GCONF: 00 x-cbid: 18031417-0040-0000-0000-000004207A32 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 18031417-0041-0000-0000-000026237F9D Message-Id: <152104824558.10112.2574989242088914440.stgit@localhost.localdomain> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2018-03-14_09:, , signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=3 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1803140193 X-Greylist: Sender passed SPF test, Sender IP whitelisted by DNSRBL, ACL 207 matched, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Wed, 14 Mar 2018 17:24:26 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Wed, 14 Mar 2018 17:24:26 +0000 (UTC) for IP:'148.163.158.5' DOMAIN:'mx0b-001b2d01.pphosted.com' HELO:'mx0a-001b2d01.pphosted.com' FROM:'sbhat@linux.vnet.ibm.com' RCPT:'' X-RedHat-Spam-Score: -0.7 (RCVD_IN_DNSWL_LOW) 148.163.158.5 mx0b-001b2d01.pphosted.com 148.163.158.5 mx0b-001b2d01.pphosted.com X-Scanned-By: MIMEDefang 2.78 on 10.5.110.38 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-loop: libvir-list@redhat.com Subject: [libvirt] [RFC PATCH 28/28] qemu: hotplug: Implement multifunction device unplug 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: , Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Thu, 15 Mar 2018 07:32:05 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Shivaprasad G Bhat --- src/qemu/qemu_driver.c | 48 +++++++++++++------- src/qemu/qemu_hotplug.c | 111 +++++++++++++++++++++++++++++++++++++++++++= ++++ src/qemu/qemu_hotplug.h | 5 ++ tests/qemuhotplugtest.c | 26 ++++++++--- 4 files changed, 165 insertions(+), 25 deletions(-) diff --git a/src/qemu/qemu_driver.c b/src/qemu/qemu_driver.c index 94f76979e5..0640395b00 100644 --- a/src/qemu/qemu_driver.c +++ b/src/qemu/qemu_driver.c @@ -7858,12 +7858,18 @@ qemuDomainDetachDeviceLiveInternal(virDomainObjPtr = vm, =20 static int qemuDomainDetachDeviceLive(virDomainObjPtr vm, - virDomainDeviceDefPtr dev, + virDomainDeviceDefListPtr devlist, virQEMUDriverPtr driver) { int ret =3D -1; + virDomainDeviceDefPtr dev =3D devlist->devs[0]; + + if (devlist->count > 1) { + ret =3D qemuDomainDetachMultifunctionDevice(vm, devlist, driver); + } else { + ret =3D qemuDomainDetachDeviceLiveInternal(vm, dev, driver); + } =20 - ret =3D qemuDomainDetachDeviceLiveInternal(vm, dev, driver); if (ret =3D=3D 0) ret =3D qemuDomainUpdateDeviceList(driver, vm, QEMU_ASYNC_JOB_NONE= ); =20 @@ -8392,17 +8398,24 @@ qemuDomainDetachDeviceConfigInternal(virDomainDefPt= r vmdef, =20 static int qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef, - virDomainDeviceDefPtr dev, + virDomainDeviceDefListPtr devlist, virCapsPtr caps, 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, caps, parse_flags, xmlopt, NULL) < 0) return -1; =20 + /* Dont allow removing the primary function alone for a multifunction + * device leading to guest start failure later. */ + if (devlist->count > 1 && qemuDomainDefValidatePCIHostdevs(vmdef) < 0) + return -1; + return 0; } =20 @@ -8765,8 +8778,9 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr = driver, { virCapsPtr caps =3D NULL; virQEMUDriverConfigPtr cfg =3D NULL; - virDomainDeviceDefPtr dev =3D NULL, dev_copy =3D NULL; unsigned int parse_flags =3D VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE; + virDomainDeviceDefListPtr devlist =3D NULL, devcopylist =3D NULL; + virDomainDeviceDefListData data =3D {.def =3D vm->def, .xmlopt =3D dri= ver->xmlopt, .caps =3D NULL}; virDomainDefPtr vmdef =3D NULL; int ret =3D -1; =20 @@ -8775,6 +8789,7 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr = driver, =20 if (!(caps =3D virQEMUDriverGetCapabilities(driver, false))) goto cleanup; + data.caps =3D caps; =20 cfg =3D virQEMUDriverGetConfig(driver); =20 @@ -8782,11 +8797,10 @@ 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, - caps, driver->xmlopt, - parse_flags); - if (dev =3D=3D NULL) + devlist =3D qemuDomainDeviceParseXMLMany(xml, &data, parse_flags); + if (!devlist) goto cleanup; + devcopylist =3D devlist; =20 if (flags & VIR_DOMAIN_AFFECT_CONFIG && flags & VIR_DOMAIN_AFFECT_LIVE) { @@ -8794,8 +8808,8 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr = driver, * create a deep copy of device as adding * to CONFIG takes one instance. */ - dev_copy =3D virDomainDeviceDefCopy(dev, vm->def, caps, driver->xm= lopt); - if (!dev_copy) + devcopylist =3D virDomainDeviceDefListCopy(devlist, &data); + if (!devcopylist) goto cleanup; } =20 @@ -8805,14 +8819,14 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPt= r driver, if (!vmdef) goto cleanup; =20 - if ((ret =3D qemuDomainDetachDeviceConfig(vmdef, dev, caps, + if ((ret =3D qemuDomainDetachDeviceConfig(vmdef, devlist, caps, parse_flags, driver->xmlopt)) < 0) goto cleanup; } =20 if (flags & VIR_DOMAIN_AFFECT_LIVE) { - if ((ret =3D qemuDomainDetachDeviceLive(vm, dev_copy, driver)) < 0) + if ((ret =3D qemuDomainDetachDeviceLive(vm, devcopylist, driver)) = < 0) goto cleanup; /* * update domain status forcibly because the domain status may be @@ -8837,9 +8851,9 @@ qemuDomainDetachDeviceLiveAndConfig(virQEMUDriverPtr = driver, cleanup: virObjectUnref(caps); virObjectUnref(cfg); - if (dev !=3D dev_copy) - virDomainDeviceDefFree(dev_copy); - virDomainDeviceDefFree(dev); + if (devlist !=3D devcopylist) + virDomainDeviceDefListFree(devcopylist); + virDomainDeviceDefListFree(devlist); virDomainDefFree(vmdef); return ret; } diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 5f6302eaf9..87acd5cf69 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -5210,6 +5210,117 @@ int qemuDomainDetachHostDevice(virQEMUDriverPtr dri= ver, =20 =20 int +qemuDomainDetachMultifunctionDevice(virDomainObjPtr vm, + virDomainDeviceDefListPtr devlist, + virQEMUDriverPtr driver) +{ + size_t i; + int ret =3D -1; + virBitmapPtr tbdmap =3D NULL, onlinemap =3D NULL; + int *functions =3D NULL; + virDomainHostdevDefPtr hostdev, detach =3D NULL; + virDomainHostdevSubsysPtr subsys =3D NULL; + int slotaggridx =3D 0; + virDomainHostdevSubsysPCIPtr pcisrc =3D NULL; + qemuDomainObjPrivatePtr priv =3D vm->privateData; + + if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DEVICE_DEL_EVENT)) + return -1; + +#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)= ); + goto cleanup; + } + } + + 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); + goto cleanup; + } + } + + /* 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 doesnt n= ot belong to" + " same slot"), pcisrc->addr.domain, pcisrc->a= ddr.bus, + pcisrc->addr.slot, pcisrc->addr.function); + goto cleanup; + } + } + + /* 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")); + goto cleanup; + } + + /* 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); + FOR_EACH_DEV_IN_DEVLIST() + 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); + cleanup: + VIR_FREE(functions); + virBitmapFree(onlinemap); + virBitmapFree(tbdmap); + +#undef FOR_EACH_DEV_IN_DEVLIST + + return ret; +} + + +int qemuDomainDetachShmemDevice(virQEMUDriverPtr driver, virDomainObjPtr vm, virDomainShmemDefPtr dev) diff --git a/src/qemu/qemu_hotplug.h b/src/qemu/qemu_hotplug.h index 7a6e2dfb60..bc850ecc44 100644 --- a/src/qemu/qemu_hotplug.h +++ b/src/qemu/qemu_hotplug.h @@ -164,6 +164,11 @@ qemuDomainAttachMultifunctionDevice(virDomainObjPtr vm, virQEMUDriverPtr driver); =20 int +qemuDomainDetachMultifunctionDevice(virDomainObjPtr vm, + virDomainDeviceDefListPtr devlist, + virQEMUDriverPtr driver); + +int qemuDomainChrInsert(virDomainDefPtr vmdef, virDomainChrDefPtr chr); virDomainChrDefPtr diff --git a/tests/qemuhotplugtest.c b/tests/qemuhotplugtest.c index 39f122e083..61557ce562 100644 --- a/tests/qemuhotplugtest.c +++ b/tests/qemuhotplugtest.c @@ -156,9 +156,14 @@ testQemuHotplugAttach(virDomainObjPtr vm, =20 static int testQemuHotplugDetach(virDomainObjPtr vm, - virDomainDeviceDefPtr dev) + virDomainDeviceDefListPtr devlist) { 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: @@ -256,7 +261,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; /*temperory */ virDomainDeviceDefListPtr devlist =3D NULL; virDomainDeviceDefListData listdata; virCapsPtr caps =3D NULL; @@ -301,7 +305,6 @@ testQemuHotplug(const void *data) devlist =3D qemuDomainDeviceParseXMLMany(device_xml, &listdata, device= _parse_flags); if (!devlist) goto cleanup; - dev =3D devlist->devs[0]; /* temporary */ =20 /* Now is the best time to feed the spoofed monitor with predefined * replies. */ @@ -343,14 +346,14 @@ testQemuHotplug(const void *data) break; =20 case DETACH: - ret =3D testQemuHotplugDetach(vm, dev); + ret =3D testQemuHotplugDetach(vm, devlist); 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 cleanup: @@ -868,16 +871,23 @@ 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_EVENT("base-live", "multifunction-hostdev-pci", false, = true, "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("hostdev2") + QMP_DEVICE_DELETED("hostdev1") + QMP_DEVICE_DELETED("hostdev0") QMP_OK); =20 qemuTestSetHostArch(driver.caps, VIR_ARCH_PPC64); - DO_TEST_ATTACH("pseries-base-live", "multifunction-hostdev-pci-2", fal= se, false, - "device_add", QMP_OK, + DO_TEST_ATTACH_EVENT("pseries-base-live", "multifunction-hostdev-pci-2= ", false, 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.caps, VIR_ARCH_X86_64); =20 DO_TEST_ATTACH("base-live", "watchdog", false, true, -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list