[PATCH rhel5-branch booty] Fix grub stage1 installation for /boot on md raid1.(#213578)

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

 



Port of commit d625c76082493ffbc4a258c1eb1604d1f0e2edaa
from master.

The patch fixes:
- /boot on raid1 + grub in mbr which didn't work
- /boot on raid1 + grub in /boot which used to install
  grub in mbr
- booting after removal of a member disk for both of the
  beforementioned cases

Resolves: rhbz#213578
---
 bootloaderInfo.py |  110 ++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 89 insertions(+), 21 deletions(-)

diff --git a/bootloaderInfo.py b/bootloaderInfo.py
index 245b4f5..6c4e7ba 100644
--- a/bootloaderInfo.py
+++ b/bootloaderInfo.py
@@ -760,7 +760,6 @@ class x86BootloaderInfo(bootloaderInfo):
                     "to /boot/, eg.\n")
 
         bootDevs = self.getPhysicalDevices(bootDev.device.getDevice())
-        bootDev = bootDev.device.getDevice()
         
         f.write('#          root %s\n' % self.grubbyPartitionName(bootDevs[0]))
         f.write("#          kernel %svmlinuz-version ro "
@@ -940,21 +939,83 @@ class x86BootloaderInfo(bootloaderInfo):
             f.write("forcelba=0\n")
         f.close()
             
-        cmds = []
-        for bootDev in bootDevs:
-            gtPart = self.getMatchingPart(bootDev, grubTarget)
-            gtDisk = self.grubbyPartitionName(getDiskPart(gtPart)[0])
-            bPart = self.grubbyPartitionName(bootDev)
-            cmd = "root %s\n" % (bPart,)
-
-            stage1Target = gtDisk
-            if target == "partition":
-                stage1Target = self.grubbyPartitionName(gtPart)
+        stage1Devs = self.getPhysicalDevices(grubTarget)
+
+        installs = [(None,
+                     self.grubbyPartitionName(stage1Devs[0]),
+                     self.grubbyPartitionName(bootDevs[0]))]
+
+        if bootDev.device.getName() == 'RAIDDevice':
+
+            matches = self.matchingBootTargets(stage1Devs, bootDevs)
+
+            # If the stage1 target disk contains member of boot raid array (mbr
+            # case) or stage1 target partition is member of boot raid array
+            # (partition case)
+            if matches:
+                # 1) install stage1 on target disk/partiton
+                stage1Dev, mdMemberBootPart = matches[0]
+                installs = [(None,
+                             self.grubbyPartitionName(stage1Dev),
+                             self.grubbyPartitionName(mdMemberBootPart))]
+                firstMdMemberDiskGrubbyName = self.grubbyDiskName(getDiskPart(mdMemberBootPart)[0])
+
+                # 2) and install stage1 on other members' disks/partitions too
+                # NOTES:
+                # - the goal is to be able to boot after a members' disk removal
+                # - so we have to use grub device names as if after removal
+                #   (i.e. the same disk name (e.g. (hd0)) for both member disks)
+                # - if member partitions have different numbers only removal of
+                #   specific one of members will work because stage2 containing
+                #   reference to config file is shared and therefore can contain
+                #   only one value
+
+                # if target is mbr, we want to install also to mbr of other
+                # members, so extend the matching list
+                matches = self.addMemberMbrs(matches, bootDevs)
+                for stage1Target, mdMemberBootPart in matches[1:]:
+                    # prepare special device mapping corresponding to member removal
+                    mdMemberBootDisk = getDiskPart(mdMemberBootPart)[0]
+                    # It can happen due to ks --driveorder option, but is it ok?
+                    if not mdMemberBootDisk in self.drivelist:
+                        continue
+                    mdRaidDeviceRemap = (firstMdMemberDiskGrubbyName,
+                                         mdMemberBootDisk)
+
+                    stage1TargetGrubbyName = self.grubbyPartitionName(stage1Target)
+                    rootPartGrubbyName = self.grubbyPartitionName(mdMemberBootPart)
+
+                    # now replace grub disk name part according to special device
+                    # mapping
+                    old = self.grubbyDiskName(mdMemberBootDisk).strip('() ')
+                    new = firstMdMemberDiskGrubbyName.strip('() ')
+                    rootPartGrubbyName = rootPartGrubbyName.replace(old, new)
+                    stage1TargetGrubbyName = stage1TargetGrubbyName.replace(old, new)
+
+                    installs.append((mdRaidDeviceRemap,
+                                     stage1TargetGrubbyName,
+                                     rootPartGrubbyName))
+
+                # This is needed for case when /boot member partitions have
+                # different numbers. Shared stage2 can contain only one reference
+                # to grub.conf file, so let's ensure that it is reference to partition
+                # on disk which we will boot from - that is, install grub to
+                # this disk as last so that its reference is not overwritten.
+                installs.reverse()
 
+        cmds = []
+        for mdRaidDeviceRemap, stage1Target, rootPart in installs:
+            if mdRaidDeviceRemap:
+                cmd = "device (%s) /dev/%s\n" % tuple(mdRaidDeviceRemap)
+            else:
+                cmd = ''
+            cmd += "root %s\n" % (rootPart,)
             cmd += "install %s%s/stage1 d %s %s/stage2 p %s%s/grub.conf" % \
-                (forcelba, grubPath, stage1Target, grubPath, bPart, grubPath)
+                (forcelba, grubPath, stage1Target, grubPath, rootPart, grubPath)
             cmds.append(cmd)
-            
+
+        bootDev = bootDev.device.getDevice()
+
         if not justConfigFile:
             #log("GRUB commands:")
             #for cmd in cmds:
@@ -994,14 +1055,21 @@ class x86BootloaderInfo(bootloaderInfo):
 
         return ""
 
-    def getMatchingPart(self, bootDev, target):
-        bootName, bootPartNum = getDiskPart(bootDev)
-        devices = self.getPhysicalDevices(target)
-        for device in devices:
-            name, partNum = getDiskPart(device)
-            if name == bootName:
-                return device
-        return devices[0]
+    def matchingBootTargets(self, stage1Devs, bootDevs):
+        matches = []
+        for stage1Dev in stage1Devs:
+            for mdBootPart in bootDevs:
+                if getDiskPart(stage1Dev)[0] == getDiskPart(mdBootPart)[0]:
+                    matches.append((stage1Dev, mdBootPart))
+        return matches
+
+    def addMemberMbrs(self, matches, bootDevs):
+        updatedMatches = list(matches)
+        bootDevsHavingStage1Dev = [match[1] for match in matches]
+        for mdBootPart in bootDevs:
+            if mdBootPart not in bootDevsHavingStage1Dev:
+               updatedMatches.append((getDiskPart(mdBootPart)[0], mdBootPart))
+        return updatedMatches
 
     def grubbyDiskName(self, name):
         return "hd%d" % self.drivelist.index(name)
-- 
1.7.4

_______________________________________________
Anaconda-devel-list mailing list
Anaconda-devel-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/anaconda-devel-list


[Index of Archives]     [Kickstart]     [Fedora Users]     [Fedora Legacy List]     [Fedora Maintainers]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [Yosemite Photos]     [KDE Users]     [Fedora Tools]
  Powered by Linux