From cbeb89933c57b9e9756c460fa07aab254b15078d Mon Sep 17 00:00:00 2001 From: Gorka Eguileor Date: Sat, 11 Feb 2017 20:58:08 +0100 Subject: [PATCH] Fix multipath flush when using friendly names When we are using friendly names for multipath the multipaths are not getting flushed, which may lead to data loss on slow connections and multipath entries with no actual paths. This happens in both iSCSI and FC connections, and it is due to the flush being requested on the WWN instead of the actual name of the device. So when we are not using friendly names the WWN and the device name are the same and our call to multipath -f will successfully flush remaining data, but when we are using friendly names they will not match, and the call to multipath -f will silently fail (return code 0) and the flush will not actually go through. When the flush doesn't happen, if there is remaining data, then the multipath will stay once the individual paths have been removed. Closes-Bug: #1663925 Change-Id: Ib93d945a5b5fca57bcac4e176d62d1412b95f2da (cherry picked from commit c0640ce13727e97832049f1d68744e715c3fa031) --- os_brick/initiator/connectors/fibre_channel.py | 14 ++++++-------- os_brick/initiator/linuxscsi.py | 2 +- .../initiator/connectors/test_fibre_channel.py | 11 ++++++++--- os_brick/tests/initiator/test_linuxscsi.py | 3 ++- 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/os_brick/initiator/connectors/fibre_channel.py b/os_brick/initiator/connectors/fibre_channel.py index 778e4b186..f80b7cfe8 100644 --- a/os_brick/initiator/connectors/fibre_channel.py +++ b/os_brick/initiator/connectors/fibre_channel.py @@ -260,21 +260,19 @@ class FibreChannelConnector(base.BaseLinuxConnector): """ devices = [] - volume_paths = self.get_volume_paths(connection_properties) wwn = None + volume_paths = self.get_volume_paths(connection_properties) + mpath_path = None for path in volume_paths: real_path = self._linuxscsi.get_name_from_path(path) - if not wwn: + if self.use_multipath and not mpath_path: wwn = self._linuxscsi.get_scsi_wwn(path) + mpath_path = self._linuxscsi.find_multipath_device_path(wwn) + if mpath_path: + self._linuxscsi.flush_multipath_device(mpath_path) device_info = self._linuxscsi.get_device_info(real_path) devices.append(device_info) - if self.use_multipath: - # There is a bug in multipath where the flushing - # doesn't remove the entry if friendly names are on - # we'll try anyway. - self._linuxscsi.flush_multipath_device(wwn) - LOG.debug("devices to remove = %s", devices) self._remove_devices(connection_properties, devices) diff --git a/os_brick/initiator/linuxscsi.py b/os_brick/initiator/linuxscsi.py index ec40ae11c..8f617aaa7 100644 --- a/os_brick/initiator/linuxscsi.py +++ b/os_brick/initiator/linuxscsi.py @@ -134,7 +134,7 @@ class LinuxSCSI(executor.Executor): LOG.debug("remove multipath device %s", device) mpath_dev = self.find_multipath_device(device) if mpath_dev: - self.flush_multipath_device(mpath_dev['id']) + self.flush_multipath_device(mpath_dev['name']) devices = mpath_dev['devices'] LOG.debug("multipath LUNs to remove %s", devices) for device in devices: diff --git a/os_brick/tests/initiator/connectors/test_fibre_channel.py b/os_brick/tests/initiator/connectors/test_fibre_channel.py index 8e505944f..3881840a4 100644 --- a/os_brick/tests/initiator/connectors/test_fibre_channel.py +++ b/os_brick/tests/initiator/connectors/test_fibre_channel.py @@ -193,6 +193,7 @@ class FibreChannelConnectorTestCase(test_connector.ConnectorTestCase): self.connector.connect_volume, connection_info['data']) + @mock.patch.object(linuxscsi.LinuxSCSI, 'find_multipath_device_path') def _test_connect_volume_multipath(self, get_device_info_mock, get_scsi_wwn_mock, get_fc_hbas_info_mock, @@ -202,7 +203,8 @@ class FibreChannelConnectorTestCase(test_connector.ConnectorTestCase): wait_for_rw_mock, find_mp_dev_mock, access_mode, - should_wait_for_rw): + should_wait_for_rw, + find_mp_device_path_mock): self.connector.use_multipath = True get_fc_hbas_mock.side_effect = self.fake_get_fc_hbas get_fc_hbas_info_mock.side_effect = self.fake_get_fc_hbas_info @@ -227,7 +229,10 @@ class FibreChannelConnectorTestCase(test_connector.ConnectorTestCase): vol = {'id': 1, 'name': name} initiator_wwn = ['1234567890123456', '1234567890123457'] - find_mp_dev_mock.return_value = '/dev/disk/by-id/dm-uuid-mpath-' + wwn + find_mp_device_path_mock.return_value = '/dev/mapper/mpatha' + find_mp_dev_mock.return_value = {"device": "dm-3", + "id": wwn, + "name": "mpatha"} connection_info = self.fibrechan_connection(vol, location, initiator_wwn) @@ -240,7 +245,7 @@ class FibreChannelConnectorTestCase(test_connector.ConnectorTestCase): self.connector.disconnect_volume(connection_info['data'], devices['devices'][0]) expected_commands = [ - 'multipath -f ' + wwn, + 'multipath -f ' + find_mp_device_path_mock.return_value, 'blockdev --flushbufs /dev/sdb', 'tee -a /sys/block/sdb/device/delete', 'blockdev --flushbufs /dev/sdc', diff --git a/os_brick/tests/initiator/test_linuxscsi.py b/os_brick/tests/initiator/test_linuxscsi.py index 8c46c8916..c4200c129 100644 --- a/os_brick/tests/initiator/test_linuxscsi.py +++ b/os_brick/tests/initiator/test_linuxscsi.py @@ -161,6 +161,7 @@ class LinuxSCSITestCase(base.TestCase): info = {"device": "dm-3", "id": "350002ac20398383d", + "name": "mpatha", "devices": devices} return info @@ -168,7 +169,7 @@ class LinuxSCSITestCase(base.TestCase): self.linuxscsi.remove_multipath_device('/dev/dm-3') expected_commands = [ - ('multipath -f 350002ac20398383d'), + ('multipath -f mpatha'), ('blockdev --flushbufs /dev/sde'), ('tee -a /sys/block/sde/device/delete'), ('blockdev --flushbufs /dev/sdf'),