summaryrefslogtreecommitdiff
path: root/kernel/module.c
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2002-11-16 19:22:06 -0800
committerLinus Torvalds <torvalds@home.transmeta.com>2002-11-16 19:22:06 -0800
commita89a8e24521557f9e1b4f01fa581dd979382b4cb (patch)
treec96797f95cd3326ea1ca00953a5e5ab5911c75dd /kernel/module.c
parentbbeabef1b1bba4a0eb2c8b6ae7418f9ac1331887 (diff)
[PATCH] Forced module unload
This is the logical counterpoint to the code which marks modules "[unsafe]" when obsolete (racy) interfaces are used. Allows "just remove the damn thing" rmmod -f, and taints the kernel. Mark it dangerous and experimental in the config file to make this doubly clear.
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c53
1 files changed, 38 insertions, 15 deletions
diff --git a/kernel/module.c b/kernel/module.c
index 728e8698422c..7f98ae91e698 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -348,12 +348,24 @@ static unsigned int module_refcount(struct module *mod)
/* This exists whether we can unload or not */
static void free_module(struct module *mod);
+#ifdef CONFIG_MODULE_FORCE_UNLOAD
+static inline int try_force(unsigned int flags)
+{
+ return (flags & O_TRUNC);
+}
+#else
+static inline int try_force(unsigned int flags)
+{
+ return 0;
+}
+#endif /* CONFIG_MODULE_FORCE_UNLOAD */
+
asmlinkage long
sys_delete_module(const char *name_user, unsigned int flags)
{
struct module *mod;
char name[MODULE_NAME_LEN];
- int ret;
+ int ret, forced = 0;
if (!capable(CAP_SYS_MODULE))
return -EPERM;
@@ -371,24 +383,29 @@ sys_delete_module(const char *name_user, unsigned int flags)
goto out;
}
+ if (!list_empty(&mod->modules_which_use_me)) {
+ /* Other modules depend on us: get rid of them first. */
+ ret = -EWOULDBLOCK;
+ goto out;
+ }
+
/* Already dying? */
if (!mod->live) {
+ /* FIXME: if (force), slam module count and wake up
+ waiter --RR */
DEBUGP("%s already dying\n", mod->name);
ret = -EBUSY;
goto out;
}
if (!mod->exit || mod->unsafe) {
- /* This module can't be removed */
- ret = -EBUSY;
- goto out;
- }
- if (!list_empty(&mod->modules_which_use_me)) {
- /* Other modules depend on us: get rid of them first. */
- ret = -EWOULDBLOCK;
- goto out;
+ forced = try_force(flags);
+ if (!forced) {
+ /* This module can't be removed */
+ ret = -EBUSY;
+ goto out;
+ }
}
-
/* Stop the machine so refcounts can't move: irqs disabled. */
DEBUGP("Stopping refcounts...\n");
ret = stop_refcounts();
@@ -396,9 +413,11 @@ sys_delete_module(const char *name_user, unsigned int flags)
goto out;
/* If it's not unused, quit unless we are told to block. */
- if ((flags & O_NONBLOCK) && module_refcount(mod) != 0)
- ret = -EWOULDBLOCK;
- else {
+ if ((flags & O_NONBLOCK) && module_refcount(mod) != 0) {
+ forced = try_force(flags);
+ if (!forced)
+ ret = -EWOULDBLOCK;
+ } else {
mod->waiter = current;
mod->live = 0;
}
@@ -407,6 +426,9 @@ sys_delete_module(const char *name_user, unsigned int flags)
if (ret != 0)
goto out;
+ if (forced)
+ goto destroy;
+
/* Since we might sleep for some time, drop the semaphore first */
up(&module_mutex);
for (;;) {
@@ -421,10 +443,11 @@ sys_delete_module(const char *name_user, unsigned int flags)
DEBUGP("Regrabbing mutex...\n");
down(&module_mutex);
+ destroy:
/* Final destruction now noone is using it. */
- mod->exit();
+ if (mod->exit)
+ mod->exit();
free_module(mod);
- ret = 0;
out:
up(&module_mutex);