Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 21 Jan 2009 04:19:18 +0000 (UTC)
From:      Andrew Thompson <thompsa@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r187511 - in head/sys: kern sys
Message-ID:  <200901210419.n0L4JIG7066134@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: thompsa
Date: Wed Jan 21 04:19:18 2009
New Revision: 187511
URL: http://svn.freebsd.org/changeset/base/187511

Log:
  Add functions WITNESS so it can be asserted that the lock is not released for a
  section of code, this uses WITNESS_NORELEASE() and WITNESS_RELEASEOK() to mark
  the boundaries. Both functions require the lock to be held when calling.
  
  This is intended for scenarios like a bus asserting that the bus lock is not
  dropped during a driver call. There doesn't appear to be a man page to
  document this in.
  
  Reviewed by:	jhb

Modified:
  head/sys/kern/subr_witness.c
  head/sys/sys/lock.h

Modified: head/sys/kern/subr_witness.c
==============================================================================
--- head/sys/kern/subr_witness.c	Wed Jan 21 02:53:00 2009	(r187510)
+++ head/sys/kern/subr_witness.c	Wed Jan 21 04:19:18 2009	(r187511)
@@ -127,6 +127,7 @@ __FBSDID("$FreeBSD$");
 
 #define	LI_RECURSEMASK	0x0000ffff	/* Recursion depth of lock instance. */
 #define	LI_EXCLUSIVE	0x00010000	/* Exclusive lock instance. */
+#define	LI_NORELEASE	0x00020000	/* Lock not allowed to be released. */
 
 /* Define this to check for blessed mutexes */
 #undef BLESSING
@@ -367,6 +368,7 @@ static struct witness_lock_order_data	*w
 					    struct witness *parent,
 					    struct witness *child);
 static void	witness_list_lock(struct lock_instance *instance);
+static void	witness_setflag(struct lock_object *lock, int flag, int set);
 
 #ifdef KDB
 #define	witness_debugger(c)	_witness_debugger(c, __func__)
@@ -1509,6 +1511,11 @@ found:
 		    instance->li_line);
 		panic("share->uexcl");
 	}
+	if ((instance->li_flags & LI_NORELEASE) != 0 && witness_watch > 0) {
+		printf("forbidden unlock of (%s) %s @ %s:%d\n", class->lc_name,
+		    lock->lo_name, file, line);
+		panic("lock marked norelease");
+	}
 
 	/* If we are recursed, unrecurse. */
 	if ((instance->li_flags & LI_RECURSEMASK) > 0) {
@@ -2224,6 +2231,48 @@ witness_assert(struct lock_object *lock,
 #endif	/* INVARIANT_SUPPORT */
 }
 
+static void
+witness_setflag(struct lock_object *lock, int flag, int set)
+{
+	struct lock_list_entry *lock_list;
+	struct lock_instance *instance;
+	struct lock_class *class;
+
+	if (lock->lo_witness == NULL || witness_watch == -1 || panicstr != NULL)
+		return;
+	class = LOCK_CLASS(lock);
+	if (class->lc_flags & LC_SLEEPLOCK)
+		lock_list = curthread->td_sleeplocks;
+	else {
+		if (witness_skipspin)
+			return;
+		lock_list = PCPU_GET(spinlocks);
+	}
+	instance = find_instance(lock_list, lock);
+	if (instance == NULL)
+		panic("%s: lock (%s) %s not locked", __func__,
+		    class->lc_name, lock->lo_name);
+
+	if (set)
+		instance->li_flags |= flag;
+	else
+		instance->li_flags &= ~flag;
+}
+
+void
+witness_norelease(struct lock_object *lock)
+{
+
+	witness_setflag(lock, LI_NORELEASE, 1);
+}
+
+void
+witness_releaseok(struct lock_object *lock)
+{
+
+	witness_setflag(lock, LI_NORELEASE, 0);
+}
+
 #ifdef DDB
 static void
 witness_ddb_list(struct thread *td)

Modified: head/sys/sys/lock.h
==============================================================================
--- head/sys/sys/lock.h	Wed Jan 21 02:53:00 2009	(r187510)
+++ head/sys/sys/lock.h	Wed Jan 21 04:19:18 2009	(r187511)
@@ -216,6 +216,8 @@ int	witness_warn(int, struct lock_object
 void	witness_assert(struct lock_object *, int, const char *, int);
 void	witness_display_spinlock(struct lock_object *, struct thread *);
 int	witness_line(struct lock_object *);
+void	witness_norelease(struct lock_object *);
+void	witness_releaseok(struct lock_object *);
 const char *witness_file(struct lock_object *);
 void	witness_thread_exit(struct thread *);
 
@@ -267,6 +269,12 @@ void	witness_thread_exit(struct thread *
 #define	WITNESS_RESTORE(lock, n) 					\
 	witness_restore((lock), __CONCAT(n, __wf), __CONCAT(n, __wl))
 
+#define	WITNESS_NORELEASE(lock)						\
+	witness_norelease(&(lock)->lock_object)
+
+#define	WITNESS_RELEASEOK(lock)						\
+	witness_releaseok(&(lock)->lock_object)
+
 #define	WITNESS_FILE(lock) 						\
 	witness_file(lock)
 
@@ -287,6 +295,8 @@ void	witness_thread_exit(struct thread *
 #define	WITNESS_SAVE_DECL(n)
 #define	WITNESS_SAVE(lock, n)
 #define	WITNESS_RESTORE(lock, n)
+#define	WITNESS_NORELEASE(lock)
+#define	WITNESS_RELEASEOK(lock)
 #define	WITNESS_FILE(lock) ("?")
 #define	WITNESS_LINE(lock) (0)
 #endif	/* WITNESS */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200901210419.n0L4JIG7066134>