[Pkg-zfsonlinux-devel] Bug#849969: root zpool broken on Debian stretch
Lukas Wunner
lukas at wunner.de
Mon Jan 2 19:00:02 UTC 2017
Package: zfs-dracut
Version: 0.6.5.8-2
Severity: important
Tags: patch
After upgrading to systemd 230 as included with Debian stretch, systems
that build their initramfs with dracut and have their root partition on
a zpool fail to boot:
On boot, /usr/lib/dracut/modules.d/98dracut-systemd/rootfs-generator.sh
generates a systemd unit to mount the "root=" kernel parameter, which
for ZFS may look like "zfs:pool/dataset" or "zfs:AUTO", a format not
understood by mount(8). As a result systemd switches to emergency mode.
A fix was committed upstream in April 2016 with a5a370227eb0 ("fix
booting via dracut generated initramfs"), but never made it into the
0.6.5.* point releases, presumably because they do not pick up fixes
in the contrib/ directory. Note that upstream has a lot more dracut
fixes but this single patch is already sufficient to make my machine
boot again.
Add a patch containing that commit. The patch makes use of the
--with-systemdunitdir configure parameter which we do not set and
which incorrectly defaults to /usr/lib/systemd/system/. (Debian uses
/lib/systemd/system/.) Amend debian/rules to set that parameter.
This obviates the need to specify the /lib/systemd/system/ path in
debian/zfs-zed.install and debian/zfsutils-linux.install, so fix those
up while at it.
-------------- next part --------------
>From e8df3b2d9405ccf62cbb5ed848d94792a55ab1b8 Mon Sep 17 00:00:00 2001
From: Lukas Wunner <lukas at wunner.de>
Date: Mon, 2 Jan 2017 19:13:47 +0100
Subject: [PATCH] zfs-dracut: Fix root zpool on Debian stretch
After upgrading to systemd 230 as included with Debian stretch, systems
that build their initramfs with dracut and have their root partition on
a zpool fail to boot:
On boot, /usr/lib/dracut/modules.d/98dracut-systemd/rootfs-generator.sh
generates a systemd unit to mount the "root=" kernel parameter, which
for ZFS may look like "zfs:pool/dataset" or "zfs:AUTO", a format not
understood by mount(8). As a result systemd switches to emergency mode.
A fix was committed upstream in April 2016 with a5a370227eb0 ("fix
booting via dracut generated initramfs"), but never made it into the
0.6.5.* point releases, presumably because they do not pick up fixes
in the contrib/ directory. Note that upstream has a lot more dracut
fixes but this single patch is already sufficient to make my machine
boot again.
Add a patch containing that commit. The patch makes use of the
--with-systemdunitdir configure parameter which we do not set and
which incorrectly defaults to /usr/lib/systemd/system/. (Debian uses
/lib/systemd/system/.) Amend debian/rules to set that parameter.
This obviates the need to specify the /lib/systemd/system/ path in
debian/zfs-zed.install and debian/zfsutils-linux.install, so fix those
up while at it.
Signed-off-by: Lukas Wunner <lukas at wunner.de>
---
...ix-booting-via-dracut-generated-initramfs.patch | 337 +++++++++++++++++++++
debian/patches/series | 1 +
debian/rules | 2 +
debian/zfs-zed.install | 2 +-
debian/zfsutils-linux.install | 12 +-
5 files changed, 347 insertions(+), 7 deletions(-)
create mode 100644 debian/patches/1004-fix-booting-via-dracut-generated-initramfs.patch
diff --git a/debian/patches/1004-fix-booting-via-dracut-generated-initramfs.patch b/debian/patches/1004-fix-booting-via-dracut-generated-initramfs.patch
new file mode 100644
index 0000000..3264aa9
--- /dev/null
+++ b/debian/patches/1004-fix-booting-via-dracut-generated-initramfs.patch
@@ -0,0 +1,337 @@
+From a5a370227eb0a3daf8992a38920d54eb3b7b3c25 Mon Sep 17 00:00:00 2001
+From: Matthew Thode <mthode at mthode.org>
+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) <rudd-o at rudd-o.com>
+Signed-off-by: Matthew Thode <mthode at mthode.org>
+Closes #3605
+Closes #4478
+---
+ configure.ac | 1 +
+ contrib/dracut/02zfsexpandknowledge/Makefile.am | 22 ++++
+ .../dracut/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 41cd00758..5037ccbe7 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 000000000..0a2170bfc
+--- /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, at bindir\@,$(bindir),g' \
++ -e 's, at sbindir\@,$(sbindir),g' \
++ -e 's, at datadir\@,$(datadir),g' \
++ -e 's, at dracutdir\@,$(dracutdir),g' \
++ -e 's, at udevdir\@,$(udevdir),g' \
++ -e 's, at udevruledir\@,$(udevruledir),g' \
++ -e 's, at 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 000000000..830ee42f6
+--- /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 b778a2744..f81d6c357 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, at udevdir\@,$(udevdir),g' \
+ -e 's, at udevruledir\@,$(udevruledir),g' \
+ -e 's, at sysconfdir\@,$(sysconfdir),g' \
++ -e 's, at 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 9eb9f5765..301375a5b 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 000000000..0e0664d0a
+--- /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 35b88c36f..1065e5e94 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
+--
+2.11.0
+
diff --git a/debian/patches/series b/debian/patches/series
index 086d2b0..08c55d9 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -6,3 +6,4 @@
enable-zed.patch
1001-cmd-python-exec-path.patch
1003-linux-4.9-compat.patch
+1004-fix-booting-via-dracut-generated-initramfs.patch
diff --git a/debian/rules b/debian/rules
index 15e0592..6dfb8c1 100755
--- a/debian/rules
+++ b/debian/rules
@@ -52,6 +52,8 @@ endif
--sbindir=/sbin \
--libdir=/lib \
--with-udevdir=/lib/udev \
+ --with-systemdunitdir=/lib/systemd/system \
+ --with-systemdpresetdir=/lib/systemd/system-preset \
--with-config=user
override_dh_auto_test:
diff --git a/debian/zfs-zed.install b/debian/zfs-zed.install
index a84fff7..bc711e6 100644
--- a/debian/zfs-zed.install
+++ b/debian/zfs-zed.install
@@ -1,5 +1,5 @@
usr/sbin/zed
etc/zfs/zed.d/*
usr/lib/*/zfs/zed.d/*
-usr/lib/systemd/system/zfs-zed.service lib/systemd/system/
+lib/systemd/system/zfs-zed.service
usr/share/man/man8/zed.8
diff --git a/debian/zfsutils-linux.install b/debian/zfsutils-linux.install
index 4407aa5..947ffd9 100644
--- a/debian/zfsutils-linux.install
+++ b/debian/zfsutils-linux.install
@@ -1,10 +1,10 @@
../tree/zfsutils-linux/* /
-usr/lib/systemd/system/zfs-mount.service lib/systemd/system/
-usr/lib/systemd/system/zfs-share.service lib/systemd/system/
-usr/lib/systemd/system/zfs-import-scan.service lib/systemd/system/
-usr/lib/systemd/system/zfs-import-cache.service lib/systemd/system/
-usr/lib/systemd/system/zfs.target lib/systemd/system/
-usr/lib/systemd/system-preset/ lib/systemd/
+lib/systemd/system/zfs-mount.service
+lib/systemd/system/zfs-share.service
+lib/systemd/system/zfs-import-scan.service
+lib/systemd/system/zfs-import-cache.service
+lib/systemd/system/zfs.target
+lib/systemd/system-preset/
usr/lib/modules-load.d/ lib/
lib/udev/
etc/default/zfs
--
2.11.0
More information about the Pkg-zfsonlinux-devel
mailing list