]> git.pld-linux.org Git - projects/geninitrd.git/blob - mod-multipath.sh
Simplify main code by moving state checks to modules itself
[projects/geninitrd.git] / mod-multipath.sh
1 #!/bin/sh
2 #
3 # geninitrd mod: dm-multipath
4 USE_MULTIPATH=${USE_MULTIPATH:-yes}
5
6 # if we should init dm-multipath at boot
7 have_multipath=no
8
9 # dm-multipath wwid which is used for rootfs
10 MPATH_WWID=
11
12 # setup geninitrd module
13 # @access       public
14 setup_mod_multipath() {
15         if [ ! -x /sbin/multipath ]; then
16                 USE_MULTIPATH=no
17         fi
18 }
19
20 # return true if node is multipath controlled
21 # @param        string $node device node to be examined
22 # @access       public
23 is_multipath() {
24         local devpath="$1"
25
26         # multipath disabled
27         if is_no "$USE_MULTIPATH"; then
28                 return 1
29         fi
30
31         # multipath nodes are under device mapper
32         if [[ "$devpath" != /dev/mapper/* ]]; then
33                 return 1
34         fi
35
36         DM_NAME=
37         eval $(dm_export "$devpath")
38         if [ -z "$DM_NAME" ]; then
39                 die "Couldn't extract DM_NAME from $devpath"
40         fi
41
42         local MPATH_WWID=${DM_UUID##*-}
43
44         # just check if it is valid.
45         local info=$(multipath -l $MPATH_WWID)
46         if [ -z "$info" ]; then
47                 return 1
48         fi
49
50         return 0
51 }
52
53 # find modules for $devpath
54 # @param        $devpath        device to be examined
55 # @access       public
56 # find dm-multipath modules for $devpath
57 # returns false if $devpath is not dm-multipath
58 find_modules_multipath() {
59         local devpath="$1"
60
61         DM_NAME=
62         eval $(dm_export "$devpath")
63         if [ -z "$DM_NAME" ]; then
64                 die "Couldn't extract DM_NAME from $devpath"
65         fi
66
67         # Partition:
68         #  DM_NAME=LUN-28p1
69         #  DM_UUID=part1-mpath-36006016002c11800a0aa05fbfae0db11
70         # Disk:
71         #  DM_NAME=LUN-28
72         #  DM_UUID=mpath-36006016002c11800a0aa05fbfae0db11
73         MPATH_WWID=${DM_UUID##*-}
74
75         local info=$(multipath -l $MPATH_WWID)
76         if [ -z "$info" ]; then
77                 return 1
78         fi
79
80         debug "Finding modules for dm-multipath (WWID=$MPATH_WWID)"
81         have_multipath=yes
82
83         local p list
84         list=$(mp_parse_devs "$info")
85         for p in $list; do
86                 find_modules_for_devpath $p
87                 lvm_ignore_devices="$lvm_ignore_devices $p"
88         done
89
90         list=$(mp_parse_hwhandler "$info")
91         for p in $list; do
92                 find_module "$p"
93         done
94
95         list=$(mp_parse_policy "$info")
96         for p in $list; do
97                 find_module "dm-$p"
98         done
99
100         find_module "dm-mod"
101         return 0
102 }
103
104 # generate initrd fragment
105 # @access       public
106 initrd_gen_multipath() {
107         if ! is_yes "$have_multipath"; then
108                 return
109         fi
110
111         inst_d /sbin /lib/udev /etc/multipath
112         inst_exec /sbin/kpartx /sbin
113         inst_exec /sbin/multipath /sbin
114
115         # for udev callouts
116         local scsi_id=$(find_tool /$_lib/udev/scsi_id /lib/udev/scsi_id /sbin/scsi_id)
117         inst_exec $scsi_id /lib/udev
118
119         if [ -d /$_lib/multipath ]; then
120                 inst_d /$_lib/multipath
121                 inst_exec /$_lib/multipath/* /$_lib/multipath
122         else
123                 inst_exec /sbin/mpath* /sbin
124         fi
125
126         egrep -v '^([   ]*$|#)' /etc/multipath.conf > $DESTDIR/etc/multipath.conf
127
128         if [ -f /etc/multipath/bindings ]; then
129                 egrep -v '^([   ]*$|#)' /etc/multipath/bindings > $DESTDIR/etc/multipath/bindings
130         else
131                 touch $DESTDIR/etc/multipath/bindings
132         fi
133
134         mount_dev
135         initrd_gen_devices
136
137         mount_sys
138         echo "export MPATH_WWID=$MPATH_WWID" | add_linuxrc
139         add_linuxrc <<-'EOF'
140                 # parse mpath_wwid= from kernel commandline
141                 for arg in $CMDLINE; do
142                         if [ "${arg##mpath_wwid=}" != "${arg}" ]; then
143                                 MPATH_WWID=${arg##mpath_wwid=}
144                                 if [ "$MPATH_WWID" = "*" ]; then
145                                         # '*' would mean activate all WWID-s
146                                         MPATH_WWID=
147                                         echo "multipath: Activating all WWID-s"
148                                 else
149                                         echo "multipath: Activating WWID=$WWID"
150                                 fi
151                         fi
152                 done
153
154                 debugshell
155                 /sbin/multipath -v 0 $MPATH_WWID
156
157                 for a in /dev/mapper/*; do
158                         [ $a = /dev/mapper/control ] && continue
159                         /sbin/kpartx -a -p p $a
160                 done
161                 debugshell
162         EOF
163 }
164
165
166 # PRIVATE METHODS
167 # export info from dmsetup
168 # param can be:
169 # - MAJOR:MINOR
170 # - /dev/dm-MINOR
171 # - /dev/mapper/DM_NAME
172 dm_export() {
173         local arg="$1"
174
175         case "$arg" in
176         *:*)
177                 local maj=${arg%:*} min=${arg#*:}
178                 dmsetup -j $maj -m $min export
179                 ;;
180         /dev/dm-*)
181                 local min=${arg#*dm-}
182                 local maj=$(awk '$2 == "device-mapper" {print $1}' /proc/devices)
183                 dm_export $maj:$min
184                 ;;
185         /dev/mapper/*)
186                 local dm_name=${arg#/dev/mapper/}
187                 dmsetup export $dm_name
188                 ;;
189         *)
190                 die "dm_export: unexpected $arg"
191                 ;;
192         esac
193 }
194
195 # parse blockdevices behind multipath device
196 # takes 'multipath -l' output as input
197 mp_parse_devs() {
198         local info="$1"
199
200         # parse "0:0:1:0 sdf" -> /dev/sdf
201         #
202         # multipath-tools-0.4.8-0.12.amd64
203         # LUN-02 (36006016002c11800ce520d27c6ebda11) dm-0 DGC     ,RAID 10
204         # [size=12G][features=1 queue_if_no_path][hwhandler=1 emc]
205         # \_ round-robin 0 [prio=0][active]
206         #  \_ 0:0:0:0 sda 8:0   [active][undef]
207         # \_ round-robin 0 [prio=0][enabled]
208         #  \_ 0:0:1:0 sdf 8:80  [active][undef]
209         #
210         # multipath-tools-0.4.8-9.x86_64
211         # LUN-14 (36006016002c118006f4f8bccc7fada11) dm-3 ,
212         # size=7.0G features='0' hwhandler='0' wp=rw
213         # |-+- policy='round-robin 0' prio=-1 status=enabled
214         # | `- #:#:#:# sde 8:64 failed undef running
215         # `-+- policy='round-robin 0' prio=-1 status=active
216         #   `- #:#:#:# sdb 8:16 active undef running
217
218         echo "$info" | awk '{
219                 if (match($0, /[#0-9]+:[#0-9]+:[#0-9]+:[#0-9]+ [^ ]+ [0-9]+:[0-9]/)) {
220                         # take whole matched part into "l" variable
221                         l = substr($0, RSTART, RLENGTH);
222                         split(l, a, " ");
223                         printf("/dev/%s\n", a[2])
224                 }
225         }'
226 }
227
228 # parse policy output for each device
229 # takes 'multipath -l' output as input
230 mp_parse_policy() {
231         local info="$1"
232
233         # multipath-tools-0.4.8-0.12.amd64
234         # LUN-02 (36006016002c11800ce520d27c6ebda11) dm-0 DGC     ,RAID 10
235         # [size=12G][features=1 queue_if_no_path][hwhandler=1 emc]
236         # \_ round-robin 0 [prio=0][active]
237         #  \_ 0:0:0:0 sda 8:0   [active][undef]
238         # \_ round-robin 0 [prio=0][enabled]
239         #  \_ 0:0:1:0 sdf 8:80  [active][undef]
240         #
241         # multipath-tools-0.4.8-9.x86_64
242         # LUN-14 (36006016002c118006f4f8bccc7fada11) dm-3 ,
243         # size=7.0G features='0' hwhandler='0' wp=rw
244         # |-+- policy='round-robin 0' prio=-1 status=enabled
245         # | `- #:#:#:# sde 8:64 failed undef running
246         # `-+- policy='round-robin 0' prio=-1 status=active
247         #   `- #:#:#:# sdb 8:16 active undef running
248
249         echo "$info" | awk '
250                 # multipath-tools-0.4.8-0.12.amd64
251                 /\[prio=/{
252                         print $2
253                 }
254                 # multipath-tools-0.4.8-9.x86_64
255                 /policy=/{
256                         if (match($0, /policy=[^ ]+/)) {
257                                 # take whole matched part into "l" variable
258                                 l = substr($0, RSTART, RLENGTH);
259                                 # remove policy= and single quote,
260                                 # which we can not use in this awk inline script, therefore the %c hack
261                                 sub(sprintf("^policy=%c?", 39), "", l);
262                                 print l
263                         }
264                 }
265         ' | sort -u
266 }
267
268 # parse hwhandler from multipath output
269 # takes 'multipath -l' output as input
270 mp_parse_hwhandler() {
271         local info="$1"
272
273         # TODO: actually the dm-emc vs scsi-dh-emc is dependant on kernel version
274         # not version of the tools installed
275
276         # multipath-tools-0.4.8-0.12.amd64
277         # [size=12G][features=1 queue_if_no_path][hwhandler=1 emc]
278         #
279         # multipath-tools-0.4.8-11.x86_64
280         # size=7.0G features='0' hwhandler='0' wp=rw
281         # size=2.0G features='1 queue_if_no_path' hwhandler='1 emc' wp=rw
282         echo "$info" | sed -ne "
283                 # multipath-tools-0.4.8-0.12.amd64
284                 /\[hwhandler=1/{
285                         s,^.*\[hwhandler=1 \([^]]*\)\].*$,dm-\1,
286                         p
287                 }
288                 # multipath-tools-0.4.8-11.x86_64
289                 /hwhandler='1/{
290                         s,^.*hwhandler='1 \([^']*\)'.*$,scsi-dh-\1,
291                         p
292                 }
293         " | sort -u
294 }
This page took 0.088278 seconds and 4 git commands to generate.