]> git.ipfire.org Git - thirdparty/dracut.git/blob - modules.d/95iscsi/module-setup.sh
Merge pull request #97 from FGrose/dmsquash-live-root
[thirdparty/dracut.git] / modules.d / 95iscsi / module-setup.sh
1 #!/bin/bash
2
3 # called by dracut
4 check() {
5 local _rootdev
6 # If our prerequisites are not met, fail anyways.
7 require_binaries iscsistart hostname iscsi-iname || return 1
8
9 # If hostonly was requested, fail the check if we are not actually
10 # booting from root.
11
12 is_iscsi() {
13 local _dev=$1
14
15 [[ -L "/sys/dev/block/$_dev" ]] || return
16 cd "$(readlink -f "/sys/dev/block/$_dev")"
17 until [[ -d sys || -d iscsi_session ]]; do
18 cd ..
19 done
20 [[ -d iscsi_session ]]
21 }
22
23 [[ $hostonly ]] || [[ $mount_needs ]] && {
24 pushd . >/dev/null
25 for_each_host_dev_and_slaves is_iscsi || return 255
26 popd >/dev/null
27 }
28 return 0
29 }
30
31 get_ibft_mod() {
32 local ibft_mac=$1
33 local iface_mac iface_mod
34 # Return the iSCSI offload module for a given MAC address
35 for iface_desc in $(iscsiadm -m iface | cut -f 2 -d ' '); do
36 iface_mod=${iface_desc%%,*}
37 iface_mac=${iface_desc#*,}
38 iface_mac=${iface_mac%%,*}
39 if [ "$ibft_mac" = "$iface_mac" ] ; then
40 echo $iface_mod
41 return 0
42 fi
43 done
44 }
45
46 install_ibft() {
47 # When iBFT / iscsi_boot is detected:
48 # - Use 'ip=ibft' to set up iBFT network interface
49 # Note: bnx2i is using a different MAC address of iSCSI offloading
50 # so the 'ip=ibft' parameter must not be set
51 # - specify firmware booting cmdline parameter
52
53 for d in /sys/firmware/* ; do
54 if [ -d ${d}/ethernet0 ] ; then
55 read ibft_mac < ${d}/ethernet0/mac
56 ibft_mod=$(get_ibft_mod $ibft_mac)
57 fi
58 if [ -z "$ibft_mod" ] && [ -d ${d}/ethernet1 ] ; then
59 read ibft_mac < ${d}/ethernet1/mac
60 ibft_mod=$(get_ibft_mod $ibft_mac)
61 fi
62 if [ -d ${d}/initiator ] ; then
63 if [ ${d##*/} = "ibft" ] && [ "$ibft_mod" != "bnx2i" ] ; then
64 echo -n "ip=ibft "
65 fi
66 echo -n "rd.iscsi.firmware=1"
67 fi
68 done
69 }
70
71 install_iscsiroot() {
72 local devpath=$1
73 local scsi_path iscsi_lun session c d conn
74 local iscsi_session iscsi_address iscsi_port iscsi_targetname iscsi_tpgt
75
76 scsi_path=${devpath%%/block*}
77 [ "$scsi_path" = "$devpath" ] && return 1
78 iscsi_lun=${scsi_path##*:}
79 [ "$iscsi_lun" = "$scsi_path" ] && return 1
80 session=${devpath%%/target*}
81 [ "$session" = "$devpath" ] && return 1
82 iscsi_session=${session##*/}
83 [ "$iscsi_session" = "$session" ] && return 1
84
85 for d in ${session}/* ; do
86 case $d in
87 *connection*)
88 c=${d##*/}
89 conn=${d}/iscsi_connection/${c}
90 if [ -d ${conn} ] ; then
91 iscsi_address=$(cat ${conn}/persistent_address)
92 iscsi_port=$(cat ${conn}/persistent_port)
93 fi
94 ;;
95 *session)
96 if [ -d ${d}/${iscsi_session} ] ; then
97 iscsi_initiator=$(cat ${d}/${iscsi_session}/initiatorname)
98 iscsi_targetname=$(cat ${d}/${iscsi_session}/targetname)
99 fi
100 ;;
101 esac
102 done
103
104 [ -z "$iscsi_address" ] && return
105 local_address=$(ip -o route get to $iscsi_address | sed -n 's/.*src \([0-9a-f.:]*\).*/\1/p')
106 ifname=$(ip -o route get to $iscsi_address | sed -n 's/.*dev \([^ ]*\).*/\1/p')
107 printf 'ip=%s:static ' ${ifname}
108
109 if [ -e /sys/class/net/$ifname/address ] ; then
110 ifmac=$(cat /sys/class/net/$ifname/address)
111 printf 'ifname=%s:%s ' ${ifname} ${ifmac}
112 fi
113
114 if [ -n "$iscsi_address" -a -n "$iscsi_targetname" ] ; then
115 if [ -n "$iscsi_port" -a "$iscsi_port" -eq 3260 ] ; then
116 iscsi_port=
117 fi
118 if [ -n "$iscsi_lun" -a "$iscsi_lun" -eq 0 ] ; then
119 iscsi_lun=
120 fi
121 # In IPv6 case rd.iscsi.initatior= must pass address in [] brackets
122 case "$iscsi_address" in
123 *:*)
124 iscsi_address="[$iscsi_address]"
125 ;;
126 esac
127 # Must be two separate lines, so that "sort | uniq" commands later
128 # can sort out rd.iscsi.initiator= duplicates
129 echo "rd.iscsi.initiator=${iscsi_initiator}"
130 echo "netroot=iscsi:${iscsi_address}::${iscsi_port}:${iscsi_lun}:${iscsi_targetname}"
131 fi
132 return 0
133 }
134
135
136 install_softiscsi() {
137 [ -d /sys/firmware/ibft ] && return 0
138
139 is_softiscsi() {
140 local _dev=$1
141 local iscsi_dev
142
143 [[ -L "/sys/dev/block/$_dev" ]] || return
144 iscsi_dev=$(cd -P /sys/dev/block/$_dev; echo $PWD)
145 install_iscsiroot $iscsi_dev
146 }
147
148 for_each_host_dev_and_slaves_all is_softiscsi || return 255
149 return 0
150 }
151
152 # called by dracut
153 depends() {
154 echo network rootfs-block
155 }
156
157 # called by dracut
158 installkernel() {
159 local _arch=$(uname -m)
160
161 instmods bnx2i qla4xxx cxgb3i cxgb4i be2iscsi
162 hostonly="" instmods iscsi_tcp iscsi_ibft crc32c iscsi_boot_sysfs
163 iscsi_module_filter() {
164 local _funcs='iscsi_register_transport'
165 # subfunctions inherit following FDs
166 local _merge=8 _side2=9
167 function bmf1() {
168 local _f
169 while read _f || [ -n "$_f" ]; do
170 case "$_f" in
171 *.ko) [[ $(< $_f) =~ $_funcs ]] && echo "$_f" ;;
172 *.ko.gz) [[ $(gzip -dc <$_f) =~ $_funcs ]] && echo "$_f" ;;
173 *.ko.xz) [[ $(xz -dc <$_f) =~ $_funcs ]] && echo "$_f" ;;
174 esac
175 done
176 return 0
177 }
178
179 function rotor() {
180 local _f1 _f2
181 while read _f1 || [ -n "$_f1" ]; do
182 echo "$_f1"
183 if read _f2; then
184 echo "$_f2" 1>&${_side2}
185 fi
186 done | bmf1 1>&${_merge}
187 return 0
188 }
189 # Use two parallel streams to filter alternating modules.
190 set +x
191 eval "( ( rotor ) ${_side2}>&1 | bmf1 ) ${_merge}>&1"
192 [[ $debug ]] && set -x
193 return 0
194 }
195
196 { find_kernel_modules_by_path drivers/scsi; if [ "$_arch" = "s390" -o "$_arch" = "s390x" ]; then find_kernel_modules_by_path drivers/s390/scsi; fi;} \
197 | iscsi_module_filter | instmods
198 }
199
200 # called by dracut
201 cmdline() {
202 local _iscsiconf=$(install_ibft)
203 {
204 if [ "$_iscsiconf" ] ; then
205 echo ${_iscsiconf}
206 else
207 install_softiscsi
208 fi
209 } | sort | uniq
210 }
211
212 # called by dracut
213 install() {
214 inst_multiple umount iscsistart hostname iscsi-iname
215 inst_multiple -o iscsiuio
216 inst_libdir_file 'libgcc_s.so*'
217
218 # Detect iBFT and perform mandatory steps
219 if [[ $hostonly_cmdline == "yes" ]] ; then
220 local _iscsiconf=$(cmdline)
221 [[ $_iscsiconf ]] && printf "%s\n" "$_iscsiconf" >> "${initdir}/etc/cmdline.d/95iscsi.conf"
222 fi
223
224 inst_hook cmdline 90 "$moddir/parse-iscsiroot.sh"
225 inst_hook cleanup 90 "$moddir/cleanup-iscsi.sh"
226 inst "$moddir/iscsiroot.sh" "/sbin/iscsiroot"
227 if ! dracut_module_included "systemd"; then
228 inst "$moddir/mount-lun.sh" "/bin/mount-lun.sh"
229 else
230 inst_multiple -o \
231 $systemdsystemunitdir/iscsi.service \
232 $systemdsystemunitdir/iscsid.service \
233 $systemdsystemunitdir/iscsid.socket \
234 $systemdsystemunitdir/iscsiuio.service \
235 $systemdsystemunitdir/iscsiuio.socket \
236 iscsiadm iscsid
237
238 mkdir -p "${initdir}/$systemdsystemunitdir/sockets.target.wants"
239 for i in \
240 iscsiuio.socket \
241 ; do
242 ln_r "$systemdsystemunitdir/${i}" "$systemdsystemunitdir/sockets.target.wants/${i}"
243 done
244
245 mkdir -p "${initdir}/$systemdsystemunitdir/basic.target.wants"
246 for i in \
247 iscsid.service \
248 ; do
249 ln_r "$systemdsystemunitdir/${i}" "$systemdsystemunitdir/basic.target.wants/${i}"
250 done
251
252 # Make sure iscsid is started after dracut-cmdline and ready for the initqueue
253 mkdir -p "${initdir}/$systemdsystemunitdir/iscsid.service.d"
254 (
255 echo "[Unit]"
256 echo "After=dracut-cmdline.service"
257 echo "Before=dracut-initqueue.service"
258 ) > "${initdir}/$systemdsystemunitdir/iscsid.service.d/dracut.conf"
259 fi
260 inst_dir /var/lib/iscsi
261 dracut_need_initqueue
262 }