Fix pci_tracker.save to delete all removed devs

The bug is that the save code modifies the self.pci_devs.object list
while iterating it. This resulted in only half of the removed devs was
deleted at each save() run. Iterating on a shallow copy of that list
fixes it.

Closes-Bug: #2115729
Change-Id: I2711be9605618c1b93104d1dbddd8c7ee73b577e
Signed-off-by: Balazs Gibizer <gibi@redhat.com>
This commit is contained in:
Balazs Gibizer
2025-07-02 18:01:41 +02:00
parent d3cb76c858
commit 0208be629c
2 changed files with 3 additions and 11 deletions

View File

@@ -15,6 +15,7 @@
# under the License.
import collections
import copy
import typing as ty
from oslo_config import cfg
@@ -97,7 +98,8 @@ class PciDevTracker(object):
self.stats.add_device(dev)
def save(self, context: ctx.RequestContext) -> None:
for dev in self.pci_devs:
devs = copy.copy(self.pci_devs.objects)
for dev in devs:
if dev.obj_what_changed():
with dev.obj_alternate_context(context):
dev.save()

View File

@@ -885,18 +885,8 @@ class PciDevTrackerTestCase(test.NoDBTestCase):
dev2.remove()
self.tracker.save(self.fake_context)
# This is https://bugs.launchpad.net/nova/+bug/2115729 as
# only one half of the removed devices are destroyed.
self.assertEqual(len(self.tracker.pci_devs), 2)
self.assertEqual(self.destroy_called, 1)
# a subsequent save will destroy half of the remaining removed devices
self.tracker.save(self.fake_context)
self.assertEqual(len(self.tracker.pci_devs), 1)
self.assertEqual(self.destroy_called, 2)
# after the fix we should see that a single save causes all the
# removed devices destroyed
# self.assertEqual(len(self.tracker.pci_devs), 1)
# self.assertEqual(self.destroy_called, 2)
def test_clean_usage(self):
inst_2 = copy.copy(self.inst)