From 07771a6efb08854842aa4493c4c6f8bbbbfc9b1e Mon Sep 17 00:00:00 2001 From: Radek Vykydal Date: Wed, 6 Apr 2011 16:02:14 +0200 Subject: [booty rhel5-branch] Fix grub stage1 installation for /boot on md raid1.(#213578) 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.3.3