Separate methods to free claimed and allocated devs
The existing PCI manager exposes a single method to free PCI resources free_instance(), which frees both claimed and allocated PCI resources for an instance. This change proposes to extend the PCI manager API with two methods: 1. free_instance_claims() : free PCI resources claims for instance. 2. free_instance_allocations() : free PCI resources allocations for instance. This change refactors free_instance() to use (1) and (2) from above. This change is required to enable SR-IOV live migration as it is required to free instance PCI allocations on the source node in case of a successful migration and free instance PCI claims on the destination node in case of an unsuccessful migration. Change-Id: Id961f0fc219f32a2cf0282859f228e87cb36ffeb Partial-Implements: blueprint libvirt-neutron-sriov-livemigration
This commit is contained in:
parent
64b4f41b24
commit
2a3179affb
|
@ -314,23 +314,43 @@ class PciDevTracker(object):
|
||||||
for dev in freed_devs:
|
for dev in freed_devs:
|
||||||
self.stats.add_device(dev)
|
self.stats.add_device(dev)
|
||||||
|
|
||||||
def _free_instance(self, instance):
|
def free_instance_allocations(self, context, instance):
|
||||||
|
"""Free devices that are in ALLOCATED state for instance.
|
||||||
|
|
||||||
|
:param context: user request context (nova.context.RequestContext)
|
||||||
|
:param instance: instance object
|
||||||
|
"""
|
||||||
|
if self.allocations.pop(instance['uuid'], None):
|
||||||
|
for dev in self.pci_devs:
|
||||||
|
if (dev.status == fields.PciDeviceStatus.ALLOCATED and
|
||||||
|
dev.instance_uuid == instance['uuid']):
|
||||||
|
self._free_device(dev)
|
||||||
|
|
||||||
|
def free_instance_claims(self, context, instance):
|
||||||
|
"""Free devices that are in CLAIMED state for instance.
|
||||||
|
|
||||||
|
:param context: user request context (nova.context.RequestContext)
|
||||||
|
:param instance: instance object
|
||||||
|
"""
|
||||||
|
if self.claims.pop(instance['uuid'], None):
|
||||||
|
for dev in self.pci_devs:
|
||||||
|
if (dev.status == fields.PciDeviceStatus.CLAIMED and
|
||||||
|
dev.instance_uuid == instance['uuid']):
|
||||||
|
self._free_device(dev)
|
||||||
|
|
||||||
|
def free_instance(self, context, instance):
|
||||||
|
"""Free devices that are in CLAIMED or ALLOCATED state for instance.
|
||||||
|
|
||||||
|
:param context: user request context (nova.context.RequestContext)
|
||||||
|
:param instance: instance object
|
||||||
|
"""
|
||||||
# Note(yjiang5): When an instance is resized, the devices in the
|
# Note(yjiang5): When an instance is resized, the devices in the
|
||||||
# destination node are claimed to the instance in prep_resize stage.
|
# destination node are claimed to the instance in prep_resize stage.
|
||||||
# However, the instance contains only allocated devices
|
# However, the instance contains only allocated devices
|
||||||
# information, not the claimed one. So we can't use
|
# information, not the claimed one. So we can't use
|
||||||
# instance['pci_devices'] to check the devices to be freed.
|
# instance['pci_devices'] to check the devices to be freed.
|
||||||
for dev in self.pci_devs:
|
self.free_instance_allocations(context, instance)
|
||||||
if dev.status in (fields.PciDeviceStatus.CLAIMED,
|
self.free_instance_claims(context, instance)
|
||||||
fields.PciDeviceStatus.ALLOCATED):
|
|
||||||
if dev.instance_uuid == instance['uuid']:
|
|
||||||
self._free_device(dev)
|
|
||||||
|
|
||||||
def free_instance(self, context, instance):
|
|
||||||
if self.allocations.pop(instance['uuid'], None):
|
|
||||||
self._free_instance(instance)
|
|
||||||
elif self.claims.pop(instance['uuid'], None):
|
|
||||||
self._free_instance(instance)
|
|
||||||
|
|
||||||
def update_pci_for_instance(self, context, instance, sign):
|
def update_pci_for_instance(self, context, instance, sign):
|
||||||
"""Update PCI usage information if devices are de/allocated.
|
"""Update PCI usage information if devices are de/allocated.
|
||||||
|
|
|
@ -546,6 +546,58 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
|
||||||
self.assertIn(pci_device.id, free_pci_device_ids)
|
self.assertIn(pci_device.id, free_pci_device_ids)
|
||||||
self.assertIsNone(self.tracker.allocations.get(instance_uuid))
|
self.assertIsNone(self.tracker.allocations.get(instance_uuid))
|
||||||
|
|
||||||
|
def test_free_instance_claims(self):
|
||||||
|
# Create an InstancePCIRequest object
|
||||||
|
pci_requests_obj = self._create_pci_requests_object(
|
||||||
|
[{'count': 1, 'spec': [{'vendor_id': 'v'}]}])
|
||||||
|
|
||||||
|
# Claim a single PCI device
|
||||||
|
claimed_devs = self.tracker.claim_instance(mock.sentinel.context,
|
||||||
|
pci_requests_obj, None)
|
||||||
|
|
||||||
|
# Assert we have exactly one claimed device for the given instance.
|
||||||
|
claimed_dev = claimed_devs[0]
|
||||||
|
instance_uuid = self.inst['uuid']
|
||||||
|
self.assertEqual(1, len(self.tracker.claims.get(instance_uuid)))
|
||||||
|
self.assertIn(claimed_dev.id,
|
||||||
|
[pci_dev.id for pci_dev in
|
||||||
|
self.tracker.claims.get(instance_uuid)])
|
||||||
|
self.assertIsNone(self.tracker.allocations.get(instance_uuid))
|
||||||
|
|
||||||
|
# Free instance claims
|
||||||
|
self.tracker.free_instance_claims(mock.sentinel.context, self.inst)
|
||||||
|
|
||||||
|
# Assert no claims for instance and all PCI devices are free
|
||||||
|
self.assertIsNone(self.tracker.claims.get(instance_uuid))
|
||||||
|
free_devs = self.tracker.pci_stats.get_free_devs()
|
||||||
|
self.assertEqual(len(fake_db_devs), len(free_devs))
|
||||||
|
|
||||||
|
def test_free_instance_allocations(self):
|
||||||
|
# Create an InstancePCIRequest object
|
||||||
|
pci_requests_obj = self._create_pci_requests_object(
|
||||||
|
[{'count': 1, 'spec': [{'vendor_id': 'v'}]}])
|
||||||
|
# Allocate a single PCI device
|
||||||
|
allocated_devs = self.tracker.claim_instance(mock.sentinel.context,
|
||||||
|
pci_requests_obj, None)
|
||||||
|
self.tracker.allocate_instance(self.inst)
|
||||||
|
|
||||||
|
# Assert we have exactly one allocated device for the given instance.
|
||||||
|
allocated_dev = allocated_devs[0]
|
||||||
|
instance_uuid = self.inst['uuid']
|
||||||
|
self.assertIsNone(self.tracker.claims.get(instance_uuid))
|
||||||
|
self.assertEqual(1, len(self.tracker.allocations.get(instance_uuid)))
|
||||||
|
self.assertIn(allocated_dev.id,
|
||||||
|
[pci_dev.id for pci_dev in
|
||||||
|
self.tracker.allocations.get(instance_uuid)])
|
||||||
|
|
||||||
|
# Free instance allocations and assert claims did not change
|
||||||
|
self.tracker.free_instance_allocations(mock.sentinel.context,
|
||||||
|
self.inst)
|
||||||
|
# Assert all PCI devices are free.
|
||||||
|
self.assertIsNone(self.tracker.allocations.get(instance_uuid))
|
||||||
|
free_devs = self.tracker.pci_stats.get_free_devs()
|
||||||
|
self.assertEqual(len(fake_db_devs), len(free_devs))
|
||||||
|
|
||||||
|
|
||||||
class PciGetInstanceDevs(test.NoDBTestCase):
|
class PciGetInstanceDevs(test.NoDBTestCase):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue