edd: use pci_dev as an additional clue for disk boot priority (#621175)
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