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
This commit is contained in:
parent
48be47ddbc
commit
50e14c608e
@ -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 @@ witness_unlock(struct lock_object *lock, int flags, const char *file, int line)
|
||||
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)
|
||||
|
@ -216,6 +216,8 @@ int witness_warn(int, struct lock_object *, const char *, ...);
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user