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 c0640ce137)
This commit is contained in:
Gorka Eguileor 2017-02-11 20:58:08 +01:00
parent 7b2d35f609
commit cbeb89933c
4 changed files with 17 additions and 13 deletions

View File

@ -260,21 +260,19 @@ class FibreChannelConnector(base.BaseLinuxConnector):
""" """
devices = [] devices = []
volume_paths = self.get_volume_paths(connection_properties)
wwn = None wwn = None
volume_paths = self.get_volume_paths(connection_properties)
mpath_path = None
for path in volume_paths: for path in volume_paths:
real_path = self._linuxscsi.get_name_from_path(path) 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) 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) device_info = self._linuxscsi.get_device_info(real_path)
devices.append(device_info) 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) LOG.debug("devices to remove = %s", devices)
self._remove_devices(connection_properties, devices) self._remove_devices(connection_properties, devices)

View File

@ -134,7 +134,7 @@ class LinuxSCSI(executor.Executor):
LOG.debug("remove multipath device %s", device) LOG.debug("remove multipath device %s", device)
mpath_dev = self.find_multipath_device(device) mpath_dev = self.find_multipath_device(device)
if mpath_dev: if mpath_dev:
self.flush_multipath_device(mpath_dev['id']) self.flush_multipath_device(mpath_dev['name'])
devices = mpath_dev['devices'] devices = mpath_dev['devices']
LOG.debug("multipath LUNs to remove %s", devices) LOG.debug("multipath LUNs to remove %s", devices)
for device in devices: for device in devices:

View File

@ -193,6 +193,7 @@ class FibreChannelConnectorTestCase(test_connector.ConnectorTestCase):
self.connector.connect_volume, self.connector.connect_volume,
connection_info['data']) connection_info['data'])
@mock.patch.object(linuxscsi.LinuxSCSI, 'find_multipath_device_path')
def _test_connect_volume_multipath(self, get_device_info_mock, def _test_connect_volume_multipath(self, get_device_info_mock,
get_scsi_wwn_mock, get_scsi_wwn_mock,
get_fc_hbas_info_mock, get_fc_hbas_info_mock,
@ -202,7 +203,8 @@ class FibreChannelConnectorTestCase(test_connector.ConnectorTestCase):
wait_for_rw_mock, wait_for_rw_mock,
find_mp_dev_mock, find_mp_dev_mock,
access_mode, access_mode,
should_wait_for_rw): should_wait_for_rw,
find_mp_device_path_mock):
self.connector.use_multipath = True self.connector.use_multipath = True
get_fc_hbas_mock.side_effect = self.fake_get_fc_hbas get_fc_hbas_mock.side_effect = self.fake_get_fc_hbas
get_fc_hbas_info_mock.side_effect = self.fake_get_fc_hbas_info 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} vol = {'id': 1, 'name': name}
initiator_wwn = ['1234567890123456', '1234567890123457'] 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, connection_info = self.fibrechan_connection(vol, location,
initiator_wwn) initiator_wwn)
@ -240,7 +245,7 @@ class FibreChannelConnectorTestCase(test_connector.ConnectorTestCase):
self.connector.disconnect_volume(connection_info['data'], self.connector.disconnect_volume(connection_info['data'],
devices['devices'][0]) devices['devices'][0])
expected_commands = [ expected_commands = [
'multipath -f ' + wwn, 'multipath -f ' + find_mp_device_path_mock.return_value,
'blockdev --flushbufs /dev/sdb', 'blockdev --flushbufs /dev/sdb',
'tee -a /sys/block/sdb/device/delete', 'tee -a /sys/block/sdb/device/delete',
'blockdev --flushbufs /dev/sdc', 'blockdev --flushbufs /dev/sdc',

View File

@ -161,6 +161,7 @@ class LinuxSCSITestCase(base.TestCase):
info = {"device": "dm-3", info = {"device": "dm-3",
"id": "350002ac20398383d", "id": "350002ac20398383d",
"name": "mpatha",
"devices": devices} "devices": devices}
return info return info
@ -168,7 +169,7 @@ class LinuxSCSITestCase(base.TestCase):
self.linuxscsi.remove_multipath_device('/dev/dm-3') self.linuxscsi.remove_multipath_device('/dev/dm-3')
expected_commands = [ expected_commands = [
('multipath -f 350002ac20398383d'), ('multipath -f mpatha'),
('blockdev --flushbufs /dev/sde'), ('blockdev --flushbufs /dev/sde'),
('tee -a /sys/block/sde/device/delete'), ('tee -a /sys/block/sde/device/delete'),
('blockdev --flushbufs /dev/sdf'), ('blockdev --flushbufs /dev/sdf'),