]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add optimized volume migration to Storwize/SVC
authorAvishay Traeger <avishay@il.ibm.com>
Wed, 10 Jul 2013 10:59:51 +0000 (13:59 +0300)
committerAvishay Traeger <avishay@il.ibm.com>
Tue, 27 Aug 2013 10:00:14 +0000 (13:00 +0300)
Add an optimized migration path for when the source and destination are
managed by the same storage. If the source and destination pools have
the same extent_size, it will use the optimal migratevdisk command.
Otherwise, it will use addvdiskcopy and rmvdiskcopy, which must be
watched until the copies are sync'ed.

Change-Id: Ic6069422f5ac7f963f4b1268c0d632a038a8474f

cinder/tests/test_storwize_svc.py
cinder/volume/drivers/storwize_svc.py

index b2a4949e5cf1bd2eb1b6db06011a4630596816fe..2bc058b53c95ac8f231e7d261fa82b6d6a126a70 100644 (file)
@@ -1,5 +1,3 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
 # Copyright 2013 IBM Corp.
 # Copyright 2012 OpenStack LLC.
 # All Rights Reserved.
@@ -62,6 +60,7 @@ class StorwizeSVCManagementSimulator:
         self._hosts_list = {}
         self._mappings_list = {}
         self._fcmappings_list = {}
+        self._other_pools = {'openstack2': {}, 'openstack3': {}}
         self._next_cmd_error = {
             'lsportip': '',
             'lsfabric': '',
@@ -118,6 +117,13 @@ class StorwizeSVCManagementSimulator:
             'CMMVC7050E': ('', 'CMMVC7050E The command failed because at '
                                'least one node in the I/O group does not '
                                'support compressed VDisks.'),
+            'CMMVC6430E': ('', 'CMMVC6430E The command failed because the '
+                               'target and source managed disk groups must '
+                               'be different.'),
+            'CMMVC6353E': ('', 'CMMVC6353E The command failed because the '
+                               'copy specified does not exist.'),
+            'CMMVC6446E': ('', 'The command failed because the managed disk '
+                               'groups have different extent sizes.'),
             # Catch-all for invalid state transitions:
             'CMMVC5903E': ('', 'CMMVC5903E The FlashCopy mapping was not '
                                'changed because the mapping or consistency '
@@ -192,8 +198,10 @@ class StorwizeSVCManagementSimulator:
         one_param_args = [
             'chapsecret',
             'cleanrate',
+            'copy',
             'copyrate',
             'delim',
+            'easytier',
             'filtervalue',
             'grainsize',
             'hbawwpn',
@@ -208,7 +216,7 @@ class StorwizeSVCManagementSimulator:
             'source',
             'target',
             'unit',
-            'easytier',
+            'vdisk',
             'warning',
             'wwpn',
         ]
@@ -308,7 +316,7 @@ class StorwizeSVCManagementSimulator:
 
     # Print mostly made-up stuff in the correct syntax, assume -bytes passed
     def _cmd_lsmdiskgrp(self, **kwargs):
-        rows = [None] * 3
+        rows = [None] * 4
         rows[0] = ['id', 'name', 'status', 'mdisk_count',
                    'vdisk_count', 'capacity', 'extent_size',
                    'free_capacity', 'virtual_capacity', 'used_capacity',
@@ -318,17 +326,23 @@ class StorwizeSVCManagementSimulator:
                    '1', str(len(self._volumes_list)), '3573412790272',
                    '256', '3529926246400', '1693247906775', '277841182',
                    '38203734097', '47', '80', 'auto', 'inactive']
-        rows[2] = ['2', 'volpool2', 'online',
+        rows[2] = ['2', 'openstack2', 'online',
                    '1', '0', '3573412790272', '256',
                    '3529432325160', '1693247906775', '277841182',
                    '38203734097', '47', '80', 'auto', 'inactive']
+        rows[3] = ['3', 'openstack3', 'online',
+                   '1', '0', '3573412790272', '128',
+                   '3529432325160', '1693247906775', '277841182',
+                   '38203734097', '47', '80', 'auto', 'inactive']
         if 'obj' not in kwargs:
             return self._print_info_cmd(rows=rows, **kwargs)
         else:
             if kwargs['obj'] == self._flags['storwize_svc_volpool_name']:
                 row = rows[1]
-            elif kwargs['obj'] == 'volpool2':
+            elif kwargs['obj'] == 'openstack2':
                 row = rows[2]
+            elif kwargs['obj'] == 'openstack3':
+                row = rows[3]
             else:
                 return self._errors['CMMVC5754E']
 
@@ -552,6 +566,16 @@ port_speed!N/A
             volume_info['grainsize'] = ''
             volume_info['compressed_copy'] = 'no'
 
+        vol_cp = {'id': '0',
+                  'status': 'online',
+                  'sync': 'yes',
+                  'primary': 'yes',
+                  'mdisk_grp_id': '1',
+                  'mdisk_grp_name': self._flags['storwize_svc_volpool_name'],
+                  'easy_tier': volume_info['easy_tier'],
+                  'compressed_copy': volume_info['compressed_copy']}
+        volume_info['copies'] = {'0': vol_cp}
+
         if volume_info['name'] in self._volumes_list:
             return self._errors['CMMVC6035E']
         else:
@@ -1144,7 +1168,135 @@ port_speed!N/A
 
         return self._print_info_cmd(rows=rows, **kwargs)
 
-    # Add host to list
+    def _cmd_migratevdisk(self, **kwargs):
+        if 'mdiskgrp' not in kwargs or 'vdisk' not in kwargs:
+            return self._errors['CMMVC5707E']
+        mdiskgrp = kwargs['mdiskgrp'].strip('\'\'')
+        vdisk = kwargs['vdisk'].strip('\'\'')
+
+        if vdisk in self._volumes_list:
+            curr_mdiskgrp = self._volumes_list
+        else:
+            for pool in self._other_pools:
+                if vdisk in pool:
+                    curr_mdiskgrp = pool
+                    break
+            else:
+                return self._errors['CMMVC5754E']
+
+        if mdiskgrp == self._flags['storwize_svc_volpool_name']:
+            tgt_mdiskgrp = self._volumes_list
+        elif mdiskgrp == 'openstack2':
+            tgt_mdiskgrp = self._other_pools['openstack2']
+        elif mdiskgrp == 'openstack3':
+            tgt_mdiskgrp = self._other_pools['openstack3']
+        else:
+            return self._errors['CMMVC5754E']
+
+        if curr_mdiskgrp == tgt_mdiskgrp:
+            return self._errors['CMMVC6430E']
+
+        vol = curr_mdiskgrp[vdisk]
+        tgt_mdiskgrp[vdisk] = vol
+        del curr_mdiskgrp[vdisk]
+        return ('', '')
+
+    def _cmd_addvdiskcopy(self, **kwargs):
+        if 'obj' not in kwargs:
+            return self._errors['CMMVC5701E']
+        vol_name = kwargs['obj'].strip('\'\'')
+        if vol_name not in self._volumes_list:
+            return self._errors['CMMVC5753E']
+        vol = self._volumes_list[vol_name]
+        if 'mdiskgrp' not in kwargs:
+            return self._errors['CMMVC5707E']
+        mdiskgrp = kwargs['mdiskgrp'].strip('\'\'')
+
+        copy_info = {}
+        copy_info['id'] = self._find_unused_id(vol['copies'])
+        copy_info['status'] = 'online'
+        copy_info['sync'] = 'no'
+        copy_info['primary'] = 'no'
+        copy_info['mdisk_grp_name'] = mdiskgrp
+        if mdiskgrp == self._flags['storwize_svc_volpool_name']:
+            copy_info['mdisk_grp_id'] = '1'
+        elif mdiskgrp == 'openstack2':
+            copy_info['mdisk_grp_id'] = '2'
+        elif mdiskgrp == 'openstack3':
+            copy_info['mdisk_grp_id'] = '3'
+        if 'easytier' in kwargs:
+            if kwargs['easytier'] == 'on':
+                copy_info['easy_tier'] = 'on'
+            else:
+                copy_info['easy_tier'] = 'off'
+        if 'rsize' in kwargs:
+            if 'compressed' in kwargs:
+                copy_info['compressed_copy'] = 'yes'
+            else:
+                copy_info['compressed_copy'] = 'no'
+        vol['copies'][copy_info['id']] = copy_info
+        return ('Vdisk [%(vid)s] copy [%(cid)s] successfully created' %
+                {'vid': vol['id'], 'cid': copy_info['id']}, '')
+
+    def _cmd_lsvdiskcopy(self, **kwargs):
+        if 'obj' not in kwargs:
+            return self._errors['CMMVC5804E']
+        name = kwargs['obj']
+        vol = self._volumes_list[name]
+        rows = []
+        rows.append(['vdisk_id', 'vdisk_name', 'copy_id', 'status', 'sync',
+                     'primary', 'mdisk_grp_id', 'mdisk_grp_name', 'capacity',
+                     'type', 'se_copy', 'easy_tier', 'easy_tier_status',
+                     'compressed_copy'])
+        for k, copy in vol['copies'].iteritems():
+            rows.append([vol['id'], vol['name'], copy['id'],
+                        copy['status'], copy['sync'], copy['primary'],
+                        copy['mdisk_grp_id'], copy['mdisk_grp_name'],
+                        vol['capacity'], 'striped', 'yes', copy['easy_tier'],
+                        'inactive', copy['compressed_copy']])
+        if 'copy' not in kwargs:
+            return self._print_info_cmd(rows=rows, **kwargs)
+        else:
+            copy_id = kwargs['copy'].strip('\'\'')
+            if copy_id not in vol['copies']:
+                return self._errors['CMMVC6353E']
+            copy = vol['copies'][copy_id]
+            rows = []
+            rows.append(['vdisk_id', vol['id']])
+            rows.append(['vdisk_name', vol['name']])
+            rows.append(['capacity', vol['capacity']])
+            rows.append(['copy_id', copy['id']])
+            rows.append(['status', copy['status']])
+            rows.append(['sync', copy['sync']])
+            copy['sync'] = 'yes'
+            rows.append(['primary', copy['primary']])
+            rows.append(['mdisk_grp_id', copy['mdisk_grp_id']])
+            rows.append(['mdisk_grp_name', copy['mdisk_grp_name']])
+            rows.append(['easy_tier', copy['easy_tier']])
+            rows.append(['easy_tier_status', 'inactive'])
+            rows.append(['compressed_copy', copy['compressed_copy']])
+
+            if 'delim' in kwargs:
+                for index in range(len(rows)):
+                    rows[index] = kwargs['delim'].join(rows[index])
+
+            return ('%s' % '\n'.join(rows), '')
+
+    def _cmd_rmvdiskcopy(self, **kwargs):
+        if 'obj' not in kwargs:
+            return self._errors['CMMVC5701E']
+        vol_name = kwargs['obj'].strip('\'\'')
+        if 'copy' not in kwargs:
+            return self._errors['CMMVC5707E']
+        copy_id = kwargs['copy'].strip('\'\'')
+        if vol_name not in self._volumes_list:
+            return self._errors['CMMVC5753E']
+        vol = self._volumes_list[vol_name]
+        if copy_id not in vol['copies']:
+            return self._errors['CMMVC6353E']
+        del vol['copies'][copy_id]
+        return ('', '')
+
     def _add_host_to_list(self, connector):
         host_info = {}
         host_info['id'] = self._find_unused_id(self._hosts_list)
@@ -1225,6 +1377,14 @@ port_speed!N/A
             out, err = self._cmd_lsfcmap(**kwargs)
         elif command == 'lsvdiskfcmappings':
             out, err = self._cmd_lsvdiskfcmappings(**kwargs)
+        elif command == 'migratevdisk':
+            out, err = self._cmd_migratevdisk(**kwargs)
+        elif command == 'addvdiskcopy':
+            out, err = self._cmd_addvdiskcopy(**kwargs)
+        elif command == 'lsvdiskcopy':
+            out, err = self._cmd_lsvdiskcopy(**kwargs)
+        elif command == 'rmvdiskcopy':
+            out, err = self._cmd_rmvdiskcopy(**kwargs)
         else:
             out, err = ('', 'ERROR: Unsupported command')
 
@@ -1281,6 +1441,7 @@ class StorwizeSVCDriverTestCase(test.TestCase):
             self._def_flags = {'san_ip': 'hostname',
                                'san_login': 'user',
                                'san_password': 'pass',
+                               'storwize_svc_volpool_name': 'openstack',
                                'storwize_svc_flashcopy_timeout': 20,
                                # Test ignore capitalization
                                'storwize_svc_connection_protocol': 'iScSi',
@@ -1292,7 +1453,7 @@ class StorwizeSVCDriverTestCase(test.TestCase):
                                'host': 'storwize-svc-test',
                                'wwpns': wwpns,
                                'initiator': initiator}
-            self.sim = StorwizeSVCManagementSimulator('volpool')
+            self.sim = StorwizeSVCManagementSimulator('openstack')
 
             self.driver.set_fake_storage(self.sim)
         else:
@@ -1969,9 +2130,10 @@ class StorwizeSVCDriverTestCase(test.TestCase):
         self.assertLessEqual(stats['free_capacity_gb'],
                              stats['total_capacity_gb'])
         self.assertEquals(stats['reserved_percentage'], 25)
+        pool = self.driver.configuration.local_conf.storwize_svc_volpool_name
         if self.USESIM:
-            self.assertEqual(stats['volume_backend_name'],
-                             'storwize-svc-sim_volpool')
+            expected = 'storwize-svc-sim_' + pool
+            self.assertEqual(stats['volume_backend_name'], expected)
             self.assertAlmostEqual(stats['total_capacity_gb'], 3328.0)
             self.assertAlmostEqual(stats['free_capacity_gb'], 3287.5)
 
@@ -1993,6 +2155,52 @@ class StorwizeSVCDriverTestCase(test.TestCase):
         self.driver.delete_snapshot(snap)
         self.driver.delete_volume(volume)
 
+    def _check_loc_info(self, capabilities, expected):
+        host = {'host': 'foo', 'capabilities': capabilities}
+        vol = {'name': 'test', 'id': 1, 'size': 1}
+        ctxt = context.get_admin_context()
+        moved, model_update = self.driver.migrate_volume(ctxt, vol, host)
+        self.assertEqual(moved, expected['moved'])
+        self.assertEqual(model_update, expected['model_update'])
+
+    def test_storwize_svc_migrate_bad_loc_info(self):
+        self._check_loc_info({}, {'moved': False, 'model_update': None})
+        cap = {'location_info': 'foo'}
+        self._check_loc_info(cap, {'moved': False, 'model_update': None})
+        cap = {'location_info': 'FooDriver:foo:bar'}
+        self._check_loc_info(cap, {'moved': False, 'model_update': None})
+        cap = {'location_info': 'StorwizeSVCDriver:foo:bar'}
+        self._check_loc_info(cap, {'moved': False, 'model_update': None})
+
+    def test_storwize_svc_migrate_same_extent_size(self):
+        def _copy_info_exc(self, name):
+            raise Exception('should not be called')
+
+        self.stubs.Set(self.driver, '_get_vdisk_copy_info', _copy_info_exc)
+        self.driver.do_setup(None)
+        loc = 'StorwizeSVCDriver:' + self.driver._system_id + ':openstack2'
+        cap = {'location_info': loc, 'extent_size': '256'}
+        host = {'host': 'foo', 'capabilities': cap}
+        ctxt = context.get_admin_context()
+        volume = self._generate_vol_info(None, None)
+        volume['volume_type_id'] = None
+        self.driver.create_volume(volume)
+        self.driver.migrate_volume(ctxt, volume, host)
+        self.driver.delete_volume(volume)
+
+    def test_storwize_svc_migrate_diff_extent_size(self):
+        self.driver.do_setup(None)
+        loc = 'StorwizeSVCDriver:' + self.driver._system_id + ':openstack3'
+        cap = {'location_info': loc, 'extent_size': '128'}
+        host = {'host': 'foo', 'capabilities': cap}
+        ctxt = context.get_admin_context()
+        volume = self._generate_vol_info(None, None)
+        volume['volume_type_id'] = None
+        self.driver.create_volume(volume)
+        self.assertNotEquals(cap['extent_size'], self.driver._extent_size)
+        self.driver.migrate_volume(ctxt, volume, host)
+        self.driver.delete_volume(volume)
+
 
 class CLIResponseTestCase(test.TestCase):
     def test_empty(self):
index a6350796e558949706ea99a74cec50aa535b4180..374da38aab514c70ee52ac5ea5354505570c5ba7 100644 (file)
@@ -131,6 +131,9 @@ class StorwizeSVCDriver(san.SanDriver):
         self._compression_enabled = False
         self._available_iogrps = []
         self._context = None
+        self._system_name = None
+        self._system_id = None
+        self._extent_size = None
 
         # Build cleanup translation tables for host names
         invalid_ch_in_host = ''
@@ -188,16 +191,25 @@ class StorwizeSVCDriver(san.SanDriver):
         LOG.debug(_('enter: do_setup'))
         self._context = ctxt
 
+        # Get storage system name and id
+        ssh_cmd = ['svcinfo', 'lssystem', '-delim', '!']
+        attributes = self._execute_command_and_parse_attributes(ssh_cmd)
+        if not attributes or not attributes['name']:
+            msg = (_('do_setup: Could not get system name'))
+            LOG.error(msg)
+            raise exception.VolumeBackendAPIException(data=msg)
+        self._system_name = attributes['name']
+        self._system_id = attributes['id']
+
         # Validate that the pool exists
-        ssh_cmd = ['svcinfo', 'lsmdiskgrp', '-delim', '!', '-nohdr']
-        out, err = self._run_ssh(ssh_cmd)
-        self._assert_ssh_return(len(out.strip()), 'do_setup',
-                                ssh_cmd, out, err)
-        search_text = '!%s!' % self.configuration.storwize_svc_volpool_name
-        if search_text not in out:
-            raise exception.InvalidInput(
-                reason=(_('pool %s doesn\'t exist')
-                        % self.configuration.storwize_svc_volpool_name))
+        pool = self.configuration.storwize_svc_volpool_name
+        ssh_cmd = ['svcinfo', 'lsmdiskgrp', '-bytes', '-delim', '!', pool]
+        attributes = self._execute_command_and_parse_attributes(ssh_cmd)
+        if not attributes:
+            msg = (_('do_setup: Pool %s does not exist') % pool)
+            LOG.error(msg)
+            raise exception.InvalidInput(reason=msg)
+        self._extent_size = attributes['extent_size']
 
         # Check if compression is supported
         self._compression_enabled = False
@@ -325,6 +337,17 @@ class StorwizeSVCDriver(san.SanDriver):
         """Ensure that the flags are set properly."""
         LOG.debug(_('enter: check_for_setup_error'))
 
+        # Check that we have the system ID information
+        if self._system_name is None:
+            exception_msg = (_('Unable to determine system name'))
+            raise exception.VolumeBackendAPIException(data=exception_msg)
+        if self._system_id is None:
+            exception_msg = (_('Unable to determine system id'))
+            raise exception.VolumeBackendAPIException(data=exception_msg)
+        if self._extent_size is None:
+            exception_msg = (_('Unable to determine pool extent size'))
+            raise exception.VolumeBackendAPIException(data=exception_msg)
+
         required_flags = ['san_ip', 'san_ssh_port', 'san_login',
                           'storwize_svc_volpool_name']
         for flag in required_flags:
@@ -961,27 +984,12 @@ class StorwizeSVCDriver(san.SanDriver):
         LOG.debug(_('enter: _create_vdisk: vdisk %s ') % name)
 
         model_update = None
-        easytier = 'on' if opts['easytier'] else 'off'
-
-        # Set space-efficient options
-        if opts['rsize'] == -1:
-            ssh_cmd_se_opt = []
-        else:
-            ssh_cmd_se_opt = ['-rsize', '%s%%' % str(opts['rsize']),
-                              '-autoexpand', '-warning',
-                              '%s%%' % str(opts['warning'])]
-            if not opts['autoexpand']:
-                ssh_cmd_se_opt.remove('-autoexpand')
-
-            if opts['compression']:
-                ssh_cmd_se_opt.append('-compressed')
-            else:
-                ssh_cmd_se_opt.extend(['-grainsize', str(opts['grainsize'])])
+        params = self._get_vdisk_create_params(opts)
 
         ssh_cmd = ['svctask', 'mkvdisk', '-name', name, '-mdiskgrp',
                    self.configuration.storwize_svc_volpool_name,
                    '-iogrp', str(opts['iogrp']), '-size', size, '-unit',
-                   units, '-easytier', easytier] + ssh_cmd_se_opt
+                   units] + params
         out, err = self._run_ssh(ssh_cmd)
         self._assert_ssh_return(len(out.strip()), '_create_vdisk',
                                 ssh_cmd, out, err)
@@ -1383,6 +1391,98 @@ class StorwizeSVCDriver(san.SanDriver):
                                 ssh_cmd, out, err)
         LOG.debug(_('leave: extend_volume: volume %s') % volume['id'])
 
+    def migrate_volume(self, ctxt, volume, host):
+        """Migrate direclty if source and dest are managed by same storage.
+
+        The method uses the migratevdisk method, which returns almost
+        immediately, if the source and target pools have the same extent_size.
+        Otherwise, it uses addvdiskcopy and rmvdiskcopy, which require waiting
+        for the copy operation to complete.
+
+        :param ctxt: Context
+        :param volume: A dictionary describing the volume to migrate
+        :param host: A dictionary describing the host to migrate to, where
+                     host['host'] is its name, and host['capabilities'] is a
+                     dictionary of its reported capabilities.
+        """
+        LOG.debug(_('enter: migrate_volume: id=%(id)s, host=%(host)s') %
+                  {'id': volume['id'], 'host': host['host']})
+
+        false_ret = (False, None)
+        if 'location_info' not in host['capabilities']:
+            return false_ret
+        info = host['capabilities']['location_info']
+        try:
+            (dest_type, dest_id, dest_pool) = info.split(':')
+        except ValueError:
+            return false_ret
+        if (dest_type != 'StorwizeSVCDriver' or dest_id != self._system_id):
+            return false_ret
+
+        if 'extent_size' not in host['capabilities']:
+            return false_ret
+        if host['capabilities']['extent_size'] == self._extent_size:
+            # If source and dest pools have the same extent size, migratevdisk
+            ssh_cmd = ['svctask', 'migratevdisk', '-mdiskgrp', dest_pool,
+                       '-vdisk', volume['name']]
+            out, err = self._run_ssh(ssh_cmd)
+            # No output should be returned from migratevdisk
+            self._assert_ssh_return(len(out.strip()) == 0, 'migrate_volume',
+                                    ssh_cmd, out, err)
+        else:
+            # If source and dest pool extent size differ, add/delete vdisk copy
+            copy_info = self._get_vdisk_copy_info(volume['name'])
+            copies = list(copy_info.keys())
+            self._driver_assert(len(copies) == 1,
+                                _('migrate_volume started with more than one '
+                                  'vdisk copy'))
+            orig_copy_id = copies[0]
+
+            opts = self._get_vdisk_params(volume['volume_type_id'])
+            params = self._get_vdisk_create_params(opts)
+            ssh_cmd = (['svctask', 'addvdiskcopy'] + params + ['-mdiskgrp',
+                       dest_pool, volume['name']])
+            out, err = self._run_ssh(ssh_cmd)
+            self._assert_ssh_return(len(out.strip()), 'migrate_volume',
+                                    ssh_cmd, out, err)
+
+            # Ensure that the output is as expected
+            match_obj = re.search('Vdisk \[([0-9]+)\] copy \[([0-9]+)\] '
+                                  'successfully created', out)
+            # Make sure we got a "successfully created" message with copy id
+            self._driver_assert(
+                match_obj is not None,
+                _('migrate_volume %(name)s - did not find '
+                  'success message in CLI output.\n '
+                  'stdout: %(out)s\n stderr: %(err)s')
+                % {'name': volume['name'], 'out': str(out), 'err': str(err)})
+
+            copy_id = match_obj.group(2)
+            sync = False
+            while not sync:
+                ssh_cmd = ['svcinfo', 'lsvdiskcopy', '-delim', '!', '-copy',
+                           copy_id, volume['name']]
+                attrs = self._execute_command_and_parse_attributes(ssh_cmd)
+                if not attrs:
+                    msg = (_('migrate_volume: Could not get vdisk copy data'))
+                    LOG.error(msg)
+                    raise exception.VolumeBackendAPIException(data=msg)
+                if attrs['sync'] == 'yes':
+                    sync = True
+                else:
+                    time.sleep(5)
+
+            ssh_cmd = ['svctask', 'rmvdiskcopy', '-copy', orig_copy_id,
+                       volume['name']]
+            out, err = self._run_ssh(ssh_cmd)
+            # No output should be returned from rmvdiskcopy
+            self._assert_ssh_return(len(out.strip()) == 0, 'migrate_volume',
+                                    ssh_cmd, out, err)
+
+        LOG.debug(_('leave: migrate_volume: id=%(id)s, host=%(host)s') %
+                  {'id': volume['id'], 'host': host['host']})
+        return (True, None)
+
     """====================================================================="""
     """ MISC/HELPERS                                                        """
     """====================================================================="""
@@ -1414,18 +1514,9 @@ class StorwizeSVCDriver(san.SanDriver):
         data['QoS_support'] = False
 
         pool = self.configuration.storwize_svc_volpool_name
-        #Get storage system name
-        ssh_cmd = ['svcinfo', 'lssystem', '-delim', '!']
-        attributes = self._execute_command_and_parse_attributes(ssh_cmd)
-        if not attributes or not attributes['name']:
-            exception_message = (_('_update_volume_stats: '
-                                   'Could not get system name.'))
-            LOG.error(exception_message)
-            raise exception.VolumeBackendAPIException(data=exception_message)
-
         backend_name = self.configuration.safe_get('volume_backend_name')
         if not backend_name:
-            backend_name = '%s_%s' % (attributes['name'], pool)
+            backend_name = '%s_%s' % (self._system_name, pool)
         data['volume_backend_name'] = backend_name
 
         ssh_cmd = ['svcinfo', 'lsmdiskgrp', '-bytes', '-delim', '!', pool]
@@ -1442,6 +1533,10 @@ class StorwizeSVCDriver(san.SanDriver):
                                     (1024 ** 3))
         data['easytier_support'] = attributes['easy_tier'] in ['on', 'auto']
         data['compression_support'] = self._compression_enabled
+        data['extent_size'] = self._extent_size
+        data['location_info'] = ('StorwizeSVCDriver:%(sys_id)s:%(pool)s' %
+                                 {'sys_id': self._system_id,
+                                  'pool': pool})
 
         self._stats = data
 
@@ -1466,6 +1561,49 @@ class StorwizeSVCDriver(san.SanDriver):
                                                ssh_cmd, out, err)
             yield port_data
 
+    def _get_vdisk_copy_info(self, vdisk):
+        ssh_cmd = ['svcinfo', 'lsvdiskcopy', '-delim', '!', vdisk]
+        out, err = self._run_ssh(ssh_cmd)
+
+        self._assert_ssh_return(len(out.strip()), '_get_vdisk_copy_info',
+                                ssh_cmd, out, err)
+        copy_lines = out.strip().split('\n')
+        self._assert_ssh_return(len(copy_lines), '_get_vdisk_copy_info',
+                                ssh_cmd, out, err)
+
+        header = copy_lines.pop(0)
+        ret = {}
+        for copy_line in copy_lines:
+            try:
+                copy_data = self._get_hdr_dic(header, copy_line, '!')
+            except exception.VolumeBackendAPIException:
+                with excutils.save_and_reraise_exception():
+                    self._log_cli_output_error('_get_vdisk_copy_info',
+                                               ssh_cmd, out, err)
+            ret[copy_data['copy_id']] = copy_data
+        return ret
+
+    def _get_vdisk_create_params(self, opts):
+        easytier = 'on' if opts['easytier'] else 'off'
+
+        # Set space-efficient options
+        if opts['rsize'] == -1:
+            params = []
+        else:
+            params = ['-rsize', '%s%%' % str(opts['rsize']),
+                      '-autoexpand', '-warning',
+                      '%s%%' % str(opts['warning'])]
+            if not opts['autoexpand']:
+                params.remove('-autoexpand')
+
+            if opts['compression']:
+                params.append('-compressed')
+            else:
+                params.extend(['-grainsize', str(opts['grainsize'])])
+
+        params.extend(['-easytier', easytier])
+        return params
+
     def _check_vdisk_opts(self, opts):
         # Check that rsize is either -1 or between 0 and 100
         if not (opts['rsize'] >= -1 and opts['rsize'] <= 100):