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