git: 02ea6033020e - main - LinuxKPI: Allow spin_lock_irqsave to be called within a critical section

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Tue, 18 Jan 2022 20:15:36 UTC
The branch main has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=02ea6033020e11afec6472bf560b0ddebd0fa97a

commit 02ea6033020e11afec6472bf560b0ddebd0fa97a
Author:     Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2022-01-18 20:14:12 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2022-01-18 20:14:12 +0000

    LinuxKPI: Allow spin_lock_irqsave to be called within a critical section
    
    with spinning on spin_trylock. dma-buf part of drm-kmod depends on this
    property and absence of it support results in "mi_switch: switch in a
    critical section" assertions [1][2].
    
    [1] https://github.com/freebsd/drm-kmod/issues/116
    [2] https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=261166
    
    MFC after:      1 week
    Reviewed by:    manu
    Differential Revision:  https://reviews.freebsd.org/D33887
---
 .../linuxkpi/common/include/linux/spinlock.h       | 27 ++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/spinlock.h b/sys/compat/linuxkpi/common/include/linux/spinlock.h
index a87cb7180b28..31d47fa73986 100644
--- a/sys/compat/linuxkpi/common/include/linux/spinlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/spinlock.h
@@ -37,6 +37,7 @@
 #include <sys/lock.h>
 #include <sys/mutex.h>
 #include <sys/kdb.h>
+#include <sys/proc.h>
 
 #include <linux/compiler.h>
 #include <linux/rwlock.h>
@@ -117,14 +118,32 @@ typedef struct {
 	local_bh_disable();			\
 } while (0)
 
-#define	spin_lock_irqsave(_l, flags) do {	\
-	(flags) = 0;				\
-	spin_lock(_l);				\
+#define	__spin_trylock_nested(_l, _n) ({		\
+	int __ret;					\
+	if (SPIN_SKIP()) {				\
+		__ret = 1;				\
+	} else {					\
+		__ret = mtx_trylock_flags(&(_l)->m, MTX_DUPOK);	\
+		if (likely(__ret != 0))			\
+			local_bh_disable();		\
+	}						\
+	__ret;						\
+})
+
+#define	spin_lock_irqsave(_l, flags) do {		\
+	(flags) = 0;					\
+	if (unlikely(curthread->td_critnest != 0))	\
+		while (!spin_trylock(_l)) {}		\
+	else						\
+		spin_lock(_l);				\
 } while (0)
 
 #define	spin_lock_irqsave_nested(_l, flags, _n) do {	\
 	(flags) = 0;					\
-	spin_lock_nested(_l, _n);			\
+	if (unlikely(curthread->td_critnest != 0))	\
+		while (!__spin_trylock_nested(_l, _n)) {}	\
+	else						\
+		spin_lock_nested(_l, _n);		\
 } while (0)
 
 #define	spin_unlock_irqrestore(_l, flags) do {		\