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>
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index cafbdc0..6b0a440 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -549,9 +549,23 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
}
free(deps);
- if (is_rmmod)
+ if (is_remove)
continue;
/* We are modprobe: load it */
@@ -894,10 +904,10 @@
}
#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 @@
}
}
#else
- if ('r' != applet0)
+ if (!(option_mask32 & OPT_r))
argv[1] = NULL;
#endif
@@ -932,10 +942,11 @@
}
/* 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);