291 lines
9.4 KiB
Diff
291 lines
9.4 KiB
Diff
From 7dff68f6d02afb1174b13c36865d4000cf63aff7 Mon Sep 17 00:00:00 2001
|
|
From: David Teigland <teigland@redhat.com>
|
|
Date: Thu, 1 Apr 2021 12:08:58 -0500
|
|
Subject: [PATCH 08/11] add dracut files
|
|
|
|
pvscan-udev-initrd.sh is shell wrapper around the
|
|
pvscan command for use in the initrd lvm udev rule.
|
|
It finds the intersection of complete VG/LVs reported
|
|
by pvscan, and the VG/LVs specified on boot cmdline.
|
|
The resulting VG or LVs are printed as env-vars that
|
|
the udev rule can IMPORT, and pass to vgchange/lvchange.
|
|
|
|
64-lvm.rules calls pvscan-udev-initrd.sh/pvscan to scan
|
|
the PV to check if any VG or LVs are complete given the
|
|
new device. The pvscan will only ever read the single
|
|
device triggering the uevent. If any VG or LVs are
|
|
complete, the udev rule uses systemd-run to run a
|
|
vgchange or lvchange command to activate the complete
|
|
VG or LVs. (Running vgchange or lvchange directly may
|
|
take longer than udev likes, so systemd-run --no-block
|
|
is used.)
|
|
---
|
|
dracut/64-lvm.rules | 44 +++++++++++++++++
|
|
dracut/module-setup.sh | 112 +++++++++++++++++++++++++++++++++++++++++++
|
|
dracut/parse-lvm.sh | 18 +++++++
|
|
dracut/pvscan-udev-initrd.sh | 57 ++++++++++++++++++++++
|
|
4 files changed, 231 insertions(+)
|
|
create mode 100644 dracut/64-lvm.rules
|
|
create mode 100755 dracut/module-setup.sh
|
|
create mode 100755 dracut/parse-lvm.sh
|
|
create mode 100755 dracut/pvscan-udev-initrd.sh
|
|
|
|
diff --git a/dracut/64-lvm.rules b/dracut/64-lvm.rules
|
|
new file mode 100644
|
|
index 0000000..174af1d
|
|
--- /dev/null
|
|
+++ b/dracut/64-lvm.rules
|
|
@@ -0,0 +1,44 @@
|
|
+# Copyright 2008,2021 Red Hat, Inc.
|
|
+#
|
|
+# Jeremy Katz <katzj@redhat.com>
|
|
+
|
|
+SUBSYSTEM!="block", GOTO="lvm_end"
|
|
+ACTION!="add|change", GOTO="lvm_end"
|
|
+# Also don't process disks that are slated to be a multipath device
|
|
+ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="lvm_end"
|
|
+KERNEL=="dm-[0-9]*", ACTION=="add", GOTO="lvm_end"
|
|
+ENV{ID_FS_TYPE}!="LVM2_member", GOTO="lvm_end"
|
|
+
|
|
+PROGRAM=="/bin/sh -c 'for i in $sys/$devpath/holders/dm-[0-9]*; do [ -e $$i ] && exit 0; done; exit 1;' ", \
|
|
+ GOTO="lvm_end"
|
|
+
|
|
+# pvscan-udev-initrd.sh is a wrapper that calls pvscan and prints
|
|
+# LVM_VG_NAME_COMPLETE='...'
|
|
+# LVM_LV_NAMES_COMPLETE='...'
|
|
+# if the given device completes a VG or LVs listed in
|
|
+# rd.lvm.vg or rd.lvm.lv
|
|
+#
|
|
+# If a VG or LVs are completed by the device, but are not
|
|
+# listed in rd.lvm.vg/lv, then they are not printed
|
|
+# (we don't want to activate VGs/LVs that are not specified.)
|
|
+#
|
|
+# If no VG or LVs are completed by the device, then
|
|
+# nothing is printed.
|
|
+#
|
|
+# LVs may be complete and activated before the VG is complete,
|
|
+# i.e. the entire VG is not necessary to activate LVs in it.
|
|
+#
|
|
+# If multiple LV names are completed from one device,
|
|
+# e.g. LVM_LV_NAMES_COMPLETE='vg/lv1 vg/lv2 vg/lv3'
|
|
+# they will be activated by one lvchange command.
|
|
+
|
|
+IMPORT{program}="pvscan-udev-initrd.sh $env{DEVNAME}"
|
|
+
|
|
+# systemd services are used to run vgchange/lvchange
|
|
+# because the lvm activation commands can run for longer
|
|
+# than udev will tolerate.
|
|
+
|
|
+ENV{LVM_VG_NAME_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run --no-block --property DefaultDependencies=no /sbin/lvm vgchange -ay --yes --ignoremonitoring --poll n --sysinit $env{LVM_VG_NAME_COMPLETE}"
|
|
+ENV{LVM_LV_NAMES_COMPLETE}=="?*", RUN+="/usr/bin/systemd-run --no-block --property DefaultDependencies=no /sbin/lvm lvchange -ay --yes -K --ignoremonitoring --poll n --sysinit $env{LVM_LV_NAMES_COMPLETE}"
|
|
+
|
|
+LABEL="lvm_end"
|
|
diff --git a/dracut/module-setup.sh b/dracut/module-setup.sh
|
|
new file mode 100755
|
|
index 0000000..51d9cd3
|
|
--- /dev/null
|
|
+++ b/dracut/module-setup.sh
|
|
@@ -0,0 +1,112 @@
|
|
+#!/bin/bash
|
|
+
|
|
+# called by dracut
|
|
+check() {
|
|
+ # No point trying to support lvm if the binaries are missing
|
|
+ require_binaries lvm || return 1
|
|
+
|
|
+ [[ $hostonly ]] || [[ $mount_needs ]] && {
|
|
+ for fs in "${host_fs_types[@]}"; do
|
|
+ [[ $fs = LVM*_member ]] && return 0
|
|
+ done
|
|
+ return 255
|
|
+ }
|
|
+
|
|
+ return 0
|
|
+}
|
|
+
|
|
+# called by dracut
|
|
+depends() {
|
|
+ # We depend on dm_mod being loaded
|
|
+ echo rootfs-block dm
|
|
+ return 0
|
|
+}
|
|
+
|
|
+# called by dracut
|
|
+cmdline() {
|
|
+ local _activated
|
|
+ declare -A _activated
|
|
+
|
|
+ for dev in "${!host_fs_types[@]}"; do
|
|
+ [ -e /sys/block/${dev#/dev/}/dm/name ] || continue
|
|
+ [ -e /sys/block/${dev#/dev/}/dm/uuid ] || continue
|
|
+ uuid=$(</sys/block/${dev#/dev/}/dm/uuid)
|
|
+ [[ "${uuid#LVM-}" == "$uuid" ]] && continue
|
|
+ dev=$(</sys/block/${dev#/dev/}/dm/name)
|
|
+ eval $(dmsetup splitname --nameprefixes --noheadings --rows "$dev" 2>/dev/null)
|
|
+ [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || return 1
|
|
+ if ! [[ ${_activated[${DM_VG_NAME}/${DM_LV_NAME}]} ]]; then
|
|
+ printf " rd.lvm.lv=%s " "${DM_VG_NAME}/${DM_LV_NAME} "
|
|
+ _activated["${DM_VG_NAME}/${DM_LV_NAME}"]=1
|
|
+ fi
|
|
+ done
|
|
+}
|
|
+
|
|
+installkernel() {
|
|
+ hostonly='' instmods dm-snapshot
|
|
+}
|
|
+
|
|
+# called by dracut
|
|
+install() {
|
|
+ local _i
|
|
+
|
|
+ inst lvm
|
|
+
|
|
+ if [[ $hostonly_cmdline == "yes" ]]; then
|
|
+ local _lvmconf=$(cmdline)
|
|
+ [[ $_lvmconf ]] && printf "%s\n" "$_lvmconf" >> "${initdir}/etc/cmdline.d/90lvm.conf"
|
|
+ fi
|
|
+
|
|
+ inst_rules "$moddir/64-lvm.rules"
|
|
+
|
|
+ if [[ $hostonly ]] || [[ $lvmconf = "yes" ]]; then
|
|
+ if [ -f $dracutsysrootdir/etc/lvm/lvm.conf ]; then
|
|
+ inst_simple -H /etc/lvm/lvm.conf
|
|
+ fi
|
|
+
|
|
+ export LVM_SUPPRESS_FD_WARNINGS=1
|
|
+ # Also install any files needed for LVM system id support.
|
|
+ if [ -f $dracutsysrootdir/etc/lvm/lvmlocal.conf ]; then
|
|
+ inst_simple -H /etc/lvm/lvmlocal.conf
|
|
+ fi
|
|
+ eval $(lvm dumpconfig global/system_id_source &>/dev/null)
|
|
+ if [ "$system_id_source" == "file" ]; then
|
|
+ eval $(lvm dumpconfig global/system_id_file)
|
|
+ if [ -f "$system_id_file" ]; then
|
|
+ inst_simple -H $system_id_file
|
|
+ fi
|
|
+ fi
|
|
+ unset LVM_SUPPRESS_FD_WARNINGS
|
|
+ fi
|
|
+
|
|
+ inst_rules 11-dm-lvm.rules
|
|
+
|
|
+ inst_script "$moddir/pvscan-udev-initrd.sh" /usr/lib/udev/pvscan-udev-initrd.sh
|
|
+ inst_hook cmdline 30 "$moddir/parse-lvm.sh"
|
|
+
|
|
+ inst_libdir_file "libdevmapper-event-lvm*.so"
|
|
+
|
|
+ if [[ $hostonly ]] && type -P lvs &>/dev/null; then
|
|
+ for dev in "${!host_fs_types[@]}"; do
|
|
+ [ -e /sys/block/${dev#/dev/}/dm/name ] || continue
|
|
+ dev=$(</sys/block/${dev#/dev/}/dm/name)
|
|
+ eval $(dmsetup splitname --nameprefixes --noheadings --rows "$dev" 2>/dev/null)
|
|
+ [[ ${DM_VG_NAME} ]] && [[ ${DM_LV_NAME} ]] || continue
|
|
+ case "$(lvs --noheadings -o segtype ${DM_VG_NAME} 2>/dev/null)" in
|
|
+ *thin*|*cache*|*era*)
|
|
+ inst_multiple -o thin_dump thin_restore thin_check thin_repair \
|
|
+ cache_dump cache_restore cache_check cache_repair \
|
|
+ era_check era_dump era_invalidate era_restore
|
|
+ break;;
|
|
+ esac
|
|
+ done
|
|
+ fi
|
|
+
|
|
+ if ! [[ $hostonly ]]; then
|
|
+ inst_multiple -o thin_dump thin_restore thin_check thin_repair \
|
|
+ cache_dump cache_restore cache_check cache_repair \
|
|
+ era_check era_dump era_invalidate era_restore
|
|
+ fi
|
|
+
|
|
+ dracut_need_initqueue
|
|
+}
|
|
diff --git a/dracut/parse-lvm.sh b/dracut/parse-lvm.sh
|
|
new file mode 100755
|
|
index 0000000..8236050
|
|
--- /dev/null
|
|
+++ b/dracut/parse-lvm.sh
|
|
@@ -0,0 +1,18 @@
|
|
+#!/bin/sh
|
|
+
|
|
+if [ -e /etc/lvm/lvm.conf ] && ! getargbool 1 rd.lvm.conf -d -n rd_NO_LVMCONF; then
|
|
+ rm -f -- /etc/lvm/lvm.conf
|
|
+fi
|
|
+
|
|
+LV_DEVS="$(getargs rd.lvm.vg -d rd_LVM_VG=) $(getargs rd.lvm.lv -d rd_LVM_LV=)"
|
|
+
|
|
+if ! getargbool 1 rd.lvm -d -n rd_NO_LVM \
|
|
+ || ( [ -z "$LV_DEVS" ] && ! getargbool 0 rd.auto ); then
|
|
+ info "rd.lvm=0: removing LVM activation"
|
|
+ rm -f -- /etc/udev/rules.d/64-lvm*.rules
|
|
+else
|
|
+ for dev in $LV_DEVS; do
|
|
+ wait_for_dev -n "/dev/$dev"
|
|
+ done
|
|
+fi
|
|
+
|
|
diff --git a/dracut/pvscan-udev-initrd.sh b/dracut/pvscan-udev-initrd.sh
|
|
new file mode 100755
|
|
index 0000000..1743771
|
|
--- /dev/null
|
|
+++ b/dracut/pvscan-udev-initrd.sh
|
|
@@ -0,0 +1,57 @@
|
|
+#!/bin/sh
|
|
+
|
|
+# pvscan wrapper called by initrd lvm udev rule to find the
|
|
+# intersection of complete VGs/LVs found by pvscan and the
|
|
+# requested VGs/LVs from the cmdline.
|
|
+#
|
|
+# Used in 64-lvm.rules as:
|
|
+# IMPORT{program}="pvscan-udev-initrd.sh $env{DEVNAME}"
|
|
+#
|
|
+# See /usr/lib/dracut/modules.d/90lvm/64-lvm.rules
|
|
+
|
|
+dev=$1
|
|
+
|
|
+type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh
|
|
+
|
|
+
|
|
+VGS=$(getargs rd.lvm.vg -d rd_LVM_VG=)
|
|
+LVS=$(getargs rd.lvm.lv -d rd_LVM_LV=)
|
|
+
|
|
+IFS=' '
|
|
+
|
|
+# pvscan will produce a single VG line, and one or more LV lines.
|
|
+# VG <name> complete
|
|
+# VG <name> incomplete
|
|
+# LV <name> complete
|
|
+# LV <name> incomplete
|
|
+#
|
|
+# LV names are printed as vgname/lvname.
|
|
+# We only care about the complete items.
|
|
+# Each pvscan will produce a single VG line,
|
|
+# and may produce zero, one or more LV lines.
|
|
+
|
|
+PVSCAN=$(/sbin/lvm pvscan --cache --listlvs --checkcomplete --journal output --config 'global/event_activation=1' $dev)
|
|
+
|
|
+read -r -a VGSARRAY <<< "$VGS"
|
|
+
|
|
+for VG in "${VGSARRAY[@]}"
|
|
+do
|
|
+ if strstr "$PVSCAN" "VG $VG complete" ; then
|
|
+ echo LVM_VG_NAME_COMPLETE=\'"$VG"\'
|
|
+ fi
|
|
+done
|
|
+
|
|
+# Combine all matching LVs into a single print containing them all,
|
|
+# e.g. LVM_LV_NAMES_COMPLETE='vg/lv1 vg/lv2'
|
|
+
|
|
+read -r -a LVSARRAY <<< "$LVS"
|
|
+
|
|
+echo -n LVM_LV_NAMES_COMPLETE=\'
|
|
+for LV in "${LVSARRAY[@]}"
|
|
+do
|
|
+ if strstr "$PVSCAN" "LV $LV complete" ; then
|
|
+ echo -n "$LV "
|
|
+ fi
|
|
+done
|
|
+echo \'
|
|
+
|
|
--
|
|
1.8.3.1
|
|
|