patch-2.3.51 linux/kernel/module.c

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

diff -u --recursive --new-file v2.3.50/linux/kernel/module.c linux/kernel/module.c
@@ -350,6 +350,21 @@
 	return error;
 }
 
+static spinlock_t unload_lock = SPIN_LOCK_UNLOCKED;
+int try_inc_mod_count(struct module *mod)
+{
+	int res = 1;
+	if (mod) {
+		spin_lock(&unload_lock);
+		if (mod->flags & MOD_DELETED)
+			res = 0;
+		else
+			__MOD_INC_USE_COUNT(mod);
+		spin_unlock(&unload_lock);
+	}
+	return res;
+}
+
 asmlinkage long
 sys_delete_module(const char *name_user)
 {
@@ -377,11 +392,18 @@
 		}
 		put_mod_name(name);
 		error = -EBUSY;
- 		if (mod->refs != NULL || __MOD_IN_USE(mod))
+ 		if (mod->refs != NULL)
 			goto out;
 
-		free_module(mod, 0);
-		error = 0;
+		spin_lock(&unload_lock);
+ 		if (!__MOD_IN_USE(mod)) {
+			mod->flags |= MOD_DELETED;
+			spin_unlock(&unload_lock);
+			free_module(mod, 0);
+			error = 0;
+		} else {
+			spin_unlock(&unload_lock);
+		}
 		goto out;
 	}
 
@@ -390,6 +412,7 @@
 	something_changed = 0;
 	for (mod = module_list; mod != &kernel_module; mod = next) {
 		next = mod->next;
+		spin_lock(&unload_lock);
 		if (mod->refs == NULL
 		    && (mod->flags & MOD_AUTOCLEAN)
 		    && (mod->flags & MOD_RUNNING)
@@ -398,11 +421,16 @@
 		    && !__MOD_IN_USE(mod)) {
 			if ((mod->flags & MOD_VISITED)
 			    && !(mod->flags & MOD_JUST_FREED)) {
+				spin_unlock(&unload_lock);
 				mod->flags &= ~MOD_VISITED;
 			} else {
+				mod->flags |= MOD_DELETED;
+				spin_unlock(&unload_lock);
 				free_module(mod, 1);
 				something_changed = 1;
 			}
+		} else {
+			spin_unlock(&unload_lock);
 		}
 	}
 	if (something_changed)
@@ -775,7 +803,6 @@
 
 	/* Let the module clean up.  */
 
-	mod->flags |= MOD_DELETED;
 	if (mod->flags & MOD_RUNNING) 
 	{
 		if(mod->cleanup)

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)