Module Name:    src
Committed By:   pgoyette
Date:           Sat Aug 21 13:17:32 UTC 2010

Modified Files:
        src/share/man/man9: module.9
        src/sys/conf: files
        src/sys/kern: init_main.c kern_module.c
        src/sys/sys: module.h param.h systm.h
Added Files:
        src/sys/kern: kern_cfglock.c

Log Message:
Define a set of new kernel locking primitives to implement the recursive
kernconfig_mutex.  Update module subsystem to use this mutex rather than
its own internal (non-recursive) mutex.  Make module_autoload() do its
own locking to be consistent with the rest of the module_xxx() calls.
Update module(9) man page appropriately.

As discussed on tech-kern over the last few weeks.

Welcome to NetBSD 5.99.39 !


To generate a diff of this commit:
cvs rdiff -u -r1.17 -r1.18 src/share/man/man9/module.9
cvs rdiff -u -r1.992 -r1.993 src/sys/conf/files
cvs rdiff -u -r1.422 -r1.423 src/sys/kern/init_main.c
cvs rdiff -u -r0 -r1.1 src/sys/kern/kern_cfglock.c
cvs rdiff -u -r1.71 -r1.72 src/sys/kern/kern_module.c
cvs rdiff -u -r1.24 -r1.25 src/sys/sys/module.h
cvs rdiff -u -r1.373 -r1.374 src/sys/sys/param.h
cvs rdiff -u -r1.239 -r1.240 src/sys/sys/systm.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man9/module.9
diff -u src/share/man/man9/module.9:1.17 src/share/man/man9/module.9:1.18
--- src/share/man/man9/module.9:1.17	Wed Aug 18 01:56:45 2010
+++ src/share/man/man9/module.9	Sat Aug 21 13:17:32 2010
@@ -1,4 +1,4 @@
-.\"	$NetBSD: module.9,v 1.17 2010/08/18 01:56:45 pgoyette Exp $
+.\"	$NetBSD: module.9,v 1.18 2010/08/21 13:17:32 pgoyette Exp $
 .\"
 .\" Copyright (c) 2010 The NetBSD Foundation, Inc.
 .\" All rights reserved.
@@ -27,7 +27,7 @@
 .\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 .\" POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd August 17, 2010
+.Dd August XXX, 2010
 .Dt MODULE 9
 .Os
 .Sh NAME
@@ -86,6 +86,8 @@
 .Vt modinfo_t
 type resides within the module itself, and contains module header info.
 .El
+.Pp
+The module subsystem is protected by the global kernconfig_mutex.
 .Sh FUNCTIONS
 .Bl -tag -width abcd
 .It Fn MODULE "class" "name" "required"
@@ -362,21 +364,37 @@
 Until this routine is called, modules can only be loaded if they were
 built-in to the kernel image or provided by the boot loader.
 .El
-.Sh LOCK PROTOCOL
-The
-.Nm
-subsystem is protected with the global
-.Vt module_mutex .
-This
-.Xr mutex 9
-must be acquired before calling any of these routines.
-As an exception, the
+.Sh PROGRAMMING CONSIDERATIONS
+The module subsystem is designed to be called recursively, but only within
+a single lwp.
+This permits one module's
+.Fn modcmd
+routine to load or unload other modules.
+.Pp
+A module is not permitted to load or unload itself.
+Attempts to load or unload a module from within its own
+.Fn modcmd
+routine will fail with
+.Er EEXIST
+or
+.Er EBUSY
+respectively.
+.Pp
+Although a module can be loaded by either
 .Fn module_load
-routine acquires the mutex itself, so one does not need to acquire it
-before calling
-.Fn module_load .
-Loading of a module and its required modules occurs as an atomic
-operation, and either completely succeeds or completely fails.
+or
+.Fn module_autoload
+it is not possible for the module's
+.Fn modcmd
+routine to distinguish between the two methods.
+Any module which needs to ensure that it does not get auto-unloaded must
+either handle the
+.Dv MODULE_CMD_AUTOUNLOAD
+command in its
+.Fn modcmd
+routine, or use
+.Fn module_hold
+to increment its reference count.
 .Sh CODE REFERENCES
 This section describes places within the
 .Nx

Index: src/sys/conf/files
diff -u src/sys/conf/files:1.992 src/sys/conf/files:1.993
--- src/sys/conf/files:1.992	Wed Jul  7 01:09:39 2010
+++ src/sys/conf/files	Sat Aug 21 13:17:32 2010
@@ -1,4 +1,4 @@
-#	$NetBSD: files,v 1.992 2010/07/07 01:09:39 chs Exp $
+#	$NetBSD: files,v 1.993 2010/08/21 13:17:32 pgoyette Exp $
 #	@(#)files.newconf	7.5 (Berkeley) 5/10/93
 
 version 	20100430
@@ -1434,6 +1434,7 @@
 file	kern/init_sysent.c
 file	kern/kern_acct.c
 file	kern/kern_auth.c
+file	kern/kern_cfglock.c
 file	kern/kern_clock.c
 file	kern/kern_condvar.c
 file	kern/kern_core.c		coredump

Index: src/sys/kern/init_main.c
diff -u src/sys/kern/init_main.c:1.422 src/sys/kern/init_main.c:1.423
--- src/sys/kern/init_main.c:1.422	Sat Jun 26 07:23:57 2010
+++ src/sys/kern/init_main.c	Sat Aug 21 13:17:31 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: init_main.c,v 1.422 2010/06/26 07:23:57 pgoyette Exp $	*/
+/*	$NetBSD: init_main.c,v 1.423 2010/08/21 13:17:31 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -97,7 +97,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.422 2010/06/26 07:23:57 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_main.c,v 1.423 2010/08/21 13:17:31 pgoyette Exp $");
 
 #include "opt_ddb.h"
 #include "opt_ipsec.h"
@@ -303,6 +303,7 @@
 	kernel_lock_init();
 	once_init();
 	mutex_init(&cpu_lock, MUTEX_DEFAULT, IPL_NONE);
+	kernconfig_lock_init();
 
 	/* Initialize the device switch tables. */
 	devsw_init();

Index: src/sys/kern/kern_module.c
diff -u src/sys/kern/kern_module.c:1.71 src/sys/kern/kern_module.c:1.72
--- src/sys/kern/kern_module.c:1.71	Wed Aug 11 12:04:49 2010
+++ src/sys/kern/kern_module.c	Sat Aug 21 13:17:31 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_module.c,v 1.71 2010/08/11 12:04:49 pgoyette Exp $	*/
+/*	$NetBSD: kern_module.c,v 1.72 2010/08/21 13:17:31 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_module.c,v 1.71 2010/08/11 12:04:49 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_module.c,v 1.72 2010/08/21 13:17:31 pgoyette Exp $");
 
 #define _MODULE_INTERNAL
 
@@ -72,7 +72,6 @@
 static int	module_autoload_on = 1;
 u_int		module_count;
 u_int		module_builtinlist;
-kmutex_t	module_lock;
 u_int		module_autotime = 10;
 u_int		module_gen = 1;
 static kcondvar_t module_thread_cv;
@@ -223,7 +222,7 @@
 		modp[i] = module_newmodule(MODULE_SOURCE_KERNEL);
 		modp[i]->mod_info = mip[i+mipskip];
 	}
-	mutex_enter(&module_lock);
+	kernconfig_lock();
 
 	/* do this in three stages for error recovery and atomicity */
 
@@ -263,7 +262,7 @@
 	}
 
  out:
-	mutex_exit(&module_lock);
+	kernconfig_unlock();
 	if (rv != 0) {
 		for (i = 0; i < nmodinfo; i++) {
 			if (modp[i])
@@ -291,13 +290,13 @@
 		if (rv)
 			return rv;
 
-		mutex_enter(&module_lock);
+		kernconfig_lock();
 		rv = module_do_unload(mi->mi_name, true);
 		if (rv) {
 			goto out;
 		}
 	} else {
-		mutex_enter(&module_lock);
+		kernconfig_lock();
 	}
 	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
 		if (strcmp(mod->mod_info->mi_name, mi->mi_name) == 0)
@@ -312,7 +311,7 @@
 	}
 
  out:
-	mutex_exit(&module_lock);
+	kernconfig_unlock();
 	return rv;
 }
 
@@ -332,7 +331,6 @@
 	if (module_map == NULL) {
 		module_map = kernel_map;
 	}
-	mutex_init(&module_lock, MUTEX_DEFAULT, IPL_NONE);
 	cv_init(&module_thread_cv, "mod_unld");
 	mutex_init(&module_thread_lock, MUTEX_DEFAULT, IPL_NONE);
 
@@ -388,11 +386,11 @@
 {
 	module_t *mod;
 
-	mutex_enter(&module_lock);
+	kernconfig_lock();
 	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
 		module_require_force(mod);
 	}
-	mutex_exit(&module_lock);
+	kernconfig_unlock();
 }
 
 static struct sysctllog *module_sysctllog;
@@ -444,7 +442,7 @@
 	module_t *mod;
 	modinfo_t *mi;
 
-	mutex_enter(&module_lock);
+	kernconfig_lock();
 	/*
 	 * Builtins first.  These will not depend on pre-loaded modules
 	 * (because the kernel would not link).
@@ -493,7 +491,7 @@
 		TAILQ_INSERT_TAIL(&module_builtins, mod, mod_chain);
 	}
 
-	mutex_exit(&module_lock);
+	kernconfig_unlock();
 }
 
 /*
@@ -534,10 +532,10 @@
 		return error;
 	}
 
-	mutex_enter(&module_lock);
+	kernconfig_lock();
 	error = module_do_load(filename, false, flags, props, NULL, class,
 	    false);
-	mutex_exit(&module_lock);
+	kernconfig_unlock();
 
 	return error;
 }
@@ -552,27 +550,31 @@
 {
 	int error;
 
-	KASSERT(mutex_owned(&module_lock));
+	kernconfig_lock();
 
 	/* Nothing if the user has disabled it. */
 	if (!module_autoload_on) {
+		kernconfig_unlock();
 		return EPERM;
 	}
 
         /* Disallow path separators and magic symlinks. */
         if (strchr(filename, '/') != NULL || strchr(filename, '@') != NULL ||
             strchr(filename, '.') != NULL) {
+		kernconfig_unlock();
         	return EPERM;
 	}
 
 	/* Authorize. */
 	error = kauth_authorize_system(kauth_cred_get(), KAUTH_SYSTEM_MODULE,
 	    0, (void *)(uintptr_t)MODCTL_LOAD, (void *)(uintptr_t)1, NULL);
-	if (error != 0) {
-		return error;
-	}
 
-	return module_do_load(filename, false, 0, NULL, NULL, class, true);
+	if (error == 0)
+		error = module_do_load(filename, false, 0, NULL, NULL, class,
+		    true);
+
+	kernconfig_unlock();
+	return error;
 }
 
 /*
@@ -592,9 +594,9 @@
 		return error;
 	}
 
-	mutex_enter(&module_lock);
+	kernconfig_lock();
 	error = module_do_unload(name, true);
-	mutex_exit(&module_lock);
+	kernconfig_unlock();
 
 	return error;
 }
@@ -609,7 +611,7 @@
 {
 	module_t *mod;
 
-	KASSERT(mutex_owned(&module_lock));
+	KASSERT(kernconfig_is_held());
 
 	TAILQ_FOREACH(mod, &module_list, mod_chain) {
 		if (strcmp(mod->mod_info->mi_name, name) == 0) {
@@ -632,14 +634,14 @@
 {
 	module_t *mod;
 
-	mutex_enter(&module_lock);
+	kernconfig_lock();
 	mod = module_lookup(name);
 	if (mod == NULL) {
-		mutex_exit(&module_lock);
+		kernconfig_unlock();
 		return ENOENT;
 	}
 	mod->mod_refcnt++;
-	mutex_exit(&module_lock);
+	kernconfig_unlock();
 
 	return 0;
 }
@@ -654,14 +656,14 @@
 {
 	module_t *mod;
 
-	mutex_enter(&module_lock);
+	kernconfig_lock();
 	mod = module_lookup(name);
 	if (mod == NULL) {
-		mutex_exit(&module_lock);
+		kernconfig_unlock();
 		panic("module_rele: gone");
 	}
 	mod->mod_refcnt--;
-	mutex_exit(&module_lock);
+	kernconfig_unlock();
 }
 
 /*
@@ -674,7 +676,7 @@
 {
 	int i;
 
-	KASSERT(mutex_owned(&module_lock));
+	KASSERT(kernconfig_is_held());
 
 	/*
 	 * If there are requisite modules, put at the head of the queue.
@@ -708,11 +710,11 @@
 	const char *p, *s;
 	char buf[MAXMODNAME];
 	modinfo_t *mi = NULL;
-	module_t *mod, *mod2, *mod_loaded;
+	module_t *mod, *mod2, *mod_loaded, *prev_active;
 	size_t len;
 	int error;
 
-	KASSERT(mutex_owned(&module_lock));
+	KASSERT(kernconfig_is_held());
 
 	/*
 	 * Search the list to see if we have a module by this name.
@@ -775,10 +777,10 @@
 	/*
 	 * Try to initialize the module.
 	 */
-	KASSERT(module_active == NULL);
+	prev_active = module_active;
 	module_active = mod;
 	error = (*mi->mi_modcmd)(MODULE_CMD_INIT, NULL);
-	module_active = NULL;
+	module_active = prev_active;
 	if (error != 0) {
 		module_error("builtin module `%s' "
 		    "failed to init", mi->mi_name);
@@ -809,18 +811,22 @@
 	       prop_dictionary_t props, module_t **modp, modclass_t class,
 	       bool autoload)
 {
-	static TAILQ_HEAD(,module) pending = TAILQ_HEAD_INITIALIZER(pending);
-	static int depth;
-	const int maxdepth = 6;
+#define MODULE_MAX_DEPTH 6
+
+	TAILQ_HEAD(pending_t, module);
+	static int depth = 0;
+	static struct pending_t *pending_lists[MODULE_MAX_DEPTH];
+	struct pending_t *pending;
+	struct pending_t new_pending = TAILQ_HEAD_INITIALIZER(new_pending);
 	modinfo_t *mi;
-	module_t *mod, *mod2;
+	module_t *mod, *mod2, *prev_active;
 	prop_dictionary_t filedict;
 	char buf[MAXMODNAME];
 	const char *s, *p;
 	int error;
 	size_t len;
 
-	KASSERT(mutex_owned(&module_lock));
+	KASSERT(kernconfig_is_held());
 
 	filedict = NULL;
 	error = 0;
@@ -828,13 +834,26 @@
 	/*
 	 * Avoid recursing too far.
 	 */
-	if (++depth > maxdepth) {
-		module_error("too many required modules");
+	if (++depth > MODULE_MAX_DEPTH) {
+		module_error("recursion too deep");
 		depth--;
 		return EMLINK;
 	}
 
 	/*
+	 * Set up the pending list for this depth.  If this is a
+	 * recursive entry, then use same list as for outer call,
+	 * else use the locally allocated list.  In either case,
+	 * remember which one we're using.
+	 */
+	if (isdep) {
+		KASSERT(depth > 1);
+		pending = pending_lists[depth - 2];
+	} else
+		pending = &new_pending;
+	pending_lists[depth - 1] = pending;
+
+	/*
 	 * Search the list of disabled builtins first.
 	 */
 	TAILQ_FOREACH(mod, &module_builtins, mod_chain) {
@@ -869,18 +888,14 @@
 		}
 	}
 	if (mod != NULL) {
-		TAILQ_INSERT_TAIL(&pending, mod, mod_chain);
+		TAILQ_INSERT_TAIL(pending, mod, mod_chain);
 	} else {
 		/*
 		 * If a requisite module, check to see if it is
 		 * already present.
 		 */
 		if (isdep) {
-			TAILQ_FOREACH(mod, &module_list, mod_chain) {
-				if (strcmp(mod->mod_info->mi_name, name) == 0) {
-					break;
-				}
-			}
+			mod = module_lookup(name);
 			if (mod != NULL) {
 				if (modp != NULL) {
 					*modp = mod;
@@ -903,7 +918,7 @@
 			depth--;
 			return error;
 		}
-		TAILQ_INSERT_TAIL(&pending, mod, mod_chain);
+		TAILQ_INSERT_TAIL(pending, mod, mod_chain);
 
 		error = module_fetch_info(mod);
 		if (error != 0) {
@@ -971,7 +986,7 @@
 	/*
 	 * Block circular dependencies.
 	 */
-	TAILQ_FOREACH(mod2, &pending, mod_chain) {
+	TAILQ_FOREACH(mod2, pending, mod_chain) {
 		if (mod == mod2) {
 			continue;
 		}
@@ -1041,10 +1056,10 @@
 			goto fail;
 		}
 	}
-	KASSERT(module_active == NULL);
+	prev_active = module_active;
 	module_active = mod;
 	error = (*mi->mi_modcmd)(MODULE_CMD_INIT, filedict ? filedict : props);
-	module_active = NULL;
+	module_active = prev_active;
 	if (filedict) {
 		prop_object_release(filedict);
 		filedict = NULL;
@@ -1062,7 +1077,7 @@
 	 * Good, the module loaded successfully.  Put it onto the
 	 * list and add references to its requisite modules.
 	 */
-	TAILQ_REMOVE(&pending, mod, mod_chain);
+	TAILQ_REMOVE(pending, mod, mod_chain);
 	module_enqueue(mod);
 	if (modp != NULL) {
 		*modp = mod;
@@ -1085,7 +1100,7 @@
 		prop_object_release(filedict);
 		filedict = NULL;
 	}
-	TAILQ_REMOVE(&pending, mod, mod_chain);
+	TAILQ_REMOVE(pending, mod, mod_chain);
 	kmem_free(mod, sizeof(*mod));
 	depth--;
 	return error;
@@ -1099,11 +1114,11 @@
 static int
 module_do_unload(const char *name, bool load_requires_force)
 {
-	module_t *mod;
+	module_t *mod, *prev_active;
 	int error;
 	u_int i;
 
-	KASSERT(mutex_owned(&module_lock));
+	KASSERT(kernconfig_is_held());
 
 	mod = module_lookup(name);
 	if (mod == NULL) {
@@ -1114,10 +1129,10 @@
 		module_print("module `%s' busy", name);
 		return EBUSY;
 	}
-	KASSERT(module_active == NULL);
+	prev_active = module_active;
 	module_active = mod;
 	error = (*mod->mod_info->mi_modcmd)(MODULE_CMD_FINI, NULL);
-	module_active = NULL;
+	module_active = prev_active;
 	if (error != 0) {
 		module_print("cannot unload module `%s' error=%d", name,
 		    error);
@@ -1223,7 +1238,7 @@
 module_find_section(const char *name, void **addr, size_t *size)
 {
 
-	KASSERT(mutex_owned(&module_lock));
+	KASSERT(kernconfig_is_held());
 	KASSERT(module_active != NULL);
 
 	return kobj_find_section(module_active->mod_kobj, name, addr, size);
@@ -1244,7 +1259,7 @@
 	int error;
 
 	for (;;) {
-		mutex_enter(&module_lock);
+		kernconfig_lock();
 		for (mod = TAILQ_FIRST(&module_list); mod != NULL; mod = next) {
 			next = TAILQ_NEXT(mod, mod_chain);
 			if (mod->mod_source == MODULE_SOURCE_KERNEL)
@@ -1271,7 +1286,7 @@
 				(void)module_do_unload(mi->mi_name, false);
 			}
 		}
-		mutex_exit(&module_lock);
+		kernconfig_unlock();
 
 		mutex_enter(&module_thread_lock);
 		(void)cv_timedwait(&module_thread_cv, &module_thread_lock,

Index: src/sys/sys/module.h
diff -u src/sys/sys/module.h:1.24 src/sys/sys/module.h:1.25
--- src/sys/sys/module.h:1.24	Sat Jun 26 07:23:57 2010
+++ src/sys/sys/module.h	Sat Aug 21 13:17:32 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: module.h,v 1.24 2010/06/26 07:23:57 pgoyette Exp $	*/
+/*	$NetBSD: module.h,v 1.25 2010/08/21 13:17:32 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -115,7 +115,6 @@
 TAILQ_HEAD(modlist, module);
 
 extern struct vm_map	*module_map;
-extern kmutex_t		module_lock;
 extern u_int		module_count;
 extern u_int		module_builtinlist;
 extern struct modlist	module_list;

Index: src/sys/sys/param.h
diff -u src/sys/sys/param.h:1.373 src/sys/sys/param.h:1.374
--- src/sys/sys/param.h:1.373	Wed Jul 28 11:03:47 2010
+++ src/sys/sys/param.h	Sat Aug 21 13:17:32 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: param.h,v 1.373 2010/07/28 11:03:47 hannken Exp $	*/
+/*	$NetBSD: param.h,v 1.374 2010/08/21 13:17:32 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -63,7 +63,7 @@
  *	2.99.9		(299000900)
  */
 
-#define	__NetBSD_Version__	599003800	/* NetBSD 5.99.38 */
+#define	__NetBSD_Version__	599003900	/* NetBSD 5.99.39 */
 
 #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \
     (m) * 1000000) + (p) * 100) <= __NetBSD_Version__)

Index: src/sys/sys/systm.h
diff -u src/sys/sys/systm.h:1.239 src/sys/sys/systm.h:1.240
--- src/sys/sys/systm.h:1.239	Sun Jan 31 02:04:43 2010
+++ src/sys/sys/systm.h	Sat Aug 21 13:17:32 2010
@@ -1,4 +1,4 @@
-/*	$NetBSD: systm.h,v 1.239 2010/01/31 02:04:43 pooka Exp $	*/
+/*	$NetBSD: systm.h,v 1.240 2010/08/21 13:17:32 pgoyette Exp $	*/
 
 /*-
  * Copyright (c) 1982, 1988, 1991, 1993
@@ -492,6 +492,11 @@
 void	_kernel_lock(int);
 void	_kernel_unlock(int, int *);
 
+void	kernconfig_lock_init(void);
+void	kernconfig_lock(void);
+void	kernconfig_unlock(void);
+bool	kernconfig_is_held(void);
+
 #if defined(MULTIPROCESSOR) || defined(_MODULE)
 #define	KERNEL_LOCK(count, lwp)			\
 do {						\

Added files:

Index: src/sys/kern/kern_cfglock.c
diff -u /dev/null src/sys/kern/kern_cfglock.c:1.1
--- /dev/null	Sat Aug 21 13:17:33 2010
+++ src/sys/kern/kern_cfglock.c	Sat Aug 21 13:17:31 2010
@@ -0,0 +1,101 @@
+/*	$NetBSD: kern_cfglock.c,v 1.1 2010/08/21 13:17:31 pgoyette Exp $ */
+
+/*-
+ * Copyright (c) 2002, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center, and by Andrew Doran.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: kern_cfglock.c,v 1.1 2010/08/21 13:17:31 pgoyette Exp $");
+
+#include <sys/param.h>
+#include <sys/cpu.h>
+#include <sys/mutex.h>
+#include <sys/lwp.h>
+#include <sys/systm.h>
+
+static kmutex_t kernconfig_mutex;
+static lwp_t *kernconfig_lwp;
+static int kernconfig_recurse;
+
+/*
+ * Functions for manipulating the kernel configuration lock.  This
+ * recursive lock should be used to protect all additions and removals
+ * of kernel functionality, such as device configuration and loading
+ * of modular kernel components.
+ */
+
+void
+kernconfig_lock_init(void)
+{
+
+	mutex_init(&kernconfig_mutex, MUTEX_DEFAULT, IPL_NONE);
+	kernconfig_lwp = NULL;
+	kernconfig_recurse = 0;
+}
+
+void
+kernconfig_lock(void)
+{
+	lwp_t	*my_lwp;
+
+	/*
+	 * It's OK to check this unlocked, since it could only be set to
+	 * curlwp by the current thread itself, and not by an interrupt
+	 * or any other LWP.
+	 */
+	KASSERT(!cpu_intr_p());
+	my_lwp = curlwp;
+	if (kernconfig_lwp == my_lwp) {
+		kernconfig_recurse++;
+		KASSERT(kernconfig_recurse > 1);
+	} else {
+		mutex_enter(&kernconfig_mutex);
+		kernconfig_lwp = my_lwp;
+		kernconfig_recurse = 1;
+	}
+}
+
+void
+kernconfig_unlock(void)
+{
+
+	KASSERT(kernconfig_is_held());
+	KASSERT(kernconfig_recurse != 0);
+	if (--kernconfig_recurse == 0) {
+		kernconfig_lwp = NULL;
+		mutex_exit(&kernconfig_mutex);
+	}
+}
+
+bool
+kernconfig_is_held(void)
+{
+
+	return mutex_owned(&kernconfig_mutex);
+}

Reply via email to