Use /usr/bin/dracut-install if available

/usr/bin/dracut-install greatly improves initramfs creation speed
master
Harald Hoyer 2012-06-29 12:07:44 +02:00
parent 7224913d16
commit 89d44e720b
2 changed files with 326 additions and 230 deletions

View File

@ -20,10 +20,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#

[[ $initdir ]] || { echo "ERROR: initdir $initdir not set" 2>&1; exit 10; }
[[ -d $initdir ]] || mkdir -p $initdir
[[ -d "$initdir/.kernelmodseen" ]] || mkdir -p "$initdir/.kernelmodseen"
export initdir

# Generic substring function. If $2 is in $1, return 0.
strstr() { [[ $1 = *$2* ]]; }
@ -394,6 +391,60 @@ check_vol_slaves() {
return 1
}

if [[ -x /usr/bin/dracut-install ]]; then
[[ $DRACUT_RESOLVE_LAZY ]] || export DRACUT_RESOLVE_DEPS=1
inst_dir() {
[[ -e ${initdir}/"$1" ]] && return 0 # already there
dracut-install ${initdir+-D "$initdir"} -d "$@"
(($? != 0)) && derror dracut-install ${initdir+-D "$initdir"} -d "$@" || :
}

inst() {
[[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
#dinfo "dracut-install -l $@"
dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@"
(($? != 0)) && derror dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@" || :
}

inst_simple() {
[[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
[[ -e $1 ]] || return 1 # no source
dracut-install ${initdir+-D "$initdir"} "$@"
(($? != 0)) && derror dracut-install ${initdir+-D "$initdir"} "$@" || :
}

inst_symlink() {
[[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
[[ -L $1 ]] || return 1
dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@"
(($? != 0)) && derror dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@" || :
}

dracut_install() {
#dinfo "initdir=$initdir dracut-install -l $@"
dracut-install ${initdir+-D "$initdir"} -a ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@"
(($? != 0)) && derror dracut-install ${initdir+-D "$initdir"} -a ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@" || :
}

inst_library() {
[[ -e ${initdir}/"${2:-$1}" ]] && return 0 # already there
[[ -e $1 ]] || return 1 # no source
dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@"
(($? != 0)) && derror dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@" || :
}

inst_binary() {
dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@"
(($? != 0)) && derror dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@" || :
}

inst_script() {
dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@"
(($? != 0)) && derror dracut-install ${initdir+-D "$initdir"} ${DRACUT_RESOLVE_DEPS+-l} ${DRACUT_FIPS_MODE+-H} "$@" || :
}

else

# Install a directory, keeping symlinks as on the original system.
# Example: if /lib points to /lib64 on the host, "inst_dir /lib/file"
# will create ${initdir}/lib64, ${initdir}/lib64/file,
@ -428,7 +479,6 @@ inst_dir() {
inst_simple() {
[[ -f "$1" ]] || return 1
strstr "$1" "/" || return 1

local _src=$1 _target="${2:-$1}"

[[ -L $_src ]] && { inst_symlink $_src $_target; return $?; }
@ -438,37 +488,33 @@ inst_simple() {
[[ -L ${initdir}/$_target ]] && return 0
[[ -d "${initdir}/${_target%/*}" ]] || inst_dir "${_target%/*}"
fi
if [[ $DRACUT_FIPS_MODE ]]; then
# install checksum files also
if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
inst "${_src%/*}/.${_src##*/}.hmac" "${_target%/*}/.${_target##*/}.hmac"
fi
fi
ddebug "Installing $_src"
cp --reflink=auto --sparse=auto -pfL "$_src" "${initdir}/$_target"
}

# find symlinks linked to given library file
# $1 = library file
# Function searches for symlinks by stripping version numbers appended to
# library filename, checks if it points to the same target and finally
# prints the list of symlinks to stdout.
#
# Example:
# rev_lib_symlinks libfoo.so.8.1
# output: libfoo.so.8 libfoo.so
# (Only if libfoo.so.8 and libfoo.so exists on host system.)
rev_lib_symlinks() {
[[ ! $1 ]] && return 0
# same as above, but specialized for symlinks
inst_symlink() {
local _src=$1 _target=${2:-$1} _realsrc
strstr "$1" "/" || return 1
[[ -L $1 ]] || return 1
[[ -L $initdir/$_target ]] && return 0
_realsrc=$(readlink -f "$_src")
if ! [[ -e $initdir/$_realsrc ]]; then
if [[ -d $_realsrc ]]; then
inst_dir "$_realsrc"
else
inst "$_realsrc"
fi
fi
[[ ! -e $initdir/${_target%/*} ]] && inst_dir "${_target%/*}"

local fn="$1" orig="$(readlink -f "$1")" links=''

[[ ${fn} =~ .*\.so\..* ]] || return 1

until [[ ${fn##*.} == so ]]; do
fn="${fn%.*}"
[[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
done

echo "${links}"
ln_r "${_realsrc}" "${_target}"
}

# Same as above, but specialized to handle dynamic libraries.
@ -479,10 +525,12 @@ inst_library() {
strstr "$1" "/" || return 1
[[ -e $initdir/$_dest ]] && return 0
if [[ -L $_src ]]; then
if [[ $DRACUT_FIPS_MODE ]]; then
# install checksum files also
if [[ -e "${_src%/*}/.${_src##*/}.hmac" ]]; then
inst "${_src%/*}/.${_src##*/}.hmac" "${_dest%/*}/.${_dest##*/}.hmac"
fi
fi
_reallib=$(readlink -f "$_src")
inst_simple "$_reallib" "$_reallib"
inst_dir "${_dest%/*}"
@ -500,19 +548,6 @@ inst_library() {
done
}

# find a binary. If we were not passed the full path directly,
# search in the usual places to find the binary.
find_binary() {
if [[ -z ${1##/*} ]]; then
if [[ -x $1 ]] || { strstr "$1" ".so" && ldd $1 &>/dev/null; }; then
echo $1
return 0
fi
fi

type -P $1
}

# Same as above, but specialized to install binary executables.
# Install binary executable, and all shared library dependencies, if any.
inst_binary() {
@ -520,7 +555,6 @@ inst_binary() {
_bin=$(find_binary "$1") || return 1
_target=${2:-$_bin}
[[ -e $initdir/$_target ]] && return 0
[[ -L $_bin ]] && { inst_symlink $_bin $_target; return $?; }
local _file _line
local _so_regex='([^ ]*/lib[^/]*/[^ ]*\.so[^ ]*)'
# I love bash!
@ -560,23 +594,87 @@ inst_script() {
inst "${BASH_REMATCH[2]}" && inst_simple "$_bin" "$@"
}

# same as above, but specialized for symlinks
inst_symlink() {
local _src=$1 _target=${2:-$1} _realsrc
strstr "$1" "/" || return 1
[[ -L $1 ]] || return 1
[[ -L $initdir/$_target ]] && return 0
_realsrc=$(readlink -f "$_src")
if ! [[ -e $initdir/$_realsrc ]]; then
if [[ -d $_realsrc ]]; then
inst_dir "$_realsrc"
else
inst "$_realsrc"
fi
fi
[[ ! -e $initdir/${_target%/*} ]] && inst_dir "${_target%/*}"
# general purpose installation function
# Same args as above.
inst() {
local _x

ln_r "${_realsrc}" "${_target}"
case $# in
1) ;;
2) [[ ! $initdir && -d $2 ]] && export initdir=$2
[[ $initdir = $2 ]] && set $1;;
3) [[ -z $initdir ]] && export initdir=$2
set $1 $3;;
*) dfatal "inst only takes 1 or 2 or 3 arguments"
exit 1;;
esac
for _x in inst_symlink inst_script inst_binary inst_simple; do
$_x "$@" && return 0
done
return 1
}

# dracut_install [-o ] <file> [<file> ... ]
# Install <file> to the initramfs image
# -o optionally install the <file> and don't fail, if it is not there
dracut_install() {
local _optional=no
if [[ $1 = '-o' ]]; then
_optional=yes
shift
fi
while (($# > 0)); do
if ! inst "$1" ; then
if [[ $_optional = yes ]]; then
dinfo "Skipping program $1 as it cannot be found and is" \
"flagged to be optional"
else
dfatal "Failed to install $1"
exit 1
fi
fi
shift
done
}

fi

# find symlinks linked to given library file
# $1 = library file
# Function searches for symlinks by stripping version numbers appended to
# library filename, checks if it points to the same target and finally
# prints the list of symlinks to stdout.
#
# Example:
# rev_lib_symlinks libfoo.so.8.1
# output: libfoo.so.8 libfoo.so
# (Only if libfoo.so.8 and libfoo.so exists on host system.)
rev_lib_symlinks() {
[[ ! $1 ]] && return 0

local fn="$1" orig="$(readlink -f "$1")" links=''

[[ ${fn} =~ .*\.so\..* ]] || return 1

until [[ ${fn##*.} == so ]]; do
fn="${fn%.*}"
[[ -L ${fn} && $(readlink -f "${fn}") == ${orig} ]] && links+=" ${fn}"
done

echo "${links}"
}

# find a binary. If we were not passed the full path directly,
# search in the usual places to find the binary.
find_binary() {
if [[ -z ${1##/*} ]]; then
if [[ -x $1 ]] || { strstr "$1" ".so" && ldd $1 &>/dev/null; }; then
echo $1
return 0
fi
fi

type -P $1
}

# attempt to install any programs specified in a udev rule
@ -658,26 +756,6 @@ inst_rules() {
done
}

# general purpose installation function
# Same args as above.
inst() {
local _x

case $# in
1) ;;
2) [[ ! $initdir && -d $2 ]] && export initdir=$2
[[ $initdir = $2 ]] && set $1;;
3) [[ -z $initdir ]] && export initdir=$2
set $1 $3;;
*) dfatal "inst only takes 1 or 2 or 3 arguments"
exit 1;;
esac
for _x in inst_symlink inst_script inst_binary inst_simple; do
$_x "$@" && return 0
done
return 1
}

# install function specialized for hooks
# $1 = type of hook, $2 = hook priority (lower runs first), $3 = hook
# All hooks should be POSIX/SuS compliant, they will be sourced by init.
@ -721,29 +799,6 @@ inst_any() {
return 1
}

# dracut_install [-o ] <file> [<file> ... ]
# Install <file> to the initramfs image
# -o optionally install the <file> and don't fail, if it is not there
dracut_install() {
local _optional=no
if [[ $1 = '-o' ]]; then
_optional=yes
shift
fi
while (($# > 0)); do
if ! inst "$1" ; then
if [[ $_optional = yes ]]; then
dinfo "Skipping program $1 as it cannot be found and is" \
"flagged to be optional"
else
dfatal "Failed to install $1"
exit 1
fi
fi
shift
done
}


# inst_libdir_file [-n <pattern>] <file> [<file>...]
# Install a <file> located on a lib directory to the initramfs image
@ -1045,7 +1100,7 @@ for_each_module_dir() {
for _mod in $_modcheck; do
strstr "$mods_to_load" "$_mod" && continue
strstr "$omit_dracutmodules" "$_mod" && continue
derror "Dracut module \"$_mod\" cannot be found."
derror "Dracut module \"$_mod\" cannot be found or installed."
done
}

@ -1126,11 +1181,8 @@ for_each_kmod_dep() {
dracut_kernel_post() {
local _moddirname=${srcmods%%/lib/modules/*}

[[ -f "$initdir/.kernelmodseen/lazylist" ]] || return 0

[[ -n ${_moddirname} ]] && _moddirname="-d ${_moddirname}/"

xargs modprobe -a $_moddirname --ignore-install --show-depends \
if [[ -f "$initdir/.kernelmodseen/lazylist" ]]; then
xargs modprobe -a ${_moddirname+-d ${_moddirname}/} --ignore-install --show-depends \
< "$initdir/.kernelmodseen/lazylist" 2>/dev/null \
| sort -u \
| while read _cmd _modpath _options; do
@ -1138,10 +1190,28 @@ dracut_kernel_post() {
echo "$_modpath"
done > "$initdir/.kernelmodseen/lazylist.dep"

( while read _modpath; do
inst_simple "$_modpath" "/lib/modules/$kernel/${_modpath##*/lib/modules/$kernel/}" || exit $?
done < "$initdir/.kernelmodseen/lazylist.dep" ) &
(
if [[ -x /usr/bin/dracut-install ]] && [[ -z $_moddirname ]]; then
xargs dracut-install ${initdir+-D "$initdir"} -a < "$initdir/.kernelmodseen/lazylist.dep"
else
while read _modpath; do
local _destpath=$_modpath
[[ $_moddirname ]] && _destpath=${_destpath##$_moddirname/}
_destpath=${_destpath##*/lib/modules/$kernel/}
inst_simple "$_modpath" "/lib/modules/$kernel/${_destpath}" || exit $?
done < "$initdir/.kernelmodseen/lazylist.dep"
fi
) &


if [[ -x /usr/bin/dracut-install ]]; then
xargs modinfo -k $kernel -F firmware < "$initdir/.kernelmodseen/lazylist.dep" \
| while read line; do
for _fwdir in $fw_dir; do
echo $_fwdir/$line;
done;
done |xargs dracut-install ${initdir+-D "$initdir"} -a -o
else
for _fw in $(xargs modinfo -k $kernel -F firmware < "$initdir/.kernelmodseen/lazylist.dep"); do
for _fwdir in $fw_dir; do
if [[ -d $_fwdir && -f $_fwdir/$_fw ]]; then
@ -1150,7 +1220,10 @@ dracut_kernel_post() {
fi
done
done
fi

wait
fi

for _f in modules.builtin.bin modules.builtin; do
[[ $srcmods/$_f ]] && break
@ -1239,7 +1312,7 @@ instmods() {
&& ! [[ "$add_drivers" =~ " ${_mod} " ]] \
&& return 0

if [[ "$_check" = "yes" ]]; then
if [[ "$_check" = "yes" ]] || ! [[ $DRACUT_KERNEL_LAZY ]]; then
# We use '-d' option in modprobe only if modules prefix path
# differs from default '/'. This allows us to use Dracut with
# old version of modprobe which doesn't have '-d' option.

View File

@ -317,7 +317,9 @@ unset NPATH
unset LD_LIBRARY_PATH
unset GREP_OPTIONS

export DRACUT_LOG_LEVEL=warning
[[ $debug ]] && {
export DRACUT_LOG_LEVEL=debug
export PS4='${BASH_SOURCE}@${LINENO}(${FUNCNAME[0]}): ';
set -x
}
@ -472,6 +474,9 @@ readonly initdir=$(mktemp --tmpdir="$TMPDIR/" -d -t initramfs.XXXXXX)
exit 1
}

export DRACUT_KERNEL_LAZY="1"
export DRACUT_RESOLVE_LAZY="1"

if [[ -f $dracutbasedir/dracut-functions.sh ]]; then
. $dracutbasedir/dracut-functions.sh
else
@ -726,6 +731,8 @@ mods_to_load=""
for_each_module_dir check_module
for_each_module_dir check_mount

strstr "$mods_to_load" "fips" && export DRACUT_FIPS_MODE=1

_isize=0 #initramfs size
modules_loaded=" "
# source our modules.
@ -770,10 +777,11 @@ done
dinfo "*** Including modules done ***"

## final stuff that has to happen

if [[ $no_kernel != yes ]]; then
dinfo "*** Installing kernel module dependencies and firmware ***"
dracut_kernel_post
dinfo "*** Installing kernel module dependencies and firmware done ***"
fi

while pop include_src src && pop include_target tgt; do
if [[ $src && $tgt ]]; then
@ -792,9 +800,9 @@ while pop include_src src && pop include_target tgt; do
mkdir -m 0755 -p "$s"
chmod --reference="$i" "$s"
fi
cp -a -t "$s" "$i"/*
cp --reflink=auto --sparse=auto -pfLr -t "$s" "$i"/*
else
cp -a -t "$s" "$i"
cp --reflink=auto --sparse=auto -pfLr -t "$s" "$i"
fi
done
fi
@ -802,10 +810,7 @@ while pop include_src src && pop include_target tgt; do
done

if [[ $kernel_only != yes ]]; then
for item in $install_items; do
dracut_install "$item"
done
unset item
(( ${#install_items[@]} > 0 )) && dracut_install ${install_items[@]}

while pop fstab_lines line; do
echo "$line 0 0" >> "${initdir}/etc/fstab"
@ -815,6 +820,15 @@ if [[ $kernel_only != yes ]]; then
cat $f >> "${initdir}/etc/fstab"
done

if [[ $DRACUT_RESOLVE_LAZY ]] && [[ -x /usr/bin/dracut-install ]]; then
dinfo "*** Resolving executable dependencies ***"
find "$initdir" -type f \
'(' -perm -0100 -or -perm -0010 -or -perm -0001 ')' \
-not -path '*.ko' -print0 \
| xargs -0 dracut-install ${initdir+-D "$initdir"} -R ${DRACUT_FIPS_MODE+-H}
dinfo "*** Resolving executable dependencies done***"
fi

# make sure that library links are correct and up to date
for f in /etc/ld.so.conf /etc/ld.so.conf.d/*; do
[[ -f $f ]] && inst_simple "$f"
@ -843,34 +857,43 @@ if [[ $do_strip = yes ]] ; then
done
fi

if [[ $do_strip = yes ]] ; then
find "$initdir" -type f \
\( -perm -0100 -or -perm -0010 -or -perm -0001 \
-or -path '*/lib/modules/*.ko' \) -print0 \
| xargs -0 strip -g 2>/dev/null
fi

type hardlink &>/dev/null && {
hardlink "$initdir" 2>&1
}

if strstr "$modules_loaded" " fips " && command -v prelink >/dev/null; then
dinfo "*** pre-unlinking files ***"
for dir in "$initdir/bin" \
"$initdir/sbin" \
"$initdir/usr/bin" \
"$initdir/usr/sbin"; do
[[ -L "$dir" ]] && continue
for i in "$dir"/*; do
[[ -L $i ]] && continue
[[ -x $i ]] && prelink -u $i &>/dev/null
done
done
dinfo "*** pre-unlinking files done ***"
fi

if [[ $do_strip = yes ]] ; then
dinfo "*** Stripping files ***"
find "$initdir" -type f \
'(' -perm -0100 -or -perm -0010 -or -perm -0001 \
-or -path '*/lib/modules/*.ko' ')' -print0 \
| xargs -0 strip -g 2>/dev/null
dinfo "*** Stripping files done ***"
fi

type hardlink &>/dev/null && {
dinfo "*** hardlinking files ***"
hardlink "$initdir" 2>&1
dinfo "*** hardlinking files done ***"
}

dinfo "*** Creating image file ***"
if ! ( cd "$initdir"; find . |cpio -R 0:0 -H newc -o --quiet| \
$compress > "$outfile"; ); then
dfatal "dracut: creation of $outfile failed"
exit 1
fi
dinfo "*** Creating image file done ***"

dinfo "Wrote $outfile:"
dinfo "$(ls -l "$outfile")"