Viewing file: weak-modules (16.1 KB) -rwxr-xr-x Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
#!/bin/bash # # weak-modules - determine which modules are kABI compatible with installed # kernels and set up the symlinks in /lib/*/weak-updates. #
# Changelog: # # 2006/12/11 - Updated logic for determining the system's initrd location, # to account for IA64 differences. (#215432)
unset LANG LC_ALL LC_COLLATE
tmpdir=$(mktemp -td ${0##*/}.XXXXXX) trap "rm -rf $tmpdir" EXIT unset ${!changed_modules_*} ${!changed_initrd_*}
if [ "ia64" == `uname -m` ]; then initrd_prefix="/boot/efi/EFI/redhat" else initrd_prefix="/boot" fi
#!/bin/sh
# rpmsort: The sort in coreutils can't sort the RPM list how we want it so we # instead transform the list into a form it will sort correctly, then sort. rpmsort() { local IFS=$' ' REVERSE="" rpmlist=($(cat))
if [ "-r" == "$1" ]; then REVERSE="-r" fi
echo ${rpmlist[@]} | \ sed -e 's/-/../g' | \ sort ${REVERSE} -n -t"." -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 -k6,6 -k7,7 \ -k8,8 -k9,9 -k10,10 | \ sed -e 's/\.\./-/g' }
# read_modules_list: # Read in a list of modules from standard input. Convert the filenames into # absolute paths and compute the kernel release for each module (either using # the modinfo section or through the absolute path. read_modules_list() { local IFS=$'\n' modules=($(cat))
for ((n = 0; n < ${#modules[@]}; n++)); do if [ ${modules[n]:0:1} != '/' ]; then modules[n]="$PWD/${modules[n]}" fi if [ -f "${modules[n]}" ]; then module_krels[n]=$(krel_of_module ${modules[n]}) else # Try to extract the kernel release from the path set -- "${modules[n]#/lib/modules/}" module_krels[n]=${1%%/*} fi done }
# read_old_initrd: compare_initrd_modules() { local old_initrd=$1 local new_initrd=$2
rm -rf "$tmpdir/old_initrd" rm -rf "$tmpdir/new_initrd" mkdir "$tmpdir/old_initrd" mkdir "$tmpdir/new_initrd"
pushd "$tmpdir/old_initrd" >/dev/null zcat "$old_initrd" | cpio -i 2>/dev/null n=0; for i in `find . -iname \*.ko|sort`; do old_initrd_modules[n]="$i" n=$((n+1)) done popd >/dev/null
pushd "$tmpdir/new_initrd" >/dev/null zcat "$new_initrd" | cpio -i 2>/dev/null n=0; for i in `find . -iname \*.ko|sort`; do new_initrd_modules[n]="$i" n=$((n+1)) done popd >/dev/null
if [ "${#old_initrd_modules[@]}" == "${#new_initrd_modules[@]}" ]; then for ((n = 0; n < ${#old_initrd_modules[@]}; n++)); do old_md5=`md5sum $tmpdir/old_initrd/${old_initrd_modules[n]}|sed -nre 's:(^\ )* .*:\1:p'` new_md5=`md5sum $tmpdir/new_initrd/${new_initrd_modules[n]}|sed -nre 's:(^\ )* .*:\1:p'` if [ ! "$old_md5" == "$new_md5" ]; then return 1 fi done else return 1 fi
return 0 }
# check_initrd: check_initrd() { local kernel=$1 local kernel_is_xen=0 local xen_kverrel=0
if [ "xen" == "`echo $kernel|sed -nre 's:^.*(xen)$:\1:p'`" \ -a "(" -e /proc/xen/xsd_kva -o ! -d /proc/xen ")" ]; then kernel_is_xen=1 xen_kverrel="`echo $kernel|sed -nre 's:^(.*)xen$:\1:p'`" else kernel_is_xen=0 fi
# This logic probably isn't needed. When are we ever actually likely to have # an unbootable system, with no kernel, *before* we run this script? :-) if [ ! -e "$initrd_prefix/initrd-$kernel.img" ]; then new_initrd="$initrd_prefix/initrd-$kernel.img" if [ "$kernel_is_xen" == "0" ]; then /sbin/new-kernel-pkg --mkinitrd --initrdfile="$new_initrd" --depmod --install "$kernel" else /sbin/new-kernel-pkg --mkinitrd --initrdfile="$new_initrd" --depmod --install --multiboot="$initrd_prefix/xen.gz-$xen_kverrel" "$kernel" fi else old_initrd="$initrd_prefix/initrd-$kernel.img" tmp_initrd="$initrd_prefix/initrd-$kernel.tmp" new_initrd="$initrd_prefix/initrd-$kernel.img"
/sbin/mkinitrd --allow-missing -f "$tmp_initrd" "$kernel"
if ! $(compare_initrd_modules "$old_initrd" "$tmp_initrd"); then mv "$old_initrd" "$old_initrd".dup_orig mv "$tmp_initrd" "$new_initrd"
if [ "$kernel_is_xen" == "0" ]; then /sbin/new-kernel-pkg --initrdfile="$new_initrd" --depmod --install "$kernel" else /sbin/new-kernel-pkg --initrdfile="$new_initrd" --depmod --install --multiboot="$initrd_prefix/xen.gz-$xen_kverrel" "$kernel" fi else rm -f "$tmp_initrd" fi fi }
# krel_of_module: # Compute the kernel release of a module. krel_of_module() { declare module=$1 /sbin/modinfo -F vermagic "$module" | awk '{print $1}' }
# module_is_compatible: # Determine if a module is compatible with a particular kernel release. Also # include any symbol deps that might be introduced by other external KMPs. module_is_compatible() { declare module=$1 krel=$2 module_krel=$(krel_of_module "$module")
if [ ! -e "$tmpdir/all-symvers-$krel-$module_krel" ]; then # Symbols exported by the "new" kernel if [ ! -e $tmpdir/symvers-$krel ]; then if [ -e /boot/symvers-$krel.gz ]; then zcat /boot/symvers-$krel.gz \ | sed -r -ne 's:^(0x[0]*[0-9a-f]{8}\t[0-9a-zA-Z_]+)\t.*:\1:p' fi > $tmpdir/symvers-$krel fi
# Symbols that other add-on modules of the "old" kernel export # (and that this module may require) if [ ! -e "$tmpdir/extra-symvers-$module_krel" ]; then if [ -e /lib/modules/$module_krel/extra ] && \ [ -n "`find /lib/modules/$module_krel/extra -type f`" ]; then find /lib/modules/$module_krel/extra -name '*.ko' \ | xargs nm \ | sed -nre 's:^[0]*([0-9a-f]{8}) A __crc_(.*):0x\1 \2:p' fi > $tmpdir/extra-symvers-$module_krel fi
sort -u $tmpdir/symvers-$krel $tmpdir/extra-symvers-$module_krel \ > "$tmpdir/all-symvers-$krel-$module_krel" fi
# If the module does not have modversions enabled, $tmpdir/modvers # will be empty. /sbin/modprobe --dump-modversions "$module" \ | sed -r -e 's:^(0x[0]*[0-9a-f]{8}\t.*):\1:' \ | sort -u \ > $tmpdir/modvers
# Only include lines of the second file in the output that don't # match lines in the first file. (The default separator is # <space>, so we are matching the whole line.) join -j 1 -v 2 $tmpdir/all-symvers-$krel-$module_krel \ $tmpdir/modvers > $tmpdir/join
if [ ! -s $tmpdir/modvers ]; then echo "Warning: Module ${module##*/} from kernel $module_krel has no" \ "modversions, so it cannot be reused for kernel $krel" >&2 elif [ -s $tmpdir/join ]; then [ -n "$verbose" ] && echo "Module ${module##*/} from kernel $module_krel is not compatible" \ "with kernel $krel in symbols:" $(sed -e 's:.* ::' $tmpdir/join) else [ -n "$verbose" ] && echo "Module ${module##*/} from kernel $module_krel is compatible" \ "with kernel $krel" return 0 fi return 1 }
# doit: # A wrapper used whenever we're going to perform a real operation. doit() { [ -n "$verbose" ] && echo "$@" [ -n "$dry_run" ] || "$@" }
usage() { echo "Usage: ${0##*/} [options] {--add-modules|--remove-modules}" echo "${0##*/} [options] {--add-kernel|--remove-kernel} {kernel-release}" cat <<'EOF' --add-modules Add a list of modules read from standard input. Create symlinks in compatible kernel's weak-updates/ directory. The list of modules is read from standard input.
--remove-modules Remove compatibility symlinks from weak-updates/ directories for a list of modules. The list of modules is read from standard input. Optionally specify --delete-modules to prevent weak-modules from attempting to locate any compatible modules to replace those being removed.
--add-kernel Add compatibility symlinks for all compatible modules to the specified or running kernel.
--remove-kernel Remove all compatibility symlinks for the specified or current kernel.
--no-initrd Do not generate an initrd.
--verbose Print the commands executed.
--dry-run Do not create/remove any files. EOF exit $1 }
# module_has_changed: # Mark if an actual change occured that we need to deal with later by calling # depmod or mkinitrd against the affected kernel. module_has_changed() {
declare module=$1 krel=$2
module=${module%.ko} module=${module##*/}
eval "changed_modules_${krel//[^a-zA-Z0-9]/_}=$krel" eval "changed_initrd_${krel//[^a-zA-Z0-9]/_}=$krel"
}
# add_modules: # Read in a list of modules from stdinput and process them for compatibility # with installed kernels under /lib/modules. add_modules() { read_modules_list || exit 1 if [ ${#modules[@]} -gt 0 ]; then for krel in $(ls /lib/modules/); do [ -e "/boot/symvers-$krel.gz" ] || continue for ((n = 0; n < ${#modules[@]}; n++)); do module="${modules[n]}" module_krel="${module_krels[n]}" case "$module" in /lib/modules/$krel/*) # Module was built against this kernel, update initrd. module_has_changed $module $krel continue ;; esac
# Module my also serve as a weak-update built against another # kernel. We need to create symlinks for compatible kernels # under /lib/modules and rerun depmod/mkinitrd for those.
subpath=`echo $module | sed -nre "s:/lib/modules/$module_krel/([^/]*)/(.*):\2:p"` weak_module="/lib/modules/$krel/weak-updates/${subpath#/}" if [ -r "$weak_module" ]; then weak_krel=$(krel_of_module "$weak_module") if [ "$weak_krel" != "$module_krel" ] && [ "$(printf "%s\n" "$weak_krel" "$module_krel" \ | rpmsort | (read input; echo "$input"; \ while read input; do true; done))" = \ "$module_krel" ]; then # Keep modules from more recent kernels. [ -n "$verbose" ] && echo \ "Keeping module ${module##*/} from kernel $weak_krel for kernel $krel" continue fi fi if module_is_compatible $module $krel; then doit mkdir -p $(dirname $weak_module) doit ln -sf $module $weak_module # Module was built against another kernel, update initrd. module_has_changed $module $krel fi done done fi }
# remove_modules: # Read in a list of modules from stdinput and process them for removal. # Parameter is noreplace to delete modules, otherwise link compat. remove_modules() { delete_modules=${1:-replace}
read_modules_list || exit 1 if [ ${#modules[@]} -gt 0 ]; then
# Hunt for all known users of this module in /lib/modules, remove them # and create symlinks to other compatible modules (downgrade) if # possible, update initrd for each modified kernel too.
krels=($(ls /lib/modules/ | rpmsort -r)) for krel in "${krels[@]}"; do [ -e "/boot/symvers-$krel.gz" ] || continue for ((n = 0; n < ${#modules[@]}; n++)); do module="${modules[n]}" module_krel="${module_krels[n]}"
# Module is going to be removed, update initrd. module_has_changed $module $krel
subpath="${module#/lib/modules/$module_krel/extra}" weak_module="/lib/modules/$krel/weak-updates/${subpath#/}" if [ "$module" == "`readlink $weak_module`" ]; then orig_module="`readlink $weak_module`" [ -n "$verbose" ] && echo \ "Removing compatible module ${module##*/} from kernel $krel" doit rm -f "$weak_module" if [ "replace" == "$delete_modules" ]; then for krel2 in "${krels[@]}"; do if [ $krel2 != $krel ]; then module="/lib/modules/$krel2/extra/${subpath#/}" [ -e "$module" ] || continue [ "$module" != "$orig_module" ] || continue if module_is_compatible "$module" "$krel"; then [ -n "$verbose" ] && echo \ "Adding compatible module ${module##*/} from kernel $krel2 instead" doit ln -s "$module" "$weak_module" module_has_changed $module $krel break fi fi done fi doit rmdir --parents --ignore-fail-on-non-empty \ "$(dirname "$weak_module")" fi done done fi }
add_kernel() { add_krel=${1:-$(uname -r)} if [ ! -e "/boot/symvers-$add_krel.gz" ]; then echo "Symvers dump file /boot/symvers-$add_krel.gz" \ "not found" >&2 exit 1 fi for krel in $(ls /lib/modules/ | rpmsort -r); do [ "$add_krel" = "$krel" ] && continue [ -d /lib/modules/$krel/extra ] || continue for module in $(find /lib/modules/$krel/extra -name '*.ko'); do subpath="${module#/lib/modules/$krel/extra}" weak_module="/lib/modules/$add_krel/weak-updates/${subpath#/}" [ -e "$weak_module" ] && continue if module_is_compatible $module $add_krel; then module_has_changed $module $add_krel doit mkdir -p $(dirname $weak_module) doit ln -sf $module $weak_module fi done done }
remove_kernel() { remove_krel=${1:-$(uname -r)} weak_modules="/lib/modules/$remove_krel/weak-updates" module_has_changed $weak_modules $remove_krel doit rm -rf "$weak_modules" doit rm -rf "$initrd_prefix/initrd-$remove_krel.img.dup_orig" }
################################################################################ ################################## MAIN GUTS ################################### ################################################################################
options=`getopt -o h --long help,add-modules,remove-modules \ --long add-kernel,remove-kernel \ --long dry-run,no-initrd,verbose,delete-modules -- "$@"`
[ $? -eq 0 ] || usage 1
eval set -- "$options"
while :; do case "$1" in --add-modules) do_add_modules=1 ;; --remove-modules) do_remove_modules=1 ;; --add-kernel) do_add_kernel=1 ;; --remove-kernel) do_remove_kernel=1 ;; --dry-run) dry_run=1 ;; --no-initrd) no_initrd=1 ;; --verbose) verbose=1 ;; --delete-modules) do_delete_modules=1 ;; -h|--help) usage 0 ;; --) shift break ;; esac shift done
if [ -n "$do_add_modules" ]; then add_modules
elif [ -n "$do_remove_modules" ]; then if [ -n "$do_delete_modules" ]; then remove_modules "noreplace" else remove_modules fi
elif [ -n "$do_add_kernel" ]; then kernel=${1:-$(uname -r)} add_kernel $kernel
elif [ -n "$do_remove_kernel" ]; then kernel=${1:-$(uname -r)} remove_kernel $kernel
exit 0 else usage 1 fi
################################################################################ ###################### CLEANUP POST ADD/REMOVE MODULE/KERNEL ################### ################################################################################
# run depmod and mkinitrd as needed for krel in ${!changed_modules_*}; do krel=${!krel}
doit /sbin/depmod -ae -F /boot/System.map-$krel $krel done
for krel in ${!changed_initrd_*}; do krel=${!krel}
if [ ! -n "$no_initrd" ]; then check_initrd $krel fi done
|