From 080476b2d383b148f6fc8d202c3b0509f9bb1d66 Mon Sep 17 00:00:00 2001 From: "Walter A. Boring IV" Date: Wed, 15 May 2013 16:00:43 -0700 Subject: Fix dangling LUN issue under load with multipath This fixes an issue where not all of the LUNs are seen by the kernel at attach time, but later become available. We now rescan the list of devices seen by multipath at detach time. Also added another unit test case. Fixes Bug: #1175366 Change-Id: Id5b313b17454ec32672373b7b564b9450466b7a2 --- nova/storage/linuxscsi.py | 4 ++++ nova/tests/test_linuxscsi.py | 11 ++++++++++- nova/tests/virt/libvirt/test_libvirt_volume.py | 1 + nova/virt/libvirt/volume.py | 10 ++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/nova/storage/linuxscsi.py b/nova/storage/linuxscsi.py index afd8aa81c..d8c8b7f50 100644 --- a/nova/storage/linuxscsi.py +++ b/nova/storage/linuxscsi.py @@ -112,8 +112,11 @@ def find_multipath_device(device): # on /etc/multipath.conf settings. if info[1][:2] == "dm": mdev = "/dev/%s" % info[1] + mdev_id = info[0] elif info[2][:2] == "dm": mdev = "/dev/%s" % info[2] + mdev_id = info[1].replace('(', '') + mdev_id = mdev_id.replace(')', '') if mdev is None: LOG.warn(_("Couldn't find multipath device %(line)s") @@ -139,6 +142,7 @@ def find_multipath_device(device): if mdev is not None: info = {"device": mdev, + "id": mdev_id, "devices": devices} return info return None diff --git a/nova/tests/test_linuxscsi.py b/nova/tests/test_linuxscsi.py index 0775b9d5b..8c098a846 100644 --- a/nova/tests/test_linuxscsi.py +++ b/nova/tests/test_linuxscsi.py @@ -43,11 +43,20 @@ class StorageLinuxSCSITestCase(test.TestCase): out = ("mpath6 (350002ac20398383d) dm-3 3PARdata,VV\n" "size=2.0G features='0' hwhandler='0' wp=rw\n" "`-+- policy='round-robin 0' prio=-1 status=active\n" - " |- 0:0:0:1 sde 8:64 active undef running\n" + " |- 0:0:0:1 sde 8:64 active undef running\n" " `- 2:0:0:1 sdf 8:80 active undef running\n" ) return out, None + def fake_execute2(*cmd, **kwargs): + out = ("350002ac20398383d dm-3 3PARdata,VV\n" + "size=2.0G features='0' hwhandler='0' wp=rw\n" + "`-+- policy='round-robin 0' prio=-1 status=active\n" + " |- 0:0:0:1 sde 8:64 active undef running\n" + " `- 2:0:0:1 sdf 8:80 active undef running\n" + ) + return out, None + self.stubs.Set(utils, 'execute', fake_execute) info = linuxscsi.find_multipath_device('/dev/sde') diff --git a/nova/tests/virt/libvirt/test_libvirt_volume.py b/nova/tests/virt/libvirt/test_libvirt_volume.py index c96bc8dda..07a1a7b2f 100644 --- a/nova/tests/virt/libvirt/test_libvirt_volume.py +++ b/nova/tests/virt/libvirt/test_libvirt_volume.py @@ -593,6 +593,7 @@ class LibvirtVolumeTestCase(test.TestCase): libvirt_driver = volume.LibvirtFibreChannelVolumeDriver(self.fake_conn) multipath_devname = '/dev/md-1' devices = {"device": multipath_devname, + "id": "1234567890", "devices": [{'device': '/dev/sdb', 'address': '1:0:0:1', 'host': 1, 'channel': 0, diff --git a/nova/virt/libvirt/volume.py b/nova/virt/libvirt/volume.py index 34fd9c772..4a11e2704 100644 --- a/nova/virt/libvirt/volume.py +++ b/nova/virt/libvirt/volume.py @@ -753,6 +753,7 @@ class LibvirtFibreChannelVolumeDriver(LibvirtBaseVolumeDriver): % {'device': mdev_info['device']}) device_path = mdev_info['device'] connection_info['data']['devices'] = mdev_info['devices'] + connection_info['data']['multipath_id'] = mdev_info['id'] else: # we didn't find a multipath device. # so we assume the kernel only sees 1 device @@ -774,6 +775,15 @@ class LibvirtFibreChannelVolumeDriver(LibvirtBaseVolumeDriver): self).disconnect_volume(connection_info, mount_device) devices = connection_info['data']['devices'] + # If this is a multipath device, we need to search again + # and make sure we remove all the devices. Some of them + # might not have shown up at attach time. + if 'multipath_id' in connection_info['data']: + multipath_id = connection_info['data']['multipath_id'] + mdev_info = linuxscsi.find_multipath_device(multipath_id) + devices = mdev_info['devices'] + LOG.debug("devices to remove = %s" % devices) + # There may have been more than 1 device mounted # by the kernel for this volume. We have to remove # all of them -- cgit