Use device-mapper-multipath's "multipath" tool to find and set up multipath devices. --- storage/devicelibs/mpath.py | 75 +++++++++++++++++++++++++++------------- storage/devices.py | 80 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 117 insertions(+), 38 deletions(-) diff --git a/storage/devicelibs/mpath.py b/storage/devicelibs/mpath.py index 4d1b262..247e837 100644 --- a/storage/devicelibs/mpath.py +++ b/storage/devicelibs/mpath.py @@ -1,4 +1,5 @@ from ..udev import * +import iutil def parseMultipathOutput(output): # this function parses output from "multipath -d", so we can use its @@ -43,57 +44,81 @@ def identifyMultipaths(devices): # [sr0, sda, sdb, sdc, sdd, sde, sde1] log.info("devices to scan for multipath: %s" % [d['name'] for d in devices]) - serials = {} + + mpathinfo = iutil.execWithCapture("multipath", ["-d",]) + if not mpathinfo: + return devices + + devmap = {} non_disk_devices = {} for d in devices: - serial = udev_device_get_serial(d) - if (not udev_device_is_disk(d)) or \ - (not d.has_key('ID_SERIAL_SHORT')): - non_disk_devices.setdefault(serial, []) - non_disk_devices[serial].append(d) + if not udev_device_is_disk(d): + non_disk_devices[d['name']] = d log.info("adding %s to non_disk_device list" % (d['name'],)) continue + devmap[d['name']] = d - serials.setdefault(serial, []) - serials[serial].append(d) - + topology = parseMultipathOutput(mpathinfo) + topomap = {} singlepath_disks = [] multipaths = [] - for serial, disks in serials.items(): + + for (name, disks) in topology.items(): + # we should really never see a disk here that's non in devmap... + for disk in disks: + if not devmap.has_key(disk) and non_disk_devices.has_key(disk): + log.warning("non-disk device %s is part of an mpath") + devmap[disk] = non_disk_devices[disk] + del non_disk_devices[disk] + + topomap[disk] = name + + for (mpname, disks) in topology.items(): if len(disks) == 1: - log.info("adding %s to singlepath_disks" % (disks[0]['name'],)) - singlepath_disks.append(disks[0]) + log.info("adding %s to singlepath_disks" % (disks[0],)) + singlepath_disks.append(devmap[disk]) else: # some usb cardreaders use multiple lun's (for different slots) # and report a fake disk serial which is the same for all the # lun's (#517603) all_usb = True - for d in disks: + for disk in disks: + d = devmap[disk] if d.get("ID_USB_DRIVER") != "usb-storage": all_usb = False break if all_usb: log.info("adding multi lun usb mass storage device to singlepath_disks: %s" % - [disk['name'] for disk in disks]) - singlepath_disks.extend(disks) + (disks,)) + singlepath_disks.extend([devmap[d] for d in disks]) continue - for d in disks: - log.info("adding %s to multipath_disks" % (d['name'],)) + for disk in disks: + d = devmap[disk] + log.info("adding %s to multipath_disks" % (disk,)) d["ID_FS_TYPE"] = "multipath_member" + d["ID_MPATH_NAME"] = mpname + + multipaths.append([devmap[d] for d in disks]) + log.info("found multipath set: [%s]" % (disks,)) - multipaths.append(disks) - log.info("found multipath set: [%s]" % [d['name'] 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['ID_SERIAL_SHORT'] for d in mpath]: - if non_disk_devices.has_key(serial): - log.info("filtering out non disk devices [%s]" % [d['name'] for d in non_disk_devices[serial]]) - del non_disk_devices[serial] + 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 devs in non_disk_devices.values(): - partition_devices += devs + for device in non_disk_devices.values(): + partition_devices.append(device) # 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/devices.py b/storage/devices.py index d5081b4..c2054e6 100644 --- a/storage/devices.py +++ b/storage/devices.py @@ -2931,8 +2931,6 @@ class MultipathDevice(DMDevice): """ self._info = info - self._isUp = False - self._pyBlockMultiPath = None self.setupIdentity() DMDevice.__init__(self, name, format=format, size=size, parents=parents, sysfsPath=sysfsPath) @@ -3010,21 +3008,77 @@ class MultipathDevice(DMDevice): else: self.parents.append(parent) - def setup(self, intf=None): - if self.status: - self.teardown() - self._isUp = True - parents = [] - for p in self.parents: - parents.append(p.path) - self._pyBlockMultiPath = block.device.MultiPath(*parents) + def teardownPartitions(self): + log_method_call(self, name=self.name, kids=self.kids) + rc = iutil.execWithRedirect("kpartx", + ["-d", "-p", "p", "/dev/mapper/%s" % self.name], + stdout = "/dev/tty5", + stderr = "/dev/tty5") + if rc: + raise MPathError("multipath partition deactivation failed for '%s'"\ + % self.name) + udev_settle() + + def setupPartitions(self): + log_method_call(self, name=self.name, kids=self.kids) + rc = iutil.execWithRedirect("kpartx", + ["-a", "-p", "p", "/dev/mapper/%s" % self.name], + stdout = "/dev/tty5", + stderr = "/dev/tty5") + if rc: + raise MPathError("multipath partition activation failed for '%s'" % + self.name) + udev_settle() + + def makeDMNodes(self): + log_method_call(self, name=self.name, kids=self.kids) + rc = iutil.execWithRedirect("dmsetup", ["mknodes"], + stdout = "/dev/tty5", + stderr = "/dev/tty5") def teardown(self, recursive=None): - if not self.status: + """ Tear down the mpath device. """ + log_method_call(self, self.name, status=self.status) + + if not self.exists and not recursive: + raise DeviceError("device has not been created", self.name) + + if self.exists and os.path.exists(self.path): + self.teardownPartitions() + rc = iutil.execWithRedirect("multipath", + ['-f', self.name], + stdout = "/dev/tty5", + stderr = "/dev/tty5") + if rc: + raise MPathError("multipath deactivation failed for '%s'" % + self.name) + udev_settle() + + if recursive: + self.teardownParents(recursive=recursive) + + def setup(self, intf=None): + """ Open, or set up, a device. """ + log_method_call(self, self.name, status=self.status) + + if not self.exists: + raise DeviceError("device has not been created", self.name) + + if self.status: return - self._isUp = False - self._pyBlockMultiPath = None + StorageDevice.setup(self, intf=intf) + udev_settle() + rc = iutil.execWithRedirect("multipath", + [self.name], + stdout = "/dev/tty5", + stderr = "/dev/tty5") + if rc: + raise MPathError("multipath activation failed for '%s'" % + self.name) + udev_settle() + self.setupPartitions() + udev_settle() class NoDevice(StorageDevice): """ A nodev device for nodev filesystems like tmpfs. """ -- 1.6.5.2 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list