From: Xiaoqin Li Date: Wed, 13 Jan 2016 06:47:42 +0000 (-0800) Subject: Storwize/SVC: Clone between different size volumes X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=d02908ba59fed2a5be6b2158313c3f5044728753;p=openstack-build%2Fcinder-build.git Storwize/SVC: Clone between different size volumes The source volume size is equal to target volume size in most cases of create_cloned_volume. But in some scenario, the target volume size may be bigger than the source volume size. SVC driver should support such scenario. Change-Id: I1598381037a516dca611f5060d3f41195bbe3e17 Closes-Bug: 1533188 --- diff --git a/cinder/tests/unit/test_storwize_svc.py b/cinder/tests/unit/test_storwize_svc.py index e18952841..a9776a0b7 100644 --- a/cinder/tests/unit/test_storwize_svc.py +++ b/cinder/tests/unit/test_storwize_svc.py @@ -2925,7 +2925,8 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): snap1 = self._generate_vol_info(vol1['name'], vol1['id']) self.driver.create_snapshot(snap1) vol2 = self._generate_vol_info(None, None) - vol3 = self._generate_vol_info(None, None) + vol3 = testutils.create_volume(self.ctxt) + vol4 = testutils.create_volume(self.ctxt) # Try to create a volume from a non-existing snapshot snap_novol = self._generate_vol_info('undefined-vol', '12345') @@ -2958,14 +2959,15 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): self.driver.create_volume_from_snapshot(vol2, snap1) self._assert_vol_exists(vol2['name'], True) - # Try to clone where source size != target size - vol3['size'] += 1 + # Try to clone where source size > target size + vol2['size'] = vol3['size'] + 1 self.assertRaises(exception.InvalidInput, self.driver.create_cloned_volume, vol3, vol2) self._assert_vol_exists(vol3['name'], False) - vol3['size'] -= 1 + # Try to clone where source size = target size + vol2['size'] = vol3['size'] if self.USESIM: self.sim.error_injection('lsfcmap', 'speed_up') self.driver.create_cloned_volume(vol3, vol2) @@ -2976,7 +2978,21 @@ class StorwizeSVCCommonDriverTestCase(test.TestCase): self.assertEqual('49', fcmap['copyrate']) self._assert_vol_exists(vol3['name'], True) + # Try to clone where source size < target size + vol4['size'] = vol2['size'] + 1 + if self.USESIM: + self.sim.error_injection('lsfcmap', 'speed_up') + self.driver.create_cloned_volume(vol4, vol2) + if self.USESIM: + # Validate copyrate was set on the flash copy + for i, fcmap in self.sim._fcmappings_list.items(): + if fcmap['target'] == vol2['name']: + self.assertEqual('49', fcmap['copyrate']) + self._assert_vol_exists(vol4['name'], True) + # Delete in the 'opposite' order to make sure it works + self.driver.delete_volume(vol4) + self._assert_vol_exists(vol4['name'], False) self.driver.delete_volume(vol3) self._assert_vol_exists(vol3['name'], False) self.driver.delete_volume(vol2) diff --git a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py index 3f32bde35..f58f77a9f 100644 --- a/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py +++ b/cinder/volume/drivers/ibm/storwize_svc/storwize_svc_common.py @@ -2190,9 +2190,16 @@ class StorwizeSVCCommonDriver(san.SanDriver, return replica_status def create_cloned_volume(self, tgt_volume, src_volume): - if src_volume['size'] != tgt_volume['size']: - msg = (_('create_cloned_volume: Source and destination ' - 'size differ.')) + """Creates a clone of the specified volume.""" + + if src_volume['size'] > tgt_volume['size']: + msg = (_("create_cloned_volume: source volume %(src_vol)s " + "size is %(src_size)dGB and doesn't fit in target " + "volume %(tgt_vol)s of size %(tgt_size)dGB.") % + {'src_vol': src_volume['name'], + 'src_size': src_volume['size'], + 'tgt_vol': tgt_volume['name'], + 'tgt_size': tgt_volume['size']}) LOG.error(msg) raise exception.InvalidInput(message=msg) @@ -2203,6 +2210,19 @@ class StorwizeSVCCommonDriver(san.SanDriver, self._helpers.create_copy(src_volume['name'], tgt_volume['name'], src_volume['id'], self.configuration, opts, True, pool=pool) + + # The source volume size is equal to target volume size + # in most of the cases. But in some scenario, the target + # volume size may be bigger than the source volume size. + # SVC does not support flashcopy between two volumes + # with two different size. So use source volume size to + # create target volume first and then extend target + # volume to orginal size. + if tgt_volume['size'] > src_volume['size']: + # extend the new created target volume to expected size. + self._extend_volume_op(tgt_volume, tgt_volume['size'], + src_volume['size']) + if opts['qos']: self._helpers.add_vdisk_qos(tgt_volume['name'], opts['qos']) @@ -2221,16 +2241,21 @@ class StorwizeSVCCommonDriver(san.SanDriver, return replica_status def extend_volume(self, volume, new_size): - LOG.debug('enter: extend_volume: volume %s', volume['id']) + self._extend_volume_op(volume, new_size) + + def _extend_volume_op(self, volume, new_size, old_size=None): + LOG.debug('enter: _extend_volume_op: volume %s', volume['id']) ret = self._helpers.ensure_vdisk_no_fc_mappings(volume['name'], allow_snaps=False) if not ret: - msg = (_('extend_volume: Extending a volume with snapshots is not ' - 'supported.')) + msg = (_('_extend_volume_op: Extending a volume with snapshots is ' + 'not supported.')) LOG.error(msg) raise exception.VolumeDriverException(message=msg) - extend_amt = int(new_size) - volume['size'] + if old_size is None: + old_size = volume['size'] + extend_amt = int(new_size) - old_size ctxt = context.get_admin_context() rep_mirror_type = self._get_volume_replicated_type_mirror(ctxt, volume) @@ -2257,7 +2282,7 @@ class StorwizeSVCCommonDriver(san.SanDriver, if rep_mirror_type and rep_status != "failed-over": self.replications.get(rep_mirror_type).create_relationship( volume, target_vol_name) - LOG.debug('leave: extend_volume: volume %s', volume['id']) + LOG.debug('leave: _extend_volume_op: volume %s', volume['id']) def add_vdisk_copy(self, volume, dest_pool, vol_type): return self._helpers.add_vdisk_copy(volume, dest_pool,