Skip to content

Commit b60f3f6

Browse files
authored
Merge pull request #43 from stackhpc/upstream/wallaby-2023-04-10
Synchronise wallaby with upstream
2 parents 47d884e + c9fc9ba commit b60f3f6

File tree

4 files changed

+108
-7
lines changed

4 files changed

+108
-7
lines changed

doc/source/admin/virtual-gpu.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,11 @@ Caveats
306306
that will cause the instance to be set back to ACTIVE. The ``suspend`` action
307307
in the ``os-instance-actions`` API will have an *Error* state.
308308

309+
.. versionchanged:: 25.0.0
310+
311+
This has been resolved in the Yoga release and backported to Xena and
312+
Wallaby. See `bug 1948705`_.
313+
309314
* Resizing an instance with a new flavor that has vGPU resources doesn't
310315
allocate those vGPUs to the instance (the instance is created without
311316
vGPU resources). The proposed workaround is to rebuild the instance after
@@ -355,6 +360,7 @@ For nested vGPUs:
355360

356361
.. _bug 1778563: https://bugs.launchpad.net/nova/+bug/1778563
357362
.. _bug 1762688: https://bugs.launchpad.net/nova/+bug/1762688
363+
.. _bug 1948705: https://bugs.launchpad.net/nova/+bug/1948705
358364

359365
.. Links
360366
.. _Intel GVT-g: https://01.org/igvt-g

nova/tests/unit/virt/libvirt/test_driver.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16570,9 +16570,15 @@ def test_resume(self):
1657016570
mock.patch.object(guest, 'sync_guest_time'),
1657116571
mock.patch.object(drvr, '_wait_for_running',
1657216572
side_effect=loopingcall.LoopingCallDone()),
16573+
mock.patch.object(drvr,
16574+
'_get_mdevs_from_guest_config',
16575+
return_value='fake_mdevs'),
16576+
mock.patch.object(drvr, '_attach_mediated_devices'),
1657316577
) as (_get_existing_domain_xml, _create_guest_with_network,
1657416578
_attach_pci_devices, get_instance_pci_devs, get_image_metadata,
16575-
mock_sync_time, mock_wait):
16579+
mock_sync_time, mock_wait,
16580+
_get_mdevs_from_guest_config,
16581+
_attach_mediated_devices):
1657616582
get_image_metadata.return_value = {'bar': 234}
1657716583

1657816584
drvr.resume(self.context, instance, network_info,
@@ -16587,6 +16593,9 @@ def test_resume(self):
1658716593
self.assertTrue(mock_sync_time.called)
1658816594
_attach_pci_devices.assert_has_calls([mock.call(guest,
1658916595
'fake_pci_devs')])
16596+
_attach_mediated_devices.assert_has_calls(
16597+
[mock.call(guest, 'fake_mdevs')]
16598+
)
1659016599

1659116600
@mock.patch.object(host.Host, '_get_domain')
1659216601
@mock.patch.object(libvirt_driver.LibvirtDriver, 'get_info')
@@ -25883,6 +25892,55 @@ def test_detach_mediated_devices_raises_exc(self):
2588325892
self.assertRaises(test.TestingException,
2588425893
self._test_detach_mediated_devices, exc)
2588525894

25895+
@mock.patch.object(libvirt_guest.Guest, 'attach_device')
25896+
def _test_attach_mediated_devices(self, side_effect, attach_device):
25897+
dom_without_vgpu = (
25898+
"""<domain> <devices>
25899+
<disk type='file' device='disk'>
25900+
<driver name='qemu' type='qcow2' cache='none'/>
25901+
<source file='xxx'/>
25902+
<target dev='vda' bus='virtio'/>
25903+
<alias name='virtio-disk0'/>
25904+
<address type='pci' domain='0x0000' bus='0x00'
25905+
slot='0x04' function='0x0'/>
25906+
</disk>
25907+
</devices></domain>""")
25908+
25909+
vgpu_xml = (
25910+
"""<domain> <devices>
25911+
<hostdev mode='subsystem' type='mdev' managed='no'
25912+
model='vfio-pci'>
25913+
<source>
25914+
<address uuid='81db53c6-6659-42a0-a34c-1507fdc72983'/>
25915+
</source>
25916+
<alias name='hostdev0'/>
25917+
<address type='pci' domain='0x0000' bus='0x00' slot='0x05'
25918+
function='0x0'/>
25919+
</hostdev>
25920+
</devices></domain>""")
25921+
25922+
attach_device.side_effect = side_effect
25923+
25924+
drvr = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True)
25925+
guest = libvirt_guest.Guest(FakeVirtDomain(fake_xml=dom_without_vgpu))
25926+
mdevs = drvr._get_mdevs_from_guest_config(vgpu_xml)
25927+
drvr._attach_mediated_devices(guest, mdevs)
25928+
return attach_device
25929+
25930+
def test_attach_mediated_devices(self):
25931+
def fake_attach_device(cfg_obj, **kwargs):
25932+
self.assertIsInstance(cfg_obj,
25933+
vconfig.LibvirtConfigGuestHostdevMDEV)
25934+
25935+
attach_mock = self._test_attach_mediated_devices(fake_attach_device)
25936+
attach_mock.assert_called_once_with(mock.ANY, live=True)
25937+
25938+
def test_attach_mediated_devices_raises_exc(self):
25939+
exc = test.TestingException()
25940+
25941+
self.assertRaises(test.TestingException,
25942+
self._test_attach_mediated_devices, exc)
25943+
2588625944
def test_storage_bus_traits__qemu_kvm(self):
2588725945
"""Test getting storage bus traits per virt type.
2588825946
"""

nova/virt/libvirt/driver.py

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3960,6 +3960,10 @@ def resume(self, context, instance, network_info, block_device_info=None):
39603960
"""resume the specified instance."""
39613961
xml = self._get_existing_domain_xml(instance, network_info,
39623962
block_device_info)
3963+
# NOTE(gsantos): The mediated devices that were removed on suspension
3964+
# are still present in the xml. Let's take their references from it
3965+
# and re-attach them.
3966+
mdevs = self._get_mdevs_from_guest_config(xml)
39633967
# NOTE(efried): The instance should already have a vtpm_secret_uuid
39643968
# registered if appropriate.
39653969
guest = self._create_guest_with_network(
@@ -3969,6 +3973,7 @@ def resume(self, context, instance, network_info, block_device_info=None):
39693973
pci_manager.get_instance_pci_devs(instance))
39703974
self._attach_direct_passthrough_ports(
39713975
context, instance, guest, network_info)
3976+
self._attach_mediated_devices(guest, mdevs)
39723977
timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_running,
39733978
instance)
39743979
timer.start(interval=0.5).wait()
@@ -7973,12 +7978,6 @@ def _detach_mediated_devices(self, guest):
79737978
guest.detach_device(mdev_cfg, live=True)
79747979
except libvirt.libvirtError as ex:
79757980
error_code = ex.get_error_code()
7976-
# NOTE(sbauza): There is a pending issue with libvirt that
7977-
# doesn't allow to hot-unplug mediated devices. Let's
7978-
# short-circuit the suspend action and set the instance back
7979-
# to ACTIVE.
7980-
# TODO(sbauza): Once libvirt supports this, amend the resume()
7981-
# operation to support reallocating mediated devices.
79827981
if error_code == libvirt.VIR_ERR_CONFIG_UNSUPPORTED:
79837982
reason = _("Suspend is not supported for instances having "
79847983
"attached vGPUs.")
@@ -7987,6 +7986,38 @@ def _detach_mediated_devices(self, guest):
79877986
else:
79887987
raise
79897988

7989+
def _attach_mediated_devices(self, guest, devs):
7990+
for mdev_cfg in devs:
7991+
try:
7992+
guest.attach_device(mdev_cfg, live=True)
7993+
except libvirt.libvirtError as ex:
7994+
error_code = ex.get_error_code()
7995+
if error_code == libvirt.VIR_ERR_DEVICE_MISSING:
7996+
LOG.warning("The mediated device %s was not found and "
7997+
"won't be reattached to %s.", mdev_cfg, guest)
7998+
else:
7999+
raise
8000+
8001+
def _get_mdevs_from_guest_config(self, xml):
8002+
"""Get all libvirt's mediated devices from a guest's config (XML) file.
8003+
We don't have to worry about those devices being used by another guest,
8004+
since they remain allocated for the current guest as long as they are
8005+
present in the XML.
8006+
8007+
:param xml: The XML from the guest we want to get a list of mdevs from.
8008+
8009+
:returns: A list containing the objects that represent the mediated
8010+
devices attached to the guest's config passed as argument.
8011+
"""
8012+
config = vconfig.LibvirtConfigGuest()
8013+
config.parse_str(xml)
8014+
8015+
devs = []
8016+
for dev in config.devices:
8017+
if isinstance(dev, vconfig.LibvirtConfigGuestHostdevMDEV):
8018+
devs.append(dev)
8019+
return devs
8020+
79908021
def _has_numa_support(self):
79918022
# This means that the host can support LibvirtConfigGuestNUMATune
79928023
# and the nodeset field in LibvirtConfigGuestMemoryBackingPage
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
fixes:
3+
- |
4+
Amended the guest resume operation to support mediated devices, as
5+
libvirt's minimum required version (v6.0.0) supports the hot-plug/unplug of
6+
mediated devices, which was addressed in v4.3.0.

0 commit comments

Comments
 (0)