git: 41959beeae1f - stable/13 - Add witness_is_owned(9)

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 16 Apr 2023 10:57:41 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=41959beeae1f463ab0421510cb28f6d77e57a61a

commit 41959beeae1f463ab0421510cb28f6d77e57a61a
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-04-10 15:54:58 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2023-04-16 10:45:58 +0000

    Add witness_is_owned(9)
    
    (cherry picked from commit 75fc6f86c38807f1fb305c065c6affcf7617b029)
---
 sys/kern/subr_witness.c | 58 ++++++++++++++++++++++++++++++++++++++++---------
 sys/sys/lock.h          |  1 +
 2 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/sys/kern/subr_witness.c b/sys/kern/subr_witness.c
index c849a191bf16..fe2e11c3bea5 100644
--- a/sys/kern/subr_witness.c
+++ b/sys/kern/subr_witness.c
@@ -2425,6 +2425,32 @@ witness_restore(struct lock_object *lock, const char *file, int line)
 	instance->li_line = line;
 }
 
+static bool
+witness_find_instance(const struct lock_object *lock,
+    struct lock_instance **instance)
+{
+#ifdef INVARIANT_SUPPORT
+	struct lock_class *class;
+
+	if (lock->lo_witness == NULL || witness_watch < 1 || KERNEL_PANICKED())
+		return (false);
+	class = LOCK_CLASS(lock);
+	if ((class->lc_flags & LC_SLEEPLOCK) != 0) {
+		*instance = find_instance(curthread->td_sleeplocks, lock);
+		return (true);
+	} else if ((class->lc_flags & LC_SPINLOCK) != 0) {
+		*instance = find_instance(PCPU_GET(spinlocks), lock);
+		return (true);
+	} else {
+		kassert_panic("Lock (%s) %s is not sleep or spin!",
+		    class->lc_name, lock->lo_name);
+		return (false);
+	}
+#else
+	return (false);
+#endif
+}
+
 void
 witness_assert(const struct lock_object *lock, int flags, const char *file,
     int line)
@@ -2433,18 +2459,9 @@ witness_assert(const struct lock_object *lock, int flags, const char *file,
 	struct lock_instance *instance;
 	struct lock_class *class;
 
-	if (lock->lo_witness == NULL || witness_watch < 1 || KERNEL_PANICKED())
+	if (!witness_find_instance(lock, &instance))
 		return;
 	class = LOCK_CLASS(lock);
-	if ((class->lc_flags & LC_SLEEPLOCK) != 0)
-		instance = find_instance(curthread->td_sleeplocks, lock);
-	else if ((class->lc_flags & LC_SPINLOCK) != 0)
-		instance = find_instance(PCPU_GET(spinlocks), lock);
-	else {
-		kassert_panic("Lock (%s) %s is not sleep or spin!",
-		    class->lc_name, lock->lo_name);
-		return;
-	}
 	switch (flags) {
 	case LA_UNLOCKED:
 		if (instance != NULL)
@@ -2497,6 +2514,27 @@ witness_assert(const struct lock_object *lock, int flags, const char *file,
 #endif	/* INVARIANT_SUPPORT */
 }
 
+/*
+ * Checks the ownership of the lock by curthread, consulting the witness list.
+ * Returns:
+ *   0  if witness is disabled or did not work
+ *   -1 if not owned
+ *   1  if owned
+ */
+int
+witness_is_owned(const struct lock_object *lock)
+{
+#ifdef INVARIANT_SUPPORT
+	struct lock_instance *instance;
+
+	if (!witness_find_instance(lock, &instance))
+		return (0);
+	return (instance == NULL ? -1 : 1);
+#else
+	return (0);
+#endif
+}
+
 static void
 witness_setflag(struct lock_object *lock, int flag, int set)
 {
diff --git a/sys/sys/lock.h b/sys/sys/lock.h
index 2db38f9df89a..4031f20946c0 100644
--- a/sys/sys/lock.h
+++ b/sys/sys/lock.h
@@ -237,6 +237,7 @@ int	witness_list_locks(struct lock_list_entry **,
 	    int (*)(const char *, ...));
 int	witness_warn(int, struct lock_object *, const char *, ...);
 void	witness_assert(const struct lock_object *, int, const char *, int);
+int	witness_is_owned(const struct lock_object *lock);
 void	witness_display_spinlock(struct lock_object *, struct thread *,
 	    int (*)(const char *, ...));
 int	witness_line(struct lock_object *);