On systems with a large number of devices, usually multipath devices,
dracut can spend a lot of time stat'ing the devices to collect the
major/minor numbers, leading to huge slowness rebuilding the initramfs
when stat'ing devices is slow (seen with oracleasm file systems in
particular).
This commit implements a basic cache stored in a file under
DRACUT_TMPDIR storing the major:minor corresponding to the specified
device.
Reproducer: create N loopback devices used as a LVM extension to volume
group hosting the root file system
# LVMVG="rhel"
# NDEVICES=200
# mkdir devices; for i in $(seq 1 $NDEVICES); do
truncate -s 10m devices/$i; losetup loop$i devices/$i
done
# vgextend $LVMVG $(/bin/ls -1 /dev/loop[0-9]*)
With standard code (tested with RHEL8.3 dracut):
# dracut -f --debug /tmp/initramfs.img $(uname -r) >/tmp/debug 2>&1
# grep -c "stat -L -c" /tmp/debug
2440
With this code:
# dracut -f --debug /tmp/initramfs.img $(uname -r) >/tmp/debug_optim 2>&1
# grep -c "stat -L -c" /tmp/debug_optim
205
Signed-off-by: Renaud Métrich <rmetrich@redhat.com>
# 8:2
get_maj_min() {
local _majmin
- _majmin="$(stat -L -c '%t:%T' "$1" 2> /dev/null)"
- printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))"
+ out="$(grep -m1 -oP "^$1 \K\S+$" "${get_maj_min_cache_file:?}")"
+ if [ -z "$out" ]; then
+ _majmin="$(stat -L -c '%t:%T' "$1" 2> /dev/null)"
+ out="$(printf "%s" "$((0x${_majmin%:*})):$((0x${_majmin#*:}))")"
+ echo "$1 $out" >> "${get_maj_min_cache_file:?}"
+ fi
+ echo -n "$out"
}
# get_devpath_block <device>
exit 1
}
+# Cache file used to optimize get_maj_min()
+declare -x -r get_maj_min_cache_file="${DRACUT_TMPDIR}/majmin_cache"
+: > "$get_maj_min_cache_file"
+
# clean up after ourselves no matter how we die.
trap '
ret=$?;