Skip to content

Commit 23c48b6

Browse files
committed
Simulate bug 1969496
As If9ab424cc7375a1f0d41b03f01c4a823216b3eb8 stated there is a way for the pci_device table to become inconsistent. Parent PF can be in 'available' state while children VFs are still in 'unavailable' state. In this situation the PF is schedulable but the PCI claim will fail to when try to mark the dependent VFs unavailable. This patch adds a test case that shows the error. Related-Bug: #1969496 Change-Id: I7b432d7a32aeb1ab765d1f731691c7841a8f1440 (cherry picked from commit 9ee5d2c)
1 parent d7bca63 commit 23c48b6

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

nova/tests/unit/pci/test_manager.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
from nova.compute import vm_states
2323
from nova import context
24+
from nova import exception
2425
from nova import objects
2526
from nova.objects import fields
2627
from nova.pci import manager
@@ -478,6 +479,61 @@ def test_set_hvdevs_unavailable_pf_removed(self):
478479
self.assertEqual('allocated', dev4_vf.status)
479480
self.assertEqual(uuidsentinel.instance1, dev4_vf.instance_uuid)
480481

482+
def test_claim_available_pf_while_child_vf_is_unavailable(self):
483+
# NOTE(gibi): this is bug 1969496. The state created here is
484+
# inconsistent and should not happen. But it did happen in some cases
485+
# where we were not able to track down the way how it happened.
486+
487+
# We start with a PF parent and a VF child. The PF is available and
488+
# the VF is unavailable.
489+
pf = copy.deepcopy(fake_db_dev_3)
490+
vf = copy.deepcopy(fake_db_dev_4)
491+
vf['status'] = fields.PciDeviceStatus.UNAVAILABLE
492+
self._create_tracker([pf, vf])
493+
494+
pf_dev = self._get_device_by_address(pf['address'])
495+
self.assertEqual('available', pf_dev.status)
496+
vf_dev = self._get_device_by_address(vf['address'])
497+
self.assertEqual('unavailable', vf_dev.status)
498+
499+
pci_requests_obj = self._create_pci_requests_object(
500+
[
501+
{
502+
'count': 1,
503+
'spec': [{'dev_type': fields.PciDeviceType.SRIOV_PF}]
504+
}
505+
],
506+
instance_uuid=uuidsentinel.instance1,
507+
)
508+
# now try to claim and allocate the PF. It should work as it is
509+
# available
510+
# This is bug 1969496 as the claim fails with exception
511+
ex = self.assertRaises(
512+
exception.PciDevicePoolEmpty,
513+
self.tracker.claim_instance,
514+
mock.sentinel.context,
515+
pci_requests_obj,
516+
None
517+
)
518+
self.assertIn(
519+
'Attempt to consume PCI device 1:0000:00:02.1 from empty pool',
520+
str(ex)
521+
)
522+
pf_dev = self._get_device_by_address(pf['address'])
523+
self.assertEqual('available', pf_dev.status)
524+
vf_dev = self._get_device_by_address(vf['address'])
525+
self.assertEqual('unavailable', vf_dev.status)
526+
527+
# This should work when the bug is fixed
528+
# self.tracker.claim_instance(
529+
# mock.sentinel.context, pci_requests_obj, None)
530+
# self.tracker.allocate_instance({'uuid': uuidsentinel.instance1})
531+
532+
# pf_dev = self._get_device_by_address(pf['address'])
533+
# self.assertEqual('allocated', pf_dev.status)
534+
# vf_dev = self._get_device_by_address(vf['address'])
535+
# self.assertEqual('unavailable', vf_dev.status)
536+
481537
def test_update_pci_for_instance_active(self):
482538
pci_requests_obj = self._create_pci_requests_object(fake_pci_requests)
483539
self.tracker.claim_instance(mock.sentinel.context,

0 commit comments

Comments
 (0)