]> git.proxmox.com Git - mirror_spl-debian.git/blobdiff - include/linux/rwsem_compat.h
Optimize spl_rwsem_is_locked()
[mirror_spl-debian.git] / include / linux / rwsem_compat.h
index fe69f01548df42e97e0c0a7d8344fb8e4c885ee9..757bb42af8c375b89f65cd30bf0699f3d24072cd 100644 (file)
 
 #include <linux/rwsem.h>
 
-#ifdef RWSEM_SPINLOCK_IS_RAW
-#define spl_rwsem_lock_irqsave(lock, flags)       \
-({                                                \
-       raw_spin_lock_irqsave(lock, flags);       \
-})
-#define spl_rwsem_unlock_irqrestore(lock, flags)  \
-({                                                \
-       raw_spin_unlock_irqrestore(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(lock, flags)       \
-({                                                \
-       spin_lock_irqsave(lock, flags);           \
-})
-#define spl_rwsem_unlock_irqrestore(lock, flags)  \
-({                                                \
-       spin_unlock_irqrestore(lock, flags);      \
-})
+#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 */
 
-#ifdef RWSEM_IS_LOCKED_TAKES_WAIT_LOCK
 /*
- * A race condition in rwsem_is_locked() was fixed in Linux 2.6.33 and the fix
- * was backported to RHEL5 as of kernel 2.6.18-190.el5.  Details can be found
- * here:
+ * 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.
  *
- * https://bugzilla.redhat.com/show_bug.cgi?id=526092
-
- * The race condition was fixed in the kernel by acquiring the semaphore's
- * wait_lock inside rwsem_is_locked().  The SPL worked around the race
- * condition by acquiring the wait_lock before calling that function, but
- * with the fix in place we must not do that.
+ * When a kernel without this fix is detected the SPL takes responsibility
+ * for acquiring the wait_lock to avoid this race.
  */
-
-#define spl_rwsem_is_locked(rwsem)                                     \
-({                                                                     \
-       rwsem_is_locked(rwsem);                                         \
-})
-
+#if defined(RWSEM_IS_LOCKED_TAKES_WAIT_LOCK)
+#define spl_rwsem_is_locked(rwsem)           rwsem_is_locked(rwsem)
 #else
+static inline int
+spl_rwsem_is_locked(struct rw_semaphore *rwsem)
+{
+       unsigned long flags;
+       int rc = 1;
 
-#define spl_rwsem_is_locked(rwsem)                                \
-({                                                                \
-       unsigned long _flags_;                                    \
-       int _rc_;                                                 \
-       spl_rwsem_lock_irqsave(&rwsem->wait_lock, _flags_);       \
-       _rc_ = rwsem_is_locked(rwsem);                            \
-       spl_rwsem_unlock_irqrestore(&rwsem->wait_lock, _flags_);  \
-       _rc_;                                                     \
-})
+       if (spl_rwsem_trylock_irqsave(&rwsem->wait_lock, flags)) {
+               rc = rwsem_is_locked(rwsem);
+               spl_rwsem_unlock_irqrestore(&rwsem->wait_lock, flags);
+       }
 
+       return (rc);
+}
 #endif /* RWSEM_IS_LOCKED_TAKES_WAIT_LOCK */
 
 #endif /* _SPL_RWSEM_COMPAT_H */