In general there is not always mbrsig on a disk (new device), so we can't
always succeed in creating the disk -> bios id mapping. On the other hand,
the pci_dev symlink in edd does not give us complete information about the
device. So we have to consider both in compareDisks().
---
kickstart.py | 4 +-
storage/__init__.py | 18 ++++--
storage/devicelibs/edd.py | 167 ++++++++++++++++++++++++++++++---------------
3 files changed, 126 insertions(+), 63 deletions(-)
diff --git a/kickstart.py b/kickstart.py
index b606ab8..67b1480 100644
--- a/kickstart.py
+++ b/kickstart.py
@@ -665,8 +665,8 @@ class PartitionData(commands.partition.F12_PartData):
storage.doAutoPart = False
if self.onbiosdisk != "":
- for (disk, biosdisk) in storage.eddDict.iteritems():
- if str(biosdisk) == self.onbiosdisk:
+ for (disk, eddinfo) in storage.eddDict.iteritems():
+ if str(eddinfo.biosdisk) == self.onbiosdisk:
self.disk = disk
break
diff --git a/storage/__init__.py b/storage/__init__.py
index 464eebf..09dab1f 100644
--- a/storage/__init__.py
+++ b/storage/__init__.py
@@ -1180,18 +1180,26 @@ class Storage(object):
return self.fsset.rootDevice
def compareDisks(self, first, second):
- if self.eddDict.has_key(first) and self.eddDict.has_key(second):
- one = self.eddDict[first]
- two = self.eddDict[second]
+ # if exactly one of the devices has a pcidev, prefer it
+ if bool(self.eddDict[first].pcidev) ^ bool(self.eddDict[second].pcidev):
+ if self.eddDict[first].pcidev:
+ return -1
+ if self.eddDict[second].pcidev:
+ return 1
+
+ # next, compare the biosdev numbers
+ if self.eddDict[first].biosdev and self.eddDict[second].biosdev:
+ one = self.eddDict[first].biosdev
+ two = self.eddDict[second].biosdev
if (one < two):
return -1
elif (one > two):
return 1
# if one is in the BIOS and the other not prefer the one in the BIOS
- if self.eddDict.has_key(first):
+ if self.eddDict[first].biosdev:
return -1
- if self.eddDict.has_key(second):
+ if self.eddDict[second].biosdev:
return 1
if first.startswith("hd"):
diff --git a/storage/devicelibs/edd.py b/storage/devicelibs/edd.py
index da03914..db2ba57 100644
--- a/storage/devicelibs/edd.py
+++ b/storage/devicelibs/edd.py
@@ -21,77 +21,132 @@
#
import os
+import os.path
import struct
import logging
log = logging.getLogger("storage")
+class EddInfo:
+ def __init__(self, biosdev):
+ self.biosdev = biosdev
+ self.pcidev = None
+
def get_edd_dict(devices):
- """Given an array of devices return a dict with the BIOS ID for them."""
+ """
+ Given an array of devices return a mapping from their devices names to their
+ EddInfo.
+
+ CAVEATS: It is important to note that the current implementation of the edd
+ kernel module is incomplete and does not give us a reliable method about
+ discovering the complete device <-> BIOS device mapping. Checking the MBR
+ signature works in most cases but will always fail e.g. on new disks that do
+ not contain an MBR yet. On the other hand, the pcidev entry which is
+ guaranteed to exist is shared across all disks connected through the same
+ PCI device and so does not provide a one-to-one relation.
+ """
+
+ # initialize the dict with blank info
edd_dict = {}
+ for dev in devices:
+ edd_dict[dev.name] = EddInfo(None)
for biosdev in range(80, 80 + 15):
+
sysfspath = "/sys/firmware/edd/int13_dev%d" % biosdev
if not os.path.exists(sysfspath):
break # We are done
- sysfspath = "/sys/firmware/edd/int13_dev%d/mbr_signature" % biosdev
- if not os.path.exists(sysfspath):
- log.warning("No mbrsig for biosdev: %d" % biosdev)
- continue
+ dev = _find_device_from_mbrsig(devices, biosdev)
+ if dev:
+ edd_dict[dev].biosdev = biosdev
+
+ (pcidev, devs_for_pcidev) = _devices_for_pcidev(devices, biosdev)
+ for d in devs_for_pcidev:
+ edd_dict[d.name].pcidev = pcidev
+
+ _dump_dict(edd_dict)
+ return edd_dict
+
+def _dump_dict(edd_dict):
+ log.debug("edd:generated dict:")
+ for key in edd_dict:
+ log.debug("%s: biosdev: %s, pcidev: %s" %
+ (key, edd_dict[key].biosdev, edd_dict[key].pcidev))
+ log.debug("edd:end of generated dict dump")
+
+def _find_device_from_mbrsig(devices, biosdev):
+ sysfspath = "/sys/firmware/edd/int13_dev%d/mbr_signature" % biosdev
+ if not os.path.exists(sysfspath):
+ log.info("edd: no mbrsig for biosdev: %d" % biosdev)
+ return None
+
+ try:
+ file = open(sysfspath, "r")
+ eddsig = file.read()
+ file.close()
+ except (IOError, OSError) as e:
+ log.info("edd: error reading EDD mbrsig for %d: %s" %
+ (biosdev, str(e)))
+ return None
+ sysfspath = "/sys/firmware/edd/int13_dev%d/sectors" % biosdev
+ try:
+ file = open(sysfspath, "r")
+ eddsize = file.read()
+ file.close()
+ except (IOError, OSError) as e:
+ eddsize = None
+
+ found = []
+ for dev in devices:
try:
- file = open(sysfspath, "r")
- eddsig = file.read()
- file.close()
- except (IOError, OSError) as e:
- log.warning("Error reading EDD mbrsig for %d: %s" %
- (biosdev, str(e)))
+ fd = os.open(dev.path, os.O_RDONLY)
+ os.lseek(fd, 440, 0)
+ mbrsig = struct.unpack('I', os.read(fd, 4))
+ os.close(fd)
+ except OSError as e:
+ log.info("edd: error reading mbrsig from disk %s: %s" %
+ (dev.name, str(e)))
continue
- sysfspath = "/sys/firmware/edd/int13_dev%d/sectors" % biosdev
- try:
- file = open(sysfspath, "r")
- eddsize = file.read()
- file.close()
- except (IOError, OSError) as e:
- eddsize = None
-
- found = []
- for dev in devices:
- try:
- fd = os.open(dev.path, os.O_RDONLY)
- os.lseek(fd, 440, 0)
- mbrsig = struct.unpack('I', os.read(fd, 4))
- os.close(fd)
- except OSError as e:
- log.warning("Error reading mbrsig from disk %s: %s" %
- (dev.name, str(e)))
- continue
-
- mbrsigStr = "0x%08x\n" % mbrsig
- if mbrsigStr == eddsig:
- if eddsize:
- sysfspath = "/sys%s/size" % dev.sysfsPath
- try:
- file = open(sysfspath, "r")
- size = file.read()
- file.close()
- except (IOError, OSError) as e:
- log.warning("Error getting size for: %s" % dev.name)
- continue
- if eddsize != size:
- continue
- found.append(dev.name)
-
- if not found:
- log.error("No matching mbr signature found for biosdev %d" %
- biosdev)
- elif len(found) > 1:
- log.error("Multiple signature matches found for biosdev %d: %s" %
- (biosdev, str(found)))
- else:
- log.info("Found %s for biosdev %d" %(found[0], biosdev))
- edd_dict[found[0]] = biosdev
+ mbrsigStr = "0x%08x\n" % mbrsig
+ if mbrsigStr == eddsig:
+ if eddsize:
+ sysfspath = "/sys%s/size" % dev.sysfsPath
+ try:
+ file = open(sysfspath, "r")
+ size = file.read()
+ file.close()
+ except (IOError, OSError) as e:
+ log.warning("Error getting size for: %s" % dev.name)
+ continue
+ if eddsize != size:
+ continue
+ found.append(dev.name)
- return edd_dict
+ if not found:
+ log.error("edd: no matching mbr signature found for biosdev %d" %
+ biosdev)
+ return None
+ elif len(found) > 1:
+ log.error("edd: multiple signature matches found for biosdev %d: %s" %
+ (biosdev, str(found)))
+ return None
+ else:
+ return found[0]
+
+def _devices_for_pcidev(devices, biosdev):
+ edd_dir = "/sys/firmware/edd/int13_dev%d" % biosdev
+ try:
+ dereferenced = os.readlink("%s/pci_dev" % edd_dir)
+ except OSError as e:
+ log.info ("edd: no pci_dev for biosdev %d" % biosdev)
+ return (None, [])
+ # get absolute and normalized path
+ sysfs_path = os.path.normpath(os.path.join(edd_dir, dereferenced))
+ if sysfs_path.startswith("/sys/"):
+ sysfs_path = sysfs_path[4:]
+ return (sysfs_path,
+ [dev for dev in devices if dev.sysfsPath.startswith(sysfs_path)]
+ )
--
1.7.3.3