[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[rhel6-branch 4/4] mpath: filter out the slave devices and their partitions.



This change necessitates from two previous commits:
1) 6e6d3df9a78730996e6ac7d463e3b50dbc164b4c, resulting in
DeviceTree.populate() being called twice now, for the second time at the
end of autopart.

2) 5c83bbf01800ca86d1c8e4cd95d14480165b344c, which causes already
coalesced mpath devices (disks and partitions) never to be torn down
during anaconda run.

Given that, we don't want to let identifyMultipath give
DeviceTree.populate() existing mpath devices (dm-0, dm-1,
etc.). populate() would try to add those before the slave mpath members
(sda, sdb) and although the addUdevDevice() logic will eventually
recursively request sda and sdb while working on dm-0, the udev info we
get for sda in sdb at that point is obtained thorugh a call to
udev_get_block_device() which will not give us a correctly filled in
ID_FS_TYPE (unlike the enriched info dictionaries that idenitfyMultipath()
gives us).

Alternative solution would be to embed a layer between DeviceTree and
udev.py. This layer would remember the additional database values that are
not returned by udev itself but rather discovered by us, such as the
"multipath_member" value of ID_FS_TYPE.

For the partitions part, the patch only does what identifyMultipath()'s
documentation promises: "3) removes the individual members of an mpath's
partitions". This step is optional and to make the function better
defined: note that e.g. sda3 will be scanned later in populate() anyway as
it will naturally still appear in udev_get_block_devices().

Resolves: rhbz#636570
---
 storage/devicelibs/mpath.py |   70 +++++++++++++++++++++++++++---------------
 storage/devicetree.py       |   13 ++++----
 storage/udev.py             |    8 +++++
 3 files changed, 59 insertions(+), 32 deletions(-)

diff --git a/storage/devicelibs/mpath.py b/storage/devicelibs/mpath.py
index 0d0efde..113c544 100644
--- a/storage/devicelibs/mpath.py
+++ b/storage/devicelibs/mpath.py
@@ -7,6 +7,31 @@ import logging
 
 log = logging.getLogger("storage")
 
+def _filter_out_mpath_devices(devices):
+    retval = []
+    for d in devices:
+        if udev_device_is_multipath(d):
+            log.debug("filtering out coalesced mpath device: %s" % d['name'])
+        else:
+            retval.append(d)
+    return retval
+
+def _filter_out_mpath_partitions(devices, multipaths):
+    """
+    Use serial numbers of the multipath members to filter devices from the
+    devices list. The returned list will only partitions that are NOT partitions
+    of the multipath members.
+    """
+    serials = set(udev_device_get_serial(d)
+                  for mpath_members in multipaths for d in mpath_members)
+    retval = []
+    for d in devices:
+        if udev_device_get_serial(d) in serials:
+            log.debug("filtering out mpath partition: %s" % d['name'])
+        else:
+            retval.append(d)
+    return retval
+
 def parseMultipathOutput(output):
     """
     Parse output from "multipath -d" or "multipath -ll" and form a topology.
@@ -84,14 +109,22 @@ def parseMultipathOutput(output):
     return mpaths
 
 def identifyMultipaths(devices):
-    # this function does a couple of things
-    # 1) identifies multipath disks
-    # 2) sets their ID_FS_TYPE to multipath_member
-    # 3) removes the individual members of an mpath's partitions
-    # sample input with multipath pair [sdb,sdc]
-    # [sr0, sda, sda1, sdb, sdb1, sdb2, sdc, sdc1, sdd, sdd1, sdd2]
-    # sample output:
-    # [sda, sdd], [[sdb, sdc]], [sr0, sda1, sdd1, sdd2]]
+    """
+    This function does a couple of things:
+    1) identifies multipath disks,
+    2) sets their ID_FS_TYPE to multipath_member,
+    3) removes the individual members of an mpath's partitions as well as any
+    coalesced multipath devices:
+
+    sample input:
+    [sr0, sda, sda1, sdb, sdb1, sdb2, sdc, sdc1, sdd, sdd1, sdd2, dm-0]
+    where:
+    [sdb, sdc] is a multipath pair
+    dm-0 is a mutliapth device already coalesced from [sdb, sdc]
+
+    sample output:
+    [sda, sdd], [[sdb, sdc]], [sr0, sda1, sdd1, sdd2]]
+    """
     log.info("devices to scan for multipath: %s" % [d['name'] for d in devices])
 
     with open("/etc/multipath.conf") as conf:
@@ -165,23 +198,10 @@ def identifyMultipaths(devices):
 
             multipaths.append([devmap[d] for d in disks])
 
-    non_disk_serials = {}
-    for name,device in non_disk_devices.items():
-        serial = udev_device_get_serial(device)
-        non_disk_serials.setdefault(serial, [])
-        non_disk_serials[serial].append(device)
-
-    for mpath in multipaths:
-        for serial in [d.get('ID_SERIAL_SHORT') for d in mpath]:
-            if non_disk_serials.has_key(serial):
-                log.info("filtering out non disk devices [%s]" % [d['name'] for d in non_disk_serials[serial]])
-                for name in [d['name'] for d in non_disk_serials[serial]]:
-                    if non_disk_devices.has_key(name):
-                        del non_disk_devices[name]
-
-    partition_devices = []
-    for device in non_disk_devices.values():
-        partition_devices.append(device)
+    # singlepaths and partitions should not contain multipath devices:
+    singlepath_disks = _filter_out_mpath_devices(singlepath_disks)
+    partition_devices = _filter_out_mpath_partitions(
+        non_disk_devices.values(), multipaths)
 
     # this is the list of devices we want to keep from the original
     # device list, but we want to maintain its original order.
diff --git a/storage/devicetree.py b/storage/devicetree.py
index 45fc455..f45e656 100644
--- a/storage/devicetree.py
+++ b/storage/devicetree.py
@@ -2026,19 +2026,18 @@ class DeviceTree(object):
                      % (livetarget,))
             self.protectedDevNames.append(livetarget)
 
-        # First iteration - let's just look for disks.
-        old_devices = {}
-
-        devices = udev_get_block_devices()
-        for dev in devices:
-            old_devices[dev['name']] = dev
-
         cfg = self.__multipathConfigWriter.write()
         open("/etc/multipath.conf", "w+").write(cfg)
         del cfg
 
+        devices = udev_get_block_devices()
         (singles, mpaths, partitions) = devicelibs.mpath.identifyMultipaths(devices)
         devices = singles + reduce(list.__add__, mpaths, []) + partitions
+        # remember all the devices idenitfyMultipaths() gave us at this point
+        old_devices = {}
+        for dev in devices:
+            old_devices[dev['name']] = dev
+
         log.info("devices to scan: %s" % [d['name'] for d in devices])
         for dev in devices:
             self.addUdevDevice(dev)
diff --git a/storage/udev.py b/storage/udev.py
index 59b7519..7ba5a9c 100644
--- a/storage/udev.py
+++ b/storage/udev.py
@@ -472,6 +472,14 @@ def udev_device_is_dmraid_partition(info, devicetree):
 
     return False
 
+def udev_device_is_multipath(info):
+    """ Return True if the device is a multipath device or a partition of one."""
+    if not udev_device_is_dm(info):
+        return False
+    if udev_device_get_name(info).startswith("mpath"):
+        return True
+    return False
+
 def udev_device_is_multipath_partition(info, devicetree):
     """ Return True if the device is a partition of a multipath device. """
     if not udev_device_is_dm(info):
-- 
1.7.3.3


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]