--- //depot/projects/smpng/sys/kern/subr_witness.c 2005/10/25 20:19:31 +++ //depot/user/jhb/lock/kern/subr_witness.c 2005/11/10 21:40:37 @@ -103,6 +103,10 @@ #include +/* Easier to stay with the old names. */ +#define lo_list lo_witness_data.lod_list +#define lo_witness lo_witness_data.lod_witness + /* Define this to check for blessed mutexes */ #undef BLESSING @@ -430,19 +434,11 @@ #endif /* - * List of all locks in the system. + * List of locks initialized prior to witness being initialized whose + * enrollment is currently deferred. */ -TAILQ_HEAD(, lock_object) all_locks = TAILQ_HEAD_INITIALIZER(all_locks); - -static struct mtx all_mtx = { - { &lock_class_mtx_sleep, /* mtx_object.lo_class */ - "All locks list", /* mtx_object.lo_name */ - "All locks list", /* mtx_object.lo_type */ - LO_INITIALIZED, /* mtx_object.lo_flags */ - { NULL, NULL }, /* mtx_object.lo_list */ - NULL }, /* mtx_object.lo_witness */ - MTX_UNOWNED, 0 /* mtx_lock, mtx_recurse */ -}; +STAILQ_HEAD(, lock_object) pending_locks = + STAILQ_HEAD_INITIALIZER(pending_locks); /* * This global is set to 0 once it becomes safe to use the witness code. @@ -456,14 +452,10 @@ static int witness_spin_warn = 0; /* - * Global variables for book keeping. + * The WITNESS-enabled diagnostic code. Note that the witness code does + * assume that the early boot is single-threaded at least until after this + * routine is completed. */ -static int lock_cur_cnt; -static int lock_max_cnt; - -/* - * The WITNESS-enabled diagnostic code. - */ static void witness_initialize(void *dummy __unused) { @@ -480,7 +472,6 @@ mtx_assert(&Giant, MA_NOTOWNED); CTR1(KTR_WITNESS, "%s: initializing witness", __func__); - TAILQ_INSERT_HEAD(&all_locks, &all_mtx.mtx_object, lo_list); mtx_init(&w_mtx, "witness lock", NULL, MTX_SPIN | MTX_QUIET | MTX_NOWITNESS); for (i = 0; i < WITNESS_COUNT; i++) @@ -509,15 +500,14 @@ witness_spin_warn = 1; /* Iterate through all locks and add them to witness. */ - mtx_lock(&all_mtx); - TAILQ_FOREACH(lock, &all_locks, lo_list) { - if (lock->lo_flags & LO_WITNESS) - lock->lo_witness = enroll(lock->lo_type, - lock->lo_class); - else - lock->lo_witness = NULL; + while (!STAILQ_EMPTY(&pending_locks)) { + lock = STAILQ_FIRST(&pending_locks); + STAILQ_REMOVE_HEAD(&pending_locks, lo_list); + KASSERT(lock->lo_flags & LO_WITNESS, + ("%s: lock %s is on pending list but not LO_WITNESS", + __func__, lock->lo_name)); + lock->lo_witness = enroll(lock->lo_type, lock->lo_class); } - mtx_unlock(&all_mtx); /* Mark the witness code as being ready for use. */ witness_cold = 0; @@ -551,6 +541,7 @@ { struct lock_class *class; + /* Various sanity checks. */ class = lock->lo_class; if (lock->lo_flags & LO_INITIALIZED) panic("%s: lock (%s) %s is already initialized", __func__, @@ -568,18 +559,22 @@ panic("%s: lock (%s) %s can not be upgradable", __func__, class->lc_name, lock->lo_name); - mtx_lock(&all_mtx); - TAILQ_INSERT_TAIL(&all_locks, lock, lo_list); + /* + * If we shouldn't watch this lock, then just clear lo_witness. + * Otherwise, if witness_cold is set, then it is too early to + * enroll this lock, so defer it to witness_initialize() by adding + * it to the pending_locks list. If it is not too early, then enroll + * the lock now. + */ lock->lo_flags |= LO_INITIALIZED; - lock_cur_cnt++; - if (lock_cur_cnt > lock_max_cnt) - lock_max_cnt = lock_cur_cnt; - mtx_unlock(&all_mtx); - if (!witness_cold && witness_watch != 0 && panicstr == NULL && - (lock->lo_flags & LO_WITNESS) != 0) + if (witness_watch == 0 || panicstr != NULL || + (lock->lo_flags & LO_WITNESS) == 0) + lock->lo_witness = NULL; + else if (witness_cold) { + STAILQ_INSERT_TAIL(&pending_locks, lock, lo_list); + lock->lo_flags |= LO_ENROLLPEND; + } else lock->lo_witness = enroll(lock->lo_type, class); - else - lock->lo_witness = NULL; } void @@ -595,8 +590,9 @@ lock->lo_class->lc_name, lock->lo_name); /* XXX: need to verify that no one holds the lock */ - w = lock->lo_witness; - if (w != NULL) { + if ((lock->lo_flags & (LO_WITNESS | LO_ENROLLPEND)) == LO_WITNESS && + lock->lo_witness != NULL) { + w = lock->lo_witness; mtx_lock_spin(&w_mtx); MPASS(w->w_refcount > 0); w->w_refcount--; @@ -609,11 +605,15 @@ mtx_unlock_spin(&w_mtx); } - mtx_lock(&all_mtx); - lock_cur_cnt--; - TAILQ_REMOVE(&all_locks, lock, lo_list); + /* + * If this lock is destroyed before witness is up and running, + * remove it from the pending list. + */ + if (lock->lo_flags & LO_ENROLLPEND) { + STAILQ_REMOVE(&pending_locks, lock, lock_object, lo_list); + lock->lo_flags &= ~LO_ENROLLPEND; + } lock->lo_flags &= ~LO_INITIALIZED; - mtx_unlock(&all_mtx); } #ifdef DDB --- //depot/projects/smpng/sys/sys/_lock.h 2004/06/23 20:40:08 +++ //depot/user/jhb/lock/sys/_lock.h 2005/11/10 19:10:18 @@ -36,8 +36,10 @@ const char *lo_name; /* Individual lock name. */ const char *lo_type; /* General lock type. */ u_int lo_flags; - TAILQ_ENTRY(lock_object) lo_list; /* List of all locks in system. */ - struct witness *lo_witness; + union { /* Data for witness. */ + STAILQ_ENTRY(lock_object) lod_list; + struct witness *lod_witness; + } lo_witness_data; }; #endif /* !_SYS__LOCK_H_ */ --- //depot/projects/smpng/sys/sys/lock.h 2005/05/27 14:58:46 +++ //depot/user/jhb/lock/sys/lock.h 2005/11/10 18:21:33 @@ -66,6 +66,7 @@ #define LO_SLEEPABLE 0x00100000 /* Lock may be held while sleeping. */ #define LO_UPGRADABLE 0x00200000 /* Lock may be upgraded/downgraded. */ #define LO_DUPOK 0x00400000 /* Don't check for duplicate acquires */ +#define LO_ENROLLPEND 0x00800000 /* On the pending enroll list. */ #define LI_RECURSEMASK 0x0000ffff /* Recursion depth of lock instance. */ #define LI_EXCLUSIVE 0x00010000 /* Exclusive lock instance. */