From fb81b16df09bedadecca9acd234ef137a427e02a Mon Sep 17 00:00:00 2001 From: Lee Yarwood Date: Mon, 28 Sep 2020 12:18:29 +0100 Subject: [PATCH] compute: Lock by instance.uuid lock during swap_volume The libvirt driver is currently the only virt driver implementing swap volume within Nova. While libvirt itself does support moving between multiple volumes attached to the same instance at the same time the current logic within the libvirt driver makes a call to virDomainGetXMLDesc that fails if there are active block jobs against any disk attached to the domain. This change simply uses an instance.uuid based lock in the compute layer to serialise requests to swap_volume to avoid this from being possible. Closes-Bug: #1896621 Change-Id: Ic5ce2580e7638a47f1ffddb4edbb503bf490504c (cherry picked from commit 6cf449bdd0d4beb95cf12311e7d2f8669e625fac) (cherry picked from commit eebf94b6540fcd16826067fac544b5a3238842a3) (cherry picked from commit f7ba1aab5f6f76ba88d6cc63cde2ec246ee61ec5) --- nova/compute/manager.py | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/nova/compute/manager.py b/nova/compute/manager.py index f7bb00df7b18..6e5d72f27a3a 100644 --- a/nova/compute/manager.py +++ b/nova/compute/manager.py @@ -6462,9 +6462,33 @@ class ComputeManager(manager.Manager): @wrap_instance_fault def swap_volume(self, context, old_volume_id, new_volume_id, instance, new_attachment_id): - """Swap volume for an instance.""" - context = context.elevated() + """Replace the old volume with the new volume within the active server + :param context: User request context + :param old_volume_id: Original volume id + :param new_volume_id: New volume id being swapped to + :param instance: Instance with original_volume_id attached + :param new_attachment_id: ID of the new attachment for new_volume_id + """ + @utils.synchronized(instance.uuid) + def _do_locked_swap_volume(context, old_volume_id, new_volume_id, + instance, new_attachment_id): + self._do_swap_volume(context, old_volume_id, new_volume_id, + instance, new_attachment_id) + _do_locked_swap_volume(context, old_volume_id, new_volume_id, instance, + new_attachment_id) + + def _do_swap_volume(self, context, old_volume_id, new_volume_id, + instance, new_attachment_id): + """Replace the old volume with the new volume within the active server + + :param context: User request context + :param old_volume_id: Original volume id + :param new_volume_id: New volume id being swapped to + :param instance: Instance with original_volume_id attached + :param new_attachment_id: ID of the new attachment for new_volume_id + """ + context = context.elevated() compute_utils.notify_about_volume_swap( context, instance, self.host, fields.NotificationPhase.START,