]> git.pld-linux.org Git - projects/geninitrd.git/blob - mod-lvm.sh
add noudevsync to vgchange to avoid lockups (it never completes)
[projects/geninitrd.git] / mod-lvm.sh
1 #!/bin/sh
2 LVM_RCSID='$Revision$ $Date::                            $'
3
4 # geninitrd mod: LVM
5 USE_LVM=${USE_LVM:-yes}
6
7 # if we should init LVM at boot
8 have_lvm=no
9
10 # LVM volumes that are needed to activate
11 # VG for root dev
12 # @internal
13 LVM_ROOTVG=""
14
15 # VG for suspend resume dev
16 LVM_SUSPENDVG=""
17
18 LVM_VGVOLUMES=""
19
20 # LVM version. Autodetected if not set.
21 # Values: 1|2
22 LVMTOOLSVERSION=
23
24 # LVM devices that should not be included in vgscan on initrd.
25 # @internal
26 lvm_ignore_devices=''
27
28 # setup geninitrd module
29 # @access       public
30 setup_mod_lvm() {
31         lvm=$(find_tool $initrd_dir/lvm /sbin/initrd-lvm)
32
33         if [ ! -x "$lvm" ]; then
34                 USE_LVM=no
35         fi
36
37         if is_yes "$USE_LVM" && [ -z "$LVMTOOLSVERSION" ]; then
38                 LVMTOOLSVERSION=$(LC_ALL=C $lvm vgchange --version 2>/dev/null | awk '/LVM version:/{if ($3 >= 2) print "2"}')
39                 if [ -z "$LVMTOOLSVERSION" ]; then
40                         die "Can't determine LVM tools version (is /sys mounted?). Please set LVMTOOLSVERSION and rerun $PROGRAM."
41                 fi
42         fi
43 }
44
45 # return true if node is lvm node
46 # @param        string $node device node to be examined
47 # @access       public
48 is_lvm() {
49         local node="$1"
50
51         # LVM not wanted
52         if is_no "$USE_LVM"; then
53                 return 1
54         fi
55
56         if [ ! -e "$node" ]; then
57                 die "check_lvm(): node $node doesn't exist!"
58                 return 1
59         fi
60
61         # block-major-58 is lvm1
62         ls -lL "$node" 2> /dev/null | awk '{if (/^b/) { if ($5 == "58,") { exit 0; } else { exit 1; } } else { exit 1; }}'
63         rc=$?
64
65         if [ $rc = 0 ]; then
66                 # is lvm1
67                 return 0
68         fi
69
70         $lvm lvdisplay "$node" > /dev/null 2>&1
71         rc=$?
72         if [ $rc -gt 127 ]; then
73                 # lvdisplay terminated by signal! most likely it segfaulted.
74                 die "Unexpected exit from 'lvdisplay $node': $rc - are your lvm tools broken?"
75         fi
76
77         return $rc
78 }
79
80 # find modules for $devpath
81 # @param        $devpath        device to be examined
82 # @access       public
83 find_modules_lvm() {
84         local devpath="$1"
85
86         verbose "LVM: $devpath is LVM node"
87
88         local vg=$(find_lvm_vg "$devpath")
89         verbose "LVM VG for $devpath: $vg"
90         LVM_VGVOLUMES=$(echo $LVM_VGVOLUMES $vg | tr ' ' '\n' | sort -u)
91
92         local pv=$(find_lvm_pv "$vg")
93         verbose "LVM PV for $vg: $pv"
94         PVDEVICES=$(echo $PVDEVICES $pv | tr ' ' '\n' | sort -u)
95
96         if [ -n "$PVDEVICES" ]; then
97                 for device in $PVDEVICES; do
98                         find_modules_for_devpath $device
99                 done
100         else
101                 die "I wasn't able to find PV. You can try to set PVDEVICES in /etc/sysconfig/geninitrd."
102         fi
103
104         if [ "$LVMTOOLSVERSION" = "2" ]; then
105                 find_module "-dm-mod"
106         elif [ "$LVMTOOLSVERSION" = "1" ]; then
107                 find_module "-lvm"
108                 find_module "-lvm-mod"
109         else
110                 die "LVM version $LVMTOOLSVERSION is not supported."
111         fi
112
113         verbose "LVM v$LVMTOOLSVERSION enabled"
114         have_lvm=yes
115 }
116
117
118 # generate initrd fragment for lvm
119 # @access       public
120 initrd_gen_lvm() {
121         if ! is_yes "$have_lvm"; then
122                 return
123         fi
124
125         verbose "Adding LVM support to initrd"
126         inst_d /tmp /newroot
127         inst_exec $lvm /bin/lvm.static
128
129         # always make /dev on tmpfs for LVM2
130         if [ "$LVMTOOLSVERSION" = "2" ]; then
131                 mount_dev
132         fi
133
134         if ! is_yes "$dev_mounted"; then
135                 inst_d /dev/mapper
136                 mknod -m 600 $DESTDIR/dev/mapper/control c 10 63
137                 for device in $PVDEVICES; do
138                         # if LVM on RAID then device might be copied already in gen_md
139                         [ -e "$DESTDIR/dev/$(basename $device)" ] && continue
140                         inst $device /dev
141                 done
142         fi
143
144         mount_tmp
145         mount_sys
146         if [ "$LVMTOOLSVERSION" = "1" ]; then
147                 add_linuxrc <<-EOF
148                         lvm vgscan -T
149                         for vg in $LVM_VGVOLUMES; do
150                                 lvm vgchange -T -a y $vg
151                         done
152                 EOF
153         else
154                 cat <<-EOF > "$DESTDIR/etc/lvm.conf"
155                 global {
156                         locking_type = 0
157                         locking_dir = "/tmp"
158                 }
159                 devices {
160                         sysfs_scan=0
161                 EOF
162                 if is_yes "$have_md"; then
163                         echo "  md_component_detection=1" >> "$DESTDIR/etc/lvm.conf"
164                 fi
165                 if is_yes "$have_dmraid" || is_yes "$have_multipath"; then
166                         echo '  types = [ "device-mapper", 254 ]' >> "$DESTDIR/etc/lvm.conf"
167                 fi
168                 if [ "$lvm_ignore_devices" ]; then
169                         # TODO: think of merging with lvm dumpconfig output
170                         echo '  filter = [' >> "$DESTDIR/etc/lvm.conf"
171                         local dev
172                         for dev in $lvm_ignore_devices; do
173                                 verbose "LVM v2: ignore device $dev"
174                                 printf '  "r|^%s.*|",\n' $dev
175                         done >> "$DESTDIR/etc/lvm.conf"
176                         echo ']' >> "$DESTDIR/etc/lvm.conf"
177                 fi
178                 # XXX filter= must be on one line!
179                 $lvm dumpconfig | awk '/filter=/' >> "$DESTDIR/etc/lvm.conf"
180                 echo "}" >> "$DESTDIR/etc/lvm.conf"
181
182                 echo "cat /etc/lvm.conf > /tmp/lvm.conf" | add_linuxrc
183
184                 initrd_gen_devices
185
186                 add_linuxrc <<-EOF
187                         ROOTDEV=$rootdev
188                         LVM_ROOTVG="$LVM_VGVOLUMES"
189                         LVM_SUSPENDVG="$LVM_SUSPENDVG"
190                 EOF
191
192                 # need awk for "s/--/-/g" subst when parsing kernel root commandline
193                 busybox_applet awk
194                 add_linuxrc <<-'EOF'
195                         # parse rootdev from kernel commandline if it begins with /
196                         case "$ROOT" in
197                                 /*)
198
199                                 # rewrite:
200                                 # /dev/mapper/sys-rootfs -> /dev/sys/rootfs
201                                 # /dev/mapper/blodnatt-blah--bleh -> /dev/blodnatt/blah-bleh
202                                 # /dev/mapper/vg--meaw-root -> /dev/vg-meaw/root
203                                 case "$ROOT" in
204                                         /dev/mapper/*-*)
205                                                 # change "--" to / (as "/" is impossible in LV name)
206                                                 local dev=$(awk -vdev="${ROOT#/dev/mapper/}" 'BEGIN{gsub(/--/, "/", dev); print dev}')
207                                                 local VG=$(awk -vdev="$dev" 'BEGIN{split(dev, v, "-"); gsub("/", "-", v[1]); print v[1]}')
208                                                 local LV=$(awk -vdev="$dev" 'BEGIN{split(dev, v, "-"); gsub("/", "-", v[2]); print v[2]}')
209                                                 ROOT=/dev/$VG/$LV
210                                         ;;
211                                 esac
212
213                                 if [ "$ROOT" != "$ROOTDEV" ]; then
214                                         ROOTDEV=$ROOT
215
216                                         echo "LVM: Using 'root=$ROOTDEV' from kernel commandline"
217                                         local tmp=${ROOTDEV#/dev/}
218                                         if [ "$tmp" != "$ROOTDEV" ]; then
219                                                 LVM_ROOTVG=${tmp%/*}
220                                                 echo "LVM: Using Volume Group '$LVM_ROOTVG' for rootfs"
221                                         fi
222                                 fi
223                                 ;;
224                         esac
225
226                         # skip duplicate VG
227                         if [ "$LVM_SUSPENDVG" = "$LVM_ROOTVG" ]; then
228                                 LVM_VGVOLUMES="$LVM_ROOTVG"
229                         else
230                                 LVM_VGVOLUMES="$LVM_SUSPENDVG $LVM_ROOTVG"
231                         fi
232
233                         # disable noise from LVM accessing devices that aren't ready.
234                         read printk < /proc/sys/kernel/printk
235                         if [ ! "$DEBUGINITRD" ]; then
236                                 echo 0 > /proc/sys/kernel/printk
237                         fi
238
239                         export LVM_SYSTEM_DIR=/tmp
240
241                         : 'Scanning for Volume Groups'
242                         lvm.static vgscan --mknodes --ignorelockingfailure
243
244                         : 'Activating Volume Groups'
245                         for vol in $LVM_VGVOLUMES; do
246                                 lvm.static vgchange --ignorelockingfailure -a y $vol --noudevsync
247                         done
248
249                         : 'Extra call to make device nodes for non lvm2-initrd (dynamic lvm2)'
250                         lvm.static vgmknodes --ignorelockingfailure
251
252                         echo "$printk" > /proc/sys/kernel/printk
253
254                         # Find out major/minor
255                         attrs="$(lvm.static lvdisplay --ignorelockingfailure -c $ROOTDEV)"
256                         if [ "$attrs" ]; then
257                                 majmin="${attrs#*$ROOTDEV*:*:*:*:*:*:*:*:*:*:*:*}"
258                                 if [ "$majmin" != "$attrs" ]; then
259                                         major="${majmin%:*}"
260                                         minor="${majmin#*:}"
261                                 fi
262                         fi
263
264                         if [ "$major" -a "$minor" ]; then
265                                 # Pass it to kernel
266                                 echo $((256 * $major + $minor)) > /proc/sys/kernel/real-root-dev
267                         fi
268
269                         debugshell
270                         unset LVM_SYSTEM_DIR
271                 EOF
272         fi
273 }
274
275
276 # PRIVATE METHODS
277
278 # find PV names from given VG name
279 # @param        string $vg Volume Group name
280 # @access       private
281 find_lvm_pv() {
282         local vg="$1"
283
284         local pv=$($lvm vgs --noheadings -o pv_name  "$vg")
285         echo $pv
286 }
287
288 # find VG name from given devnode
289 # @param        string $devnode device node to be examined
290 # @access       private
291 find_lvm_vg() {
292         local devnode="$1"
293
294         local vg=$($lvm lvs --noheadings -o vg_name  "$devnode")
295         echo $vg
296 }
This page took 0.054939 seconds and 4 git commands to generate.