patch-2.1.86 linux/kernel/module.c

Next file: linux/kernel/printk.c
Previous file: linux/kernel/ksyms.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.85/linux/kernel/module.c linux/kernel/module.c
@@ -54,7 +54,7 @@
 static long get_mod_name(const char *user_name, char **buf);
 static void put_mod_name(char *buf);
 static struct module *find_module(const char *name);
-static void free_module(struct module *);
+static void free_module(struct module *, int tag_freed);
 
 
 /*
@@ -363,6 +363,7 @@
 	struct module *mod, *next;
 	char *name;
 	long error = -EPERM;
+	int something_changed;
 
 	lock_kernel();
 	if (!suser())
@@ -386,25 +387,35 @@
  		if (mod->refs != NULL || __MOD_IN_USE(mod))
 			goto out;
 
-		free_module(mod);
+		free_module(mod, 0);
 		error = 0;
 		goto out;
 	}
 
 	/* Do automatic reaping */
+restart:
+	something_changed = 0;
 	for (mod = module_list; mod != &kernel_module; mod = next) {
 		next = mod->next;
-		if (mod->refs == NULL &&
-		    ((mod->flags
-		      & (MOD_AUTOCLEAN|MOD_RUNNING|MOD_DELETED|MOD_USED_ONCE))
-		     == (MOD_AUTOCLEAN|MOD_RUNNING|MOD_USED_ONCE)) &&
-		    !__MOD_IN_USE(mod)) {
-			if (mod->flags & MOD_VISITED)
+		if (mod->refs == NULL
+		    && (mod->flags & MOD_AUTOCLEAN)
+		    && (mod->flags & MOD_RUNNING)
+		    && !(mod->flags & MOD_DELETED)
+		    && (mod->flags & MOD_USED_ONCE)
+		    && !__MOD_IN_USE(mod)) {
+			if ((mod->flags & MOD_VISITED)
+			    && !(mod->flags & MOD_JUST_FREED)) {
 				mod->flags &= ~MOD_VISITED;
-			else
-				free_module(mod);
+			} else {
+				free_module(mod, 1);
+				something_changed = 1;
+			}
 		}
 	}
+	if (something_changed)
+		goto restart;
+	for (mod = module_list; mod != &kernel_module; mod = mod->next)
+		mod->flags &= ~MOD_JUST_FREED;
 	error = 0;
 out:
 	unlock_kernel();
@@ -764,7 +775,7 @@
  */
 
 static void
-free_module(struct module *mod)
+free_module(struct module *mod, int tag_freed)
 {
 	struct module_ref *dep;
 	unsigned i;
@@ -786,6 +797,8 @@
 		for (pp = &dep->dep->refs; *pp != dep; pp = &(*pp)->next_ref)
 			continue;
 		*pp = dep->next_ref;
+		if (tag_freed && dep->dep->refs == NULL)
+			dep->dep->flags |= MOD_JUST_FREED;
 	}
 
 	/* And from the main module list.  */

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov