RBD: fix volume reference handling in clone logic
This patch fixes a bug in volume cloning where the source volume is prematurely closed. If the destination volume requires flattening and an exception occurs during flattening, the code attempts to perform cleanup operations on an already closed volume. This resulted in a segmentation fault which causes cinder to restart. Co-authored-by: Jon Bernard <jobernar@redhat.com> Change-Id: Ib713aa91b775d8ec07ffdb24dfe1db1b6ecf2921 Closes-Bug: #1794956 (cherry picked from commit394fbd7e20
) (cherry picked from commit7bfd3c4dcf
)
This commit is contained in:
parent
252be28572
commit
47caae4cbb
|
@ -1045,10 +1045,13 @@ class RBDTestCase(test.TestCase):
|
|||
(self.mock_rbd.Image.return_value.protect_snap
|
||||
.assert_called_once_with('.'.join(
|
||||
(self.volume_b.name, 'clone_snap'))))
|
||||
# We expect clone() to be called exactly once.
|
||||
self.assertEqual(
|
||||
1, self.mock_rbd.RBD.return_value.clone.call_count)
|
||||
# Without flattening, only the source volume is opened,
|
||||
# so only one call to close() should occur.
|
||||
self.assertEqual(
|
||||
2, self.mock_rbd.Image.return_value.close.call_count)
|
||||
1, self.mock_rbd.Image.return_value.close.call_count)
|
||||
self.assertTrue(mock_get_clone_depth.called)
|
||||
mock_resize.assert_not_called()
|
||||
mock_enable_repl.assert_not_called()
|
||||
|
@ -1084,7 +1087,7 @@ class RBDTestCase(test.TestCase):
|
|||
image.protect_snap.assert_called_once_with(name + '.clone_snap')
|
||||
self.assertEqual(1, self.mock_rbd.RBD.return_value.clone.call_count)
|
||||
self.assertEqual(
|
||||
2, self.mock_rbd.Image.return_value.close.call_count)
|
||||
1, self.mock_rbd.Image.return_value.close.call_count)
|
||||
mock_get_clone_depth.assert_called_once_with(
|
||||
self.mock_client().__enter__(), self.volume_a.name)
|
||||
mock_resize.assert_not_called()
|
||||
|
@ -1114,7 +1117,7 @@ class RBDTestCase(test.TestCase):
|
|||
self.assertEqual(
|
||||
1, self.mock_rbd.RBD.return_value.clone.call_count)
|
||||
self.assertEqual(
|
||||
2, self.mock_rbd.Image.return_value.close.call_count)
|
||||
1, self.mock_rbd.Image.return_value.close.call_count)
|
||||
self.assertTrue(mock_get_clone_depth.called)
|
||||
self.assertEqual(
|
||||
1, mock_resize.call_count)
|
||||
|
@ -1171,7 +1174,7 @@ class RBDTestCase(test.TestCase):
|
|||
|
||||
# We expect the driver to close both volumes, so 2 is expected
|
||||
self.assertEqual(
|
||||
3, self.mock_rbd.Image.return_value.close.call_count)
|
||||
2, self.mock_rbd.Image.return_value.close.call_count)
|
||||
self.assertTrue(mock_get_clone_depth.called)
|
||||
mock_enable_repl.assert_not_called()
|
||||
|
||||
|
|
|
@ -669,6 +669,7 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||
except Exception as e:
|
||||
src_volume.unprotect_snap(clone_snap)
|
||||
src_volume.remove_snap(clone_snap)
|
||||
src_volume.close()
|
||||
msg = (_("Failed to clone '%(src_vol)s@%(src_snap)s' to "
|
||||
"'%(dest)s', error: %(error)s") %
|
||||
{'src_vol': src_name,
|
||||
|
@ -677,8 +678,6 @@ class RBDDriver(driver.CloneableImageVD, driver.MigrateVD,
|
|||
'error': e})
|
||||
LOG.exception(msg)
|
||||
raise exception.VolumeBackendAPIException(data=msg)
|
||||
finally:
|
||||
src_volume.close()
|
||||
|
||||
depth = self._get_clone_depth(client, src_name)
|
||||
# If dest volume is a clone and rbd_max_clone_depth reached,
|
||||
|
|
Loading…
Reference in New Issue