-/*****************************************************************************\
+/*
* Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
* Copyright (C) 2007 The Regents of the University of California.
* Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
*
* You should have received a copy of the GNU General Public License along
* with the SPL. If not, see <http://www.gnu.org/licenses/>.
-\*****************************************************************************/
+ */
#ifndef _SPL_RWSEM_COMPAT_H
-#define _SPL_RWSEM_COMPAT_H
+#define _SPL_RWSEM_COMPAT_H
#include <linux/rwsem.h>
-#if defined(RWSEM_SPINLOCK_IS_RAW)
-#define spl_rwsem_lock_irqsave(lk, fl) raw_spin_lock_irqsave(lk, fl)
-#define spl_rwsem_unlock_irqrestore(lk, fl) raw_spin_unlock_irqrestore(lk, fl)
-#define spl_rwsem_trylock_irqsave(lk, fl) raw_spin_trylock_irqsave(lk, fl)
+#if defined(CONFIG_PREEMPT_RT_FULL)
+#define SPL_RWSEM_SINGLE_READER_VALUE (1)
+#define SPL_RWSEM_SINGLE_WRITER_VALUE (0)
+#elif defined(CONFIG_RWSEM_GENERIC_SPINLOCK)
+#define SPL_RWSEM_SINGLE_READER_VALUE (1)
+#define SPL_RWSEM_SINGLE_WRITER_VALUE (-1)
#else
-#define spl_rwsem_lock_irqsave(lk, fl) spin_lock_irqsave(lk, fl)
-#define spl_rwsem_unlock_irqrestore(lk, fl) spin_unlock_irqrestore(lk, fl)
-#define spl_rwsem_trylock_irqsave(lk, fl) spin_trylock_irqsave(lk, fl)
-#endif /* RWSEM_SPINLOCK_IS_RAW */
+#define SPL_RWSEM_SINGLE_READER_VALUE (RWSEM_ACTIVE_READ_BIAS)
+#define SPL_RWSEM_SINGLE_WRITER_VALUE (RWSEM_ACTIVE_WRITE_BIAS)
+#endif
-/*
- * Prior to Linux 2.6.33 there existed a race condition in rwsem_is_locked().
- * The semaphore's activity was checked outside of the wait_lock which
- * could result in some readers getting the incorrect activity value.
- *
- * When a kernel without this fix is detected the SPL takes responsibility
- * for acquiring the wait_lock to avoid this race.
- */
-#if defined(RWSEM_IS_LOCKED_TAKES_WAIT_LOCK)
-#define spl_rwsem_is_locked(rwsem) rwsem_is_locked(rwsem)
+/* Linux 3.16 changed activity to count for rwsem-spinlock */
+#if defined(CONFIG_PREEMPT_RT_FULL)
+#define RWSEM_COUNT(sem) sem->read_depth
+#elif defined(HAVE_RWSEM_ACTIVITY)
+#define RWSEM_COUNT(sem) sem->activity
+/* Linux 4.8 changed count to an atomic_long_t for !rwsem-spinlock */
+#elif defined(HAVE_RWSEM_ATOMIC_LONG_COUNT)
+#define RWSEM_COUNT(sem) atomic_long_read(&(sem)->count)
#else
-static inline int
-spl_rwsem_is_locked(struct rw_semaphore *rwsem)
-{
- unsigned long flags;
- int rc = 1;
+#define RWSEM_COUNT(sem) sem->count
+#endif
+
+int rwsem_tryupgrade(struct rw_semaphore *rwsem);
- if (spl_rwsem_trylock_irqsave(&rwsem->wait_lock, flags)) {
- rc = rwsem_is_locked(rwsem);
- spl_rwsem_unlock_irqrestore(&rwsem->wait_lock, flags);
- }
+#if defined(RWSEM_SPINLOCK_IS_RAW)
+#define spl_rwsem_lock_irqsave(lk, fl) raw_spin_lock_irqsave(lk, fl)
+#define spl_rwsem_unlock_irqrestore(lk, fl) \
+ raw_spin_unlock_irqrestore(lk, fl)
+#define spl_rwsem_trylock_irqsave(lk, fl) raw_spin_trylock_irqsave(lk, fl)
+#else
+#define spl_rwsem_lock_irqsave(lk, fl) spin_lock_irqsave(lk, fl)
+#define spl_rwsem_unlock_irqrestore(lk, fl) spin_unlock_irqrestore(lk, fl)
+#define spl_rwsem_trylock_irqsave(lk, fl) spin_trylock_irqsave(lk, fl)
+#endif /* RWSEM_SPINLOCK_IS_RAW */
- return (rc);
-}
-#endif /* RWSEM_IS_LOCKED_TAKES_WAIT_LOCK */
+#define spl_rwsem_is_locked(rwsem) rwsem_is_locked(rwsem)
#endif /* _SPL_RWSEM_COMPAT_H */