1 |
From 07771a6efb08854842aa4493c4c6f8bbbbfc9b1e Mon Sep 17 00:00:00 2001 |
2 |
From: Radek Vykydal <rvykydal@redhat.com> |
3 |
Date: Wed, 6 Apr 2011 16:02:14 +0200 |
4 |
Subject: [booty rhel5-branch] Fix grub stage1 installation for /boot on md raid1.(#213578) |
5 |
|
6 |
Port of commit d625c76082493ffbc4a258c1eb1604d1f0e2edaa |
7 |
from master. |
8 |
|
9 |
The patch fixes: |
10 |
- /boot on raid1 + grub in mbr which didn't work |
11 |
- /boot on raid1 + grub in /boot which used to install |
12 |
grub in mbr |
13 |
- booting after removal of a member disk for both of the |
14 |
beforementioned cases |
15 |
|
16 |
Resolves: rhbz#213578 |
17 |
--- |
18 |
bootloaderInfo.py | 110 ++++++++++++++++++++++++++++++++++++++++++---------- |
19 |
1 files changed, 89 insertions(+), 21 deletions(-) |
20 |
|
21 |
diff --git a/bootloaderInfo.py b/bootloaderInfo.py |
22 |
index 245b4f5..6c4e7ba 100644 |
23 |
--- a/bootloaderInfo.py |
24 |
+++ b/bootloaderInfo.py |
25 |
@@ -760,7 +760,6 @@ class x86BootloaderInfo(bootloaderInfo): |
26 |
"to /boot/, eg.\n") |
27 |
|
28 |
bootDevs = self.getPhysicalDevices(bootDev.device.getDevice()) |
29 |
- bootDev = bootDev.device.getDevice() |
30 |
|
31 |
f.write('# root %s\n' % self.grubbyPartitionName(bootDevs[0])) |
32 |
f.write("# kernel %svmlinuz-version ro " |
33 |
@@ -940,21 +939,83 @@ class x86BootloaderInfo(bootloaderInfo): |
34 |
f.write("forcelba=0\n") |
35 |
f.close() |
36 |
|
37 |
- cmds = [] |
38 |
- for bootDev in bootDevs: |
39 |
- gtPart = self.getMatchingPart(bootDev, grubTarget) |
40 |
- gtDisk = self.grubbyPartitionName(getDiskPart(gtPart)[0]) |
41 |
- bPart = self.grubbyPartitionName(bootDev) |
42 |
- cmd = "root %s\n" % (bPart,) |
43 |
- |
44 |
- stage1Target = gtDisk |
45 |
- if target == "partition": |
46 |
- stage1Target = self.grubbyPartitionName(gtPart) |
47 |
+ stage1Devs = self.getPhysicalDevices(grubTarget) |
48 |
+ |
49 |
+ installs = [(None, |
50 |
+ self.grubbyPartitionName(stage1Devs[0]), |
51 |
+ self.grubbyPartitionName(bootDevs[0]))] |
52 |
+ |
53 |
+ if bootDev.device.getName() == 'RAIDDevice': |
54 |
+ |
55 |
+ matches = self.matchingBootTargets(stage1Devs, bootDevs) |
56 |
+ |
57 |
+ # If the stage1 target disk contains member of boot raid array (mbr |
58 |
+ # case) or stage1 target partition is member of boot raid array |
59 |
+ # (partition case) |
60 |
+ if matches: |
61 |
+ # 1) install stage1 on target disk/partiton |
62 |
+ stage1Dev, mdMemberBootPart = matches[0] |
63 |
+ installs = [(None, |
64 |
+ self.grubbyPartitionName(stage1Dev), |
65 |
+ self.grubbyPartitionName(mdMemberBootPart))] |
66 |
+ firstMdMemberDiskGrubbyName = self.grubbyDiskName(getDiskPart(mdMemberBootPart)[0]) |
67 |
+ |
68 |
+ # 2) and install stage1 on other members' disks/partitions too |
69 |
+ # NOTES: |
70 |
+ # - the goal is to be able to boot after a members' disk removal |
71 |
+ # - so we have to use grub device names as if after removal |
72 |
+ # (i.e. the same disk name (e.g. (hd0)) for both member disks) |
73 |
+ # - if member partitions have different numbers only removal of |
74 |
+ # specific one of members will work because stage2 containing |
75 |
+ # reference to config file is shared and therefore can contain |
76 |
+ # only one value |
77 |
+ |
78 |
+ # if target is mbr, we want to install also to mbr of other |
79 |
+ # members, so extend the matching list |
80 |
+ matches = self.addMemberMbrs(matches, bootDevs) |
81 |
+ for stage1Target, mdMemberBootPart in matches[1:]: |
82 |
+ # prepare special device mapping corresponding to member removal |
83 |
+ mdMemberBootDisk = getDiskPart(mdMemberBootPart)[0] |
84 |
+ # It can happen due to ks --driveorder option, but is it ok? |
85 |
+ if not mdMemberBootDisk in self.drivelist: |
86 |
+ continue |
87 |
+ mdRaidDeviceRemap = (firstMdMemberDiskGrubbyName, |
88 |
+ mdMemberBootDisk) |
89 |
+ |
90 |
+ stage1TargetGrubbyName = self.grubbyPartitionName(stage1Target) |
91 |
+ rootPartGrubbyName = self.grubbyPartitionName(mdMemberBootPart) |
92 |
+ |
93 |
+ # now replace grub disk name part according to special device |
94 |
+ # mapping |
95 |
+ old = self.grubbyDiskName(mdMemberBootDisk).strip('() ') |
96 |
+ new = firstMdMemberDiskGrubbyName.strip('() ') |
97 |
+ rootPartGrubbyName = rootPartGrubbyName.replace(old, new) |
98 |
+ stage1TargetGrubbyName = stage1TargetGrubbyName.replace(old, new) |
99 |
+ |
100 |
+ installs.append((mdRaidDeviceRemap, |
101 |
+ stage1TargetGrubbyName, |
102 |
+ rootPartGrubbyName)) |
103 |
+ |
104 |
+ # This is needed for case when /boot member partitions have |
105 |
+ # different numbers. Shared stage2 can contain only one reference |
106 |
+ # to grub.conf file, so let's ensure that it is reference to partition |
107 |
+ # on disk which we will boot from - that is, install grub to |
108 |
+ # this disk as last so that its reference is not overwritten. |
109 |
+ installs.reverse() |
110 |
|
111 |
+ cmds = [] |
112 |
+ for mdRaidDeviceRemap, stage1Target, rootPart in installs: |
113 |
+ if mdRaidDeviceRemap: |
114 |
+ cmd = "device (%s) /dev/%s\n" % tuple(mdRaidDeviceRemap) |
115 |
+ else: |
116 |
+ cmd = '' |
117 |
+ cmd += "root %s\n" % (rootPart,) |
118 |
cmd += "install %s%s/stage1 d %s %s/stage2 p %s%s/grub.conf" % \ |
119 |
- (forcelba, grubPath, stage1Target, grubPath, bPart, grubPath) |
120 |
+ (forcelba, grubPath, stage1Target, grubPath, rootPart, grubPath) |
121 |
cmds.append(cmd) |
122 |
- |
123 |
+ |
124 |
+ bootDev = bootDev.device.getDevice() |
125 |
+ |
126 |
if not justConfigFile: |
127 |
#log("GRUB commands:") |
128 |
#for cmd in cmds: |
129 |
@@ -994,14 +1055,21 @@ class x86BootloaderInfo(bootloaderInfo): |
130 |
|
131 |
return "" |
132 |
|
133 |
- def getMatchingPart(self, bootDev, target): |
134 |
- bootName, bootPartNum = getDiskPart(bootDev) |
135 |
- devices = self.getPhysicalDevices(target) |
136 |
- for device in devices: |
137 |
- name, partNum = getDiskPart(device) |
138 |
- if name == bootName: |
139 |
- return device |
140 |
- return devices[0] |
141 |
+ def matchingBootTargets(self, stage1Devs, bootDevs): |
142 |
+ matches = [] |
143 |
+ for stage1Dev in stage1Devs: |
144 |
+ for mdBootPart in bootDevs: |
145 |
+ if getDiskPart(stage1Dev)[0] == getDiskPart(mdBootPart)[0]: |
146 |
+ matches.append((stage1Dev, mdBootPart)) |
147 |
+ return matches |
148 |
+ |
149 |
+ def addMemberMbrs(self, matches, bootDevs): |
150 |
+ updatedMatches = list(matches) |
151 |
+ bootDevsHavingStage1Dev = [match[1] for match in matches] |
152 |
+ for mdBootPart in bootDevs: |
153 |
+ if mdBootPart not in bootDevsHavingStage1Dev: |
154 |
+ updatedMatches.append((getDiskPart(mdBootPart)[0], mdBootPart)) |
155 |
+ return updatedMatches |
156 |
|
157 |
def grubbyDiskName(self, name): |
158 |
return "hd%d" % self.drivelist.index(name) |
159 |
-- |
160 |
1.7.3.3 |
161 |
|