From a5a370227eb0a3daf8992a38920d54eb3b7b3c25 Mon Sep 17 00:00:00 2001 From: Matthew Thode Date: Wed, 30 Mar 2016 18:59:15 -0500 Subject: [PATCH] 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) Signed-off-by: Matthew Thode Closes #3605 Closes #4478 --- configure.ac | 1 + .../dracut/02zfsexpandknowledge/Makefile.am | 22 +++ .../02zfsexpandknowledge/module-setup.sh.in | 132 ++++++++++++++++++ contrib/dracut/90zfs/Makefile.am | 3 + contrib/dracut/90zfs/module-setup.sh.in | 19 ++- contrib/dracut/90zfs/zfs-generator.sh.in | 39 ++++++ contrib/dracut/Makefile.am | 2 +- 7 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 contrib/dracut/02zfsexpandknowledge/Makefile.am create mode 100755 contrib/dracut/02zfsexpandknowledge/module-setup.sh.in create mode 100644 contrib/dracut/90zfs/zfs-generator.sh.in diff --git a/configure.ac b/configure.ac index 41cd007581..5037ccbe73 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/contrib/dracut/02zfsexpandknowledge/Makefile.am b/contrib/dracut/02zfsexpandknowledge/Makefile.am new file mode 100644 index 0000000000..0a2170bfc6 --- /dev/null +++ b/contrib/dracut/02zfsexpandknowledge/Makefile.am @@ -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) diff --git a/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in b/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in new file mode 100755 index 0000000000..830ee42f64 --- /dev/null +++ b/contrib/dracut/02zfsexpandknowledge/module-setup.sh.in @@ -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 +} diff --git a/contrib/dracut/90zfs/Makefile.am b/contrib/dracut/90zfs/Makefile.am index b778a27448..f81d6c3575 100644 --- a/contrib/dracut/90zfs/Makefile.am +++ b/contrib/dracut/90zfs/Makefile.am @@ -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:: diff --git a/contrib/dracut/90zfs/module-setup.sh.in b/contrib/dracut/90zfs/module-setup.sh.in index 9eb9f57652..301375a5b3 100755 --- a/contrib/dracut/90zfs/module-setup.sh.in +++ b/contrib/dracut/90zfs/module-setup.sh.in @@ -40,16 +40,22 @@ install() { dracut_install awk dracut_install head inst_hook cmdline 95 "${moddir}/parse-zfs.sh" - inst_hook mount 98 "${moddir}/mount-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 } diff --git a/contrib/dracut/90zfs/zfs-generator.sh.in b/contrib/dracut/90zfs/zfs-generator.sh.in new file mode 100644 index 0000000000..0e0664d0ac --- /dev/null +++ b/contrib/dracut/90zfs/zfs-generator.sh.in @@ -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" diff --git a/contrib/dracut/Makefile.am b/contrib/dracut/Makefile.am index 35b88c36fb..1065e5e94f 100644 --- a/contrib/dracut/Makefile.am +++ b/contrib/dracut/Makefile.am @@ -1,3 +1,3 @@ -SUBDIRS = 90zfs +SUBDIRS = 02zfsexpandknowledge 90zfs EXTRA_DIST = README.dracut.markdown