summaryrefslogtreecommitdiffstats
path: root/sys/kern
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2003-03-24 21:03:53 +0000
committerjhb <jhb@FreeBSD.org>2003-03-24 21:03:53 +0000
commit966c72c3455be2bc91181aa09b807b58a8b4deb9 (patch)
treeb9dfa84319d09ada516aa5ba270aaf4d10054b02 /sys/kern
parentfd221086efb2f2aa47c70b46fea051fd850215e6 (diff)
downloadFreeBSD-src-966c72c3455be2bc91181aa09b807b58a8b4deb9.zip
FreeBSD-src-966c72c3455be2bc91181aa09b807b58a8b4deb9.tar.gz
- Remove witness_dead and just use witness_watch instead. If witness_watch
is set to 0, it now has the same affect as setting witness_dead used to have. - Added a sysctl handler that allows root to change witness_watch from a non-zero value to zero to disable witness at runtime. Note that you can't turn witness back on once it is off. You can only turn it off as a one-way switch. - Added a comment describing the possible values of witness_watch.
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/subr_witness.c72
1 files changed, 51 insertions, 21 deletions
diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c
index d22d964..94c9390 100644
--- a/sys/kern/subr_witness.c
+++ b/sys/kern/subr_witness.c
@@ -166,6 +166,7 @@ static int rebalancetree(struct witness_list *list);
static void removechild(struct witness *parent, struct witness *child);
static int reparentchildren(struct witness *newparent,
struct witness *oldparent);
+static int sysctl_debug_witness_watch(SYSCTL_HANDLER_ARGS);
static void witness_displaydescendants(void(*)(const char *fmt, ...),
struct witness *, int indent);
static const char *fixup_filename(const char *file);
@@ -189,9 +190,19 @@ static void witness_display(void(*)(const char *fmt, ...));
MALLOC_DEFINE(M_WITNESS, "witness", "witness structure");
+/*
+ * If set to 0, witness is disabled. If set to 1, witness performs full lock
+ * order checking for all locks. If set to 2 or higher, then witness skips
+ * the full lock order check if the lock being acquired is at a higher level
+ * (i.e. farther down in the tree) than the current lock. This last mode is
+ * somewhat experimental and not considered fully safe. At runtime, this
+ * value may be set to 0 to turn off witness. witness is not allowed be
+ * turned on once it is turned off, however.
+ */
static int witness_watch = 1;
TUNABLE_INT("debug.witness_watch", &witness_watch);
-SYSCTL_INT(_debug, OID_AUTO, witness_watch, CTLFLAG_RD, &witness_watch, 0, "");
+SYSCTL_PROC(_debug, OID_AUTO, witness_watch, CTLFLAG_RW | CTLTYPE_INT, NULL, 0,
+ sysctl_debug_witness_watch, "I", "witness is watching lock operations");
#ifdef DDB
/*
@@ -235,7 +246,6 @@ 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 int witness_dead; /* fatal error, probably no memory */
static struct witness w_data[WITNESS_COUNT];
static struct witness_child_list_entry w_childdata[WITNESS_CHILDCOUNT];
@@ -406,6 +416,26 @@ witness_initialize(void *dummy __unused)
}
SYSINIT(witness_init, SI_SUB_WITNESS, SI_ORDER_FIRST, witness_initialize, NULL)
+static int
+sysctl_debug_witness_watch(SYSCTL_HANDLER_ARGS)
+{
+ int error, value;
+
+ value = witness_watch;
+ error = sysctl_handle_int(oidp, &value, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ error = suser(req->td);
+ if (error != 0)
+ return (error);
+ if (value == witness_watch)
+ return (0);
+ if (value != 0)
+ return (EINVAL);
+ witness_watch = 0;
+ return (0);
+}
+
void
witness_init(struct lock_object *lock)
{
@@ -435,7 +465,7 @@ witness_init(struct lock_object *lock)
if (lock_cur_cnt > lock_max_cnt)
lock_max_cnt = lock_cur_cnt;
mtx_unlock(&all_mtx);
- if (!witness_cold && !witness_dead && panicstr == NULL &&
+ if (!witness_cold && witness_watch != 0 && panicstr == NULL &&
(lock->lo_flags & LO_WITNESS) != 0)
lock->lo_witness = enroll(lock->lo_type, class);
else
@@ -556,7 +586,7 @@ witness_lock(struct lock_object *lock, int flags, const char *file, int line)
int go_into_ddb = 0;
#endif
- if (witness_cold || witness_dead || lock->lo_witness == NULL ||
+ if (witness_cold || witness_watch == 0 || lock->lo_witness == NULL ||
panicstr != NULL)
return;
w = lock->lo_witness;
@@ -834,7 +864,7 @@ witness_upgrade(struct lock_object *lock, int flags, const char *file, int line)
struct lock_class *class;
KASSERT(!witness_cold, ("%s: witness_cold", __func__));
- if (lock->lo_witness == NULL || witness_dead || panicstr != NULL)
+ if (lock->lo_witness == NULL || witness_watch == 0 || panicstr != NULL)
return;
class = lock->lo_class;
file = fixup_filename(file);
@@ -869,7 +899,7 @@ witness_downgrade(struct lock_object *lock, int flags, const char *file,
struct lock_class *class;
KASSERT(!witness_cold, ("%s: witness_cold", __func__));
- if (lock->lo_witness == NULL || witness_dead || panicstr != NULL)
+ if (lock->lo_witness == NULL || witness_watch == 0 || panicstr != NULL)
return;
class = lock->lo_class;
file = fixup_filename(file);
@@ -903,7 +933,7 @@ witness_unlock(struct lock_object *lock, int flags, const char *file, int line)
register_t s;
int i, j;
- if (witness_cold || witness_dead || lock->lo_witness == NULL ||
+ if (witness_cold || witness_watch == 0 || lock->lo_witness == NULL ||
panicstr != NULL)
return;
td = curthread;
@@ -993,7 +1023,7 @@ witness_warn(int flags, struct lock_object *lock, const char *fmt, ...)
va_list ap;
int i, n;
- if (witness_cold || witness_dead || panicstr != NULL)
+ if (witness_cold || witness_watch == 0 || panicstr != NULL)
return (0);
n = 0;
td = curthread;
@@ -1050,7 +1080,7 @@ witness_file(struct lock_object *lock)
{
struct witness *w;
- if (witness_cold || witness_dead || lock->lo_witness == NULL)
+ if (witness_cold || witness_watch == 0 || lock->lo_witness == NULL)
return ("?");
w = lock->lo_witness;
return (w->w_file);
@@ -1061,7 +1091,7 @@ witness_line(struct lock_object *lock)
{
struct witness *w;
- if (witness_cold || witness_dead || lock->lo_witness == NULL)
+ if (witness_cold || witness_watch == 0 || lock->lo_witness == NULL)
return (0);
w = lock->lo_witness;
return (w->w_line);
@@ -1072,7 +1102,7 @@ enroll(const char *description, struct lock_class *lock_class)
{
struct witness *w;
- if (!witness_watch || witness_dead || panicstr != NULL)
+ if (!witness_watch || witness_watch == 0 || panicstr != NULL)
return (NULL);
if ((lock_class->lc_flags & LC_SPINLOCK) && witness_skipspin)
return (NULL);
@@ -1428,12 +1458,12 @@ witness_get(void)
{
struct witness *w;
- if (witness_dead) {
+ if (witness_watch == 0) {
mtx_unlock_spin(&w_mtx);
return (NULL);
}
if (STAILQ_EMPTY(&w_free)) {
- witness_dead = 1;
+ witness_watch = 0;
mtx_unlock_spin(&w_mtx);
printf("%s: witness exhausted\n", __func__);
return (NULL);
@@ -1456,13 +1486,13 @@ witness_child_get(void)
{
struct witness_child_list_entry *wcl;
- if (witness_dead) {
+ if (witness_watch == 0) {
mtx_unlock_spin(&w_mtx);
return (NULL);
}
wcl = w_child_free;
if (wcl == NULL) {
- witness_dead = 1;
+ witness_watch = 0;
mtx_unlock_spin(&w_mtx);
printf("%s: witness exhausted\n", __func__);
return (NULL);
@@ -1485,12 +1515,12 @@ witness_lock_list_get(void)
{
struct lock_list_entry *lle;
- if (witness_dead)
+ if (witness_watch == 0)
return (NULL);
mtx_lock_spin(&w_mtx);
lle = w_lock_list_free;
if (lle == NULL) {
- witness_dead = 1;
+ witness_watch = 0;
mtx_unlock_spin(&w_mtx);
printf("%s: witness exhausted\n", __func__);
return (NULL);
@@ -1563,7 +1593,7 @@ witness_save(struct lock_object *lock, const char **filep, int *linep)
struct lock_instance *instance;
KASSERT(!witness_cold, ("%s: witness_cold", __func__));
- if (lock->lo_witness == NULL || witness_dead || panicstr != NULL)
+ if (lock->lo_witness == NULL || witness_watch == 0 || panicstr != NULL)
return;
if ((lock->lo_class->lc_flags & LC_SLEEPLOCK) == 0)
panic("%s: lock (%s) %s is not a sleep lock", __func__,
@@ -1582,7 +1612,7 @@ witness_restore(struct lock_object *lock, const char *file, int line)
struct lock_instance *instance;
KASSERT(!witness_cold, ("%s: witness_cold", __func__));
- if (lock->lo_witness == NULL || witness_dead || panicstr != NULL)
+ if (lock->lo_witness == NULL || witness_watch == 0 || panicstr != NULL)
return;
if ((lock->lo_class->lc_flags & LC_SLEEPLOCK) == 0)
panic("%s: lock (%s) %s is not a sleep lock", __func__,
@@ -1603,7 +1633,7 @@ witness_assert(struct lock_object *lock, int flags, const char *file, int line)
#ifdef INVARIANT_SUPPORT
struct lock_instance *instance;
- if (lock->lo_witness == NULL || witness_dead || panicstr != NULL)
+ if (lock->lo_witness == NULL || witness_watch == 0 || panicstr != NULL)
return;
if ((lock->lo_class->lc_flags & LC_SLEEPLOCK) != 0)
instance = find_instance(curthread->td_sleeplocks, lock);
@@ -1667,7 +1697,7 @@ witness_list(struct thread *td)
KASSERT(!witness_cold, ("%s: witness_cold", __func__));
KASSERT(db_active, ("%s: not in the debugger", __func__));
- if (witness_dead)
+ if (witness_watch == 0)
return;
witness_list_locks(&td->td_sleeplocks);
OpenPOWER on IntegriCloud