summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_witness.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/subr_witness.c')
-rw-r--r--sys/kern/subr_witness.c105
1 files changed, 41 insertions, 64 deletions
diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c
index d2e84a5..1d9dfcb 100644
--- a/sys/kern/subr_witness.c
+++ b/sys/kern/subr_witness.c
@@ -113,10 +113,6 @@ __FBSDID("$FreeBSD$");
#define KTR_WITNESS 0
#endif
-/* Easier to stay with the old names. */
-#define lo_list lo_witness_data.lod_list
-#define lo_witness lo_witness_data.lod_witness
-
#define LI_RECURSEMASK 0x0000ffff /* Recursion depth of lock instance. */
#define LI_EXCLUSIVE 0x00010000 /* Exclusive lock instance. */
@@ -126,6 +122,7 @@ __FBSDID("$FreeBSD$");
#define WITNESS_COUNT 1024
#define WITNESS_CHILDCOUNT (WITNESS_COUNT * 4)
#define WITNESS_SBUFSIZE 32768
+#define WITNESS_PENDLIST 512
/*
* XXX: This is somewhat bogus, as we assume here that at most 1024 threads
* will hold LOCK_NCHILDREN * 2 locks. We handle failure ok, and we should
@@ -204,10 +201,15 @@ struct witness_order_list_entry {
struct lock_class *w_class;
};
+struct witness_pendhelp {
+ const char *wh_type;
+ struct lock_object *wh_lock;
+};
+
#ifdef BLESSING
static int blessed(struct witness *, struct witness *);
#endif
-static int depart(struct witness *w);
+static void depart(struct witness *w);
static struct witness *enroll(const char *description,
struct lock_class *lock_class);
static int insertchild(struct witness *parent, struct witness *child);
@@ -218,7 +220,7 @@ static void removechild(struct witness *parent, struct witness *child);
static int sysctl_debug_witness_watch(SYSCTL_HANDLER_ARGS);
static int sysctl_debug_witness_graphs(SYSCTL_HANDLER_ARGS);
static const char *fixup_filename(const char *file);
-static void witness_addgraph(struct sbuf *sb, struct witness *w);
+static void witness_addgraph(struct sbuf *sb, struct witness *parent);
static struct witness *witness_get(void);
static void witness_free(struct witness *m);
static struct witness_child_list_entry *witness_child_get(void);
@@ -296,6 +298,8 @@ static struct witness_list w_spin = STAILQ_HEAD_INITIALIZER(w_spin);
static struct witness_list w_sleep = STAILQ_HEAD_INITIALIZER(w_sleep);
static struct witness_child_list_entry *w_child_free = NULL;
static struct lock_list_entry *w_lock_list_free = NULL;
+static struct witness_pendhelp pending_locks[WITNESS_PENDLIST];
+static u_int pending_cnt;
static int w_free_cnt, w_spin_cnt, w_sleep_cnt, w_child_free_cnt, w_child_cnt;
SYSCTL_INT(_debug_witness, OID_AUTO, free_cnt, CTLFLAG_RD, &w_free_cnt, 0, "");
@@ -525,13 +529,6 @@ static int blessed_count =
#endif
/*
- * List of locks initialized prior to witness being initialized whose
- * enrollment is currently deferred.
- */
-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.
*/
static int witness_cold = 1;
@@ -591,13 +588,13 @@ witness_initialize(void *dummy __unused)
witness_spin_warn = 1;
/* Iterate through all locks and add them to witness. */
- while (!STAILQ_EMPTY(&pending_locks)) {
- lock = STAILQ_FIRST(&pending_locks);
- STAILQ_REMOVE_HEAD(&pending_locks, lo_list);
+ for (i = 0; pending_locks[i].wh_lock != NULL; i++) {
+ lock = pending_locks[i].wh_lock;
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_CLASS(lock));
+ lock->lo_witness = enroll(pending_locks[i].wh_type,
+ LOCK_CLASS(lock));
}
/* Mark the witness code as being ready for use. */
@@ -659,7 +656,7 @@ sysctl_debug_witness_graphs(SYSCTL_HANDLER_ARGS)
}
void
-witness_init(struct lock_object *lock)
+witness_init(struct lock_object *lock, const char *type)
{
struct lock_class *class;
@@ -689,10 +686,13 @@ witness_init(struct lock_object *lock)
(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;
+ pending_locks[pending_cnt].wh_lock = lock;
+ pending_locks[pending_cnt++].wh_type = type;
+ if (pending_cnt > WITNESS_PENDLIST)
+ panic("%s: pending locks list is too small, bump it\n",
+ __func__);
} else
- lock->lo_witness = enroll(lock->lo_type, class);
+ lock->lo_witness = enroll(type, class);
}
void
@@ -707,28 +707,15 @@ witness_destroy(struct lock_object *lock)
class->lc_name, lock->lo_name);
/* XXX: need to verify that no one holds the lock */
- if ((lock->lo_flags & (LO_WITNESS | LO_ENROLLPEND)) == LO_WITNESS &&
- lock->lo_witness != NULL) {
+ if ((lock->lo_flags & LO_WITNESS) && lock->lo_witness != NULL) {
w = lock->lo_witness;
mtx_lock_spin(&w_mtx);
MPASS(w->w_refcount > 0);
w->w_refcount--;
- /*
- * Lock is already released if we have an allocation failure
- * and depart() fails.
- */
- if (w->w_refcount != 0 || depart(w))
- mtx_unlock_spin(&w_mtx);
- }
-
- /*
- * 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;
+ if (w->w_refcount == 0)
+ depart(w);
+ mtx_unlock_spin(&w_mtx);
}
}
@@ -925,7 +912,7 @@ witness_defineorder(struct lock_object *lock1, struct lock_object *lock2)
/* Try to add the new order. */
CTR3(KTR_WITNESS, "%s: adding %s as a child of %s", __func__,
- lock2->lo_type, lock1->lo_type);
+ lock2->lo_witness->w_name, lock1->lo_witness->w_name);
if (!itismychild(lock1->lo_witness, lock2->lo_witness))
return (ENOMEM);
mtx_unlock_spin(&w_mtx);
@@ -1034,7 +1021,7 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file,
return;
w->w_same_squawked = 1;
printf("acquiring duplicate lock of same type: \"%s\"\n",
- lock->lo_type);
+ w->w_name);
printf(" 1st %s @ %s:%d\n", lock1->li_lock->lo_name,
lock1->li_file, lock1->li_line);
printf(" 2nd %s @ %s:%d\n", lock->lo_name, file, line);
@@ -1164,21 +1151,19 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file,
if (i < 0) {
printf(" 1st %p %s (%s) @ %s:%d\n",
lock1->li_lock, lock1->li_lock->lo_name,
- lock1->li_lock->lo_type, lock1->li_file,
- lock1->li_line);
+ w1->w_name, lock1->li_file, lock1->li_line);
printf(" 2nd %p %s (%s) @ %s:%d\n", lock,
- lock->lo_name, lock->lo_type, file, line);
+ lock->lo_name, w->w_name, file, line);
} else {
printf(" 1st %p %s (%s) @ %s:%d\n",
lock2->li_lock, lock2->li_lock->lo_name,
- lock2->li_lock->lo_type, lock2->li_file,
- lock2->li_line);
+ lock2->li_lock->lo_witness->w_name,
+ lock2->li_file, lock2->li_line);
printf(" 2nd %p %s (%s) @ %s:%d\n",
lock1->li_lock, lock1->li_lock->lo_name,
- lock1->li_lock->lo_type, lock1->li_file,
- lock1->li_line);
+ w1->w_name, lock1->li_file, lock1->li_line);
printf(" 3rd %p %s (%s) @ %s:%d\n", lock,
- lock->lo_name, lock->lo_type, file, line);
+ lock->lo_name, w->w_name, file, line);
}
#ifdef KDB
goto debugger;
@@ -1198,7 +1183,7 @@ witness_checkorder(struct lock_object *lock, int flags, const char *file,
!(lock1->li_lock == &Giant.lock_object &&
(lock->lo_flags & LO_SLEEPABLE) != 0)) {
CTR3(KTR_WITNESS, "%s: adding %s as a child of %s", __func__,
- lock->lo_type, lock1->li_lock->lo_type);
+ w->w_name, lock1->li_lock->lo_witness->w_name);
if (!itismychild(lock1->li_lock->lo_witness, w))
/* Witness is dead. */
return;
@@ -1533,8 +1518,10 @@ enroll(const char *description, struct lock_class *lock_class)
return (w);
}
}
- if ((w = witness_get()) == NULL)
+ if ((w = witness_get()) == NULL) {
+ printf("WITNESS: unable to allocate a new witness object\n");
goto out;
+ }
w->w_name = description;
w->w_class = lock_class;
w->w_refcount = 1;
@@ -1567,7 +1554,7 @@ out:
}
/* Don't let the door bang you on the way out... */
-static int
+static void
depart(struct witness *w)
{
struct witness_child_list_entry *wcl, *nwcl;
@@ -1610,8 +1597,6 @@ depart(struct witness *w)
STAILQ_REMOVE(list, w, witness, w_typelist);
STAILQ_REMOVE(&w_all, w, witness, w_list);
witness_free(w);
-
- return (1);
}
/*
@@ -1646,7 +1631,6 @@ insertchild(struct witness *parent, struct witness *child)
static int
itismychild(struct witness *parent, struct witness *child)
{
- struct witness_list *list;
MPASS(child != NULL && parent != NULL);
if ((parent->w_class->lc_flags & (LC_SLEEPLOCK | LC_SPINLOCK)) !=
@@ -1656,14 +1640,7 @@ itismychild(struct witness *parent, struct witness *child)
__func__, parent->w_class->lc_name,
child->w_class->lc_name);
- if (!insertchild(parent, child))
- return (0);
-
- if (parent->w_class->lc_flags & LC_SLEEPLOCK)
- list = &w_sleep;
- else
- list = &w_spin;
- return (1);
+ return (insertchild(parent, child));
}
static void
@@ -1864,8 +1841,8 @@ witness_list_lock(struct lock_instance *instance)
lock = instance->li_lock;
printf("%s %s %s", (instance->li_flags & LI_EXCLUSIVE) != 0 ?
"exclusive" : "shared", LOCK_CLASS(lock)->lc_name, lock->lo_name);
- if (lock->lo_type != lock->lo_name)
- printf(" (%s)", lock->lo_type);
+ if (lock->lo_witness->w_name != lock->lo_name)
+ printf(" (%s)", lock->lo_witness->w_name);
printf(" r = %d (%p) locked @ %s:%d\n",
instance->li_flags & LI_RECURSEMASK, lock, instance->li_file,
instance->li_line);
OpenPOWER on IntegriCloud