Blob Blame History Raw
From 794b2d2c753489635b922457a5ccb06669f37268 Mon Sep 17 00:00:00 2001
From: Harald Hoyer <harald@redhat.com>
Date: Thu, 23 Jul 2015 10:35:06 +0200
Subject: [PATCH] Use dracut-install to install kernel modules

dracut-install can now install kernel modules and their corresponding
firmware files.
---
 Makefile                                           |   1 +
 dracut-init.sh                                     | 178 +------
 dracut.sh                                          |   8 +-
 install/dracut-install.c                           | 536 +++++++++++++++++++--
 modules.d/50drm/module-setup.sh                    |  63 +--
 modules.d/90crypt/module-setup.sh                  |   4 +-
 modules.d/90dm/module-setup.sh                     |   3 +-
 modules.d/90kernel-modules/module-setup.sh         |  53 +-
 modules.d/90kernel-network-modules/module-setup.sh |  45 +-
 modules.d/90multipath/module-setup.sh              |  39 +-
 modules.d/95iscsi/module-setup.sh                  |  41 +-
 modules.d/95nfs/module-setup.sh                    |   2 +-
 12 files changed, 580 insertions(+), 393 deletions(-)

diff --git a/Makefile b/Makefile
index 8281f90..0a1ae6c 100644
--- a/Makefile
+++ b/Makefile
@@ -61,6 +61,7 @@ install/util.o: install/util.c install/util.h install/macro.h install/log.h
 install/strv.o: install/strv.c install/strv.h install/util.h install/macro.h install/log.h
 
 install/dracut-install: $(DRACUT_INSTALL_OBJECTS)
+	$(CC) $(LDFLAGS) -o $@ $(DRACUT_INSTALL_OBJECTS) $(LDLIBS) -lkmod
 
 dracut-install: install/dracut-install
 	ln -fs $< $@
diff --git a/dracut-init.sh b/dracut-init.sh
index a8b78ce..e26d97a 100644
--- a/dracut-init.sh
+++ b/dracut-init.sh
@@ -218,6 +218,13 @@ dracut_install() {
     inst_multiple "$@"
 }
 
+dracut_instmods() {
+    [[ $no_kernel = yes ]] && return
+    $DRACUT_INSTALL \
+        ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${hostonly:+-H} ${omit_drivers:+-N "$omit_drivers"} ${srcmods:+--kerneldir "$srcmods"} -m "$@"
+    (($? != 0)) && derror FAILED: $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${hostonly:+-H} ${omit_drivers:+-N "$omit_drivers"} ${srcmods:+--kerneldir "$srcmods"} -m "$@" || :
+}
+
 inst_library() {
     local _hostonly_install
     if [[ "$1" == "-H" ]]; then
@@ -847,11 +854,6 @@ install_kmod_with_fw() {
     [[ -e "${initdir}/lib/modules/$kernel/${1##*/lib/modules/$kernel/}" ]] \
         && return 0
 
-    if [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && [[ -e "$DRACUT_KERNEL_LAZY_HASHDIR/${1##*/}" ]]; then
-        read ret < "$DRACUT_KERNEL_LAZY_HASHDIR/${1##*/}"
-        return $ret
-    fi
-
     if [[ $omit_drivers ]]; then
         local _kmod=${1##*/}
         _kmod=${_kmod%.ko*}
@@ -876,9 +878,6 @@ install_kmod_with_fw() {
 
     inst_simple "$1" "/lib/modules/$kernel/${1##*/lib/modules/$kernel/}"
     ret=$?
-    [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && \
-        [[ -d "$DRACUT_KERNEL_LAZY_HASHDIR" ]] && \
-        echo $ret > "$DRACUT_KERNEL_LAZY_HASHDIR/${1##*/}"
     (($ret != 0)) && return $ret
 
     local _modname=${1##*/} _fwdir _found _fw
@@ -925,51 +924,6 @@ dracut_kernel_post() {
     local _moddirname=${srcmods%%/lib/modules/*}
     local _pid
 
-    if [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && [[ -f "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist" ]]; then
-        xargs -r modprobe -a ${_moddirname:+-d ${_moddirname}/} \
-            --ignore-install --show-depends --set-version $kernel \
-            < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist" 2>/dev/null \
-            | sort -u \
-            | while read _cmd _modpath _options || [ -n "$_cmd" ]; do
-            [[ $_cmd = insmod ]] || continue
-            echo "$_modpath"
-        done > "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep"
-
-        (
-            if [[ $DRACUT_INSTALL ]] && [[ -z $_moddirname ]]; then
-                xargs -r $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} -a < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep"
-            else
-                while read _modpath || [ -n "$_modpath" ]; do
-                    local _destpath=$_modpath
-                    [[ $_moddirname ]] && _destpath=${_destpath##$_moddirname/}
-                    _destpath=${_destpath##*/lib/modules/$kernel/}
-                    inst_simple "$_modpath" "/lib/modules/$kernel/${_destpath}" || exit $?
-                done < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep"
-            fi
-        ) &
-        _pid=$(jobs -p | while read a  || [ -n "$a" ]; do printf ":$a";done)
-        _pid=${_pid##*:}
-
-        if [[ $DRACUT_INSTALL ]]; then
-            xargs -r modinfo -k $kernel -F firmware < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep" \
-                | while read line || [ -n "$line" ]; do
-                for _fwdir in $fw_dir; do
-                    echo $_fwdir/$line;
-                done;
-            done | xargs -r $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} -a -o
-        else
-            for _fw in $(xargs -r modinfo -k $kernel -F firmware < "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist.dep"); do
-                for _fwdir in $fw_dir; do
-                    [[ -d $_fwdir && -f $_fwdir/$_fw ]] || continue
-                    inst_simple "$_fwdir/$_fw" "/lib/firmware/$_fw"
-                    break
-                done
-            done
-        fi
-
-        wait $_pid
-    fi
-
     for _f in modules.builtin.bin modules.builtin modules.order; do
         [[ $srcmods/$_f ]] && inst_simple "$srcmods/$_f" "/lib/modules/$kernel/$_f"
     done
@@ -981,7 +935,6 @@ dracut_kernel_post() {
         exit 1
     fi
 
-    [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && rm -fr -- "$DRACUT_KERNEL_LAZY_HASHDIR"
 }
 
 [[ "$kernel_current" ]] || export kernel_current=$(uname -r)
@@ -1038,113 +991,32 @@ find_kernel_modules () {
     find_kernel_modules_by_path  drivers
 }
 
-# instmods [-c [-s]] <kernel module> [<kernel module> ... ]
-# instmods [-c [-s]] <kernel subsystem>
-# install kernel modules along with all their dependencies.
-# <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
 instmods() {
+    # instmods [-c [-s]] <kernel module> [<kernel module> ... ]
+    # instmods [-c [-s]] <kernel subsystem>
+    # install kernel modules along with all their dependencies.
+    # <kernel subsystem> can be e.g. "=block" or "=drivers/usb/storage"
+    # -c check
+    # -s silent
+    local _optional="-o"
+    local _silent
+    local _ret
     [[ $no_kernel = yes ]] && return
-    # called [sub]functions inherit _fderr
-    local _fderr=9
-    local _check=no
-    local _silent=no
     if [[ $1 = '-c' ]]; then
-        _check=yes
+        _optional=""
         shift
     fi
-
     if [[ $1 = '-s' ]]; then
-        _silent=yes
+        _silent=1
         shift
     fi
-
-    function inst1mod() {
-        local _ret=0 _mod="$1"
-        case $_mod in
-            =*)
-                ( [[ "$_mpargs" ]] && echo $_mpargs
-                    find_kernel_modules_by_path "${_mod#=}" ) \
-                        | instmods
-                ((_ret+=$?))
-                ;;
-            --*) _mpargs+=" $_mod" ;;
-            *)
-                _mod=${_mod##*/}
-                # Check for aliased modules
-                _modalias=$(modinfo -k $kernel -F filename $_mod 2> /dev/null)
-                _modalias=${_modalias%.ko*}
-                if [[ $_modalias ]] && [ "${_modalias##*/}" != "${_mod%.ko*}" ] ; then
-                    _mod=${_modalias##*/}
-                fi
-
-                # if we are already installed, skip this module and go on
-                # to the next one.
-                if [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && \
-                    [[ -f "$DRACUT_KERNEL_LAZY_HASHDIR/${_mod%.ko*}" ]]; then
-                    read _ret <"$DRACUT_KERNEL_LAZY_HASHDIR/${_mod%.ko*}"
-                    return $_ret
-                fi
-
-                _mod=${_mod/-/_}
-                if [[ $omit_drivers ]] && [[ "$_mod" =~ $omit_drivers ]]; then
-                    dinfo "Omitting driver ${_mod##$srcmods}"
-                    return 0
-                fi
-
-                # If we are building a host-specific initramfs and this
-                # module is not already loaded, move on to the next one.
-                [[ $hostonly ]] \
-                    && ! module_is_host_only "$_mod" \
-                    && return 0
-
-                if [[ "$_check" = "yes" ]] || ! [[ $DRACUT_KERNEL_LAZY_HASHDIR ]]; 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.
-                    local _moddirname=${srcmods%%/lib/modules/*}
-                    [[ -n ${_moddirname} ]] && _moddirname="-d ${_moddirname}/"
-
-                    # ok, load the module, all its dependencies, and any firmware
-                    # it may require
-                    for_each_kmod_dep install_kmod_with_fw $_mod \
-                        --set-version $kernel ${_moddirname} $_mpargs
-                    ((_ret+=$?))
-                else
-                    [[ $DRACUT_KERNEL_LAZY_HASHDIR ]] && \
-                        echo ${_mod%.ko*} >> "$DRACUT_KERNEL_LAZY_HASHDIR/lazylist"
-                fi
-                ;;
-        esac
-        return $_ret
-    }
-
-    function instmods_1() {
-        local _mod _mpargs
-        if (($# == 0)); then  # filenames from stdin
-            while read _mod || [ -n "$_mod" ]; do
-                inst1mod "${_mod%.ko*}" || {
-                    if [[ "$_check" == "yes" ]] && [[ "$_silent" == "no" ]]; then
-                        dfatal "Failed to install module $_mod"
-                    fi
-                }
-            done
-        fi
-        while (($# > 0)); do  # filenames as arguments
-            inst1mod ${1%.ko*} || {
-                if [[ "$_check" == "yes" ]] && [[ "$_silent" == "no" ]]; then
-                    dfatal "Failed to install module $1"
-                fi
-            }
-            shift
-        done
-        return 0
-    }
-
-    local _ret _filter_not_found='FATAL: Module .* not found.'
-    # Capture all stderr from modprobe to _fderr. We could use {var}>...
-    # redirections, but that would make dracut require bash4 at least.
-    eval "( instmods_1 \"\$@\" ) ${_fderr}>&1" \
-        | while read line || [ -n "$line" ]; do [[ "$line" =~ $_filter_not_found ]] || echo $line;done | derror
+    if (($# == 0)); then
+        read -r -d '' -a args
+        set -- "${args[@]}"
+    fi
+    $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"}  ${hostonly:+-H} ${omit_drivers:+-N "$omit_drivers"} ${_optional:+-o} ${_silent:+--silent} ${srcmods:+--kerneldir "$srcmods"} -m "$@"
     _ret=$?
+    (($_ret != 0)) && [[ -z "$_silent" ]] && derror FAILED: $DRACUT_INSTALL ${initdir:+-D "$initdir"} ${loginstall:+-L "$loginstall"} ${hostonly:+-H} ${omit_drivers:+-N "$omit_drivers"} ${_optional:+-o} ${_silent:+--silent} ${srcmods:+--kerneldir "$srcmods"} -m "$@" || :
+    [[ "$optional" ]] && return 0
     return $_ret
 }
diff --git a/dracut.sh b/dracut.sh
index 37ae350..f6d0439 100755
--- a/dracut.sh
+++ b/dracut.sh
@@ -733,7 +733,7 @@ stdloglvl=$((stdloglvl + verbosity_mod_l))
 [[ $mdadmconf_l ]] && mdadmconf=$mdadmconf_l
 [[ $lvmconf_l ]] && lvmconf=$lvmconf_l
 [[ $dracutbasedir ]] || dracutbasedir=/usr/lib/dracut
-[[ $fw_dir ]] || fw_dir="/lib/firmware/updates /lib/firmware /lib/firmware/$kernel"
+[[ $fw_dir ]] || fw_dir="/lib/firmware/updates:/lib/firmware:/lib/firmware/$kernel"
 [[ $tmpdir_l ]] && tmpdir="$tmpdir_l"
 [[ $tmpdir ]] || tmpdir=/var/tmp
 [[ $INITRD_COMPRESS ]] && compress=$INITRD_COMPRESS
@@ -750,6 +750,7 @@ stdloglvl=$((stdloglvl + verbosity_mod_l))
 [[ $kernel_image_l ]] && kernel_image="$kernel_image_l"
 
 # eliminate IFS hackery when messing with fw_dir
+export DRACUT_FIRMWARE_PATH=${fw_dir// /:}
 fw_dir=${fw_dir//:/ }
 
 # check for logfile and try to create one if it doesn't exist
@@ -839,7 +840,6 @@ trap '
 # clean up after ourselves no matter how we die.
 trap 'exit 1;' SIGINT
 
-export DRACUT_KERNEL_LAZY="1"
 export DRACUT_RESOLVE_LAZY="1"
 
 if [[ $print_cmdline ]]; then
@@ -1436,9 +1436,9 @@ if [[ $no_kernel != yes ]]; then
         hostonly='' instmods -c $filesystems
     fi
 
-    dinfo "*** Installing kernel module dependencies and firmware ***"
+    dinfo "*** Installing kernel module dependencies ***"
     dracut_kernel_post
-    dinfo "*** Installing kernel module dependencies and firmware done ***"
+    dinfo "*** Installing kernel module dependencies done ***"
 
     if [[ $noimageifnotneeded == yes ]] && [[ $hostonly ]]; then
         if [[ ! -f "$initdir/lib/dracut/need-initqueue" ]] && \
diff --git a/install/dracut-install.c b/install/dracut-install.c
index 3b48ba8..a20e06c 100644
--- a/install/dracut-install.c
+++ b/install/dracut-install.c
@@ -22,7 +22,7 @@
 #ifndef _GNU_SOURCE
 #define _GNU_SOURCE
 #endif
-
+#undef _FILE_OFFSET_BITS
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -38,6 +38,9 @@
 #include <sys/wait.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
+#include <libkmod.h>
+#include <fts.h>
+#include <regex.h>
 
 #include "log.h"
 #include "hashmap.h"
@@ -48,16 +51,31 @@ static bool arg_hmac = false;
 static bool arg_createdir = false;
 static int arg_loglevel = -1;
 static bool arg_optional = false;
+static bool arg_silent = false;
 static bool arg_all = false;
+static bool arg_module = false;
 static bool arg_resolvelazy = false;
 static bool arg_resolvedeps = false;
 static bool arg_hostonly = false;
 static char *destrootdir = NULL;
+static char *kerneldir = NULL;
+static char **firmwaredirs = NULL;
+static char **pathdirs;
 static char *logdir = NULL;
 static char *logfile = NULL;
 FILE *logfile_f = NULL;
 static Hashmap *items = NULL;
 static Hashmap *items_failed = NULL;
+static regex_t mod_filter_path;
+static regex_t mod_filter_nopath;
+static regex_t mod_filter_symbol;
+static regex_t mod_filter_nosymbol;
+static regex_t mod_filter_noname;
+static bool arg_mod_filter_path = false;
+static bool arg_mod_filter_nopath = false;
+static bool arg_mod_filter_symbol = false;
+static bool arg_mod_filter_nosymbol = false;
+static bool arg_mod_filter_noname = false;
 
 static int dracut_install(const char *src, const char *dst, bool isdir, bool resolvedeps, bool hashdst);
 
@@ -516,6 +534,18 @@ void dracut_log_cp(const char *path)
                 log_error("Could not append '%s' to logfile '%s': %m", path, logfile);
 }
 
+static bool check_hashmap(Hashmap *hm, const char *item)
+{
+        char *existing;
+        existing = hashmap_get(hm, item);
+        if (existing) {
+                if (strcmp(existing, item) == 0) {
+                        return true;
+                }
+        }
+        return false;
+}
+
 static int dracut_install(const char *src, const char *dst, bool isdir, bool resolvedeps, bool hashdst)
 {
         struct stat sb, db;
@@ -524,26 +554,17 @@ static int dracut_install(const char *src, const char *dst, bool isdir, bool res
         int ret;
         bool src_exists = true;
         char *i = NULL;
-        char *existing;
 
         log_debug("dracut_install('%s', '%s')", src, dst);
 
-        existing = hashmap_get(items_failed, src);
-        if (existing) {
-                if (strcmp(existing, src) == 0) {
-                        log_debug("hash hit items_failed for '%s'", src);
-                        return 1;
-                }
+        if (check_hashmap(items_failed, src)) {
+                log_debug("hash hit items_failed for '%s'", src);
+                return 1;
         }
 
-        if (hashdst) {
-                existing = hashmap_get(items, dst);
-                if (existing) {
-                        if (strcmp(existing, dst) == 0) {
-                                log_debug("hash hit items for '%s'", dst);
-                                return 0;
-                        }
-                }
+        if (hashdst && check_hashmap(items, dst)) {
+                log_debug("hash hit items for '%s'", dst);
+                return 0;
         }
 
         if (lstat(src, &sb) < 0) {
@@ -678,7 +699,7 @@ static int dracut_install(const char *src, const char *dst, bool isdir, bool res
         log_debug("dracut_install ret = %d", ret);
         log_info("cp '%s' '%s'", src, fulldstpath);
 
-        if (arg_hostonly)
+        if (arg_hostonly && !arg_module)
                 mark_hostonly(dst);
 
         ret += cp(src, fulldstpath);
@@ -751,6 +772,9 @@ static int parse_argv(int argc, char *argv[])
 
         enum {
                 ARG_VERSION = 0x100,
+                ARG_SILENT,
+                ARG_KERNELDIR,
+                ARG_FIRMWAREDIRS,
                 ARG_DEBUG
         };
 
@@ -765,13 +789,22 @@ static int parse_argv(int argc, char *argv[])
                 {"optional", no_argument, NULL, 'o'},
                 {"hostonly", no_argument, NULL, 'H'},
                 {"all", no_argument, NULL, 'a'},
+                {"module", no_argument, NULL, 'm'},
                 {"fips", no_argument, NULL, 'f'},
                 {"destrootdir", required_argument, NULL, 'D'},
                 {"logdir", required_argument, NULL, 'L'},
+                {"mod-filter-path", required_argument, NULL, 'p'},
+                {"mod-filter-nopath", required_argument, NULL, 'P'},
+                {"mod-filter-symbol", required_argument, NULL, 's'},
+                {"mod-filter-nosymbol", required_argument, NULL, 'S'},
+                {"mod-filter-noname", required_argument, NULL, 'N'},
+                {"silent", no_argument, NULL, ARG_SILENT},
+                {"kerneldir", required_argument, NULL, ARG_KERNELDIR},
+                {"firmwaredirs", required_argument, NULL, ARG_FIRMWAREDIRS},
                 {NULL, 0, NULL, 0}
         };
 
-        while ((c = getopt_long(argc, argv, "adfhlL:oD:HR", options, NULL)) != -1) {
+        while ((c = getopt_long(argc, argv, "madfhlL:oD:HRp:P:s:S:N:", options, NULL)) != -1) {
                 switch (c) {
                 case ARG_VERSION:
                         puts(PROGRAM_VERSION_STRING);
@@ -782,6 +815,9 @@ static int parse_argv(int argc, char *argv[])
                 case ARG_DEBUG:
                         arg_loglevel = LOG_DEBUG;
                         break;
+                case ARG_SILENT:
+                        arg_silent = true;
+                        break;
                 case 'v':
                         arg_loglevel = LOG_INFO;
                         break;
@@ -797,12 +833,56 @@ static int parse_argv(int argc, char *argv[])
                 case 'a':
                         arg_all = true;
                         break;
+                case 'm':
+                        arg_module = true;
+                        break;
                 case 'D':
                         destrootdir = strdup(optarg);
                         break;
+                case 'p':
+                        if (regcomp(&mod_filter_path, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
+                                log_error("Module path filter %s is not a regular expression", optarg);
+                                exit(EXIT_FAILURE);
+                        }
+                        arg_mod_filter_path = true;
+                        break;
+                case 'P':
+                        if (regcomp(&mod_filter_nopath, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
+                                log_error("Module path filter %s is not a regular expression", optarg);
+                                exit(EXIT_FAILURE);
+                        }
+                        arg_mod_filter_nopath = true;
+                        break;
+                case 's':
+                        if (regcomp(&mod_filter_symbol, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
+                                log_error("Module symbol filter %s is not a regular expression", optarg);
+                                exit(EXIT_FAILURE);
+                        }
+                        arg_mod_filter_symbol = true;
+                        break;
+                case 'S':
+                        if (regcomp(&mod_filter_nosymbol, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
+                                log_error("Module symbol filter %s is not a regular expression", optarg);
+                                exit(EXIT_FAILURE);
+                        }
+                        arg_mod_filter_nosymbol = true;
+                        break;
+                case 'N':
+                        if (regcomp(&mod_filter_noname, optarg, REG_NOSUB|REG_EXTENDED) != 0) {
+                                log_error("Module symbol filter %s is not a regular expression", optarg);
+                                exit(EXIT_FAILURE);
+                        }
+                        arg_mod_filter_noname = true;
+                        break;
                 case 'L':
                         logdir = strdup(optarg);
                         break;
+                case ARG_KERNELDIR:
+                        kerneldir = strdup(optarg);
+                        break;
+                case ARG_FIRMWAREDIRS:
+                        firmwaredirs = strv_split(optarg, ":");
+                        break;
                 case 'f':
                         arg_hmac = true;
                         break;
@@ -817,6 +897,22 @@ static int parse_argv(int argc, char *argv[])
                 }
         }
 
+        if (arg_module) {
+                if (!firmwaredirs) {
+                        char *path = NULL;
+
+                        path = getenv("DRACUT_FIRMWARE_PATH");
+
+                        if (path == NULL) {
+                                log_error("Environment variable DRACUT_FIRMWARE_PATH is not set");
+                                exit(EXIT_FAILURE);
+                        }
+
+                        log_debug("DRACUT_FIRMWARE_PATH=%s", path);
+
+                        firmwaredirs = strv_split(path, ":");
+                }
+        }
         if (!optind || optind == argc) {
                 log_error("No SOURCE argument given");
                 usage(EXIT_FAILURE);
@@ -858,24 +954,11 @@ static int resolve_lazy(int argc, char **argv)
 
 static char **find_binary(const char *src)
 {
-        char *path = NULL;
-        _cleanup_strv_free_ char **p = NULL;
         char **ret = NULL;
         char **q;
         char *newsrc = NULL;
 
-        path = getenv("PATH");
-
-        if (path == NULL) {
-                log_error("PATH is not set");
-                exit(EXIT_FAILURE);
-        }
-
-        log_debug("PATH=%s", path);
-
-        p = strv_split(path, ":");
-
-        STRV_FOREACH(q, p) {
+        STRV_FOREACH(q, pathdirs) {
                 struct stat sb;
                 int r;
 
@@ -976,10 +1059,381 @@ static int install_all(int argc, char **argv)
         return r;
 }
 
+static int install_firmware(struct kmod_module *mod)
+{
+        struct kmod_list *l, *list = NULL;
+        int ret;
+
+        char **q;
+
+        ret = kmod_module_get_info(mod, &list);
+        if (ret < 0) {
+                log_error("could not get modinfo from '%s': %s\n",
+                          kmod_module_get_name(mod), strerror(-ret));
+                return ret;
+        }
+        kmod_list_foreach(l, list) {
+                const char *key = kmod_module_info_get_key(l);
+                const char *value = NULL;
+                char *fwpath = NULL;
+
+                if (!streq("firmware", key))
+                        continue;
+
+                value = kmod_module_info_get_value(l);
+                log_debug("Firmware %s", value);
+                ret = -1;
+                STRV_FOREACH(q, firmwaredirs) {
+                        struct stat sb;
+                        int r;
+
+                        r = asprintf(&fwpath, "%s/%s", *q, value);
+                        if (r < 0) {
+                                log_error("Out of memory!");
+                                exit(EXIT_FAILURE);
+                        }
+
+                        if (stat(fwpath, &sb) != 0) {
+                                log_debug("stat(%s) != 0", fwpath);
+                                free(fwpath);
+                                fwpath = NULL;
+                                continue;
+                        }
+
+                        ret = dracut_install(fwpath, fwpath, false, false, true);
+                        if (ret == 0)
+                                log_debug("dracut_install '%s' OK", fwpath);
+                }
+
+                if (ret != 0) {
+                        log_info("Possible missing firmware %s for kernel module %s", value, kmod_module_get_name(mod));
+                }
+        }
+        return 0;
+}
+
+static bool check_module_symbols(struct kmod_module *mod)
+{
+        struct kmod_list *itr, *deplist = NULL;
+
+        if (!arg_mod_filter_symbol && !arg_mod_filter_nosymbol)
+                return true;
+
+        if (kmod_module_get_dependency_symbols(mod, &deplist) < 0) {
+                log_debug("kmod_module_get_dependency_symbols failed");
+                if (arg_mod_filter_symbol)
+                        return false;
+                return true;
+        }
+
+        if (arg_mod_filter_nosymbol) {
+                kmod_list_foreach(itr, deplist) {
+                        const char *symbol = kmod_module_symbol_get_symbol(itr);
+                        // log_debug("Checking symbol %s", symbol);
+                        if (regexec(&mod_filter_nosymbol, symbol, 0, NULL, 0) == 0) {
+                                kmod_module_dependency_symbols_free_list(deplist);
+                                log_debug("Module %s: symbol %s matched exclusion filter", kmod_module_get_name(mod), symbol);
+                                return false;
+                        }
+                }
+        }
+
+        if (arg_mod_filter_symbol) {
+                kmod_list_foreach(itr, deplist) {
+                        const char *symbol = kmod_module_dependency_symbol_get_symbol(itr);
+                        // log_debug("Checking symbol %s", symbol);
+                        if (regexec(&mod_filter_symbol, symbol, 0, NULL, 0) == 0) {
+                                kmod_module_dependency_symbols_free_list(deplist);
+                                log_debug("Module %s: symbol %s matched inclusion filter", kmod_module_get_name(mod), symbol);
+                                return true;
+                        }
+                }
+                kmod_module_dependency_symbols_free_list(deplist);
+                return false;
+        }
+
+        kmod_module_dependency_symbols_free_list(deplist);
+        return true;
+}
+
+
+static bool check_module_path(const char *path)
+{
+        if (arg_mod_filter_nopath && (regexec(&mod_filter_nopath, path, 0, NULL, 0) == 0)) {
+                log_debug("Path %s matched exclusion filter", path);
+                return false;
+        }
+
+        if (arg_mod_filter_path && (regexec(&mod_filter_path, path, 0, NULL, 0) != 0)) {
+                log_debug("Path %s matched inclusion filter", path);
+                return false;
+        }
+        return true;
+}
+
+static int install_module(struct kmod_module *mod)
+{
+        int ret = 0;
+        int state;
+        struct kmod_list *itr, *modlist = NULL;
+        const char *path = NULL;
+        const char *name = NULL;
+        state = kmod_module_get_initstate(mod);
+
+        name = kmod_module_get_name(mod);
+        if (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0))
+                return 0;
+
+        if (arg_hostonly && (state != KMOD_MODULE_BUILTIN) && (state != KMOD_MODULE_LIVE)) {
+                log_debug("dracut_install '%s' not hostonly", name);
+                return 0;
+        }
+
+        path = kmod_module_get_path(mod);
+        if (!path)
+                return -ENOENT;
+
+        if (check_hashmap(items_failed, path))
+                return 1;
+
+        if (check_hashmap(items, path))
+                return 0;
+
+        if (!check_module_path(path) || !check_module_symbols(mod)) {
+                log_debug("No symbol or patch match for '%s'", path);
+                return 0;
+        }
+
+        log_debug("dracut_install '%s'", path);
+        ret = dracut_install(path, path, false, false, true);
+        if (ret == 0) {
+                log_debug("dracut_install '%s' OK", kmod_module_get_name(mod));
+        } else if (!arg_optional) {
+                if (!arg_silent)
+                        log_error("dracut_install '%s' ERROR", kmod_module_get_name(mod));
+                return ret;
+        }
+        install_firmware(mod);
+
+        modlist = kmod_module_get_dependencies(mod);
+        kmod_list_foreach(itr, modlist) {
+                mod = kmod_module_get_module(itr);
+                path = kmod_module_get_path(mod);
+                name = kmod_module_get_name(mod);
+                if (arg_mod_filter_noname && (regexec(&mod_filter_noname, name, 0, NULL, 0) == 0)) {
+                        kmod_module_unref(mod);
+                        continue;
+                }
+                ret = dracut_install(path, path, false, false, true);
+                if (ret == 0) {
+                        log_debug("dracut_install '%s' OK", kmod_module_get_name(mod));
+                        install_firmware(mod);
+                } else {
+                        log_error("dracut_install '%s' ERROR", kmod_module_get_name(mod));
+                }
+                kmod_module_unref(mod);
+        }
+        kmod_module_unref_list(modlist);
+
+        return ret;
+}
+
+static int install_modules(int argc, char **argv)
+{
+        struct kmod_ctx *ctx = NULL;
+        struct kmod_list *itr, *modlist = NULL;
+        struct kmod_module *mod = NULL, *mod_o = NULL;
+
+        const char *modname = NULL;
+        int i;
+
+        ctx = kmod_new(kerneldir, NULL);
+
+        for (i = 0; i < argc; i++) {
+                int r = 0;
+                int ret = 0;
+                log_debug("Handle module '%s'", argv[i]);
+
+                if (argv[i][0] == '/') {
+                        r = kmod_module_new_from_path(ctx, argv[i], &mod_o);
+                        if (r < 0) {
+                                log_debug("Failed to lookup modules path '%s': %m", argv[i]);
+                                if (!arg_optional)
+                                        return -ENOENT;
+                                continue;
+                        }
+                        /* Check, if we have to load another module with that name instead */
+                        modname = kmod_module_get_name(mod_o);
+                        if (!modname) {
+                                if (!arg_optional) {
+                                        if (!arg_silent)
+                                                log_error("Failed to get name for module '%s'", argv[i]);
+                                        return -ENOENT;
+                                }
+                                log_info("Failed to get name for module '%s'", argv[i]);
+                                continue;
+                        }
+                        r = kmod_module_new_from_lookup(ctx, modname, &modlist);
+                        kmod_module_unref(mod_o);
+                        if (r < 0) {
+                                if (!arg_optional) {
+                                        if (!arg_silent)
+                                                log_error("3 Failed to lookup alias '%s': %d", modname, r);
+                                        return -ENOENT;
+                                }
+                                log_info("3 Failed to lookup alias '%s': %d", modname, r);
+                                continue;
+                        }
+                        if (!modlist) {
+                                if (!arg_optional) {
+                                        if (!arg_silent)
+                                                log_error("Failed to find module '%s' %s", modname, argv[i]);
+                                        return -ENOENT;
+                                }
+                                log_info("Failed to find module '%s' %s", modname, argv[i]);
+                                continue;
+                        }
+                        kmod_list_foreach(itr, modlist) {
+                                mod = kmod_module_get_module(itr);
+                                ret = install_module(mod);
+                        }
+                        kmod_module_unref_list(modlist);
+                        modlist = 0;
+                } else if (argv[i][0] == '=') {
+                        char *path1, *path2, *path3;
+                        FTS *fts;
+                        log_debug("Handling =%s", &argv[i][1]);
+                        /* FIXME and add more paths*/
+                        {
+                                int r;
+                                r = asprintf(&path2, "%s/kernel/%s", kerneldir, &argv[i][1]);
+                                if (r < 0) {
+                                        log_error("Out of memory!");
+                                        exit(EXIT_FAILURE);
+                                }
+
+                                r = asprintf(&path1, "%s/extra/%s", kerneldir, &argv[i][1]);
+                                if (r < 0) {
+                                        log_error("Out of memory!");
+                                        exit(EXIT_FAILURE);
+                                }
+
+                                r = asprintf(&path3, "%s/updates/%s", kerneldir, &argv[i][1]);
+                                if (r < 0) {
+                                        log_error("Out of memory!");
+                                        exit(EXIT_FAILURE);
+                                }
+
+                                char *paths[] = { path1, path2, path3, NULL };
+                                fts = fts_open(paths, FTS_COMFOLLOW|FTS_NOCHDIR|FTS_NOSTAT|FTS_LOGICAL, NULL);
+                        }
+                        for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
+                                if((ftsent->fts_info == FTS_D) && !check_module_path(ftsent->fts_accpath)) {
+                                        fts_set(fts, ftsent, FTS_SKIP);
+                                        log_debug("Skipping %s", ftsent->fts_accpath);
+                                        continue;
+                                }
+                                if((ftsent->fts_info != FTS_F) && (ftsent->fts_info != FTS_SL)) {
+                                        log_debug("Ignoring %s", ftsent->fts_accpath);
+                                        continue;
+                                }
+                                log_debug("Handling %s", ftsent->fts_accpath);
+                                r = kmod_module_new_from_path(ctx, ftsent->fts_accpath, &mod_o);
+                                if (r < 0) {
+                                        log_debug("Failed to lookup modules path '%s': %m", ftsent->fts_accpath);
+                                        continue;
+                                }
+#if 1
+                                /* Check, if we have to load another module with that name instead */
+                                modname = kmod_module_get_name(mod_o);
+                                if (!modname) {
+                                        log_error("Failed to get name for module '%s'", ftsent->fts_accpath);
+                                        continue;
+                                }
+                                r = kmod_module_new_from_lookup(ctx, modname, &modlist);
+                                kmod_module_unref(mod_o);
+                                if (r < 0) {
+                                        log_error("2 Failed to lookup alias '%s': %m", modname);
+                                        kmod_module_unref_list(modlist);
+                                        continue;
+                                }
+                                if (!modlist) {
+                                        log_error("Failed to find module '%s' %s", modname, ftsent->fts_accpath);
+                                        kmod_module_unref_list(modlist);
+                                        continue;
+                                }
+                                kmod_list_foreach(itr, modlist) {
+                                        mod = kmod_module_get_module(itr);
+                                        ret = install_module(mod);
+                                        kmod_module_unref(mod);
+                                }
+                                kmod_module_unref_list(modlist);
+                                modlist = 0;
+#else
+                                ret = install_module(mod_o);
+                                kmod_module_unref(mod_o);
+#endif
+
+                        }
+                        if (errno) {
+                                log_error("FTS ERROR: %m");
+                        }
+                        fts_close(fts);
+                        free(path1); path1 = NULL;
+                        free(path2); path2 = NULL;
+                        free(path3); path3 = NULL;
+                } else {
+                        char *modname = argv[i];
+                        if (endswith(modname, ".ko")) {
+                                int len = strlen(modname);
+                                modname[len-3]=0;
+                        }
+                        if (endswith(modname, ".ko.xz") || endswith(modname, ".ko.gz")) {
+                                int len = strlen(modname);
+                                modname[len-6]=0;
+                        }
+                        r = kmod_module_new_from_lookup(ctx, modname, &modlist);
+                        if (r < 0) {
+                                if (!arg_optional) {
+                                        if (!arg_silent)
+                                                log_error("Failed to lookup alias '%s': %m", modname);
+                                        return -ENOENT;
+                                }
+                                log_info("Failed to lookup alias '%s': %m", modname);
+                                continue;
+                        }
+                        if (!modlist) {
+                                if (!arg_optional) {
+                                        if (!arg_silent)
+                                                log_error("Failed to find module '%s'", modname);
+                                        return -ENOENT;
+                                }
+                                log_info("Failed to find module '%s'", modname);
+                                continue;
+                        }
+                        kmod_list_foreach(itr, modlist) {
+                                mod = kmod_module_get_module(itr);
+                                ret = install_module(mod);
+                                kmod_module_unref(mod);
+                        }
+                        kmod_module_unref_list(modlist);
+                        modlist = 0;
+                }
+
+                if ((ret != 0) && (!arg_optional)) {
+                        if (!arg_silent)
+                                log_error("ERROR: installing '%s'", argv[i]);
+                        return EXIT_FAILURE;
+                }
+        }
+        return EXIT_SUCCESS;
+}
+
 int main(int argc, char **argv)
 {
         int r;
         char *i;
+        char *path = NULL;
 
         r = parse_argv(argc, argv);
         if (r <= 0)
@@ -993,6 +1447,17 @@ int main(int argc, char **argv)
 
         log_open();
 
+        path = getenv("PATH");
+
+        if (path == NULL) {
+                log_error("PATH is not set");
+                exit(EXIT_FAILURE);
+        }
+
+        log_debug("PATH=%s", path);
+
+        pathdirs = strv_split(path, ":");
+
         umask(0022);
 
         if (destrootdir == NULL || strlen(destrootdir) == 0) {
@@ -1059,7 +1524,9 @@ int main(int argc, char **argv)
                 }
         }
 
-        if (arg_resolvelazy) {
+        if (arg_module) {
+                r = install_modules(argc - optind, &argv[optind]);
+        } else if (arg_resolvelazy) {
                 r = resolve_lazy(argc - optind, &argv[optind]);
         } else if (arg_all || (argc - optind > 2) || ((argc - optind) == 1)) {
                 r = install_all(argc - optind, &argv[optind]);
@@ -1085,6 +1552,7 @@ int main(int argc, char **argv)
         hashmap_free(items_failed);
 
         free(destrootdir);
-
+        strv_free(firmwaredirs);
+        strv_free(pathdirs);
         return r;
 }
diff --git a/modules.d/50drm/module-setup.sh b/modules.d/50drm/module-setup.sh
index 55a214e..e0b2959 100755
--- a/modules.d/50drm/module-setup.sh
+++ b/modules.d/50drm/module-setup.sh
@@ -15,40 +15,6 @@ installkernel() {
     local _modname
     # Include KMS capable drm drivers
 
-    drm_module_filter() {
-        local _drm_drivers='drm_crtc_init'
-        local _ret
-        # subfunctions inherit following FDs
-        local _merge=8 _side2=9
-        function nmf1() {
-            local _fname _fcont
-            while read _fname || [ -n "$_fname" ]; do
-                case "$_fname" in
-                    *.ko)    _fcont="$(<        $_fname)" ;;
-                    *.ko.gz) _fcont="$(gzip -dc $_fname)" ;;
-                    *.ko.xz) _fcont="$(xz -dc   $_fname)" ;;
-                esac
-                [[   $_fcont =~ $_drm_drivers
-                && ! $_fcont =~ iw_handler_get_spy ]] \
-                && echo "$_fname"
-            done
-        }
-        function rotor() {
-            local _f1 _f2
-            while read _f1 || [ -n "$_f1" ]; do
-                echo "$_f1"
-                if read _f2; then
-                    echo "$_f2" 1>&${_side2}
-                fi
-            done | nmf1 1>&${_merge}
-        }
-        # Use two parallel streams to filter alternating modules.
-        set +x
-        eval "( ( rotor ) ${_side2}>&1 | nmf1 ) ${_merge}>&1"
-        [[ $debug ]] && set -x
-        return 0
-    }
-
     if [[ "$(uname -p)" == arm* ]]; then
         # arm specific modules needed by drm
         instmods \
@@ -62,20 +28,19 @@ installkernel() {
 
     instmods amdkfd hyperv_fb
 
-    for _modname in $(find_kernel_modules_by_path drivers/gpu/drm \
-        | drm_module_filter) ; do
-        # if the hardware is present, include module even if it is not currently loaded,
-        # as we could e.g. be in the installer; nokmsboot boot parameter will disable
-        # loading of the driver if needed
-        if [[ $hostonly ]] && modinfo -F alias $_modname | sed -e 's,\?,\.,g' -e 's,\*,\.\*,g' \
-            | grep -qxf - /sys/bus/{pci/devices,soc/devices/soc?}/*/modalias 2>/dev/null; then
-            hostonly='' instmods $_modname
-            # if radeon.ko is installed, we want amdkfd also
-            if strstr "$_modname" radeon.ko; then
-                hostonly='' instmods amdkfd
+    # if the hardware is present, include module even if it is not currently loaded,
+    # as we could e.g. be in the installer; nokmsboot boot parameter will disable
+    # loading of the driver if needed
+    if [[ $hostonly ]]; then
+        for i in /sys/bus/{pci/devices,soc/devices/soc?}/*/modalias; do
+            [[ -e $i ]] || continue
+            if hostonly="" dracut_instmods -s "drm_crtc_init" $(<$i) 2>/dev/null; then
+                if strstr $(modinfo -F filename $(<$i) 2>/dev/null) radeon.ko; then
+                    hostonly='' instmods amdkfd
+                fi
             fi
-            continue
-        fi
-        instmods $_modname
-    done
+        done
+    else
+        dracut_instmods -s "drm_crtc_init" "=drivers/gpu/drm"
+    fi
 }
diff --git a/modules.d/90crypt/module-setup.sh b/modules.d/90crypt/module-setup.sh
index 5d964f4..6c377ef 100755
--- a/modules.d/90crypt/module-setup.sh
+++ b/modules.d/90crypt/module-setup.sh
@@ -24,8 +24,10 @@ depends() {
 
 # called by dracut
 installkernel() {
-    instmods dm_crypt =crypto
     hostonly="" instmods drbg
+    arch=$(arch)
+    [[ $arch == x86_64 ]] && arch=x86
+    instmods dm_crypt =crypto =drivers/crypto =arch/$arch/crypto
 }
 
 # called by dracut
diff --git a/modules.d/90dm/module-setup.sh b/modules.d/90dm/module-setup.sh
index 419e8b1..2b8e39f 100755
--- a/modules.d/90dm/module-setup.sh
+++ b/modules.d/90dm/module-setup.sh
@@ -13,8 +13,7 @@ depends() {
 
 # called by dracut
 installkernel() {
-    instmods =drivers/md
-    instmods dm_mod dm-cache dm-cache-mq dm-cache-cleaner
+    instmods =drivers/md dm_mod dm-cache dm-cache-mq dm-cache-cleaner
 }
 
 # called by dracut
diff --git a/modules.d/90kernel-modules/module-setup.sh b/modules.d/90kernel-modules/module-setup.sh
index 300adc7..e97d598 100755
--- a/modules.d/90kernel-modules/module-setup.sh
+++ b/modules.d/90kernel-modules/module-setup.sh
@@ -2,54 +2,25 @@
 
 # called by dracut
 installkernel() {
-    if [[ -z $drivers ]]; then
-        block_module_filter() {
-            local _blockfuncs='ahci_platform_get_resources|ata_scsi_ioctl|scsi_add_host|blk_cleanup_queue|register_mtd_blktrans|scsi_esp_register|register_virtio_device|usb_stor_disconnect|mmc_add_host|sdhci_add_host'
-            # subfunctions inherit following FDs
-            local _merge=8 _side2=9
-            function bmf1() {
-                local _f
-                while read _f || [ -n "$_f" ]; do case "$_f" in
-                    *.ko)    [[ $(<         $_f) =~ $_blockfuncs ]] && echo "$_f" ;;
-                    *.ko.gz) [[ $(gzip -dc <$_f) =~ $_blockfuncs ]] && echo "$_f" ;;
-                    *.ko.xz) [[ $(xz -dc   <$_f) =~ $_blockfuncs ]] && echo "$_f" ;;
-                    esac
-                done
-                return 0
-            }
-            function rotor() {
-                local _f1 _f2
-                while read _f1 || [ -n "$_f1" ]; do
-                    echo "$_f1"
-                    if read _f2; then
-                        echo "$_f2" 1>&${_side2}
-                    fi
-                done | bmf1 1>&${_merge}
-                return 0
-            }
-            # Use two parallel streams to filter alternating modules.
-            set +x
-            eval "( ( rotor ) ${_side2}>&1 | bmf1 ) ${_merge}>&1"
-            [[ $debug ]] && set -x
-            return 0
-        }
+    local _blockfuncs='ahci_platform_get_resources|ata_scsi_ioctl|scsi_add_host|blk_cleanup_queue|register_mtd_blktrans|scsi_esp_register|register_virtio_device|usb_stor_disconnect|mmc_add_host|sdhci_add_host|scsi_add_host_with_dma'
 
+    if [[ -z $drivers ]]; then
         hostonly='' instmods \
             sr_mod sd_mod scsi_dh ata_piix hid_generic unix \
-            ehci-hcd ehci-pci ehci-platform \
+            ehci-hcd ehci-pci \
             ohci-hcd ohci-pci \
             uhci-hcd \
             xhci-hcd xhci-pci xhci-plat-hcd \
+            ehci-platform
+
+        instmods \
             "=drivers/hid" \
             "=drivers/input/serio" \
             "=drivers/input/keyboard" \
-            "=drivers/usb/storage"
-
-        instmods \
             yenta_socket scsi_dh_rdac scsi_dh_emc scsi_dh_alua \
             atkbd i8042 usbhid firewire-ohci pcmcia hv-vmbus \
             virtio virtio_blk virtio_ring virtio_pci virtio_scsi \
-            "=drivers/pcmcia" =ide
+            "=drivers/pcmcia" =ide "=drivers/usb/storage"
 
         if [[ "$(uname -p)" == arm* ]]; then
             # arm specific modules
@@ -62,20 +33,16 @@ installkernel() {
                 ${NULL}
         fi
 
-
-        find_kernel_modules  |  block_module_filter  |  instmods
+        dracut_instmods -s "${_blockfuncs}" "=drivers"
 
         # if not on hostonly mode, install all known filesystems,
         # if the required list is not set via the filesystems variable
         if ! [[ $hostonly ]]; then
             if [[ -z $filesystems ]]; then
-                silent_omit_drivers="kernel/fs/nfs|kernel/fs/nfsd|kernel/fs/lockd" \
-                    instmods '=fs'
+                dracut_instmods -P ".*/(kernel/fs/nfs|kernel/fs/nfsd|kernel/fs/lockd)/.*" '=fs'
             fi
         else
-            for i in "${host_fs_types[@]}"; do
-                hostonly='' instmods $i
-            done
+            hostonly='' instmods "${host_fs_types[@]}"
         fi
     fi
     :
diff --git a/modules.d/90kernel-network-modules/module-setup.sh b/modules.d/90kernel-network-modules/module-setup.sh
index 18d7d96..c004ff8 100755
--- a/modules.d/90kernel-network-modules/module-setup.sh
+++ b/modules.d/90kernel-network-modules/module-setup.sh
@@ -14,47 +14,14 @@ depends() {
 installkernel() {
     # Include wired net drivers, excluding wireless
     local _arch=$(uname -m)
+    local _net_drivers='eth_type_trans|register_virtio_device|usbnet_open'
+    local _unwanted_drivers='/(wireless|isdn|uwb|net/ethernet|net/phy|net/team)/'
 
-    net_module_filter() {
-        local _net_drivers='eth_type_trans|register_virtio_device|usbnet_open'
-        local _unwanted_drivers='/(wireless|isdn|uwb|net/ethernet|net/phy|net/team)/'
-        local _ret
-        # subfunctions inherit following FDs
-        local _merge=8 _side2=9
-        function nmf1() {
-            local _fname _fcont
-            while read _fname; do
-                [[ $_fname =~ $_unwanted_drivers ]] && continue
-                case "$_fname" in
-                    *.ko)    _fcont="$(<        $_fname)" ;;
-                    *.ko.gz) _fcont="$(gzip -dc $_fname)" ;;
-                    *.ko.xz) _fcont="$(xz -dc   $_fname)" ;;
-                esac
-                [[   $_fcont =~ $_net_drivers
-                && ! $_fcont =~ iw_handler_get_spy ]] \
-                && echo "$_fname"
-            done
-            return 0
-        }
-        function rotor() {
-            local _f1 _f2
-            while read _f1; do
-                echo "$_f1"
-                if read _f2; then
-                    echo "$_f2" 1>&${_side2}
-                fi
-            done | nmf1 1>&${_merge}
-            return 0
-        }
-        # Use two parallel streams to filter alternating modules.
-        set +x
-        eval "( ( rotor ) ${_side2}>&1 | nmf1 ) ${_merge}>&1"
-        [[ $debug ]] && set -x
-        return 0
-    }
+    if [ "$_arch" = "s390" -o "$_arch" = "s390x" ]; then
+        _s390drivers="=drivers/s390/net"
+    fi
 
-    { find_kernel_modules_by_path drivers/net; if [ "$_arch" = "s390" -o "$_arch" = "s390x" ]; then find_kernel_modules_by_path drivers/s390/net; fi; } \
-        | net_module_filter | instmods
+    dracut_instmods -P ".*${_unwanted_drivers}.*" -s "$_net_drivers" "=drivers/net" ${_s390drivers:+"$_s390drivers"}
 
     #instmods() will take care of hostonly
     instmods \
diff --git a/modules.d/90multipath/module-setup.sh b/modules.d/90multipath/module-setup.sh
index a808678..27817bd 100755
--- a/modules.d/90multipath/module-setup.sh
+++ b/modules.d/90multipath/module-setup.sh
@@ -51,41 +51,14 @@ cmdline() {
 installkernel() {
     local _ret
     local _arch=$(uname -m)
-    mp_mod_filter() {
-        local _funcs='scsi_register_device_handler|dm_dirty_log_type_register|dm_register_path_selector|dm_register_target'
-        # subfunctions inherit following FDs
-        local _merge=8 _side2=9
-        function bmf1() {
-            local _f
-            while read _f || [ -n "$_f" ]; do
-                case "$_f" in
-                    *.ko)    [[ $(<         $_f) =~ $_funcs ]] && echo "$_f" ;;
-                    *.ko.gz) [[ $(gzip -dc <$_f) =~ $_funcs ]] && echo "$_f" ;;
-                    *.ko.xz) [[ $(xz -dc   <$_f) =~ $_funcs ]] && echo "$_f" ;;
-                esac
-            done
-            return 0
-        }
+    local _funcs='scsi_register_device_handler|dm_dirty_log_type_register|dm_register_path_selector|dm_register_target'
+    local _s390
 
-        function rotor() {
-            local _f1 _f2
-            while read _f1 || [ -n "$_f1" ]; do
-                echo "$_f1"
-                if read _f2; then
-                    echo "$_f2" 1>&${_side2}
-                fi
-            done | bmf1 1>&${_merge}
-            return 0
-        }
-        # Use two parallel streams to filter alternating modules.
-        set +x
-        eval "( ( rotor ) ${_side2}>&1 | bmf1 ) ${_merge}>&1"
-        [[ $debug ]] && set -x
-        return 0
-    }
+    if [ "$_arch" = "s390" -o "$_arch" = "s390x" ]; then
+        _s390drivers="=drivers/s390/scsi"
+    fi
 
-    ( find_kernel_modules_by_path drivers/scsi; if [ "$_arch" = "s390" -o "$_arch" = "s390x" ]; then find_kernel_modules_by_path drivers/s390/scsi; fi;
-      find_kernel_modules_by_path drivers/md )  |  mp_mod_filter  |  hostonly='' instmods
+    hostonly='' dracut_instmods -s "$_funcs" "=drivers/scsi" "=drivers/md" ${_s390drivers:+"$_s390drivers"}
 }
 
 # called by dracut
diff --git a/modules.d/95iscsi/module-setup.sh b/modules.d/95iscsi/module-setup.sh
index beb80e3..203e313 100755
--- a/modules.d/95iscsi/module-setup.sh
+++ b/modules.d/95iscsi/module-setup.sh
@@ -157,44 +157,17 @@ depends() {
 # called by dracut
 installkernel() {
     local _arch=$(uname -m)
+    local _funcs='iscsi_register_transport'
 
     instmods bnx2i qla4xxx cxgb3i cxgb4i be2iscsi
     hostonly="" instmods iscsi_tcp iscsi_ibft crc32c iscsi_boot_sysfs
-    iscsi_module_filter() {
-        local _funcs='iscsi_register_transport'
-        # subfunctions inherit following FDs
-        local _merge=8 _side2=9
-        function bmf1() {
-            local _f
-            while read _f || [ -n "$_f" ]; do
-                case "$_f" in
-                    *.ko)    [[ $(<         $_f) =~ $_funcs ]] && echo "$_f" ;;
-                    *.ko.gz) [[ $(gzip -dc <$_f) =~ $_funcs ]] && echo "$_f" ;;
-                    *.ko.xz) [[ $(xz -dc   <$_f) =~ $_funcs ]] && echo "$_f" ;;
-                esac
-            done
-            return 0
-        }
-
-        function rotor() {
-            local _f1 _f2
-            while read _f1 || [ -n "$_f1" ]; do
-                echo "$_f1"
-                if read _f2; then
-                    echo "$_f2" 1>&${_side2}
-                fi
-            done | bmf1 1>&${_merge}
-            return 0
-        }
-        # Use two parallel streams to filter alternating modules.
-        set +x
-        eval "( ( rotor ) ${_side2}>&1 | bmf1 ) ${_merge}>&1"
-        [[ $debug ]] && set -x
-        return 0
-    }
 
-    { find_kernel_modules_by_path drivers/scsi; if [ "$_arch" = "s390" -o "$_arch" = "s390x" ]; then find_kernel_modules_by_path drivers/s390/scsi; fi;} \
-    | iscsi_module_filter  |  instmods
+    if [ "$_arch" = "s390" -o "$_arch" = "s390x" ]; then
+        _s390drivers="=drivers/s390/scsi"
+    fi
+
+    dracut_instmods -s "$_funcs" "=drivers/scsi" ${_s390drivers:+"$_s390drivers"}
+
 }
 
 # called by dracut
diff --git a/modules.d/95nfs/module-setup.sh b/modules.d/95nfs/module-setup.sh
index 6f039bd..9767e57 100755
--- a/modules.d/95nfs/module-setup.sh
+++ b/modules.d/95nfs/module-setup.sh
@@ -25,7 +25,7 @@ depends() {
 
 # called by dracut
 installkernel() {
-    instmods nfs sunrpc ipv6 nfsv2 nfsv3 nfsv4 nfs_acl nfs_layout_nfsv41_files
+    instmods =net/sunrpc =fs/nfs ipv6 nfs_acl nfs_layout_nfsv41_files
 }
 
 cmdline() {