Teach WITNESS about the interlocks used with lockmgr. This removes a bunch
of spurious witness warnings since lockmgr grew witness support. Before this, every time you passed an interlock to a lockmgr lock WITNESS treated it as a LOR. Reviewed by: attilio
This commit is contained in:
parent
ceee59fa5a
commit
413134305e
@ -375,7 +375,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk,
|
||||
case LK_SHARED:
|
||||
if (LK_CAN_WITNESS(flags))
|
||||
WITNESS_CHECKORDER(&lk->lock_object, LOP_NEWORDER,
|
||||
file, line);
|
||||
file, line, ilk);
|
||||
for (;;) {
|
||||
x = lk->lk_lock;
|
||||
|
||||
@ -505,7 +505,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk,
|
||||
case LK_EXCLUSIVE:
|
||||
if (LK_CAN_WITNESS(flags))
|
||||
WITNESS_CHECKORDER(&lk->lock_object, LOP_NEWORDER |
|
||||
LOP_EXCLUSIVE, file, line);
|
||||
LOP_EXCLUSIVE, file, line, ilk);
|
||||
|
||||
/*
|
||||
* If curthread already holds the lock and this one is
|
||||
@ -724,7 +724,7 @@ __lockmgr_args(struct lock *lk, u_int flags, struct lock_object *ilk,
|
||||
case LK_DRAIN:
|
||||
if (LK_CAN_WITNESS(flags))
|
||||
WITNESS_CHECKORDER(&lk->lock_object, LOP_NEWORDER |
|
||||
LOP_EXCLUSIVE, file, line);
|
||||
LOP_EXCLUSIVE, file, line, ilk);
|
||||
|
||||
/*
|
||||
* Trying to drain a lock we already own will result in a
|
||||
|
@ -177,7 +177,7 @@ _mtx_lock_flags(struct mtx *m, int opts, const char *file, int line)
|
||||
("mtx_lock() of spin mutex %s @ %s:%d", m->lock_object.lo_name,
|
||||
file, line));
|
||||
WITNESS_CHECKORDER(&m->lock_object, opts | LOP_NEWORDER | LOP_EXCLUSIVE,
|
||||
file, line);
|
||||
file, line, NULL);
|
||||
|
||||
_get_sleep_lock(m, curthread, opts, file, line);
|
||||
LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file,
|
||||
@ -221,7 +221,7 @@ _mtx_lock_spin_flags(struct mtx *m, int opts, const char *file, int line)
|
||||
("mtx_lock_spin: recursed on non-recursive mutex %s @ %s:%d\n",
|
||||
m->lock_object.lo_name, file, line));
|
||||
WITNESS_CHECKORDER(&m->lock_object, opts | LOP_NEWORDER | LOP_EXCLUSIVE,
|
||||
file, line);
|
||||
file, line, NULL);
|
||||
_get_spin_lock(m, curthread, opts, file, line);
|
||||
LOCK_LOG_LOCK("LOCK", &m->lock_object, opts, m->mtx_recurse, file,
|
||||
line);
|
||||
@ -506,7 +506,7 @@ _thread_lock_flags(struct thread *td, int opts, const char *file, int line)
|
||||
("thread_lock: recursed on non-recursive mutex %s @ %s:%d\n",
|
||||
m->lock_object.lo_name, file, line));
|
||||
WITNESS_CHECKORDER(&m->lock_object,
|
||||
opts | LOP_NEWORDER | LOP_EXCLUSIVE, file, line);
|
||||
opts | LOP_NEWORDER | LOP_EXCLUSIVE, file, line, NULL);
|
||||
while (!_obtain_lock(m, tid)) {
|
||||
if (m->mtx_lock == tid) {
|
||||
m->mtx_recurse++;
|
||||
|
@ -433,7 +433,7 @@ void _rm_wlock_debug(struct rmlock *rm, const char *file, int line)
|
||||
|
||||
|
||||
WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE,
|
||||
file, line);
|
||||
file, line, NULL);
|
||||
|
||||
_rm_wlock(rm);
|
||||
|
||||
@ -460,7 +460,7 @@ _rm_rlock_debug(struct rmlock *rm, struct rm_priotracker *tracker,
|
||||
{
|
||||
|
||||
|
||||
WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER , file, line);
|
||||
WITNESS_CHECKORDER(&rm->lock_object, LOP_NEWORDER , file, line, NULL);
|
||||
|
||||
_rm_rlock(rm, tracker);
|
||||
|
||||
|
@ -206,7 +206,7 @@ _rw_wlock(struct rwlock *rw, const char *file, int line)
|
||||
KASSERT(rw->rw_lock != RW_DESTROYED,
|
||||
("rw_wlock() of destroyed rwlock @ %s:%d", file, line));
|
||||
WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
|
||||
line);
|
||||
line, NULL);
|
||||
__rw_wlock(rw, curthread, file, line);
|
||||
LOCK_LOG_LOCK("WLOCK", &rw->lock_object, 0, rw->rw_recurse, file, line);
|
||||
WITNESS_LOCK(&rw->lock_object, LOP_EXCLUSIVE, file, line);
|
||||
@ -283,7 +283,7 @@ _rw_rlock(struct rwlock *rw, const char *file, int line)
|
||||
KASSERT(rw_wowner(rw) != curthread,
|
||||
("%s (%s): wlock already held @ %s:%d", __func__,
|
||||
rw->lock_object.lo_name, file, line));
|
||||
WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER, file, line);
|
||||
WITNESS_CHECKORDER(&rw->lock_object, LOP_NEWORDER, file, line, NULL);
|
||||
|
||||
for (;;) {
|
||||
/*
|
||||
|
@ -211,7 +211,7 @@ _sx_slock(struct sx *sx, int opts, const char *file, int line)
|
||||
MPASS(curthread != NULL);
|
||||
KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
|
||||
("sx_slock() of destroyed sx @ %s:%d", file, line));
|
||||
WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER, file, line);
|
||||
WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER, file, line, NULL);
|
||||
error = __sx_slock(sx, opts, file, line);
|
||||
if (!error) {
|
||||
LOCK_LOG_LOCK("SLOCK", &sx->lock_object, 0, 0, file, line);
|
||||
@ -254,7 +254,7 @@ _sx_xlock(struct sx *sx, int opts, const char *file, int line)
|
||||
KASSERT(sx->sx_lock != SX_LOCK_DESTROYED,
|
||||
("sx_xlock() of destroyed sx @ %s:%d", file, line));
|
||||
WITNESS_CHECKORDER(&sx->lock_object, LOP_NEWORDER | LOP_EXCLUSIVE, file,
|
||||
line);
|
||||
line, NULL);
|
||||
error = __sx_xlock(sx, curthread, opts, file, line);
|
||||
if (!error) {
|
||||
LOCK_LOG_LOCK("XLOCK", &sx->lock_object, 0, sx->sx_recurse,
|
||||
|
@ -1011,10 +1011,10 @@ witness_defineorder(struct lock_object *lock1, struct lock_object *lock2)
|
||||
|
||||
void
|
||||
witness_checkorder(struct lock_object *lock, int flags, const char *file,
|
||||
int line)
|
||||
int line, struct lock_object *interlock)
|
||||
{
|
||||
struct lock_list_entry **lock_list, *lle;
|
||||
struct lock_instance *lock1, *lock2;
|
||||
struct lock_instance *lock1, *lock2, *plock;
|
||||
struct lock_class *class;
|
||||
struct witness *w, *w1;
|
||||
struct thread *td;
|
||||
@ -1093,12 +1093,26 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file,
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the previously acquired lock, but ignore interlocks.
|
||||
*/
|
||||
plock = &(*lock_list)->ll_children[(*lock_list)->ll_count - 1];
|
||||
if (interlock != NULL && plock->li_lock == interlock) {
|
||||
if ((*lock_list)->ll_count == 1) {
|
||||
/*
|
||||
* The interlock is the only lock we hold, so
|
||||
* nothing to do.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
plock = &(*lock_list)->ll_children[(*lock_list)->ll_count - 2];
|
||||
}
|
||||
|
||||
/*
|
||||
* Try to perform most checks without a lock. If this succeeds we
|
||||
* can skip acquiring the lock and return success.
|
||||
*/
|
||||
lock1 = &(*lock_list)->ll_children[(*lock_list)->ll_count - 1];
|
||||
w1 = lock1->li_lock->lo_witness;
|
||||
w1 = plock->li_lock->lo_witness;
|
||||
if (witness_lock_order_check(w1, w))
|
||||
return;
|
||||
|
||||
@ -1141,12 +1155,20 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file,
|
||||
|
||||
MPASS(j < WITNESS_COUNT);
|
||||
lock1 = &lle->ll_children[i];
|
||||
w1 = lock1->li_lock->lo_witness;
|
||||
|
||||
/*
|
||||
* Ignore the interlock the first time we see it.
|
||||
*/
|
||||
if (interlock != NULL && interlock == lock1->li_lock) {
|
||||
interlock = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* If this lock doesn't undergo witness checking,
|
||||
* then skip it.
|
||||
*/
|
||||
w1 = lock1->li_lock->lo_witness;
|
||||
if (w1 == NULL) {
|
||||
KASSERT((lock1->li_lock->lo_flags & LO_WITNESS) == 0,
|
||||
("lock missing witness structure"));
|
||||
@ -1271,7 +1293,6 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file,
|
||||
return;
|
||||
}
|
||||
}
|
||||
lock1 = &(*lock_list)->ll_children[(*lock_list)->ll_count - 1];
|
||||
|
||||
/*
|
||||
* If requested, build a new lock order. However, don't build a new
|
||||
@ -1280,11 +1301,11 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file,
|
||||
* always come before Giant.
|
||||
*/
|
||||
if (flags & LOP_NEWORDER &&
|
||||
!(lock1->li_lock == &Giant.lock_object &&
|
||||
!(plock->li_lock == &Giant.lock_object &&
|
||||
(lock->lo_flags & LO_SLEEPABLE) != 0)) {
|
||||
CTR3(KTR_WITNESS, "%s: adding %s as a child of %s", __func__,
|
||||
w->w_name, lock1->li_lock->lo_witness->w_name);
|
||||
itismychild(lock1->li_lock->lo_witness, w);
|
||||
w->w_name, plock->li_lock->lo_witness->w_name);
|
||||
itismychild(plock->li_lock->lo_witness, w);
|
||||
}
|
||||
out:
|
||||
mtx_unlock_spin(&w_mtx);
|
||||
|
@ -203,7 +203,8 @@ void spinlock_exit(void);
|
||||
void witness_init(struct lock_object *, const char *);
|
||||
void witness_destroy(struct lock_object *);
|
||||
int witness_defineorder(struct lock_object *, struct lock_object *);
|
||||
void witness_checkorder(struct lock_object *, int, const char *, int);
|
||||
void witness_checkorder(struct lock_object *, int, const char *, int,
|
||||
struct lock_object *);
|
||||
void witness_lock(struct lock_object *, int, const char *, int);
|
||||
void witness_upgrade(struct lock_object *, int, const char *, int);
|
||||
void witness_downgrade(struct lock_object *, int, const char *, int);
|
||||
@ -231,8 +232,8 @@ void witness_thread_exit(struct thread *);
|
||||
#define WITNESS_DESTROY(lock) \
|
||||
witness_destroy(lock)
|
||||
|
||||
#define WITNESS_CHECKORDER(lock, flags, file, line) \
|
||||
witness_checkorder((lock), (flags), (file), (line))
|
||||
#define WITNESS_CHECKORDER(lock, flags, file, line, interlock) \
|
||||
witness_checkorder((lock), (flags), (file), (line), (interlock))
|
||||
|
||||
#define WITNESS_DEFINEORDER(lock1, lock2) \
|
||||
witness_defineorder((struct lock_object *)(lock1), \
|
||||
@ -276,7 +277,7 @@ void witness_thread_exit(struct thread *);
|
||||
#define WITNESS_INIT(lock, type)
|
||||
#define WITNESS_DESTROY(lock)
|
||||
#define WITNESS_DEFINEORDER(lock1, lock2) 0
|
||||
#define WITNESS_CHECKORDER(lock, flags, file, line)
|
||||
#define WITNESS_CHECKORDER(lock, flags, file, line, interlock)
|
||||
#define WITNESS_LOCK(lock, flags, file, line)
|
||||
#define WITNESS_UPGRADE(lock, flags, file, line)
|
||||
#define WITNESS_DOWNGRADE(lock, flags, file, line)
|
||||
@ -296,10 +297,10 @@ void witness_thread_exit(struct thread *);
|
||||
*/
|
||||
#define witness_check(l) \
|
||||
WITNESS_CHECKORDER(&(l)->lock_object, LOP_EXCLUSIVE, LOCK_FILE, \
|
||||
LOCK_LINE)
|
||||
LOCK_LINE, NULL)
|
||||
|
||||
#define witness_check_shared(l) \
|
||||
WITNESS_CHECKORDER(&(l)->lock_object, 0, LOCK_FILE, LOCK_LINE)
|
||||
WITNESS_CHECKORDER(&(l)->lock_object, 0, LOCK_FILE, LOCK_LINE, NULL)
|
||||
|
||||
#endif /* _KERNEL */
|
||||
#endif /* _SYS_LOCK_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user