diff --git a/SOURCES/kmod-modprobe-ignore-builtin-module-on-recursive-removing.patch b/SOURCES/kmod-modprobe-ignore-builtin-module-on-recursive-removing.patch new file mode 100644 index 0000000..69c1bd5 --- /dev/null +++ b/SOURCES/kmod-modprobe-ignore-builtin-module-on-recursive-removing.patch @@ -0,0 +1,83 @@ +From 52a0ba82e1ad180f9f91920db70a758fac49466a Mon Sep 17 00:00:00 2001 +From: Yauheni Kaliuta +Date: Thu, 31 Oct 2019 20:12:53 +0200 +Subject: [PATCH] modprobe: ignore builtin module on recursive removing + +If there are built-in dependencies and any of them is built-in in +the kernel, modprobe -r fails with + +modprobe: FATAL: Module module_name is builtin. + +It makes sense to ignore such dependencies for the case when +removing is called for non-top level module. + +Example: cifs module, it declares bunch of softdeps and the first +one fails on some kernel configs: + +modprobe: FATAL: Module gcm is builtin. + +Signed-off-by: Yauheni Kaliuta +--- + tools/modprobe.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/tools/modprobe.c b/tools/modprobe.c +index a9e2331567af..44cd15c2bf57 100644 +--- a/tools/modprobe.c ++++ b/tools/modprobe.c +@@ -353,7 +353,8 @@ static int rmmod_do_remove_module(struct kmod_module *mod) + return err; + } + +-static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies); ++static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies, ++ bool ignore_builtin); + + static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors) + { +@@ -361,7 +362,7 @@ static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors) + + kmod_list_foreach_reverse(l, list) { + struct kmod_module *m = kmod_module_get_module(l); +- int r = rmmod_do_module(m, false); ++ int r = rmmod_do_module(m, false, true); + kmod_module_unref(m); + + if (r < 0 && stop_on_errors) +@@ -371,7 +372,8 @@ static int rmmod_do_deps_list(struct kmod_list *list, bool stop_on_errors) + return 0; + } + +-static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies) ++static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies, ++ bool ignore_builtin) + { + const char *modname = kmod_module_get_name(mod); + struct kmod_list *pre = NULL, *post = NULL; +@@ -401,8 +403,12 @@ static int rmmod_do_module(struct kmod_module *mod, bool do_dependencies) + } + goto error; + } else if (state == KMOD_MODULE_BUILTIN) { +- LOG("Module %s is builtin.\n", modname); +- err = -ENOENT; ++ if (ignore_builtin) { ++ err = 0; ++ } else { ++ LOG("Module %s is builtin.\n", modname); ++ err = -ENOENT; ++ } + goto error; + } + } +@@ -462,7 +468,7 @@ static int rmmod(struct kmod_ctx *ctx, const char *alias) + + kmod_list_foreach(l, list) { + struct kmod_module *mod = kmod_module_get_module(l); +- err = rmmod_do_module(mod, true); ++ err = rmmod_do_module(mod, true, false); + kmod_module_unref(mod); + if (err < 0) + break; +-- +2.24.0 + diff --git a/SOURCES/weak-modules b/SOURCES/weak-modules index dd163cc..65806d0 100644 --- a/SOURCES/weak-modules +++ b/SOURCES/weak-modules @@ -3,15 +3,6 @@ # weak-modules - determine which modules are kABI compatible with installed # kernels and set up the symlinks in /lib/*/weak-updates. # -# This is an updated version of the script which doesn't support -# multiple installation of the same out-of-tree module (stored in the -# 'extra' subdirectory) for multiple kernels. This assumption is -# supposed to be verified at the rpm level of the packages delivering -# these modules. There are some checks for this assumption, however we -# really don't solve this situation. This limitation allows for a much -# simpler version of the script. Previous version tried to work in this -# case but was incorrect in some cases. - unset LANG LC_ALL LC_COLLATE tmpdir=$(mktemp -td ${0##*/}.XXXXXX) @@ -32,6 +23,14 @@ declare -A weak_modules_before declare -A groups declare -A grouped_modules +# output of validate_weak_links, one iteration +# short_name -> path +declare -A compatible_modules + +# state for update_modules_for_krel (needed for add_kernel case) +# short_name -> path +declare -A installed_modules + # doit: # A wrapper used whenever we're going to perform a real operation. doit() { @@ -473,6 +472,29 @@ prepare_sandbox() { depmod="$depmod_orig -C $conf" } +# discard_installed: +# remove installed_modules[] from modules[] +discard_installed() +{ + local short_name + + for m in "${!modules[@]}"; do + short_name="$(module_short_name "${modules[$m]}")" + + [[ -z "${installed_modules[$short_name]}" ]] && continue + + unset "modules[$m]" + done +} + +# update_installed: +# add compatible_modules[] to installed_modules[] +update_installed() +{ + for m in "${!compatible_modules[@]}"; do + installed_modules[$m]="${compatible_modules[$m]}" + done +} # finish_sandbox: # restore global state after sandboxing @@ -568,6 +590,7 @@ find_systemmap_file() { # the given kernel) # - check the state after validation to produce needed messages # and trigger initrd regeneration if the list changed. +# update_modules_for_krel() { local krel="$1" local func="$2" @@ -579,12 +602,24 @@ update_modules_for_krel() { global_link_state_save $krel + # remove already installed from modules[] + discard_installed + + # do not run heavy validation procedure if no modules to install + if [[ "${#modules[@]}" -eq 0 ]]; then + finish_sandbox $krel + return + fi + $func $krel if ! validate_weak_links $krel && [[ -z "$force_update" ]]; then global_link_state_restore $krel fi + # add compatible to installed + update_installed + global_link_state_announce_changes $krel finish_sandbox $krel @@ -600,12 +635,16 @@ update_modules() { local func="$1" local force_update="$2" local module_krel + declare -a saved_modules read_modules_list || exit 1 [[ ${#modules[@]} -gt 0 ]] || return + saved_modules=("${modules[@]}") for krel in $(find_installed_kernels); do update_modules_for_krel $krel $func $force_update + modules=("${saved_modules[@]}") + installed_modules=() done for module in "${modules[@]}"; do @@ -630,7 +669,7 @@ add_weak_links() { module_krel="$(krel_of_module $module)" case "$module" in - /lib/modules/$krel/*) + $BASEDIR/lib/modules/$krel/*) # Module already installed to the current kernel continue ;; esac @@ -698,6 +737,7 @@ remove_weak_links() { # # Returns 0 (success) if proposal is fine or # 1 (false) if some incompatible symlinks were removed +# initializes global hashmap compatible_modules with all the valid ones validate_weak_links() { local krel="$1" local basedir=${BASEDIR:+-b $BASEDIR} @@ -715,6 +755,7 @@ validate_weak_links() { local is_configuration_valid=0 tmp=$(mktemp -p $tmpdir) + compatible_modules=() if ! [[ -e $tmpdir/symvers-$krel ]]; then local symvers_path=$(find_symvers_file "$krel") @@ -779,6 +820,9 @@ validate_weak_links() { module_krel=$(krel_of_module $target) if [[ "$module" == "$target" ]]; then + short_name="$(module_short_name "$module")" + compatible_modules+=([$short_name]="$module") + pr_verbose "Module ${module##*/} from kernel $module_krel is compatible with kernel $krel" fi done @@ -877,9 +921,12 @@ add_modules() { # do_make_groups: # Takes tmp file which contains preprocessed modules.dep # output (or modules.dep) +# # reads modules.dep format information from stdin # produces groups associative array # the group is a maximum subset of modules having at least a link +# +# more fine tuned extra filtering. do_make_groups() { local tmp="$1" @@ -890,6 +937,8 @@ do_make_groups() while read i; do mods=($i) + echo "${mods[0]}" |grep -q "extra/" || continue + # if the module already met, then its dependencies already counted module_group="${grouped_modules[${mods[0]}]}" [[ -n $module_group ]] && continue @@ -898,6 +947,8 @@ do_make_groups() group_name="${mods[0]}" for mod in "${mods[@]}"; do + echo "$mod" |grep -q "extra/" || continue + # if there is already such group, # it is a subset of the one being created # due to depmod output @@ -915,26 +966,32 @@ do_make_groups() # preprocess output for make_groups # depmod -n produces also aliases, so it cuts them off # also it removes colon after the first module -filter_depmod_deps() +cut_depmod_deps() { awk 'BEGIN { pr = 1 } /^#/{ pr = 0 } pr == 1 {sub(":",""); print $0}' } -# make_abs_path: +# filter_extra_absoluted: # Takes kernel version # makes full path from the relative module path # (produced by depmod for in-kernel-dir modules) -make_abs_path() +# filter only extra/ modules +filter_extra_absoluted() { local kver="$1" local mod declare -a mods while read i; do + # skip non-extra. The check is not perfect, but ok + # to speed up handling in general cases + echo "$i" |grep -q "extra/" || continue + mods=($i) for j in "${!mods[@]}"; do mod="${mods[$j]}" - [[ ${mod:0:1} == "/" ]] || mod="/lib/modules/$kver/$mod" + + [[ ${mod:0:1} == "/" ]] || mod="$BASEDIR/lib/modules/$kver/$mod" mods[$j]="$mod" done echo "${mods[@]}" @@ -942,20 +999,20 @@ make_abs_path() } # make_groups: -# takes krel and a file with the list of modules, +# takes k -- kernel version, we are installing extras from # prepares and feeds to do_make_groups # to create the module groups (global) make_groups() { - local krel="$1" - local tmp1="$2" + local k="$1" local tmp2=$(mktemp -p $tmpdir) + local basedir=${BASEDIR:+-b $BASEDIR} groups=() grouped_modules=() - $depmod -n $krel $(cat $tmp1) 2>/dev/null | - filter_depmod_deps | make_abs_path $krel > $tmp2 + $depmod -n $basedir $k 2>/dev/null | + cut_depmod_deps | filter_extra_absoluted $k > $tmp2 do_make_groups $tmp2 @@ -976,11 +1033,11 @@ add_kernel() { exit 1 fi - for k in $(find_kernels_with_extra | rpmsort); do + for k in $(find_kernels_with_extra | rpmsort -r); do [[ "$krel" == "$k" ]] && continue find_modules $k extra > $tmp - is_empty_file "$tmp" || make_groups $krel $tmp + is_empty_file "$tmp" || make_groups $k # reuse tmp diff --git a/SPECS/kmod.spec b/SPECS/kmod.spec index 0b4bb5e..cf0fad5 100644 --- a/SPECS/kmod.spec +++ b/SPECS/kmod.spec @@ -1,6 +1,6 @@ Name: kmod Version: 25 -Release: 13%{?dist} +Release: 16%{?dist} Summary: Linux kernel module management utilities Group: System Environment/Kernel @@ -13,6 +13,7 @@ Exclusiveos: Linux Patch01: kmod-signature-do-not-report-wrong-data-for-pkc-7-signatu.patch Patch02: kmod-libkmod-signature-implement-pkcs7-parsing-with-opens.patch +Patch03: kmod-modprobe-ignore-builtin-module-on-recursive-removing.patch BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) BuildRequires: chrpath @@ -55,6 +56,7 @@ applications that wish to load or unload Linux kernel modules. %setup -q %patch01 -p1 %patch02 -p1 +%patch03 -p1 %build export V=1 @@ -123,6 +125,19 @@ install -m 0644 %{SOURCE2} $RPM_BUILD_ROOT%{_sysconfdir}/depmod.d/dist.conf %{_libdir}/libkmod.so %changelog +* Mon Dec 9 2019 Yauheni Kaliuta - 25-16 +- weak-modules: update_modules_for_krel: always finish sandbox +- weak-modules: groupping: use dependencies of extra/ provider + Resolves: rhbz#1778889 + +* Mon Dec 9 2019 Yauheni Kaliuta - 25-15 +- weak-modules: reverse checking order for add-kernel + Resolves: rhbz#1755196 + +* Mon Dec 2 2019 Yauheni Kaliuta - 25-14 +- modprobe: do not fail on built-in modules + Resolves: rhbz#1767513 + * Tue Apr 16 2019 Yauheni Kaliuta - 25-13 - weak-modules: handle independent modules in one run Resolves: rhbz#1695763