fix booting via dracut generated initramfs

Dracut and Systemd updated how they integrate with each other, because
of this our current integrations stopped working (around the time
4.1.13 came out).  This patch addresses that issue and gets us booting
again.

Thanks to @Rudd-O for doing the work to get dracut working again and
letting me submit this on his behalf.

Signed-off-by: Manuel Amador (Rudd-O) <rudd-o@rudd-o.com>
Signed-off-by: Matthew Thode <mthode@mthode.org>
Closes #3605
Closes #4478
This commit is contained in:
Matthew Thode 2016-03-30 18:59:15 -05:00 committed by Brian Behlendorf
parent 232604b58e
commit a5a370227e
7 changed files with 216 additions and 2 deletions

View File

@ -114,6 +114,7 @@ AC_CONFIG_FILES([
contrib/Makefile
contrib/bash_completion.d/Makefile
contrib/dracut/Makefile
contrib/dracut/02zfsexpandknowledge/Makefile
contrib/dracut/90zfs/Makefile
contrib/initramfs/Makefile
module/Makefile

View File

@ -0,0 +1,22 @@
pkgdracutdir = $(dracutdir)/modules.d/02zfsexpandknowledge
pkgdracut_SCRIPTS = \
module-setup.sh
EXTRA_DIST = \
$(top_srcdir)/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in
$(pkgdracut_SCRIPTS):
-$(SED) -e 's,@bindir\@,$(bindir),g' \
-e 's,@sbindir\@,$(sbindir),g' \
-e 's,@datadir\@,$(datadir),g' \
-e 's,@dracutdir\@,$(dracutdir),g' \
-e 's,@udevdir\@,$(udevdir),g' \
-e 's,@udevruledir\@,$(udevruledir),g' \
-e 's,@sysconfdir\@,$(sysconfdir),g' \
"$(top_srcdir)/contrib/dracut/02zfsexpandknowledge/$@.in" >'$@'
clean-local::
-$(RM) $(pkgdracut_SCRIPTS)
distclean-local::
-$(RM) $(pkgdracut_SCRIPTS)

View File

@ -0,0 +1,132 @@
#!/bin/sh
get_devtype() {
local typ
typ=$(udevadm info --query=property --name="$1" | grep "^ID_FS_TYPE=" | sed 's|^ID_FS_TYPE=||')
if [ "$typ" = "" ] ; then
typ=$(blkid -c /dev/null "$1" -o value -s TYPE)
fi
echo "$typ"
}
get_pool_devices() {
# also present in 99zfssystemd
local poolconfigtemp
local poolconfigoutput
local pooldev
local prefix
poolconfigtemp=`mktemp`
@sbindir@/zpool list -v -H "$1" > "$poolconfigtemp" 2>&1
if [ "$?" != "0" ] ; then
poolconfigoutput=$(cat "$poolconfigtemp")
dinfo "zfsexpandknowledge: pool $1 cannot be listed: $poolconfigoutput"
else
while read pooldev ; do
for prefix in /dev/disk/* /dev/mapper ; do
if [ -e "$prefix"/"$pooldev" ] ; then
dinfo "zfsexpandknowledge: pool $1 has device $prefix/$pooldev"
echo `readlink -f "$prefix"/"$pooldev"`
break
fi
done
done < <(cat "$poolconfigtemp" | awk -F '\t' 'NR>1 { print $2 }')
fi
rm -f "$poolconfigtemp"
}
find_zfs_block_devices() {
local dev
local blockdev
local mp
local fstype
local pool
local key
local n
local poolconfigoutput
numfields=`head -1 /proc/self/mountinfo | awk '{print NF}'`
if [ "$numfields" == "10" ] ; then
fields="n n n n mp n n fstype dev n"
else
fields="n n n n mp n n n fstype dev n"
fi
while read $fields ; do
if [ "$fstype" != "zfs" ]; then continue ; fi
if [ "$mp" == "$1" ]; then
pool=$(echo "$dev" | cut -d / -f 1)
get_pool_devices "$pool"
fi
done < /proc/self/mountinfo
}
array_contains () {
local e
for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
return 1
}
check() {
local mp
local dev
local blockdevs
local fstype
local majmin
local _slavedev
local _slavedevname
local _slavedevtype
local _slavemajmin
local _dev
if [[ $hostonly ]]; then
for mp in \
"/" \
"/etc" \
"/bin" \
"/sbin" \
"/lib" \
"/lib64" \
"/usr" \
"/usr/bin" \
"/usr/sbin" \
"/usr/lib" \
"/usr/lib64" \
"/boot";
do
mp=$(readlink -f "$mp")
mountpoint "$mp" >/dev/null 2>&1 || continue
blockdevs=$(find_zfs_block_devices "$mp")
if [ -z "$blockdevs" ] ; then continue ; fi
dinfo "zfsexpandknowledge: block devices backing ZFS dataset $mp: $blockdevs"
for dev in $blockdevs
do
array_contains "$dev" "${host_devs[@]}" || host_devs+=("$dev")
fstype=$(get_devtype "$dev")
host_fs_types["$dev"]="$fstype"
majmin=$(get_maj_min "$dev")
if [[ -d /sys/dev/block/$majmin/slaves ]] ; then
for _slavedev in /sys/dev/block/$majmin/slaves/*; do
[[ -f $_slavedev/dev ]] || continue
_slavedev=/dev/$(basename "$_slavedev")
_slavedevname=$(udevadm info --query=property --name="$_slavedev" | grep "^DEVNAME=" | sed 's|^DEVNAME=||')
_slavedevtype=$(get_devtype "$_slavedevname")
_slavemajmin=$(get_maj_min "$_slavedevname")
dinfo "zfsexpandknowledge: slave block device backing ZFS dataset $mp: $_slavedevname"
array_contains "$_slavedevname" "${host_devs[@]}" || host_devs+=("$_slavedevname")
host_fs_types["$_slavedevname"]="$_slavedevtype"
done
fi
done
done
for a in "${host_devs[@]}"
do
dinfo "zfsexpandknowledge: host device $a"
done
for a in "${!host_fs_types[@]}"
do
dinfo "zfsexpandknowledge: device $a of type ${host_fs_types[$a]}"
done
fi
return 1
}

View File

@ -4,6 +4,7 @@ pkgdracut_SCRIPTS = \
module-setup.sh \
mount-zfs.sh \
parse-zfs.sh \
zfs-generator.sh \
zfs-lib.sh
EXTRA_DIST = \
@ -11,6 +12,7 @@ EXTRA_DIST = \
$(top_srcdir)/contrib/dracut/90zfs/module-setup.sh.in \
$(top_srcdir)/contrib/dracut/90zfs/mount-zfs.sh.in \
$(top_srcdir)/contrib/dracut/90zfs/parse-zfs.sh.in \
$(top_srcdir)/contrib/dracut/90zfs/zfs-generator.sh.in \
$(top_srcdir)/contrib/dracut/90zfs/zfs-lib.sh.in
$(pkgdracut_SCRIPTS):
@ -19,6 +21,7 @@ $(pkgdracut_SCRIPTS):
-e 's,@udevdir\@,$(udevdir),g' \
-e 's,@udevruledir\@,$(udevruledir),g' \
-e 's,@sysconfdir\@,$(sysconfdir),g' \
-e 's,@systemdunitdir\@,$(systemdunitdir),g' \
"$(top_srcdir)/contrib/dracut/90zfs/$@.in" >'$@'
distclean-local::

View File

@ -40,16 +40,22 @@ install() {
dracut_install awk
dracut_install head
inst_hook cmdline 95 "${moddir}/parse-zfs.sh"
if [ -n "$systemdutildir" ] ; then
inst_script "${moddir}/zfs-generator.sh" "$systemdutildir"/system-generators/dracut-zfs-generator
else
inst_hook mount 98 "${moddir}/mount-zfs.sh"
fi
inst_hook shutdown 30 "${moddir}/export-zfs.sh"
inst_simple "${moddir}/zfs-lib.sh" "/lib/dracut-zfs-lib.sh"
if [ -e @sysconfdir@/zfs/zpool.cache ]; then
inst @sysconfdir@/zfs/zpool.cache
type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/zpool.cache
fi
if [ -e @sysconfdir@/zfs/vdev_id.conf ]; then
inst @sysconfdir@/zfs/vdev_id.conf
type mark_hostonly >/dev/null 2>&1 && mark_hostonly @sysconfdir@/zfs/vdev_id.conf
fi
# Synchronize initramfs and system hostid
@ -58,4 +64,15 @@ install() {
CC=`hostid | cut -b 5,6`
DD=`hostid | cut -b 7,8`
printf "\x${DD}\x${CC}\x${BB}\x${AA}" > "${initdir}/etc/hostid"
if dracut_module_included "systemd"; then
mkdir -p "${initdir}/$systemdsystemunitdir/initrd.target.wants"
for _item in scan cache ; do
dracut_install @systemdunitdir@/zfs-import-$_item.service
if ! [ -L "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import-$_item.service ]; then
ln -s ../zfs-import-$_item.service "${initdir}/$systemdsystemunitdir/initrd.target.wants"/zfs-import-$_item.service
type mark_hostonly >/dev/null 2>&1 && mark_hostonly @systemdunitdir@/zfs-import-$_item.service
fi
done
fi
}

View File

@ -0,0 +1,39 @@
#!/bin/bash
GENERATOR_DIR="$1"
[ -z "$GENERATOR_DIR" ] && exit 1
[ -f /lib/dracut-lib.sh ] && dracutlib=/lib/dracut-lib.sh
[ -f /usr/lib/dracut/modules.d/99base/dracut-lib.sh ] && dracutlib=/usr/lib/dracut/modules.d/99base/dracut-lib.sh
type getarg >/dev/null 2>&1 || . "$dracutlib"
[ -z "$root" ] && root=$(getarg root=)
[ -z "$rootfstype" ] && rootfstype=$(getarg rootfstype=)
[ -z "$rootflags" ] && rootflags=$(getarg rootflags=)
[ "${root##zfs:}" = "${root}" -a "${root##ZFS=}" = "${root}" -a "$rootfstype" != "zfs" ] && exit 0
rootfstype=zfs
if echo "${rootflags}" | grep -q zfsutil ; then
true
else
rootflags=zfsutil
fi
root="${root##zfs:}"
root="${root##ZFS=}"
[ -d "$GENERATOR_DIR" ] || mkdir "$GENERATOR_DIR"
[ -d "$GENERATOR_DIR/sysroot.mount.d" ] || mkdir "$GENERATOR_DIR/sysroot.mount.d"
{
echo "[Unit]"
echo "After=zfs-import-scan.service"
echo "After=zfs-import-cache.service"
echo ""
echo "[Mount]"
echo "What=${root}"
echo "Type=${rootfstype}"
echo "Options=${rootflags}"
} > "$GENERATOR_DIR/sysroot.mount.d/zfs-enhancement.conf"

View File

@ -1,3 +1,3 @@
SUBDIRS = 90zfs
SUBDIRS = 02zfsexpandknowledge 90zfs
EXTRA_DIST = README.dracut.markdown