[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