summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config/spl-build.m417
-rwxr-xr-xconfigure82
-rw-r--r--include/linux/rwsem_compat.h63
-rw-r--r--include/sys/rwlock.h38
-rw-r--r--spl_config.h.in3
5 files changed, 172 insertions, 31 deletions
diff --git a/config/spl-build.m4 b/config/spl-build.m4
index facaf7404..0b9f8f430 100644
--- a/config/spl-build.m4
+++ b/config/spl-build.m4
@@ -77,6 +77,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
SPL_AC_5ARGS_PROC_HANDLER
SPL_AC_KVASPRINTF
SPL_AC_3ARGS_FILE_FSYNC
+ SPL_AC_EXPORTED_RWSEM_IS_LOCKED
])
AC_DEFUN([SPL_AC_MODULE_SYMVERS], [
@@ -1598,3 +1599,19 @@ AC_DEFUN([SPL_AC_3ARGS_FILE_FSYNC], [
AC_MSG_RESULT(no)
])
])
+
+dnl #
+dnl # 2.6.33 API change. Also backported in RHEL5 as of 2.6.18-190.el5.
+dnl # Earlier versions of rwsem_is_locked() were inline and had a race
+dnl # condition. The fixed version is exported as a symbol. The race
+dnl # condition is fixed by acquiring sem->wait_lock, so we must not
+dnl # call that version while holding sem->wait_lock.
+dnl #
+AC_DEFUN([SPL_AC_EXPORTED_RWSEM_IS_LOCKED], [
+ SPL_CHECK_SYMBOL_EXPORT(
+ [rwsem_is_locked],
+ [lib/rwsem-spinlock.c],
+ [AC_DEFINE(RWSEM_IS_LOCKED_TAKES_WAIT_LOCK, 1,
+ [rwsem_is_locked() acquires sem->wait_lock])],
+ [])
+])
diff --git a/configure b/configure
index bcef31e47..285c9a434 100755
--- a/configure
+++ b/configure
@@ -15130,6 +15130,47 @@ fi
+
+ { $as_echo "$as_me:$LINENO: checking whether symbol rwsem_is_locked is exported" >&5
+$as_echo_n "checking whether symbol rwsem_is_locked is exported... " >&6; }
+ grep -q -E '[[:space:]]rwsem_is_locked[[:space:]]' \
+ $LINUX_OBJ/Module*.symvers 2>/dev/null
+ rc=$?
+ if test $rc -ne 0; then
+ export=0
+ for file in lib/rwsem-spinlock.c; do
+ grep -q -E "EXPORT_SYMBOL.*(rwsem_is_locked)" \
+ "$LINUX_OBJ/$file" 2>/dev/null
+ rc=$?
+ if test $rc -eq 0; then
+ export=1
+ break;
+ fi
+ done
+ if test $export -eq 0; then
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+
+ else
+ { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define RWSEM_IS_LOCKED_TAKES_WAIT_LOCK 1
+_ACEOF
+
+ fi
+ else
+ { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define RWSEM_IS_LOCKED_TAKES_WAIT_LOCK 1
+_ACEOF
+
+ fi
+
+
;;
user)
@@ -18643,6 +18684,47 @@ fi
+ { $as_echo "$as_me:$LINENO: checking whether symbol rwsem_is_locked is exported" >&5
+$as_echo_n "checking whether symbol rwsem_is_locked is exported... " >&6; }
+ grep -q -E '[[:space:]]rwsem_is_locked[[:space:]]' \
+ $LINUX_OBJ/Module*.symvers 2>/dev/null
+ rc=$?
+ if test $rc -ne 0; then
+ export=0
+ for file in lib/rwsem-spinlock.c; do
+ grep -q -E "EXPORT_SYMBOL.*(rwsem_is_locked)" \
+ "$LINUX_OBJ/$file" 2>/dev/null
+ rc=$?
+ if test $rc -eq 0; then
+ export=1
+ break;
+ fi
+ done
+ if test $export -eq 0; then
+ { $as_echo "$as_me:$LINENO: result: no" >&5
+$as_echo "no" >&6; }
+
+ else
+ { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define RWSEM_IS_LOCKED_TAKES_WAIT_LOCK 1
+_ACEOF
+
+ fi
+ else
+ { $as_echo "$as_me:$LINENO: result: yes" >&5
+$as_echo "yes" >&6; }
+
+cat >>confdefs.h <<\_ACEOF
+#define RWSEM_IS_LOCKED_TAKES_WAIT_LOCK 1
+_ACEOF
+
+ fi
+
+
+
if test "x$AWK" != xgawk; then
diff --git a/include/linux/rwsem_compat.h b/include/linux/rwsem_compat.h
new file mode 100644
index 000000000..67a82bb44
--- /dev/null
+++ b/include/linux/rwsem_compat.h
@@ -0,0 +1,63 @@
+/*****************************************************************************\
+ * 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).
+ * Written by Brian Behlendorf <[email protected]>.
+ * UCRL-CODE-235197
+ *
+ * This file is part of the SPL, Solaris Porting Layer.
+ * For details, see <http://github.com/behlendorf/spl/>.
+ *
+ * The SPL is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * The SPL is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * 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
+
+#include <linux/rwsem.h>
+
+#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:
+ *
+ * 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.
+ */
+
+#define spl_rwsem_is_locked(rwsem) \
+({ \
+ rwsem_is_locked(rwsem); \
+})
+
+#else
+
+#define spl_rwsem_is_locked(rwsem) \
+({ \
+ unsigned long _flags_; \
+ int _rc_; \
+ spin_lock_irqsave(&rwsem->wait_lock, _flags_); \
+ _rc_ = rwsem_is_locked(rwsem); \
+ spin_unlock_irqrestore(&rwsem->wait_lock, _flags_); \
+ _rc_; \
+})
+
+#endif /* RWSEM_IS_LOCKED_TAKES_WAIT_LOCK */
+
+#endif /* _SPL_RWSEM_COMPAT_H */
diff --git a/include/sys/rwlock.h b/include/sys/rwlock.h
index eb763ec78..3d9808599 100644
--- a/include/sys/rwlock.h
+++ b/include/sys/rwlock.h
@@ -27,6 +27,7 @@
#include <sys/types.h>
#include <linux/rwsem.h>
+#include <linux/rwsem_compat.h>
typedef enum {
RW_DRIVER = 2,
@@ -46,12 +47,6 @@ typedef struct {
#define SEM(rwp) ((struct rw_semaphore *)(rwp))
-static inline kthread_t *
-spl_rw_get_owner(krwlock_t *rwp)
-{
- return rwp->rw_owner;
-}
-
static inline void
spl_rw_set_owner(krwlock_t *rwp)
{
@@ -79,7 +74,7 @@ rw_owner(krwlock_t *rwp)
kthread_t *owner;
spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
- owner = spl_rw_get_owner(rwp);
+ owner = rwp->rw_owner;
spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
return owner;
@@ -88,40 +83,21 @@ rw_owner(krwlock_t *rwp)
static inline int
RW_READ_HELD(krwlock_t *rwp)
{
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
- rc = (rwsem_is_locked(SEM(rwp)) && spl_rw_get_owner(rwp) == NULL);
- spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
-
- return rc;
+ return (spl_rwsem_is_locked(SEM(rwp)) &&
+ rw_owner(rwp) == NULL);
}
static inline int
RW_WRITE_HELD(krwlock_t *rwp)
{
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
- rc = (rwsem_is_locked(SEM(rwp)) && spl_rw_get_owner(rwp) == current);
- spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
-
- return rc;
+ return (spl_rwsem_is_locked(SEM(rwp)) &&
+ rw_owner(rwp) == current);
}
static inline int
RW_LOCK_HELD(krwlock_t *rwp)
{
- unsigned long flags;
- int rc;
-
- spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
- rc = rwsem_is_locked(SEM(rwp));
- spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
-
- return rc;
+ return spl_rwsem_is_locked(SEM(rwp));
}
/*
diff --git a/spl_config.h.in b/spl_config.h.in
index 8d57a63ea..d3928f4ba 100644
--- a/spl_config.h.in
+++ b/spl_config.h.in
@@ -229,6 +229,9 @@
/* Define to the version of this package. */
#undef PACKAGE_VERSION
+/* rwsem_is_locked() acquires sem->wait_lock */
+#undef RWSEM_IS_LOCKED_TAKES_WAIT_LOCK
+
/* Define the project alias string. */
#undef SPL_META_ALIAS