diff options
Diffstat (limited to 'modules.d/90lvm')
-rw-r--r-- | modules.d/90lvm/64-lvm.rules | 29 | ||||
-rwxr-xr-x | modules.d/90lvm/lvm_scan.sh | 176 | ||||
-rwxr-xr-x | modules.d/90lvm/module-setup.sh | 117 | ||||
-rwxr-xr-x | modules.d/90lvm/parse-lvm.sh | 17 |
4 files changed, 339 insertions, 0 deletions
diff --git a/modules.d/90lvm/64-lvm.rules b/modules.d/90lvm/64-lvm.rules new file mode 100644 index 0000000..1ad4911 --- /dev/null +++ b/modules.d/90lvm/64-lvm.rules @@ -0,0 +1,29 @@ +# hacky rules to try to activate lvm when we get new block devs... +# +# Copyright 2008, Red Hat, Inc. +# Jeremy Katz <katzj@redhat.com> + + +SUBSYSTEM!="block", GOTO="lvm_end" +ACTION!="add|change", GOTO="lvm_end" + +# If the md device is active (indicated by array_state), then set the flag +# LVM_MD_PV_ACTIVATED=1 indicating that the md device for the PV is ready +# to be used. The lvm udev rule running in root will check that this flag +# is set before it will process the md device (it wants to avoid +# processing an md device that exists but is not yet ready to be used.) +KERNEL=="md[0-9]*", ACTION=="change", ENV{ID_FS_TYPE}=="LVM2_member", ENV{LVM_MD_PV_ACTIVATED}!="1", TEST=="md/array_state", ENV{LVM_MD_PV_ACTIVATED}="1" + +# 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}!="LVM?_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" + +RUN+="/sbin/initqueue --settled --onetime --unique /sbin/lvm_scan" +RUN+="/sbin/initqueue --timeout --name 51-lvm_scan --onetime --unique /sbin/lvm_scan --activationmode degraded" +RUN+="/bin/sh -c '>/tmp/.lvm_scan-%k;'" + +LABEL="lvm_end" diff --git a/modules.d/90lvm/lvm_scan.sh b/modules.d/90lvm/lvm_scan.sh new file mode 100755 index 0000000..980e449 --- /dev/null +++ b/modules.d/90lvm/lvm_scan.sh @@ -0,0 +1,176 @@ +#!/bin/sh + +# run lvm scan if udev has settled + +extraargs="$*" +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=) + +# shellcheck disable=SC2174 +[ -d /etc/lvm ] || mkdir -m 0755 -p /etc/lvm +[ -d /run/lvm ] || mkdir -m 0755 -p /run/lvm +# build a list of devices to scan +lvmdevs=$( + for f in /tmp/.lvm_scan-*; do + [ -e "$f" ] || continue + printf '%s' "${f##/tmp/.lvm_scan-} " + done +) + +check_lvm_ver() { + maj=$1 + min=$2 + ver=$3 + # --poll is supported since 2.2.57 + [ "$4" -lt "$maj" ] && return 1 + [ "$4" -gt "$maj" ] && return 0 + [ "$5" -lt "$min" ] && return 1 + [ "$5" -gt "$min" ] && return 0 + [ "$6" -ge "$ver" ] && return 0 + return 1 +} + +no_lvm_conf_filter() { + if [ ! -e /etc/lvm/lvm.conf ]; then + return 0 + fi + + if [ -e /run/lvm/initrd_no_filter ]; then + return 0 + fi + + if [ -e /run/lvm/initrd_filter ]; then + return 1 + fi + + if [ -e /run/lvm/initrd_global_filter ]; then + return 1 + fi + + # Save lvm config results in /run to avoid running + # lvm config commands for every PV that's scanned. + + filter=$(lvm config devices/filter 2> /dev/null | grep "$filter=") + if [ -n "$filter" ]; then + printf '%s\n' "$filter" > /run/lvm/initrd_filter + return 1 + fi + + global_filter=$(lvm config devices/global_filter 2> /dev/null | grep "$global_filter=") + if [ -n "$global_filter" ]; then + printf '%s\n' "$global_filter" > /run/lvm/initrd_global_filter + return 1 + fi + + # /etc/lvm/lvm.conf exists with no filter setting + true > /run/lvm/initrd_no_filter + return 0 +} + +# If no lvm.conf exists, create a basic one with a global section. +if [ ! -e /etc/lvm/lvm.conf ]; then + { + echo 'global {' + echo '}' + } > /etc/lvm/lvm.conf + lvmwritten=1 +fi + +# Save the original lvm.conf before appending a filter setting. +if [ ! -e /etc/lvm/lvm.conf.orig ]; then + cp /etc/lvm/lvm.conf /etc/lvm/lvm.conf.orig +fi + +# If the original lvm.conf does not contain a filter setting, +# then generate a filter and append it to the original lvm.conf. +# The filter is generated from the list PVs that have been seen +# so far (each has been processed by the lvm udev rule.) +if no_lvm_conf_filter; then + { + echo 'devices {' + printf ' filter = [ ' + for dev in $lvmdevs; do + printf '"a|^/dev/%s$|", ' "$dev" + done + echo '"r/.*/" ]' + echo '}' + } > /etc/lvm/lvm.conf.filter + lvmfilter=1 + cat /etc/lvm/lvm.conf.orig /etc/lvm/lvm.conf.filter > /etc/lvm/lvm.conf +fi + +# hopefully this output format will never change, e.g.: +# LVM version: 2.02.53(1) (2009-09-25) +OLDIFS=$IFS +IFS=. +# shellcheck disable=SC2046 +set -- $(lvm version 2> /dev/null) +IFS=$OLDIFS +maj=${1##*:} +min=$2 +sub=${3%% *} +sub=${sub%%\(*} + +# For lvchange and vgchange use --sysinit which: +# disables polling (--poll n) +# ignores monitoring (--ignoremonitoring) +# ignores locking failures (--ignorelockingfailure) +# disables hints (--nohints) +# +# For lvs and vgscan: +# disable locking (--nolocking) +# disable hints (--nohints) + +activate_args="--sysinit $extraargs" +unset extraargs + +export LVM_SUPPRESS_LOCKING_FAILURE_MESSAGES=1 + +scan_args="--nolocking" + +check_lvm_ver 2 3 14 "$maj" "$min" "$sub" \ + && scan_args="$scan_args --nohints" + +if [ -n "$LVS" ]; then + info "Scanning devices $lvmdevs for LVM logical volumes $LVS" + # shellcheck disable=SC2086 + LVSLIST=$(lvm lvs $scan_args --noheading -o lv_full_name,segtype $LVS) + info "$LVSLIST" + + # Only attempt to activate an LV if it appears in the lvs output. + for LV in $LVS; do + if strstr "$LVSLIST" "$LV"; then + # This lvchange is expected to fail if all PVs used by + # the LV are not yet present. Premature/failed lvchange + # could be avoided by reporting if an LV is complete + # from the lvs command above and skipping this lvchange + # if the LV is not lised as complete. + # shellcheck disable=SC2086 + lvm lvchange --yes -K -ay $activate_args "$LV" 2>&1 | vinfo + fi + done +fi + +if [ -z "$LVS" ] || [ -n "$VGS" ]; then + info "Scanning devices $lvmdevs for LVM volume groups $VGS" + # shellcheck disable=SC2086 + lvm vgscan $scan_args 2>&1 | vinfo + # shellcheck disable=SC2086 + lvm vgchange -ay $activate_args $VGS 2>&1 | vinfo +fi + +if [ "$lvmwritten" ]; then + rm -f -- /etc/lvm/lvm.conf +elif [ "$lvmfilter" ]; then + # revert filter that was appended to existing lvm.conf + cp /etc/lvm/lvm.conf.orig /etc/lvm/lvm.conf + rm -f -- /etc/lvm/lvm.conf.filter +fi +unset lvmwritten +unset lvmfilter + +udevadm settle + +need_shutdown diff --git a/modules.d/90lvm/module-setup.sh b/modules.d/90lvm/module-setup.sh new file mode 100755 index 0000000..7ba4c69 --- /dev/null +++ b/modules.d/90lvm/module-setup.sh @@ -0,0 +1,117 @@ +#!/bin/bash + +# called by dracut +check() { + # No point trying to support lvm if the binaries are missing + require_binaries lvm grep || 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='' dracut_instmods -o -P ".*/(bcache/|md-cluster).*" "=drivers/md" +} + +# called by dracut +install() { + inst_multiple lvm grep + + if [[ $hostonly_cmdline == "yes" ]]; then + local _lvmconf + _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 + + # Gentoo ebuild for LVM2 prior to 2.02.63-r1 doesn't install above rules + # files, but provides the one below: + inst_rules 64-device-mapper.rules + # debian udev rules + inst_rules 56-lvm.rules 60-persistent-storage-lvm.rules + + inst_script "$moddir/lvm_scan.sh" /sbin/lvm_scan + inst_hook cmdline 30 "$moddir/parse-lvm.sh" + + if [[ $hostonly ]] && find_binary 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)" + # shellcheck disable=SC2015 + [[ ${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/modules.d/90lvm/parse-lvm.sh b/modules.d/90lvm/parse-lvm.sh new file mode 100755 index 0000000..d774882 --- /dev/null +++ b/modules.d/90lvm/parse-lvm.sh @@ -0,0 +1,17 @@ +#!/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 |