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