diff options
Diffstat (limited to 'modules.d/90mdraid')
-rw-r--r-- | modules.d/90mdraid/59-persistent-storage-md.rules | 24 | ||||
-rw-r--r-- | modules.d/90mdraid/65-md-incremental-imsm.rules | 44 | ||||
-rwxr-xr-x | modules.d/90mdraid/md-shutdown.sh | 23 | ||||
-rwxr-xr-x | modules.d/90mdraid/mdmon-pre-shutdown.sh | 13 | ||||
-rwxr-xr-x | modules.d/90mdraid/mdmon-pre-udev.sh | 4 | ||||
-rwxr-xr-x | modules.d/90mdraid/mdraid-cleanup.sh | 21 | ||||
-rwxr-xr-x | modules.d/90mdraid/mdraid-needshutdown.sh | 9 | ||||
-rwxr-xr-x | modules.d/90mdraid/mdraid-waitclean.sh | 24 | ||||
-rwxr-xr-x | modules.d/90mdraid/mdraid_start.sh | 70 | ||||
-rwxr-xr-x | modules.d/90mdraid/module-setup.sh | 139 | ||||
-rwxr-xr-x | modules.d/90mdraid/parse-md.sh | 64 |
11 files changed, 435 insertions, 0 deletions
diff --git a/modules.d/90mdraid/59-persistent-storage-md.rules b/modules.d/90mdraid/59-persistent-storage-md.rules new file mode 100644 index 0000000..0d745cc --- /dev/null +++ b/modules.d/90mdraid/59-persistent-storage-md.rules @@ -0,0 +1,24 @@ +SUBSYSTEM!="block", GOTO="md_end" +ACTION!="add|change", GOTO="md_end" +# Also don't process disks that are slated to be a multipath device +ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="md_end" + +KERNEL!="md[0-9]*|md_d[0-9]*|md/*", KERNEL!="md*", GOTO="md_end" + +# partitions have no md/{array_state,metadata_version} +ENV{DEVTYPE}=="partition", GOTO="md_ignore_state" + +# container devices have a metadata version of e.g. 'external:ddf' and +# never leave state 'inactive' +ATTR{md/metadata_version}=="external:[A-Za-z]*", ATTR{md/array_state}=="inactive", GOTO="md_ignore_state" +TEST!="md/array_state", GOTO="md_end" +ATTR{md/array_state}=="|clear|inactive", GOTO="md_end" + +LABEL="md_ignore_state" + +IMPORT{program}="/sbin/mdadm --detail --export $tempnode" +IMPORT{builtin}="blkid" +OPTIONS+="link_priority=100" +OPTIONS+="watch" +OPTIONS+="db_persist" +LABEL="md_end" diff --git a/modules.d/90mdraid/65-md-incremental-imsm.rules b/modules.d/90mdraid/65-md-incremental-imsm.rules new file mode 100644 index 0000000..6697f15 --- /dev/null +++ b/modules.d/90mdraid/65-md-incremental-imsm.rules @@ -0,0 +1,44 @@ +# This file causes block devices with Linux RAID (mdadm) signatures to +# automatically cause mdadm to be run. +# See udev(8) for syntax + +ACTION!="add|change", GOTO="md_end" +SUBSYSTEM!="block", GOTO="md_end" +ENV{rd_NO_MD}=="?*", GOTO="md_end" +KERNEL=="md*", ENV{ID_FS_TYPE}!="linux_raid_member", GOTO="md_end" +KERNEL=="md*", ACTION!="change", GOTO="md_end" + +# Also don't process disks that are slated to be a multipath device +ENV{DM_MULTIPATH_DEVICE_PATH}=="1", GOTO="md_end" + +ENV{ID_FS_TYPE}=="ddf_raid_member|isw_raid_member|linux_raid_member", GOTO="md_try" +GOTO="md_end" + +LABEL="md_try" +ENV{ID_FS_TYPE}=="isw_raid_member", ENV{rd_NO_MDIMSM}=="?*", GOTO="md_end" +ENV{ID_FS_TYPE}=="ddf_raid_member", ENV{rd_NO_MDDDF}=="?*", GOTO="md_end" + +# already done ? +PROGRAM="/bin/sh -c 'for i in $sys/$devpath/holders/md[0-9_]*; do [ -e $$i ] && exit 0; done; exit 1;' ", \ + GOTO="md_end" + +# for native arrays - array's uuid has to be specified +# for containers - container's uuid has to be specified +# TODO : how to get embedded array's uuid having container's component ? +# +# UUID CHECK + +ENV{DEVTYPE}!="partition", \ + RUN+="/sbin/partx -d --nr 1-1024 $env{DEVNAME}" + +RUN+="/sbin/initqueue --timeout --name 50-mdraid_start --onetime --unique /sbin/mdraid_start" + +# +# Incrementally build the md array; this will automatically assemble +# any eventual containers as well (imsm, ddf) +# +LABEL="md_incremental" + +RUN+="/sbin/mdadm -I $env{DEVNAME}" + +LABEL="md_end" diff --git a/modules.d/90mdraid/md-shutdown.sh b/modules.d/90mdraid/md-shutdown.sh new file mode 100755 index 0000000..ca768a9 --- /dev/null +++ b/modules.d/90mdraid/md-shutdown.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +_do_md_shutdown() { + local ret + local final="$1" + info "Waiting for mdraid devices to be clean." + mdadm -vv --wait-clean --scan | vinfo + ret=$? + info "Disassembling mdraid devices." + mdadm -vv --stop --scan | vinfo + ret=$((ret + $?)) + if [ "x$final" != "x" ]; then + info "/proc/mdstat:" + vinfo < /proc/mdstat + fi + return $ret +} + +if command -v mdadm > /dev/null; then + _do_md_shutdown "$1" +else + : +fi diff --git a/modules.d/90mdraid/mdmon-pre-shutdown.sh b/modules.d/90mdraid/mdmon-pre-shutdown.sh new file mode 100755 index 0000000..a5cd850 --- /dev/null +++ b/modules.d/90mdraid/mdmon-pre-shutdown.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +_do_mdmon_takeover() { + local ret + mdmon --takeover --all + ret=$? + [ $ret -eq 0 ] && info "Taking over mdmon processes." + return $ret +} + +if command -v mdmon > /dev/null; then + _do_mdmon_takeover "$1" +fi diff --git a/modules.d/90mdraid/mdmon-pre-udev.sh b/modules.d/90mdraid/mdmon-pre-udev.sh new file mode 100755 index 0000000..b15cca8 --- /dev/null +++ b/modules.d/90mdraid/mdmon-pre-udev.sh @@ -0,0 +1,4 @@ +#!/bin/sh +# save state dir for mdmon/mdadm for the real root +[ -d /run/mdadm ] || mkdir -m 0755 -p /run/mdadm +# backward compat link diff --git a/modules.d/90mdraid/mdraid-cleanup.sh b/modules.d/90mdraid/mdraid-cleanup.sh new file mode 100755 index 0000000..ce50733 --- /dev/null +++ b/modules.d/90mdraid/mdraid-cleanup.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh + +containers="" +for md in /dev/md[0-9_]*; do + [ -b "$md" ] || continue + udevinfo="$(udevadm info --query=property --name="$md")" + strstr "$udevinfo" "DEVTYPE=partition" && continue + if strstr "$udevinfo" "MD_LEVEL=container"; then + containers="$containers $md" + continue + fi + mdadm -S "$md" > /dev/null 2>&1 +done + +for md in $containers; do + mdadm -S "$md" > /dev/null 2>&1 +done + +unset containers udevinfo diff --git a/modules.d/90mdraid/mdraid-needshutdown.sh b/modules.d/90mdraid/mdraid-needshutdown.sh new file mode 100755 index 0000000..f248c4b --- /dev/null +++ b/modules.d/90mdraid/mdraid-needshutdown.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh + +for md in /dev/md[0-9_]*; do + [ -b "$md" ] || continue + need_shutdown + break +done diff --git a/modules.d/90mdraid/mdraid-waitclean.sh b/modules.d/90mdraid/mdraid-waitclean.sh new file mode 100755 index 0000000..9317962 --- /dev/null +++ b/modules.d/90mdraid/mdraid-waitclean.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +if getargbool 0 rd.md.waitclean; then + type getarg > /dev/null 2>&1 || . /lib/dracut-lib.sh + containers="" + for md in /dev/md[0-9_]*; do + [ -b "$md" ] || continue + udevinfo="$(udevadm info --query=property --name="$md")" + strstr "$udevinfo" "DEVTYPE=partition" && continue + if strstr "$udevinfo" "MD_LEVEL=container"; then + containers="$containers $md" + continue + fi + info "Waiting for $md to become clean" + mdadm -W "$md" > /dev/null 2>&1 + done + + for md in $containers; do + info "Waiting for $md to become clean" + mdadm -W "$md" > /dev/null 2>&1 + done + + unset containers udevinfo +fi diff --git a/modules.d/90mdraid/mdraid_start.sh b/modules.d/90mdraid/mdraid_start.sh new file mode 100755 index 0000000..d8c5de2 --- /dev/null +++ b/modules.d/90mdraid/mdraid_start.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +type getargs > /dev/null 2>&1 || . /lib/dracut-lib.sh + +_md_start() { + local _udevinfo + local _path_s + local _path_d + local _md="$1" + + _udevinfo="$(udevadm info --query=property --name="${_md}")" + strstr "$_udevinfo" "MD_LEVEL=container" && return 0 + strstr "$_udevinfo" "DEVTYPE=partition" && return 0 + + _path_s="/sys/$(udevadm info -q path -n "${_md}")/md/array_state" + [ ! -r "$_path_s" ] && return 0 + + # inactive ? + [ "$(cat "$_path_s")" != "inactive" ] && return 0 + + mdadm -R "${_md}" 2>&1 | vinfo + + # still inactive ? + [ "$(cat "$_path_s")" = "inactive" ] && return 0 + + _path_d="${_path_s%/*}/degraded" + [ ! -r "$_path_d" ] && return 0 + : > "$hookdir"/initqueue/work +} + +_md_force_run() { + local _md + local _UUID + local _MD_UUID + + _MD_UUID=$(getargs rd.md.uuid -d rd_MD_UUID=) + [ -n "$_MD_UUID" ] || getargbool 0 rd.auto || return + + if [ -n "$_MD_UUID" ]; then + _MD_UUID=$(str_replace "$_MD_UUID" "-" "") + _MD_UUID=$(str_replace "$_MD_UUID" ":" "") + + for _md in /dev/md[0-9_]*; do + [ -b "$_md" ] || continue + _UUID=$( + /sbin/mdadm -D --export "$_md" \ + | while read -r line || [ -n "$line" ]; do + str_starts "$line" "MD_UUID=" || continue + printf "%s" "${line#MD_UUID=}" + done + ) + + [ -z "$_UUID" ] && continue + _UUID=$(str_replace "$_UUID" ":" "") + + # check if we should handle this device + strstr "$_MD_UUID" "$_UUID" || continue + + _md_start "${_md}" + done + else + # try to force-run anything not running yet + for _md in /dev/md[0-9_]*; do + [ -b "$_md" ] || continue + _md_start "${_md}" + done + fi +} + +_md_force_run diff --git a/modules.d/90mdraid/module-setup.sh b/modules.d/90mdraid/module-setup.sh new file mode 100755 index 0000000..6179a98 --- /dev/null +++ b/modules.d/90mdraid/module-setup.sh @@ -0,0 +1,139 @@ +#!/bin/bash + +# called by dracut +check() { + local dev holder + + # No mdadm? No mdraid support. + require_binaries mdadm expr || return 1 + + [[ $hostonly ]] || [[ $mount_needs ]] && { + for dev in "${!host_fs_types[@]}"; do + [[ ${host_fs_types[$dev]} != *_raid_member ]] && continue + + DEVPATH=$(get_devpath_block "$dev") + + for holder in "$DEVPATH"/holders/*; do + [[ -e $holder ]] || continue + [[ -e "$holder/md" ]] && return 0 + break + done + + done + return 255 + } + + return 0 +} + +# called by dracut +depends() { + echo rootfs-block + return 0 +} + +# called by dracut +installkernel() { + instmods '=drivers/md' +} + +# called by dracut +cmdline() { + local _activated dev line UUID + declare -A _activated + + for dev in "${!host_fs_types[@]}"; do + [[ ${host_fs_types[$dev]} != *_raid_member ]] && continue + + UUID=$( + /sbin/mdadm --examine --export "$dev" \ + | while read -r line || [[ "$line" ]]; do + [[ ${line#MD_UUID=} == "$line" ]] && continue + printf "%s" "${line#MD_UUID=} " + done + ) + + [[ -z $UUID ]] && continue + + if ! [[ ${_activated[${UUID}]} ]]; then + printf "%s" " rd.md.uuid=${UUID}" + _activated["${UUID}"]=1 + fi + + done +} + +# called by dracut +install() { + local rule rule_path + inst_multiple cat expr + inst_multiple -o mdmon + inst "$(command -v partx)" /sbin/partx + inst "$(command -v mdadm)" /sbin/mdadm + + if [[ $hostonly_cmdline == "yes" ]]; then + local _raidconf + _raidconf=$(cmdline) + [[ $_raidconf ]] && printf "%s\n" "$_raidconf" >> "${initdir}/etc/cmdline.d/90mdraid.conf" + fi + + # <mdadm-3.3 udev rule + inst_rules 64-md-raid.rules + # >=mdadm-3.3 udev rules + inst_rules 63-md-raid-arrays.rules 64-md-raid-assembly.rules + # remove incremental assembly from stock rules, so they don't shadow + # 65-md-inc*.rules and its fine-grained controls, or cause other problems + # when we explicitly don't want certain components to be incrementally + # assembled + for rule in 64-md-raid.rules 64-md-raid-assembly.rules; do + rule_path="${initdir}${udevdir}/rules.d/${rule}" + # shellcheck disable=SC2016 + [ -f "${rule_path}" ] && sed -i -r \ + -e '/(RUN|IMPORT\{program\})\+?="[[:alpha:]/]*mdadm[[:blank:]]+(--incremental|-I)[[:blank:]]+(--export )?(\$env\{DEVNAME\}|\$tempnode|\$devnode)/d' \ + "${rule_path}" + done + + inst_rules "$moddir/65-md-incremental-imsm.rules" + + inst_rules "$moddir/59-persistent-storage-md.rules" + + if [[ $hostonly ]] || [[ $mdadmconf == "yes" ]]; then + if [[ -f $dracutsysrootdir/etc/mdadm.conf ]]; then + inst -H /etc/mdadm.conf + else + [[ -f $dracutsysrootdir/etc/mdadm/mdadm.conf ]] && inst -H /etc/mdadm/mdadm.conf /etc/mdadm.conf + fi + if [[ -d $dracutsysrootdir/etc/mdadm.conf.d ]]; then + local f + inst_dir /etc/mdadm.conf.d + for f in /etc/mdadm.conf.d/*.conf; do + [[ -f "$dracutsysrootdir$f" ]] || continue + inst -H "$f" + done + fi + fi + + inst_hook pre-udev 30 "$moddir/mdmon-pre-udev.sh" + inst_hook pre-trigger 30 "$moddir/parse-md.sh" + inst_hook pre-mount 10 "$moddir/mdraid-waitclean.sh" + inst_hook cleanup 99 "$moddir/mdraid-needshutdown.sh" + inst_hook shutdown 30 "$moddir/md-shutdown.sh" + inst_script "$moddir/mdraid-cleanup.sh" /sbin/mdraid-cleanup + inst_script "$moddir/mdraid_start.sh" /sbin/mdraid_start + if dracut_module_included "systemd"; then + if [[ -e $dracutsysrootdir$systemdsystemunitdir/mdmon@.service ]]; then + inst_simple "$systemdsystemunitdir"/mdmon@.service + fi + if [[ -e $dracutsysrootdir$systemdsystemunitdir/mdadm-last-resort@.service ]]; then + inst_simple "$systemdsystemunitdir"/mdadm-last-resort@.service + fi + if [[ -e $dracutsysrootdir$systemdsystemunitdir/mdadm-last-resort@.timer ]]; then + inst_simple "$systemdsystemunitdir"/mdadm-last-resort@.timer + fi + if [[ -e $dracutsysrootdir$systemdsystemunitdir/mdadm-grow-continue@.service ]]; then + inst_simple "$systemdsystemunitdir"/mdadm-grow-continue@.service + fi + fi + inst_hook pre-shutdown 30 "$moddir/mdmon-pre-shutdown.sh" + dracut_need_initqueue +} diff --git a/modules.d/90mdraid/parse-md.sh b/modules.d/90mdraid/parse-md.sh new file mode 100755 index 0000000..4d3a6b2 --- /dev/null +++ b/modules.d/90mdraid/parse-md.sh @@ -0,0 +1,64 @@ +#!/bin/sh +# we really need to use `expr substr` with dash +# shellcheck disable=SC2003 disable=SC2308 + +MD_UUID=$(getargs rd.md.uuid -d rd_MD_UUID=) +# normalize the uuid +MD_UUID=$(str_replace "$MD_UUID" "-" "") +MD_UUID=$(str_replace "$MD_UUID" ":" "") + +if { [ -z "$MD_UUID" ] && ! getargbool 0 rd.auto; } || ! getargbool 1 rd.md -d -n rd_NO_MD; then + info "rd.md=0: removing MD RAID activation" + udevproperty rd_NO_MD=1 +else + # rewrite the md rules to only process the specified raid array + if [ -n "$MD_UUID" ]; then + for f in /etc/udev/rules.d/65-md-incremental*.rules; do + [ -e "$f" ] || continue + while read -r line || [ -n "$line" ]; do + if [ "${line%%UUID CHECK}" != "$line" ]; then + for uuid in $MD_UUID; do + printf 'ENV{ID_FS_UUID}=="%s", GOTO="md_uuid_ok"\n' "$(expr substr "$uuid" 1 8)-$(expr substr "$uuid" 9 4)-$(expr substr "$uuid" 13 4)-$(expr substr "$uuid" 17 4)-$(expr substr "$uuid" 21 12)" + done + # shellcheck disable=SC2016 + printf 'IMPORT{program}="/sbin/mdadm --examine --export $tempnode"\n' + for uuid in $MD_UUID; do + printf 'ENV{MD_UUID}=="%s", GOTO="md_uuid_ok"\n' "$(expr substr "$uuid" 1 8):$(expr substr "$uuid" 9 8):$(expr substr "$uuid" 17 8):$(expr substr "$uuid" 25 8)" + done + printf 'GOTO="md_end"\n' + printf 'LABEL="md_uuid_ok"\n' + else + echo "$line" + fi + done < "${f}" > "${f}.new" + mv "${f}.new" "$f" + done + for uuid in $MD_UUID; do + uuid="$(expr substr "$uuid" 1 8):$(expr substr "$uuid" 9 8):$(expr substr "$uuid" 17 8):$(expr substr "$uuid" 25 8)" + wait_for_dev "/dev/disk/by-id/md-uuid-${uuid}" + done + fi +fi + +if [ -e /etc/mdadm.conf ] && getargbool 1 rd.md.conf -d -n rd_NO_MDADMCONF; then + udevproperty rd_MDADMCONF=1 + rm -f -- "$hookdir"/pre-pivot/*mdraid-cleanup.sh +fi + +if ! getargbool 1 rd.md.conf -d -n rd_NO_MDADMCONF; then + rm -f -- /etc/mdadm/mdadm.conf /etc/mdadm.conf + ln -s "$(command -v mdraid-cleanup)" "$hookdir"/pre-pivot/31-mdraid-cleanup.sh 2> /dev/null +fi + +# noiswmd nodmraid for anaconda / rc.sysinit compatibility +# note nodmraid really means nobiosraid, so we don't want MDIMSM then either +if ! getargbool 1 rd.md.imsm -d -n rd_NO_MDIMSM -n noiswmd -n nodmraid; then + info "no MD RAID for imsm/isw raids" + udevproperty rd_NO_MDIMSM=1 +fi + +# same thing with ddf containers +if ! getargbool 1 rd.md.ddf -n rd_NO_MDDDF -n noddfmd -n nodmraid; then + info "no MD RAID for SNIA ddf raids" + udevproperty rd_NO_MDDDF=1 +fi |