modprobe-small: fix and simplify rmmod

"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>
This commit is contained in:
Denys Vlasenko 2015-02-07 20:44:46 +01:00
parent 782ee2aa0e
commit 68c048fb23

View File

@ -549,9 +549,23 @@ static int already_loaded(const char *name)
return ret; return ret;
} }
#else #else
#define already_loaded(name) is_rmmod #define already_loaded(name) 0
#endif #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) * Given modules definition and module name (or alias, or symbol)
* load/remove the module respecting dependencies. * 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 **infovec;
module_info *info; module_info *info;
int infoidx; 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); dbg1_error_msg("process_module('%s','%s')", name, cmdline_options);
replace(name, '-', '_'); 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 * modprobe -r pci:v00008086d00007010sv00000000sd00000000bc01sc01i80
* won't unload modules (there are more than one) * won't unload modules (there are more than one)
* which have this alias. * 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); dbg1_error_msg("nothing to do for '%s'", name);
return; return;
} }
options = NULL; options = NULL;
if (!is_rmmod) { if (!is_remove) {
char *opt_filename = xasprintf("/etc/modules/%s", name); char *opt_filename = xasprintf("/etc/modules/%s", name);
options = xmalloc_open_read_close(opt_filename, NULL); options = xmalloc_open_read_close(opt_filename, NULL);
if (options) if (options)
@ -621,7 +645,7 @@ static void process_module(char *name, const char *cmdline_options)
0 /* depth */ 0 /* depth */
); );
dbg1_error_msg("dirscan complete"); 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 */ if (module_found_idx >= 0) { /* module was found */
infovec = xzalloc(2 * sizeof(infovec[0])); infovec = xzalloc(2 * sizeof(infovec[0]));
infovec[0] = &modinfo[module_found_idx]; infovec[0] = &modinfo[module_found_idx];
@ -634,7 +658,7 @@ static void process_module(char *name, const char *cmdline_options)
if (!infovec) { if (!infovec) {
/* both dirscan and find_alias found nothing */ /* 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); bb_error_msg("module '%s' not found", name);
//TODO: _and_die()? or should we continue (un)loading modules listed on cmdline? //TODO: _and_die()? or should we continue (un)loading modules listed on cmdline?
goto ret; goto ret;
@ -648,29 +672,15 @@ static void process_module(char *name, const char *cmdline_options)
* a *list* of modinfo pointers from find_alias(). * a *list* of modinfo pointers from find_alias().
*/ */
/* rmmod or modprobe -r? unload module(s) */ /* modprobe -r? unload module(s) */
if (is_rmmod) { if (is_remove) {
infoidx = 0; infoidx = 0;
while ((info = infovec[infoidx++]) != NULL) { while ((info = infovec[infoidx++]) != NULL) {
int r; int r = rmmod(bb_get_last_path_component_nostrip(info->pathname));
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);
if (r != 0) { if (r != 0) {
if (!(option_mask32 & OPT_q)) goto ret; /* error */
bb_perror_msg("remove '%s'", modname);
goto ret;
} }
} }
if (applet_name[0] == 'r') {
/* rmmod: do not remove dependencies, exit */
goto ret;
}
/* modprobe -r: we do not stop here - /* modprobe -r: we do not stop here -
* continue to unload modules on which the module depends: * continue to unload modules on which the module depends:
* "-r --remove: option causes modprobe to remove a module. * "-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); free(deps);
if (is_rmmod) if (is_remove)
continue; continue;
/* We are modprobe: load it */ /* 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 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. */ * insmod/modprobe takes one module name, the rest are parameters. */
options = NULL; options = NULL;
if ('r' != applet0) { if (!(option_mask32 & OPT_r)) {
char **arg = argv; char **arg = argv;
while (*++arg) { while (*++arg) {
/* Enclose options in quotes */ /* Enclose options in quotes */
@ -908,7 +918,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
} }
} }
#else #else
if ('r' != applet0) if (!(option_mask32 & OPT_r))
argv[1] = NULL; argv[1] = NULL;
#endif #endif
@ -932,10 +942,11 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv)
} }
/* Try to load modprobe.dep.bb */ /* Try to load modprobe.dep.bb */
load_dep_bb(); if ('r' != applet0) /* not rmmod */
load_dep_bb();
/* Load/remove modules. /* 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 { do {
process_module(*argv, options); process_module(*argv, options);
} while (*++argv); } while (*++argv);