mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-12-05 03:39:02 +00:00
- Move the 'clk' spinlock below other spin locks since KTR trace events
may need the clock lock for nanotime(). - Add KTR trace events for lock list manipulations and other witness operations. - Use a temporary variable instead of setting the lock list head directly and then setting up the links to add a new lock list entry to the lock list. This small race could result in witness "forgetting" about all the locks held by this process temporarily during an interrupt. - Close a more fatal race condition when removing a lock from a list. Removing a lock from the list entails both decrementing the count of items in this bucket as well as shuffling items in the current bucket up a notch to replace the gap left by the removed item. Wrap these operations in a critical section.
This commit is contained in:
parent
1715f07da3
commit
b7e554f5d6
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=78785
@ -208,7 +208,6 @@ static struct witness_order_list_entry order_lists[] = {
|
||||
{ "ng_worklist", &lock_class_mtx_spin },
|
||||
{ "ithread table lock", &lock_class_mtx_spin },
|
||||
{ "sched lock", &lock_class_mtx_spin },
|
||||
{ "clk", &lock_class_mtx_spin },
|
||||
{ "callout", &lock_class_mtx_spin },
|
||||
/*
|
||||
* leaf locks
|
||||
@ -220,6 +219,7 @@ static struct witness_order_list_entry order_lists[] = {
|
||||
#endif
|
||||
{ "smp rendezvous", &lock_class_mtx_spin },
|
||||
#endif
|
||||
{ "clk", &lock_class_mtx_spin },
|
||||
{ NULL, NULL },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
@ -284,6 +284,7 @@ witness_initialize(void *dummy __unused)
|
||||
mtx_unlock(&Giant);
|
||||
mtx_assert(&Giant, MA_NOTOWNED);
|
||||
|
||||
CTR1(KTR_WITNESS, "%s: initializing witness", __func__);
|
||||
STAILQ_INSERT_HEAD(&all_locks, &all_mtx.mtx_object, lo_list);
|
||||
mtx_init(&w_mtx, "witness lock", MTX_SPIN | MTX_QUIET | MTX_NOWITNESS);
|
||||
for (i = 0; i < WITNESS_COUNT; i++)
|
||||
@ -380,6 +381,8 @@ witness_destroy(struct lock_object *lock)
|
||||
mtx_lock_spin(&w_mtx);
|
||||
w->w_refcount--;
|
||||
if (w->w_refcount == 0) {
|
||||
CTR1(KTR_WITNESS, "Marking witness %s as dead",
|
||||
w->w_name);
|
||||
w->w_name = "(dead)";
|
||||
w->w_file = "(dead)";
|
||||
w->w_line = 0;
|
||||
@ -538,6 +541,9 @@ witness_lock(struct lock_object *lock, int flags, const char *file, int line)
|
||||
lock1->li_line);
|
||||
panic("recurse");
|
||||
}
|
||||
CTR3(KTR_WITNESS, "witness_lock: pid %d recursed on %s r=%d",
|
||||
curproc->p_pid, lock->lo_name,
|
||||
lock1->li_flags & LI_RECURSEMASK);
|
||||
lock1->li_file = file;
|
||||
lock1->li_line = line;
|
||||
return;
|
||||
@ -662,6 +668,8 @@ witness_lock(struct lock_object *lock, int flags, const char *file, int line)
|
||||
}
|
||||
}
|
||||
lock1 = &(*lock_list)->ll_children[(*lock_list)->ll_count - 1];
|
||||
CTR2(KTR_WITNESS, "Adding %s as a child of %s", lock->lo_name,
|
||||
lock1->li_lock->lo_name);
|
||||
if (!itismychild(lock1->li_lock->lo_witness, w))
|
||||
mtx_unlock_spin(&w_mtx);
|
||||
|
||||
@ -675,11 +683,13 @@ out:
|
||||
|
||||
lle = *lock_list;
|
||||
if (lle == NULL || lle->ll_count == LOCK_NCHILDREN) {
|
||||
*lock_list = witness_lock_list_get();
|
||||
if (*lock_list == NULL)
|
||||
lle = witness_lock_list_get();
|
||||
if (lle == NULL)
|
||||
return;
|
||||
(*lock_list)->ll_next = lle;
|
||||
lle = *lock_list;
|
||||
lle->ll_next = *lock_list;
|
||||
CTR2(KTR_WITNESS, "witness_lock: pid %d added lle %p",
|
||||
curproc->p_pid, lle);
|
||||
*lock_list = lle;
|
||||
}
|
||||
lock1 = &lle->ll_children[lle->ll_count++];
|
||||
lock1->li_lock = lock;
|
||||
@ -689,6 +699,8 @@ out:
|
||||
lock1->li_flags = LI_EXCLUSIVE;
|
||||
else
|
||||
lock1->li_flags = 0;
|
||||
CTR3(KTR_WITNESS, "witness_lock: pid %d added %s as lle[%d]",
|
||||
curproc->p_pid, lock->lo_name, lle->ll_count - 1);
|
||||
}
|
||||
|
||||
void
|
||||
@ -698,6 +710,7 @@ witness_unlock(struct lock_object *lock, int flags, const char *file, int line)
|
||||
struct lock_instance *instance;
|
||||
struct lock_class *class;
|
||||
struct proc *p;
|
||||
critical_t s;
|
||||
int i, j;
|
||||
|
||||
if (witness_cold || witness_dead || lock->lo_witness == NULL ||
|
||||
@ -739,16 +752,30 @@ witness_unlock(struct lock_object *lock, int flags, const char *file, int line)
|
||||
}
|
||||
/* If we are recursed, unrecurse. */
|
||||
if ((instance->li_flags & LI_RECURSEMASK) > 0) {
|
||||
CTR3(KTR_WITNESS,
|
||||
"witness_unlock: pid %d unrecursed on %s r=%d",
|
||||
curproc->p_pid,
|
||||
instance->li_lock->lo_name,
|
||||
instance->li_flags);
|
||||
instance->li_flags--;
|
||||
goto out;
|
||||
}
|
||||
s = critical_enter();
|
||||
CTR3(KTR_WITNESS,
|
||||
"witness_unlock: pid %d removed %s from lle[%d]",
|
||||
curproc->p_pid, instance->li_lock->lo_name,
|
||||
(*lock_list)->ll_count - 1);
|
||||
(*lock_list)->ll_count--;
|
||||
for (j = i; j < (*lock_list)->ll_count; j++)
|
||||
(*lock_list)->ll_children[j] =
|
||||
(*lock_list)->ll_children[j + 1];
|
||||
critical_exit(s);
|
||||
if ((*lock_list)->ll_count == 0) {
|
||||
lle = *lock_list;
|
||||
*lock_list = lle->ll_next;
|
||||
CTR2(KTR_WITNESS,
|
||||
"witness_unlock: pid %d removed lle %p",
|
||||
curproc->p_pid, lle);
|
||||
witness_lock_list_free(lle);
|
||||
}
|
||||
goto out;
|
||||
@ -803,8 +830,14 @@ again:
|
||||
lock1->li_lock == &Giant.mtx_object)
|
||||
continue;
|
||||
if ((lock1->li_lock->lo_flags & LO_SLEEPABLE) != 0) {
|
||||
if (check_only == 0)
|
||||
if (check_only == 0) {
|
||||
CTR3(KTR_WITNESS,
|
||||
"pid %d: sleeping with (%s) %s held",
|
||||
curproc->p_pid,
|
||||
lock1->li_lock->lo_class->lc_name,
|
||||
lock1->li_lock->lo_name);
|
||||
lock1->li_flags |= LI_SLEPT;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
n++;
|
||||
|
Loading…
Reference in New Issue
Block a user