Handle "dead" witnesses better in the situation of several short term locks

being created and destroyed without a single long-term one around to ensure
the witness associated with that group of locks stays alive.  The pipe
mutexes are an example of this group.  For a dead witness we no longer
clear the witness name.  Instead, when looking up the witness for a lock,
if a dead witness' (a witness with a refcount of 0) w_name pointer is
identical to the witness name of the lock then we revive that witness
instead of using a new witness for the lock.  This results in far fewer
dead witness objects and also better preserves locking orders over the long
term resulting in more correct lock order checking.  Note that we can't
ever derefence w_name of a dead witness since we don't know if the string
it is pointing to has been free()'d or kldunload()'d out from under us.
This commit is contained in:
John Baldwin 2002-06-06 19:04:38 +00:00
parent fa7212543f
commit 8dcb900b62

View File

@ -381,14 +381,8 @@ witness_destroy(struct lock_object *lock)
w = lock->lo_witness;
if (w != NULL) {
mtx_lock_spin(&w_mtx);
MPASS(w->w_refcount > 0);
w->w_refcount--;
if (w->w_refcount == 0) {
CTR2(KTR_WITNESS,
"%s: marking witness %s as dead", __func__, w->w_name);
w->w_name = "(dead)";
w->w_file = "(dead)";
w->w_line = 0;
}
mtx_unlock_spin(&w_mtx);
}
@ -451,7 +445,7 @@ witness_display(void(*prnt)(const char *fmt, ...))
*/
prnt("\nLocks which were never acquired:\n");
STAILQ_FOREACH(w, &w_all, w_list) {
if (w->w_file != NULL)
if (w->w_file != NULL || w->w_refcount == 0)
continue;
prnt("%s\n", w->w_name);
}
@ -937,7 +931,8 @@ enroll(const char *description, struct lock_class *lock_class)
return (NULL);
mtx_lock_spin(&w_mtx);
STAILQ_FOREACH(w, &w_all, w_list) {
if (strcmp(description, w->w_name) == 0) {
if (w->w_name == description || (w->w_refcount > 0 &&
strcmp(description, w->w_name) == 0)) {
w->w_refcount++;
mtx_unlock_spin(&w_mtx);
if (lock_class != w->w_class)
@ -1149,10 +1144,13 @@ witness_displaydescendants(void(*prnt)(const char *fmt, ...),
prnt("%-2d", level);
for (i = 0; i < level; i++)
prnt(" ");
prnt("%s", parent->w_name);
if (parent->w_file != NULL)
prnt(" -- last acquired @ %s:%d\n", parent->w_file,
parent->w_line);
if (parent->w_refcount > 0) {
prnt("%s", parent->w_name);
if (parent->w_file != NULL)
prnt(" -- last acquired @ %s:%d\n", parent->w_file,
parent->w_line);
} else
prnt("(dead)\n");
for (wcl = parent->w_children; wcl != NULL; wcl = wcl->wcl_next)
for (i = 0; i < wcl->wcl_count; i++)
witness_displaydescendants(prnt,