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
1 changed files with 43 additions and 32 deletions

View 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);