]>
Commit | Line | Data |
---|---|---|
67aa84bd ER |
1 | #!/bin/sh |
2 | # | |
3 | # geninitrd mod: LVM | |
4 | ||
5 | # if we should init LVM at boot | |
6 | have_lvm=no | |
7 | ||
8 | # LVM volumes that are needed to activate | |
9 | # VG for root dev | |
10 | # @internal | |
11 | ROOTVG="" | |
12 | ||
13 | # VG for suspend resume dev | |
14 | SUSPENDVG="" | |
15 | ||
16 | VGVOLUMES="" | |
17 | ||
18 | if [ -x /sbin/lvm ]; then | |
19 | USE_LVM=yes | |
20 | else | |
21 | USE_LVM=no | |
22 | fi | |
23 | ||
24 | # LVM devices that should not be included in vgscan on initrd. | |
25 | # @internal | |
26 | lvm_ignore_devices='' | |
27 | ||
28 | # return true if node is lvm node | |
29 | # @param string $node device node to be examined | |
30 | # @access public | |
31 | is_lvm() { | |
32 | local node="$1" | |
33 | ||
34 | # LVM not wanted | |
35 | if is_no "$USE_LVM"; then | |
36 | return 1 | |
37 | fi | |
38 | ||
39 | if [ ! -e "$node" ]; then | |
40 | die "check_lvm(): node $node doesn't exist!" | |
41 | return 1 | |
42 | fi | |
43 | ||
44 | # block-major-58 is lvm1 | |
45 | ls -lL "$node" 2> /dev/null | awk '{if (/^b/) { if ($5 == "58,") { exit 0; } else { exit 1; } } else { exit 1; }}' | |
46 | rc=$? | |
47 | ||
48 | if [ $rc = 0 ]; then | |
49 | # is lvm1 | |
50 | return 0 | |
51 | fi | |
52 | ||
53 | /sbin/lvm lvdisplay "$node" > /dev/null 2>&1 | |
54 | rc=$? | |
55 | if [ $rc -gt 127 ]; then | |
56 | # lvdisplay terminated by signal! most likely it segfaulted. | |
57 | die "Unexpected exit from 'lvdisplay $node': $rc - are your lvm tools broken?" | |
58 | fi | |
59 | ||
60 | return $rc | |
61 | } | |
62 | ||
63 | # find modules for $devpath | |
64 | # @param $devpath device to be examined | |
65 | # @access public | |
66 | find_modules_lvm() { | |
67 | local devpath="$1" | |
68 | ||
69 | debug "LVM: $devpath is LVM node" | |
70 | ||
71 | if [ ! -f /sbin/initrd-lvm -o ! -x /sbin/lvdisplay -o ! -x /sbin/pvdisplay ]; then | |
72 | die "root on LVM but /sbin/initrd-lvm, /sbin/lvdisplay and /sbin/pvdisplay not found. Please install lvm(2) and lvm(2)-initrd package and rerun $PROGRAM." | |
73 | fi | |
74 | ||
75 | if [ -z "$LVMTOOLSVERSION" ]; then | |
76 | LVMTOOLSVERSION=$(/sbin/initrd-lvm vgchange --version 2>/dev/null|head -n 1|awk '{gsub("vgchange: Logical Volume Manager ",NIL); gsub("LVM version: ",NIL); gsub(/\..*/,NIL); print $1}') | |
77 | if [ -z "$LVMTOOLSVERSION" ]; then | |
78 | die "Can't determine LVM tools version. Please set LVMTOOLSVERSION and rerun $PROGRAM." | |
79 | fi | |
80 | fi | |
81 | ||
82 | local vg=$(find_lvm_vg "$devpath") | |
83 | debug "LVM VG for $devpath: $vg" | |
84 | VGVOLUMES=$(echo $VGVOLUMES $vg | tr ' ' '\n' | sort -u) | |
85 | ||
86 | local pv=$(find_lvm_pv "$vg") | |
87 | debug "LVM PV for $vg: $pv" | |
88 | PVDEVICES=$(echo $PVDEVICES $pv | tr ' ' '\n' | sort -u) | |
89 | ||
90 | if [ -n "$PVDEVICES" ]; then | |
91 | for device in $PVDEVICES; do | |
92 | find_modules_for_devpath $device | |
93 | done | |
94 | else | |
95 | die "I wasn't able to find PV (via lvdisplay and pvdisplay). You can try to set PVDEVICES in /etc/sysconfig/geninitrd." | |
96 | fi | |
97 | ||
98 | if [ "$LVMTOOLSVERSION" = "2" ]; then | |
99 | findmodule "-dm-mod" | |
100 | elif [ "$LVMTOOLSVERSION" = "1" ]; then | |
101 | findmodule "-lvm" | |
102 | findmodule "-lvm-mod" | |
103 | else | |
104 | die "LVM version $LVMTOOLSVERSION is not supported yet." | |
105 | fi | |
106 | ||
107 | debug "LVM v$LVMTOOLSVERSION enabled" | |
108 | have_lvm=yes | |
109 | } | |
110 | ||
111 | ||
112 | # generate initrd fragment for lvm | |
113 | # @access public | |
114 | initrd_gen_lvm() { | |
115 | debug "Adding LVM support to initrd" | |
116 | inst_d /tmp /newroot | |
117 | inst_exec /sbin/initrd-lvm /bin/lvm.static | |
118 | ||
119 | # always make /dev on tmpfs for LVM2 | |
120 | if [ "$LVMTOOLSVERSION" = "2" ]; then | |
121 | mount_dev | |
122 | fi | |
123 | ||
124 | if ! is_yes "$dev_mounted"; then | |
125 | inst_d /dev/mapper | |
126 | mknod $DESTDIR/dev/mapper/control c 10 63 | |
127 | for device in $PVDEVICES; do | |
128 | # if LVM on RAID then device might be copied already in gen_md | |
129 | [ -e "$DESTDIR/dev/$(basename $device)" ] && continue | |
130 | inst $device /dev | |
131 | done | |
132 | fi | |
133 | ||
134 | mount_tmp | |
135 | if [ "$LVMTOOLSVERSION" = "1" ]; then | |
136 | add_linuxrc <<-EOF | |
137 | lvm vgscan -T | |
138 | for vg in $VGVOLUMES; do | |
139 | lvm vgchange -T -a y $vg | |
140 | done | |
141 | EOF | |
142 | else | |
143 | echo "cat /etc/lvm.conf > /tmp/lvm.conf" | add_linuxrc | |
144 | echo "global {" > "$DESTDIR/etc/lvm.conf" | |
145 | echo " locking_type = 0" >> "$DESTDIR/etc/lvm.conf" | |
146 | echo " locking_dir = \"/tmp\"" >> "$DESTDIR/etc/lvm.conf" | |
147 | echo "}" >> "$DESTDIR/etc/lvm.conf" | |
148 | echo "devices {" >> "$DESTDIR/etc/lvm.conf" | |
149 | echo " sysfs_scan=0" >> "$DESTDIR/etc/lvm.conf" | |
150 | if is_yes "$have_md"; then | |
151 | echo " md_component_detection = 1" >> "$DESTDIR/etc/lvm.conf" | |
152 | fi | |
153 | if is_yes "$have_dmraid" || is_yes "$have_multipath"; then | |
154 | echo ' types = [ "device-mapper", 254 ]' >> "$DESTDIR/etc/lvm.conf" | |
155 | fi | |
156 | if [ "$lvm_ignore_devices" ]; then | |
157 | # TODO: think of merging with lvm dumpconfig output | |
158 | echo ' filter = [' >> "$DESTDIR/etc/lvm.conf" | |
159 | local dev | |
160 | for dev in $lvm_ignore_devices; do | |
161 | debug "LVM v2: ignore device $dev" | |
162 | printf ' "r|^%s.*|",\n' $dev | |
163 | done >> "$DESTDIR/etc/lvm.conf" | |
164 | echo ']' >> "$DESTDIR/etc/lvm.conf" | |
165 | fi | |
166 | # XXX filter= must be on one line! | |
167 | lvm dumpconfig | awk '/filter=/' >> "$DESTDIR/etc/lvm.conf" | |
168 | echo "}" >> "$DESTDIR/etc/lvm.conf" | |
169 | ||
170 | initrd_gen_devices | |
171 | ||
172 | add_linuxrc <<-EOF | |
173 | export ROOTDEV=$rootdev | |
174 | export ROOTVG="$VGVOLUMES" | |
175 | export SUSPENDVG=$SUSPENDVG | |
176 | EOF | |
177 | add_linuxrc <<-'EOF' | |
178 | # parse rootdev from kernel commandline if it begins with / | |
179 | case "$ROOT" in | |
180 | /*) | |
181 | if [ "$ROOT" != "$ROOTDEV" ]; then | |
182 | ROOTDEV=$ROOT | |
183 | echo "LVM: Using 'root=$ROOTDEV' from kernel commandline" | |
184 | local tmp=${ROOTDEV#/dev/} | |
185 | if [ "$tmp" != "$ROOTDEV" ]; then | |
186 | ROOTVG=${tmp%/*} | |
187 | echo "LVM: Using Volume Group '$ROOTVG' for rootfs" | |
188 | fi | |
189 | fi | |
190 | ;; | |
191 | esac | |
192 | ||
193 | # skip duplicate VG | |
194 | if [ "$SUSPENDVG" = "$ROOTVG" ]; then | |
195 | export VGVOLUMES="$ROOTVG" | |
196 | else | |
197 | export VGVOLUMES="$SUSPENDVG $ROOTVG" | |
198 | fi | |
199 | ||
200 | # disable noise from LVM accessing devices that aren't ready. | |
201 | read printk < /proc/sys/kernel/printk | |
202 | if [ ! "$DEBUGINITRD" ]; then | |
203 | echo 0 > /proc/sys/kernel/printk | |
204 | fi | |
205 | ||
206 | export LVM_SYSTEM_DIR=/tmp | |
207 | : 'Scanning for Volume Groups' | |
208 | lvm.static vgscan --mknodes --ignorelockingfailure 2>/dev/null | |
209 | ||
210 | : 'Activating Volume Groups' | |
211 | for vol in $VGVOLUMES; do | |
212 | lvm.static vgchange --ignorelockingfailure -a y $vol 2>/dev/null | |
213 | done | |
214 | ||
215 | echo "$printk" > /proc/sys/kernel/printk | |
216 | ||
217 | # Find out major/minor | |
218 | attrs="$(lvm.static lvdisplay --ignorelockingfailure -c $ROOTDEV 2>/dev/null)" | |
219 | if [ "$attrs" ]; then | |
220 | majmin="${attrs#*$ROOTDEV*:*:*:*:*:*:*:*:*:*:*:*}" | |
221 | if [ "$majmin" != "$attrs" ]; then | |
222 | major="${majmin%:*}" | |
223 | minor="${majmin#*:}" | |
224 | fi | |
225 | fi | |
226 | ||
227 | if [ "$major" -a "$minor" ]; then | |
228 | # Pass it to kernel | |
229 | echo $((256 * $major + $minor)) > /proc/sys/kernel/real-root-dev | |
230 | else | |
231 | echo 2>&1 "Error figuring out real root device for $ROOTDEV!" | |
232 | echo 2>&1 "System will not most likely boot up! So dropping you to a shell!" | |
233 | echo 2>&1 "" | |
234 | sh | |
235 | fi | |
236 | EOF | |
237 | fi | |
238 | } | |
239 | ||
240 | ||
241 | # PRIVATE METHODS | |
242 | ||
243 | # find PV names from given VG name | |
244 | # @param string $vg Volume Group name | |
245 | # @access private | |
246 | find_lvm_pv() { | |
247 | local vg="$1" | |
248 | ||
249 | local pv=$(/sbin/vgdisplay -C --noheadings -o pv_name "$vg") | |
250 | echo $pv | |
251 | } | |
252 | ||
253 | # find VG name from given devnode | |
254 | # @param string $devnode device node to be examined | |
255 | # @access private | |
256 | find_lvm_vg() { | |
257 | local devnode="$1" | |
258 | ||
259 | local vg=$(/sbin/lvdisplay -C --noheadings -o vg_name "$devnode") | |
260 | echo $vg | |
261 | } |