kdumpctl: Detect block device driver change for initramfs rebuild

Previous we rebuild the initramfs when kenrel load module list changed,
but this is not very stable as some async services may load/unload
kernel modules, and cause unnecessary initramfs rebuild.

Instead, it's better to just check if the module required to dump to
the dump target is loaded or not, and rebuild if not loaded. This
avoids most false-positives, and ensure local target change is always
covered.

Currently only local fs dump target is covered, because this check
requires the dump target to be mounted when building the initramfs,
this guarantee that the module is in the loaded kernel module list,
else we may still get some false positive.

dracut-install could be leveraged to combine the modalias list with
kernel loaded module list as a more stable module list in the initramfs,
but upstream dracut change need to be done first.

Passed test on a KVM VM, changing the storage between SATA/USB/VirtIO
will trigger initramfs rebuild and didn't notice any false-positive.
Also passed test on my laptop with no false-positive.

Signed-off-by: Kairui Song <kasong@redhat.com>
Acked-by: Dave Young <dyoung@redhat.com>
This commit is contained in:
Kairui Song 2019-05-07 14:19:18 +08:00
parent 09f50350d9
commit 1c1159a586

View File

@ -357,6 +357,9 @@ check_dump_fs_modified()
local _old_dev _old_mntpoint _old_fstype
local _new_dev _new_mntpoint _new_fstype
local _target _path _dracut_args
local _target_drivers _module_name
local _old_drivers="$(lsinitrd $TARGET_INITRD -f /usr/lib/dracut/loaded-kernel-modules.txt | tr '\n' ' ')"
# No need to check in case of mount target specified via "dracut_args".
if is_mount_in_dracut_args; then
@ -385,6 +388,36 @@ check_dump_fs_modified()
fi
fi
_record_block_drivers() {
local _drivers
if [[ -b /dev/block/$1 ]]; then
_drivers=$(udevadm info -a "/dev/block/$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p')
fi
if [[ -b $1 ]]; then
_drivers=$(udevadm info -a "$1" | sed -n 's/\s*DRIVERS=="\(\S\+\)"/\1/p')
fi
for _driver in $_drivers; do
if ! [[ " $_target_drivers " == *" $_driver "* ]]; then
_target_drivers="$_target_drivers $_driver"
fi
done
return 1
}
check_block_and_slaves_all _record_block_drivers "$(get_maj_min "$_target")"
for _driver in $_target_drivers; do
# Target is mounted already, if module is not included by current kernel,
# could be a deprecated/invalid driver name or a built-in module
_module_name=$(modinfo --set-version "$kdump_kver" -F name $_driver 2>/dev/null)
if [ $? -ne 0 ] || [ -z "$_module_name" ]; then
continue
fi
if ! [[ " $_old_drivers " == *" $_module_name "* ]]; then
echo "Detected change in block device driver, new loaded module: $_module_name"
return 1
fi
done
if [[ $(expr substr $_new_fstype 1 3) = "nfs" ]];then
_new_dev=$_target
else