Bug#678696: Event based block device handling (fixes USB and nested devices problem)
Package: initramfs-tools
Version: 0.106
Severity: wishlist
Tags: patch
Hi,
the attached patch adds an event based loop for block devices to the
init script. New blockdevices are recorded in
/run/initramfs/block-events by an udev rule as they appear. The init
script repeadately waits for that and then calls
/scripts/local-block/* with a list of new devices storedin NEWDEVS
until $ROOT and $resume (if set) exists or a timeout is reached.
This fixes the problem that USB devices take too long to be
discovered and crypto, raid, lvm or multipath can't be started on
them. It also adds support for arbitrary nestings of them, e.g. raid5
over raid1.
For the event loop I needed the $resume device translated to the
device node earlier. This was previously done in
scripts/local-premount/resume. It was essentially the same code used
to translate the $ROOT so I created a new function translate_device()
in script/functions and used that for both $ROOT and $resume.
Note: hooks/block-event and scripts/block-event are executable, not
represented in the patch.
MfG
Goswin
-- System Information:
Debian Release: wheezy/sid
APT prefers unstable
APT policy: (500, 'unstable')
Architecture: amd64 (x86_64)
Kernel: Linux 3.2.0-2-amd64 (SMP w/4 CPU cores)
Locale: LANG=C, LC_CTYPE=de_DE (charmap=ISO-8859-1)
Shell: /bin/sh linked to /bin/dash
Versions of packages initramfs-tools depends on:
ii cpio 2.11-7
ii klibc-utils 2.0~rc3-1
ii module-init-tools 3.16-1
ii udev 175-3.1
Versions of packages initramfs-tools recommends:
ii busybox 1:1.19.3-5
Versions of packages initramfs-tools suggests:
ii bash-completion 1:1.99-3
-- no debconf information
Description: event based loop
This patch adds an event based loop for block devices to the init
script. New blockdevices are recorded in /run/initramfs/block-events
by an udev rule as they appear. The init script repeadately waits for
that and then calls /scripts/local-block/* with a list of new devices
storedin NEWDEVS until $ROOT and $resume (if set) exists or a timeout
is reached.
.
This fixes the problem that USB devices take too long to be
discovered and crypto, raid, lvm or multipath can't be started on
them. It also adds support for arbitrary nestings of them, e.g. raid5
over raid1.
.
For the event loop I needed the $resume device translated to the
device node earlier. This was previously done in
scripts/local-premount/resume. It was essentially the same code used
to translate the $ROOT so I created a new function translate_device()
in script/functions and used that for both $ROOT and $resume.
.
Note: hooks/block-event and scripts/block-event are executable, not
represented in the patch.
Author: Goswin von Brederlow
Last-Update: 2012-06-23
--
diff -Nru initramfs-tools-0.106/hooks/block-event initramfs-tools-0.106a0mrvn1/hooks/block-event
--- initramfs-tools-0.106/hooks/block-event 1970-01-01 01:00:00.000000000 +0100
+++ initramfs-tools-0.106a0mrvn1/hooks/block-event 2012-06-23 18:52:54.000000000 +0200
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+mkdir -p $DESTDIR/etc/udev/rules.d
+
+cat > $DESTDIR/etc/udev/rules.d/99-block-event.rules << EOF
+# we are only interested in add and change actions for block devices
+ACTION=="remove", GOTO="block_event_end"
+SUBSYSTEM!="block", GOTO="block_event_end"
+
+RUN+="/scripts/block-event $name"
+
+LABEL="block_event_end"
+EOF
diff -Nru initramfs-tools-0.106/init initramfs-tools-0.106a0mrvn1/init
--- initramfs-tools-0.106/init 2012-06-06 15:04:52.000000000 +0200
+++ initramfs-tools-0.106a0mrvn1/init 2012-06-23 21:14:40.000000000 +0200
@@ -69,41 +69,10 @@
init=${x#init=}
;;
root=*)
- ROOT=${x#root=}
- case $ROOT in
- LABEL=*)
- ROOT="${ROOT#LABEL=}"
-
- # support any / in LABEL= path (escape to \x2f)
- case "${ROOT}" in
- */*)
- if command -v sed >/dev/null 2>&1; then
- ROOT="$(echo ${ROOT} | sed 's,/,\\x2f,g')"
- else
- if [ "${ROOT}" != "${ROOT#/}" ]; then
- ROOT="\x2f${ROOT#/}"
- fi
- if [ "${ROOT}" != "${ROOT%/}" ]; then
- ROOT="${ROOT%/}\x2f"
- fi
- IFS='/'
- newroot=
- for s in $ROOT; do
- newroot="${newroot:+${newroot}\\x2f}${s}"
- done
- unset IFS
- ROOT="${newroot}"
- fi
- esac
- ROOT="/dev/disk/by-label/${ROOT}"
- ;;
- UUID=*)
- ROOT="/dev/disk/by-uuid/${ROOT#UUID=}"
- ;;
- /dev/nfs)
+ ROOT=$(translate_device ${x#root=})
+ if [ $ROOT = "/dev/nfs" ]; then
[ -z "${BOOT}" ] && BOOT=nfs
- ;;
- esac
+ fi
;;
rootflags=*)
ROOTFLAGS="-o ${x#rootflags=}"
@@ -190,7 +159,7 @@
export noresume
unset resume
else
- resume=${RESUME:-}
+ resume=$(translate_device ${RESUME:-})
fi
maybe_break top
@@ -205,6 +174,39 @@
[ -n "${netconsole}" ] && modprobe netconsole netconsole="${netconsole}"
+maybe_break events
+TIMEOUT=20
+COUNT=$TIMEOUT
+echo "Waiting for $ROOT"
+if [ -n "$resume" ]; then
+ echo "Waiting for $resume"
+fi
+# run at least once
+touch /dev/.initramfs/block-events
+while [ $COUNT -gt 0 ]; do
+ sleep 1
+ COUNT=$((COUNT-1))
+ echo -ne "Waiting ($COUNT) \r"
+ wait_for_udev
+ mv 2>/dev/null /run/initramfs/block-events /run/initramfs/block-events.processing && \
+ {
+ echo "Found new block devices... "
+ COUNT=$TIMEOUT
+ export NEWDEVS=$(cat /run/initramfs/block-events.processing)
+ wait_for_udev
+ run_scripts /scripts/local-block
+ }
+ if [ -n "$resume" ]; then
+ if [ -e $ROOT ] && [ -e $resume ]; then
+ break
+ fi
+ else
+ if [ -e $ROOT ]; then
+ break;
+ fi
+ fi
+done
+
maybe_break premount
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/init-premount"
run_scripts /scripts/init-premount
@@ -309,6 +311,10 @@
unset readonly
unset resume
unset resume_offset
+unset COUNT
+unset TIMEOUT
+unset WAIT
+unset NEWDEVS
# Move virtual filesystems over to the real filesystem
mount -n -o move /sys ${rootmnt}/sys
diff -Nru initramfs-tools-0.106/scripts/block-event initramfs-tools-0.106a0mrvn1/scripts/block-event
--- initramfs-tools-0.106/scripts/block-event 1970-01-01 01:00:00.000000000 +0100
+++ initramfs-tools-0.106a0mrvn1/scripts/block-event 2012-06-23 18:48:41.000000000 +0200
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+echo >>/run/initramfs/block-events $1
diff -Nru initramfs-tools-0.106/scripts/functions initramfs-tools-0.106a0mrvn1/scripts/functions
--- initramfs-tools-0.106/scripts/functions 2012-06-06 15:04:52.000000000 +0200
+++ initramfs-tools-0.106a0mrvn1/scripts/functions 2012-06-23 19:34:36.000000000 +0200
@@ -423,3 +423,47 @@
command -v udevadm >/dev/null 2>&1 || return 0
udevadm settle ${1:+--timeout=$1}
}
+
+# Translate device name to device node
+# Parameter: root or resume argument
+# Echos path to device node to stdout
+translate_device()
+{
+ local DEV newdev
+ DEV=$1
+ case $DEV in
+ LABEL=*)
+ DEV="${DEV#LABEL=}"
+
+ # support any / in LABEL= path (escape to \x2f)
+ case "${DEV}" in
+ */*)
+ if command -v sed >/dev/null 2>&1; then
+ DEV="$(echo ${DEV} | sed 's,/,\\x2f,g')"
+ else
+ if [ "${DEV}" != "${DEV#/}" ]; then
+ DEV="\x2f${DEV#/}"
+ fi
+ if [ "${DEV}" != "${DEV%/}" ]; then
+ DEV="${DEV%/}\x2f"
+ fi
+ IFS='/'
+ newdev=
+ for s in $DEV; do
+ newdev="${newdev:+${newdev}\\x2f}${s}"
+ done
+ unset IFS
+ DEV="${newdev}"
+ fi
+ esac
+ DEV="/dev/disk/by-label/${DEV}"
+ ;;
+ UUID=*)
+ DEV="/dev/disk/by-uuid/${DEV#UUID=}"
+ ;;
+ /dev/nfs)
+ DEV=
+ ;;
+ esac
+ echo $DEV
+}
diff -Nru initramfs-tools-0.106/scripts/local-premount/resume initramfs-tools-0.106a0mrvn1/scripts/local-premount/resume
--- initramfs-tools-0.106/scripts/local-premount/resume 2010-06-17 14:15:13.000000000 +0200
+++ initramfs-tools-0.106a0mrvn1/scripts/local-premount/resume 2012-06-23 21:15:34.000000000 +0200
@@ -19,38 +19,6 @@
exit 0
fi
-case $resume in
-LABEL=*)
- resume="${resume#LABEL=}"
-
- # support any / in LABEL= path (escape to \x2f)
- case "${resume}" in
- */*)
- if command -v sed >/dev/null 2>&1; then
- resume="$(echo ${resume} | sed 's,/,\\x2f,g')"
- else
- if [ "${resume}" != "${resume#/}" ]; then
- resume="\x2f${resume#/}"
- fi
- if [ "${resume}" != "${resume%/}" ]; then
- resume="${resume%/}\x2f"
- fi
- IFS='/'
- newresume=
- for s in $resume; do
- newresume="${newresume:+${newresume}\\x2f}${s}"
- done
- unset IFS
- resume="${newresume}"
- fi
- esac
- resume="/dev/disk/by-label/${resume}"
- ;;
-UUID=*)
- resume="/dev/disk/by-uuid/${resume#UUID=}"
- ;;
-esac
-
[ ! -e "${resume}" ] && exit 0
[ ! -e /sys/power/resume ] && exit 0
Reply to: