From 75fc6f86c38807f1fb305c065c6affcf7617b029 Mon Sep 17 00:00:00 2001 From: Konstantin Belousov Date: Mon, 10 Apr 2023 18:54:58 +0300 Subject: [PATCH] Add witness_is_owned(9) which returns an indicator if the current thread owns the specified lock. Reviewed by: jah, markj Tested by: pho Sponsored by: The FreeBSD Foundation MFC after: 1 week Differential revision: https://reviews.freebsd.org/D39477 --- 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 97f68c812a76..839e4a4ce54b 100644 --- a/sys/kern/subr_witness.c +++ b/sys/kern/subr_witness.c @@ -2429,6 +2429,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) @@ -2437,18 +2463,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) @@ -2501,6 +2518,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 *);