On 01/20/2010 04:19 PM, Peter Jones wrote: > Use device-mapper-multipath's "multipath" tool to find and set up > multipath devices. > --- > storage/devicelibs/mpath.py | 91 +++++++++++++++++++++++++++++-------------- > storage/devices.py | 78 ++++++++++++++++++++++++++++++------- > 2 files changed, 125 insertions(+), 44 deletions(-) > > diff --git a/storage/devicelibs/mpath.py b/storage/devicelibs/mpath.py > index 4d1b262..0f3efc2 100644 > --- a/storage/devicelibs/mpath.py > +++ b/storage/devicelibs/mpath.py > @@ -1,10 +1,13 @@ > from ..udev import * > +import iutil > > def parseMultipathOutput(output): > # this function parses output from "multipath -d", so we can use its > # logic for our topology. It returns a structure like: > # [ {'mpathb':['sdb','sdc']}, ... ] > mpaths = {} > + if output is None: > + return mpaths This, of course, is still wrong. > > name = None > devices = [] > @@ -37,63 +40,91 @@ def identifyMultipaths(devices): > # 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 pairs [sda,sdc] and [sdb,sdd] > - # [sr0, sda, sda1, sdb, sda2, sdc, sdd, sdc1, sdc2, sde, sde1] > + # sample input with multipath pair [sdb,sdc] > + # [sr0, sda, sda1, sdb, sdb1, sdb2, sdc, sdc1, sdd, sdd1, sdd2] > # sample output: > - # [sr0, sda, sdb, sdc, sdd, sde, sde1] > - > + # [sda, sdd], [[sdb, sdc]], [sr0, sda1, sdd1, sdd2]] > log.info("devices to scan for multipath: %s" % [d['name'] for d in devices]) > - serials = {} > + > + topology = parseMultipathOutput(iutil.execWithCapture("multipath", ["-d",])) > + # find the devices that aren't in topology, and add them into it... > + topodevs = reduce(lambda x,y: x.union(y), topology.values(), set()) > + for name in set([d['name'] for d in devices]).difference(topodevs): > + topology[name] = [name] > + > + 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 > - > - serials.setdefault(serial, []) > - serials[serial].append(d) > + devmap[d['name']] = d > > singlepath_disks = [] > multipaths = [] > - for serial, disks in serials.items(): > + > + for name, disks in topology.items(): > if len(disks) == 1: > - log.info("adding %s to singlepath_disks" % (disks[0]['name'],)) > - singlepath_disks.append(disks[0]) > + if not non_disk_devices.has_key(disks[0]): > + log.info("adding %s to singlepath_disks" % (disks[0],)) > + singlepath_disks.append(devmap[disks[0]]) > 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: > + # see if we've got any non-disk devices on our mpath list. > + # If so, they're probably false-positives. > + non_disks = False > + for disk in disks: > + d = devmap[disk] > if d.get("ID_USB_DRIVER") != "usb-storage": > all_usb = False > - break > + if (not devmap.has_key(disk)) and non_disk_devices.has_key(disk): > + non_disks = True > + > 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 > + > + if non_disks: > + log.warning("non-disk device %s is part of an mpath") > + for disk in disks: > + if devmap.has_key(disk): > + del devmap[disk] > + if topology.has_key(disk): > + del topology[disk] > continue > > - for d in disks: > - log.info("adding %s to multipath_disks" % (d['name'],)) > + log.info("found multipath set: %s" % (disks,)) > + 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"] = name > + > + multipaths.append([devmap[d] for d in 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 131db2a..0da4aed 100644 > --- a/storage/devices.py > +++ b/storage/devices.py > @@ -2931,11 +2931,8 @@ 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) > parents=parents, sysfsPath=sysfsPath, > exists=True) > > @@ -3008,21 +3005,74 @@ 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 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. """ -- Peter Computers have already beaten communists at chess. The next thing you know, they'll be beating humans. -- Dale _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list