diff options
author | thompsa <thompsa@FreeBSD.org> | 2009-01-21 04:19:18 +0000 |
---|---|---|
committer | thompsa <thompsa@FreeBSD.org> | 2009-01-21 04:19:18 +0000 |
commit | 50e14c608efac2da56f8271a909fc7bc5396f053 (patch) | |
tree | 1a88a1f2553a5d499bb94b56aedbe8ab634b7f12 /sys/kern/subr_witness.c | |
parent | 48be47ddbcdf20ebb6e51798a78ac0707dc19ed3 (diff) | |
download | FreeBSD-src-50e14c608efac2da56f8271a909fc7bc5396f053.zip FreeBSD-src-50e14c608efac2da56f8271a909fc7bc5396f053.tar.gz |
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
Diffstat (limited to 'sys/kern/subr_witness.c')
-rw-r--r-- | sys/kern/subr_witness.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c index ce6aad1..60ab288 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -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 *witness_lock_order_get( 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, int flags, const char *file, int line) #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) |