modprobe-small: fix and simplify rmmod
authorDenys Vlasenko <vda.linux@googlemail.com>
Sat, 7 Feb 2015 19:44:46 +0000 (20:44 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Sat, 7 Feb 2015 19:44:46 +0000 (20:44 +0100)
"rmmod OUT_OF_TREE_MODULE" was not working, because module is not in depmod file.

In general, rmmod doesn't need scanning, it simply unloads every argv[i].

function                                             old     new   delta
rmmod                                                  -      63     +63
modprobe_main                                        449     465     +16
process_module                                       705     667     -38
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/1 up/down: 79/-38)             Total: 41 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
modutils/modprobe-small.c

index cafbdc0b2dcc98083bc539e9cdcea613231ca1d1..6b0a4400c999da14b6e2931edd034cfa542345c2 100644 (file)
@@ -549,9 +549,23 @@ static int already_loaded(const char *name)
        return ret;
 }
 #else
-#define already_loaded(name) is_rmmod
+#define already_loaded(name) 0
 #endif
 
+static int rmmod(const char *filename)
+{
+       int r;
+       char modname[MODULE_NAME_LEN];
+
+       filename2modname(filename, modname);
+       r = delete_module(modname, O_NONBLOCK | O_EXCL);
+       dbg1_error_msg("delete_module('%s', O_NONBLOCK | O_EXCL):%d", modname, r);
+       if (r != 0 && !(option_mask32 & OPT_q)) {
+               bb_perror_msg("remove '%s'", modname);
+       }
+       return r;
+}
+
 /*
  * Given modules definition and module name (or alias, or symbol)
  * load/remove the module respecting dependencies.
@@ -568,26 +582,36 @@ static void process_module(char *name, const char *cmdline_options)
        module_info **infovec;
        module_info *info;
        int infoidx;
-       int is_rmmod = (option_mask32 & OPT_r) != 0;
+       int is_remove = (option_mask32 & OPT_r) != 0;
 
        dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
 
        replace(name, '-', '_');
 
-       dbg1_error_msg("already_loaded:%d is_rmmod:%d", already_loaded(name), is_rmmod);
+       dbg1_error_msg("already_loaded:%d is_remove:%d", already_loaded(name), is_remove);
+
+       if (applet_name[0] == 'r') {
+               /* rmmod.
+                * Does not remove dependencies, no need to scan, just remove.
+                * (compat note: this allows and strips .ko suffix)
+                */
+               rmmod(name);
+               return;
+       }
+
        /*
-        * We used to have "is_rmmod != already_loaded(name)" check here, but
+        * We used to have "is_remove != already_loaded(name)" check here, but
         *  modprobe -r pci:v00008086d00007010sv00000000sd00000000bc01sc01i80
         * won't unload modules (there are more than one)
         * which have this alias.
         */
-       if (!is_rmmod && already_loaded(name)) {
+       if (!is_remove && already_loaded(name)) {
                dbg1_error_msg("nothing to do for '%s'", name);
                return;
        }
 
        options = NULL;
-       if (!is_rmmod) {
+       if (!is_remove) {
                char *opt_filename = xasprintf("/etc/modules/%s", name);
                options = xmalloc_open_read_close(opt_filename, NULL);
                if (options)
@@ -621,7 +645,7 @@ static void process_module(char *name, const char *cmdline_options)
                        0 /* depth */
                );
                dbg1_error_msg("dirscan complete");
-               /* Module was not found, or load failed, or is_rmmod */
+               /* Module was not found, or load failed, or is_remove */
                if (module_found_idx >= 0) { /* module was found */
                        infovec = xzalloc(2 * sizeof(infovec[0]));
                        infovec[0] = &modinfo[module_found_idx];
@@ -634,7 +658,7 @@ static void process_module(char *name, const char *cmdline_options)
 
        if (!infovec) {
                /* both dirscan and find_alias found nothing */
-               if (!is_rmmod && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
+               if (!is_remove && applet_name[0] != 'd') /* it wasn't rmmod or depmod */
                        bb_error_msg("module '%s' not found", name);
 //TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
                goto ret;
@@ -648,29 +672,15 @@ static void process_module(char *name, const char *cmdline_options)
         * a *list* of modinfo pointers from find_alias().
         */
 
-       /* rmmod or modprobe -r? unload module(s) */
-       if (is_rmmod) {
+       /* modprobe -r? unload module(s) */
+       if (is_remove) {
                infoidx = 0;
                while ((info = infovec[infoidx++]) != NULL) {
-                       int r;
-                       char modname[MODULE_NAME_LEN];
-
-                       filename2modname(
-                               bb_get_last_path_component_nostrip(info->pathname), modname);
-                       r = delete_module(modname, O_NONBLOCK | O_EXCL);
-                       dbg1_error_msg("delete_module('%s', O_NONBLOCK | O_EXCL):%d", modname, r);
+                       int r = rmmod(bb_get_last_path_component_nostrip(info->pathname));
                        if (r != 0) {
-                               if (!(option_mask32 & OPT_q))
-                                       bb_perror_msg("remove '%s'", modname);
-                               goto ret;
+                               goto ret; /* error */
                        }
                }
-
-               if (applet_name[0] == 'r') {
-                       /* rmmod: do not remove dependencies, exit */
-                       goto ret;
-               }
-
                /* modprobe -r: we do not stop here -
                 * continue to unload modules on which the module depends:
                 * "-r --remove: option causes modprobe to remove a module.
@@ -691,7 +701,7 @@ static void process_module(char *name, const char *cmdline_options)
                }
                free(deps);
 
-               if (is_rmmod)
+               if (is_remove)
                        continue;
 
                /* We are modprobe: load it */
@@ -894,10 +904,10 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
        }
 
 #if ENABLE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE
-       /* If not rmmod, parse possible module options given on command line.
+       /* If not rmmod/-r, parse possible module options given on command line.
         * insmod/modprobe takes one module name, the rest are parameters. */
        options = NULL;
-       if ('r' != applet0) {
+       if (!(option_mask32 & OPT_r)) {
                char **arg = argv;
                while (*++arg) {
                        /* Enclose options in quotes */
@@ -908,7 +918,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
                }
        }
 #else
-       if ('r' != applet0)
+       if (!(option_mask32 & OPT_r))
                argv[1] = NULL;
 #endif
 
@@ -932,10 +942,11 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
        }
 
        /* Try to load modprobe.dep.bb */
-       load_dep_bb();
+       if ('r' != applet0) /* not rmmod */
+               load_dep_bb();
 
        /* Load/remove modules.
-        * Only rmmod loops here, modprobe has only argv[0] */
+        * Only rmmod/modprobe -r loops here, insmod/modprobe has only argv[0] */
        do {
                process_module(*argv, options);
        } while (*++argv);